@taskforcehq/taskforce 0.3.329 → 0.3.330
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/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/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/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 +27 -26
- 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 +48 -1
- package/dist/core/McpTokenService.d.ts +23 -1
- package/dist/core/McpTokenService.js +93 -10
- 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 +32 -0
- package/dist/core/Taskforce.js +125 -4
- package/dist/core/types.d.ts +8 -0
- 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 +10 -0
- package/dist/mcp/httpProtocolRouting.js +19 -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 +384 -97
- package/dist/mcp/taskPlanningRegistrar.js +23 -4
- package/dist/mcp/toolProfiles.d.ts +2 -0
- package/dist/mcp/toolProfiles.js +10 -0
- package/dist/mcp/toolRegistry.d.ts +1 -0
- package/dist/mcp/toolRegistry.js +1 -0
- 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/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 +12 -14
- package/dist/server/routes/admin.d.ts +4 -0
- package/dist/server/routes/admin.js +112 -3
- 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 +19 -0
- package/dist/server/routes/shared.js +95 -19
- 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/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 +126 -0
- package/dist/services/executorPhaseAIssuerCore.js +295 -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 +1 -1
- package/dist/services/taskforceAgentMcpBridge.js +7 -24
- 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 +11 -0
- package/dist/storage/postgresWorker.js +9 -1
- package/dist/storage/postgresWorkerProtocol.d.ts +1 -0
- package/dist/storage/taskforceAgentConnectionBindingStore.d.ts +31 -0
- package/dist/storage/taskforceAgentConnectionBindingStore.js +84 -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/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 +29 -0
- package/dist/sync/syncApplyHandlers.d.ts +2 -0
- package/dist/sync/syncApplyHandlers.js +10 -1
- 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 +11 -0
- package/dist/sync/v3/durableWorkflowRuntimeMutationRouter.js +39 -10
- 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/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/localTaskStatusOutboxService.d.ts +8 -0
- package/dist/sync/v3/localTaskStatusOutboxService.js +219 -12
- package/dist/sync/v3/syncDurabilityStore.d.ts +34 -0
- package/dist/sync/v3/syncDurabilityStore.js +168 -2
- 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/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/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/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/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-OcSz1PkK.js +1 -0
- package/dist/ui/assets/AiProfilesModule-ByhYW5Xi.js +1 -0
- package/dist/ui/assets/{AnnotatedAttachmentWorkspace-B68Wg-RV.js → AnnotatedAttachmentWorkspace-BTM6nIg_.js} +1 -1
- package/dist/ui/assets/{AssetTraySortControl-C8Rztyal.js → AssetTraySortControl-DabEG8L4.js} +1 -1
- package/dist/ui/assets/{ContextAttachmentManager-Cj3c7X9y.js → ContextAttachmentManager-Coa8yVGM.js} +1 -1
- package/dist/ui/assets/{DocumentWorkspace-B5uvzems.js → DocumentWorkspace-BB0qhdix.js} +1 -1
- package/dist/ui/assets/{EntityActivityTimeline-BVFvCB5R.js → EntityActivityTimeline-CZ8x4UJE.js} +1 -1
- package/dist/ui/assets/{PlanningModule-B5DWQOGz.js → PlanningModule-pRPjR7v5.js} +1 -1
- package/dist/ui/assets/{PlansPage-AY4cGWco.js → PlansPage-D86pZSSl.js} +1 -1
- package/dist/ui/assets/{TaskContextUpload-DZxTVesW.js → TaskContextUpload-BVIkU9yT.js} +1 -1
- package/dist/ui/assets/TaskSettings-Cv1mNhv_.js +12 -0
- package/dist/ui/assets/TaskforceAgentsModule-b-8R25cJ.css +1 -0
- package/dist/ui/assets/TaskforceAgentsModule-gmH-PD2q.js +24 -0
- package/dist/ui/assets/{WorkflowManagerModule-DEr5di_r.js → WorkflowManagerModule-DbfnHJ-f.js} +1 -1
- package/dist/ui/assets/index-BZ-hdZSk.css +1 -0
- package/dist/ui/assets/index-CTsDBaef.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 +22 -4
- package/dist/ui/assets/AiIdentityRosterCard-BZM4aQnM.js +0 -1
- package/dist/ui/assets/AiProfilesModule-BbAEWtHH.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';
|
|
@@ -747,6 +746,9 @@ function createOwnedTaskforceMcpCore(projectRoot, tenantId, localDataOwnerPermit
|
|
|
747
746
|
},
|
|
748
747
|
});
|
|
749
748
|
}
|
|
749
|
+
export function createStatelessTaskforceMcpServer(options = {}, factory = createTaskforceMcpServer) {
|
|
750
|
+
return factory({ ...options, resourceSubscriptionMode: 'disabled' });
|
|
751
|
+
}
|
|
750
752
|
export function createTaskforceMcpServer(options = {}) {
|
|
751
753
|
// In dev (tsx), this module lives in src/mcp/.
|
|
752
754
|
// In prod, it lives in dist/mcp/.
|
|
@@ -754,6 +756,9 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
754
756
|
const PROJECT_NAME = path.basename(PROJECT_ROOT);
|
|
755
757
|
const logStartup = options.logStartup !== false;
|
|
756
758
|
const runtimeMode = options.runtimeMode === 'cloud' ? 'cloud' : 'local';
|
|
759
|
+
const modernProtocol = options.protocolEra === 'modern';
|
|
760
|
+
const supportsLegacyResourceSubscriptions = !modernProtocol
|
|
761
|
+
&& options.resourceSubscriptionMode === 'legacy-long-lived';
|
|
757
762
|
const applicationBaseUrl = normalizeTaskforceApplicationBaseUrl(options.applicationBaseUrl)
|
|
758
763
|
|| (runtimeMode === 'cloud'
|
|
759
764
|
? resolveCloudApplicationBaseUrl()
|
|
@@ -836,8 +841,6 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
836
841
|
};
|
|
837
842
|
const operationIdentityScope = options.operationIdentityScope
|
|
838
843
|
? {
|
|
839
|
-
generation: String(options.operationIdentityScope.generation || '').trim(),
|
|
840
|
-
sessionId: String(options.operationIdentityScope.sessionId || '').trim(),
|
|
841
844
|
connectionInstance: String(options.operationIdentityScope.connectionInstance || '').trim(),
|
|
842
845
|
}
|
|
843
846
|
: null;
|
|
@@ -845,7 +848,7 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
845
848
|
throw new Error('Shared MCP operation identity scope is incomplete.');
|
|
846
849
|
}
|
|
847
850
|
const runtimeRequestNamespace = operationIdentityScope
|
|
848
|
-
? fingerprintWorkspaceSyncPayload({ kind: 'shared-mcp-
|
|
851
|
+
? fingerprintWorkspaceSyncPayload({ kind: 'shared-mcp-process', ...operationIdentityScope })
|
|
849
852
|
: runtimeMode === 'cloud'
|
|
850
853
|
? String(options.auth?.requestId || '').trim() || randomUUID()
|
|
851
854
|
: randomUUID();
|
|
@@ -1204,8 +1207,8 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
1204
1207
|
}, {
|
|
1205
1208
|
capabilities: {
|
|
1206
1209
|
resources: {
|
|
1207
|
-
subscribe: true,
|
|
1208
|
-
listChanged: true,
|
|
1210
|
+
...(supportsLegacyResourceSubscriptions ? { subscribe: true } : {}),
|
|
1211
|
+
...(!modernProtocol ? { listChanged: true } : {}),
|
|
1209
1212
|
},
|
|
1210
1213
|
tools: {},
|
|
1211
1214
|
},
|
|
@@ -2225,42 +2228,38 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
2225
2228
|
return null;
|
|
2226
2229
|
return resolved;
|
|
2227
2230
|
}
|
|
2228
|
-
function resolveFinishTaskReviewer(task) {
|
|
2231
|
+
function resolveFinishTaskReviewer(task, reviewer) {
|
|
2232
|
+
if (reviewer !== undefined) {
|
|
2233
|
+
const resolvedReviewer = resolveRuntimeTaskAssigneeInput(reviewer);
|
|
2234
|
+
const actor = resolvedReviewer
|
|
2235
|
+
? core.resolveWorkspaceActor(ACTIVE_WORKSPACE_ID, resolvedReviewer)
|
|
2236
|
+
: null;
|
|
2237
|
+
const eligible = actor?.kind === 'ai'
|
|
2238
|
+
? core.listAiProfiles(ACTIVE_WORKSPACE_ID).some((profile) => profile.id === actor.id)
|
|
2239
|
+
: core.listWorkspaceUsers(ACTIVE_WORKSPACE_ID).some((user) => (user.userId === actor?.id
|
|
2240
|
+
&& String(user.status || '').trim().toLowerCase() === 'active'
|
|
2241
|
+
&& user.disabled !== true));
|
|
2242
|
+
if (!actor || actor.meta?.unresolved === true || !eligible) {
|
|
2243
|
+
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');
|
|
2244
|
+
}
|
|
2245
|
+
return { assignee: actor.id, source: 'explicit' };
|
|
2246
|
+
}
|
|
2229
2247
|
const existingAssignee = String(task?.assignee || '').trim();
|
|
2230
2248
|
if (existingAssignee) {
|
|
2231
2249
|
const existingActor = core.resolveWorkspaceActor(ACTIVE_WORKSPACE_ID, existingAssignee);
|
|
2232
|
-
|
|
2250
|
+
const eligibleExistingHuman = existingActor?.kind === 'human'
|
|
2251
|
+
&& existingActor.meta?.unresolved !== true
|
|
2252
|
+
&& core.listWorkspaceUsers(ACTIVE_WORKSPACE_ID).some((user) => (user.userId === existingActor.id
|
|
2253
|
+
&& String(user.status || '').trim().toLowerCase() === 'active'
|
|
2254
|
+
&& user.disabled !== true));
|
|
2255
|
+
if (eligibleExistingHuman) {
|
|
2233
2256
|
return {
|
|
2234
2257
|
assignee: existingActor.id,
|
|
2235
2258
|
source: 'existing_human_owner',
|
|
2236
2259
|
};
|
|
2237
2260
|
}
|
|
2238
2261
|
}
|
|
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');
|
|
2262
|
+
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
2263
|
}
|
|
2265
2264
|
function getActiveMcpActorRef() {
|
|
2266
2265
|
if (activeAiProfileId)
|
|
@@ -2301,13 +2300,19 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
2301
2300
|
}).task;
|
|
2302
2301
|
}
|
|
2303
2302
|
if (!useStatusBoundary) {
|
|
2304
|
-
return core.updateTask(input.task.id, input.updates, ACTIVE_WORKSPACE_ID, {
|
|
2303
|
+
return core.updateTask(input.task.id, input.updates, ACTIVE_WORKSPACE_ID, {
|
|
2304
|
+
actorRef: getActiveMcpActorRef(),
|
|
2305
|
+
...(input.deferNotifications ? { persistBackup: false, emitRealtime: false } : {}),
|
|
2306
|
+
});
|
|
2305
2307
|
}
|
|
2306
2308
|
const unsupported = Object.keys(input.updates).filter((field) => (!durableStatusControlFields.has(field) && !durableTaskMetadataFieldNames.has(field)));
|
|
2307
2309
|
if (unsupported.length > 0) {
|
|
2308
2310
|
throw new TaskforceRuleError(`Combined durable task status update contains unsupported fields: ${unsupported.sort().join(', ')}.`, 400, 'TASK_STATUS_INVALID_PAYLOAD');
|
|
2309
2311
|
}
|
|
2310
2312
|
const status = String(hasStatus ? input.updates.status : input.task.status || 'task').trim();
|
|
2313
|
+
if (status === 'review' && String(input.task.status || '').trim() !== 'review' && !input.reviewHandoff) {
|
|
2314
|
+
throw new McpPublicError('Moving a task to review requires finish_task with a nonblank evidence comment.', 'TASK_REVIEW_HANDOFF_REQUIRED', 400);
|
|
2315
|
+
}
|
|
2311
2316
|
const metadataPatch = selectDurableTaskMetadataPatch(input.updates);
|
|
2312
2317
|
delete metadataPatch.assignee;
|
|
2313
2318
|
const assigneeIntent = input.assigneeIntent || (Object.prototype.hasOwnProperty.call(input.updates, 'assignee')
|
|
@@ -2322,10 +2327,73 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
2322
2327
|
: null;
|
|
2323
2328
|
return durableTaskMutationRouter.setStatus({
|
|
2324
2329
|
taskId: input.task.id,
|
|
2325
|
-
payload: {
|
|
2330
|
+
payload: {
|
|
2331
|
+
status,
|
|
2332
|
+
assigneeIntent,
|
|
2333
|
+
canceledReason,
|
|
2334
|
+
metadataPatch,
|
|
2335
|
+
...(input.reviewHandoff ? { reviewHandoff: input.reviewHandoff } : {}),
|
|
2336
|
+
},
|
|
2326
2337
|
actorRef: getActiveMcpActorRef(),
|
|
2327
2338
|
}).task;
|
|
2328
2339
|
}
|
|
2340
|
+
function mutateTaskReviewHandoffThroughBoundary(input) {
|
|
2341
|
+
const validation = validateStructuredCommentForAdd(input.handoffComment);
|
|
2342
|
+
if (!validation.ok)
|
|
2343
|
+
throw new McpPublicError(validation.message);
|
|
2344
|
+
const actorRef = getActiveMcpActorRef();
|
|
2345
|
+
const operationId = requireStableMcpRequestId('operation', `review-handoff-comment:${input.task.id}`);
|
|
2346
|
+
const commentId = requireStableMcpRequestId('comment', `review-handoff:${input.task.id}`);
|
|
2347
|
+
const comment = {
|
|
2348
|
+
id: commentId,
|
|
2349
|
+
author: actorRef,
|
|
2350
|
+
submittedAuthor: actorRef,
|
|
2351
|
+
text: input.handoffComment,
|
|
2352
|
+
};
|
|
2353
|
+
if (durableTaskMutationRouter.enabled) {
|
|
2354
|
+
return mutateTaskThroughStatusBoundary({
|
|
2355
|
+
task: input.task,
|
|
2356
|
+
updates: input.updates,
|
|
2357
|
+
assigneeIntent: input.assigneeIntent,
|
|
2358
|
+
reviewHandoff: { comment },
|
|
2359
|
+
});
|
|
2360
|
+
}
|
|
2361
|
+
let updated;
|
|
2362
|
+
try {
|
|
2363
|
+
updated = core.getDatabaseAdapter().transaction(() => {
|
|
2364
|
+
mutateTaskThroughStatusBoundary({
|
|
2365
|
+
task: input.task,
|
|
2366
|
+
updates: input.updates,
|
|
2367
|
+
assigneeIntent: input.assigneeIntent,
|
|
2368
|
+
deferNotifications: true,
|
|
2369
|
+
});
|
|
2370
|
+
const durableRouter = getDurableTaskCommentMutationRouter(actorRef, operationId);
|
|
2371
|
+
const task = durableRouter.enabled
|
|
2372
|
+
? durableRouter.append({
|
|
2373
|
+
taskId: input.task.id,
|
|
2374
|
+
comment: { ...comment, timestamp: new Date().toISOString() },
|
|
2375
|
+
}).task
|
|
2376
|
+
: core.addComment(input.task.id, input.handoffComment, actorRef, ACTIVE_WORKSPACE_ID, {
|
|
2377
|
+
actorRef,
|
|
2378
|
+
persistBackup: false,
|
|
2379
|
+
emitRealtime: false,
|
|
2380
|
+
commentId,
|
|
2381
|
+
});
|
|
2382
|
+
if (!task)
|
|
2383
|
+
throw new Error(`Task ${input.task.id} not found`);
|
|
2384
|
+
return task;
|
|
2385
|
+
})();
|
|
2386
|
+
}
|
|
2387
|
+
catch (error) {
|
|
2388
|
+
try {
|
|
2389
|
+
core.notifyDurableTaskMetadataCommitted(ACTIVE_WORKSPACE_ID, input.task.id);
|
|
2390
|
+
}
|
|
2391
|
+
catch { /* Preserve the original handoff failure. */ }
|
|
2392
|
+
throw error;
|
|
2393
|
+
}
|
|
2394
|
+
core.notifyDurableTaskMetadataCommitted(ACTIVE_WORKSPACE_ID, input.task.id);
|
|
2395
|
+
return updated;
|
|
2396
|
+
}
|
|
2329
2397
|
function mutateTaskLifecycleThroughBoundary(input) {
|
|
2330
2398
|
if (!durableTaskMutationRouter.enabled)
|
|
2331
2399
|
return input.legacy();
|
|
@@ -3706,7 +3774,7 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
3706
3774
|
const hydratedWorkstream = core.getWorkstream(workstream.id, ACTIVE_WORKSPACE_ID) || workstream;
|
|
3707
3775
|
return { id: hydratedWorkstream.id, workstream: hydratedWorkstream };
|
|
3708
3776
|
}
|
|
3709
|
-
server.setRequestHandler(
|
|
3777
|
+
server.setRequestHandler('resources/list', async () => {
|
|
3710
3778
|
const resources = [
|
|
3711
3779
|
{
|
|
3712
3780
|
uri: RESOURCE_CONFIG_URI,
|
|
@@ -3753,7 +3821,7 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
3753
3821
|
resources,
|
|
3754
3822
|
};
|
|
3755
3823
|
});
|
|
3756
|
-
server.setRequestHandler(
|
|
3824
|
+
server.setRequestHandler('resources/templates/list', async () => {
|
|
3757
3825
|
if (!hasPermission(RESOURCE_PERMISSIONS.task)) {
|
|
3758
3826
|
return { resourceTemplates: [] };
|
|
3759
3827
|
}
|
|
@@ -3785,7 +3853,7 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
3785
3853
|
],
|
|
3786
3854
|
};
|
|
3787
3855
|
});
|
|
3788
|
-
server.setRequestHandler(
|
|
3856
|
+
server.setRequestHandler('resources/read', async (request) => {
|
|
3789
3857
|
const uri = request.params.uri;
|
|
3790
3858
|
assertResourcePermission(uri);
|
|
3791
3859
|
if (uri === RESOURCE_CONFIG_URI) {
|
|
@@ -3891,24 +3959,26 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
3891
3959
|
}
|
|
3892
3960
|
throw new Error(`Unknown resource URI: ${uri}`);
|
|
3893
3961
|
});
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3962
|
+
if (supportsLegacyResourceSubscriptions) {
|
|
3963
|
+
server.setRequestHandler('resources/subscribe', async (request) => {
|
|
3964
|
+
const uri = request.params.uri;
|
|
3965
|
+
if (!isSupportedResourceUri(uri)) {
|
|
3966
|
+
throw new Error(`Unsupported resource URI for subscribe: ${uri}`);
|
|
3967
|
+
}
|
|
3968
|
+
assertResourcePermission(uri);
|
|
3969
|
+
resourceSubscriptions.add(uri);
|
|
3970
|
+
return {};
|
|
3971
|
+
});
|
|
3972
|
+
server.setRequestHandler('resources/unsubscribe', async (request) => {
|
|
3973
|
+
const uri = request.params.uri;
|
|
3974
|
+
if (!isSupportedResourceUri(uri)) {
|
|
3975
|
+
throw new Error(`Unsupported resource URI for unsubscribe: ${uri}`);
|
|
3976
|
+
}
|
|
3977
|
+
assertResourcePermission(uri);
|
|
3978
|
+
resourceSubscriptions.delete(uri);
|
|
3979
|
+
return {};
|
|
3980
|
+
});
|
|
3981
|
+
}
|
|
3912
3982
|
/**
|
|
3913
3983
|
* Tool Definitions
|
|
3914
3984
|
*/
|
|
@@ -4024,16 +4094,19 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
4024
4094
|
const tool = registeredTools.find((candidate) => candidate.name === name);
|
|
4025
4095
|
return tool ? materializeToolDescriptor(tool, buildToolDescriptorContext()) : null;
|
|
4026
4096
|
};
|
|
4027
|
-
|
|
4097
|
+
const listTools = async () => {
|
|
4028
4098
|
const context = buildToolDescriptorContext();
|
|
4029
4099
|
const tools = registeredTools
|
|
4030
4100
|
.map((tool) => materializeToolDescriptor(tool, context))
|
|
4031
4101
|
.filter((tool) => (isMcpToolVisibleInProfile(tool.name, activeToolProfile)
|
|
4032
4102
|
&& hasPermission(TOOL_PERMISSIONS[tool.name])));
|
|
4033
4103
|
return {
|
|
4034
|
-
|
|
4104
|
+
// Descriptors are validated by Taskforce's JSON Schema contract before
|
|
4105
|
+
// registration; v2 narrows the equivalent recursive JSON value type.
|
|
4106
|
+
tools: tools,
|
|
4035
4107
|
};
|
|
4036
|
-
}
|
|
4108
|
+
};
|
|
4109
|
+
server.setRequestHandler('tools/list', listTools);
|
|
4037
4110
|
const resolvePlanningAttachmentTarget = (targetType, inputId) => {
|
|
4038
4111
|
if (targetType === 'initiative') {
|
|
4039
4112
|
const { id, initiative } = resolveInitiativeByIdentifierOrThrow(inputId);
|
|
@@ -4953,7 +5026,9 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
4953
5026
|
const taskLifecycleCommandService = createTaskLifecycleCommandService({
|
|
4954
5027
|
formatTaskIdentifier,
|
|
4955
5028
|
resolveAssigneeLabel: (assignee) => core.resolveWorkspaceActor(ACTIVE_WORKSPACE_ID, assignee)?.label || assignee,
|
|
4956
|
-
setStatus: (input) =>
|
|
5029
|
+
setStatus: (input) => input.handoffComment
|
|
5030
|
+
? mutateTaskReviewHandoffThroughBoundary(input)
|
|
5031
|
+
: mutateTaskThroughStatusBoundary(input),
|
|
4957
5032
|
mutateLifecycle: (input) => mutateTaskLifecycleThroughBoundary({
|
|
4958
5033
|
taskId: input.taskId,
|
|
4959
5034
|
mutationKind: input.mutationKind,
|
|
@@ -4973,7 +5048,7 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
4973
5048
|
});
|
|
4974
5049
|
},
|
|
4975
5050
|
}),
|
|
4976
|
-
resolveReviewer: (task) => resolveFinishTaskReviewer(task),
|
|
5051
|
+
resolveReviewer: (task, reviewer) => resolveFinishTaskReviewer(task, reviewer),
|
|
4977
5052
|
});
|
|
4978
5053
|
const planningCommandPreparationService = new PlanningCommandPreparationService({
|
|
4979
5054
|
resolveOwner: resolvePlanningOwnerInput,
|
|
@@ -4986,12 +5061,17 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
4986
5061
|
listItems: (taskId) => core.listChecklistItems(taskId, ACTIVE_WORKSPACE_ID),
|
|
4987
5062
|
createId: (scope, key) => requireStableMcpRequestId(scope, key),
|
|
4988
5063
|
now: () => new Date().toISOString(),
|
|
4989
|
-
replace: ({ taskId, items, operationId }) => {
|
|
5064
|
+
replace: ({ taskId, items, operationId, expectedDetailRevision, requireDurableIdempotency, itemUpdateIntent, }) => {
|
|
4990
5065
|
const actorRef = getActiveMcpActorRef();
|
|
4991
5066
|
const durableRouter = getDurableTaskChecklistMutationRouter(actorRef, operationId);
|
|
5067
|
+
if (requireDurableIdempotency) {
|
|
5068
|
+
requireDurableExplicitIdempotency(durableRouter.enabled, 'task checklist');
|
|
5069
|
+
}
|
|
4992
5070
|
return durableRouter.enabled
|
|
4993
|
-
? durableRouter.replace({ taskId, items }).task
|
|
4994
|
-
:
|
|
5071
|
+
? durableRouter.replace({ taskId, items, expectedDetailRevision, itemUpdateIntent }).task
|
|
5072
|
+
: expectedDetailRevision
|
|
5073
|
+
? core.updateTaskIfDetailRevisionMatches(taskId, expectedDetailRevision, { checklistItems: items }, ACTIVE_WORKSPACE_ID, { actorRef })
|
|
5074
|
+
: core.updateTask(taskId, { checklistItems: items }, ACTIVE_WORKSPACE_ID, { actorRef });
|
|
4995
5075
|
},
|
|
4996
5076
|
});
|
|
4997
5077
|
const annotatedAttachmentCommandService = createAnnotatedAttachmentCommandService({
|
|
@@ -5014,7 +5094,7 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
5014
5094
|
}
|
|
5015
5095
|
function rethrowChecklistCommandError(error) {
|
|
5016
5096
|
if (error instanceof TaskChecklistCommandError) {
|
|
5017
|
-
if (error.code === 'TASK_NOT_FOUND') {
|
|
5097
|
+
if (error.code === 'TASK_NOT_FOUND' || error.code === 'TASK_CHECKLIST_ITEM_NOT_FOUND') {
|
|
5018
5098
|
throw new McpPublicError(error.message, 'MCP_NOT_FOUND', error.statusCode);
|
|
5019
5099
|
}
|
|
5020
5100
|
throw new McpPublicError(error.message);
|
|
@@ -5455,6 +5535,9 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
5455
5535
|
requiresCommentEvidence: step.requiresCommentEvidence,
|
|
5456
5536
|
} : {}),
|
|
5457
5537
|
}));
|
|
5538
|
+
const currentStep = assignment.execution.status === 'running'
|
|
5539
|
+
? assignment.steps.find((step) => step.id === assignment.execution.currentStepId)
|
|
5540
|
+
: undefined;
|
|
5458
5541
|
return {
|
|
5459
5542
|
content: [{ type: 'text', text: JSON.stringify({
|
|
5460
5543
|
task: withTaskUrl({ id: task.id, referenceLabel: formatTaskIdentifier(task), title: task.title }),
|
|
@@ -5466,11 +5549,23 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
5466
5549
|
currentStepId: assignment.execution.currentStepId || null,
|
|
5467
5550
|
steps,
|
|
5468
5551
|
},
|
|
5552
|
+
completionCall: currentStep ? {
|
|
5553
|
+
tool: 'complete_workflow_step',
|
|
5554
|
+
arguments: {
|
|
5555
|
+
taskId,
|
|
5556
|
+
executionId: assignment.execution.id,
|
|
5557
|
+
stepId: currentStep.id,
|
|
5558
|
+
},
|
|
5559
|
+
} : null,
|
|
5469
5560
|
}, null, 2) }],
|
|
5470
5561
|
};
|
|
5471
5562
|
}
|
|
5472
5563
|
case "complete_workflow_step": {
|
|
5473
5564
|
const { taskId, executionId, stepId, evidenceCommentId } = args;
|
|
5565
|
+
const normalizedEvidenceCommentId = evidenceCommentId == null ? undefined : evidenceCommentId;
|
|
5566
|
+
if (areWorkflowRuntimeMutationsFenced()) {
|
|
5567
|
+
throw new McpPublicError('Workflow execution changes are temporarily paused.', 'WORKFLOW_RUNTIME_MUTATIONS_FENCED', 503);
|
|
5568
|
+
}
|
|
5474
5569
|
const { task } = resolveTaskByIdentifierOrThrow(taskId);
|
|
5475
5570
|
ensureResolvedProfileForSessionBootstrap();
|
|
5476
5571
|
const agentProfileId = String(activeAiProfileId || '').trim();
|
|
@@ -5483,7 +5578,7 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
5483
5578
|
throw new McpPublicError('The workflow execution does not belong to this task.', 'WORKFLOW_TASK_MISMATCH', 409);
|
|
5484
5579
|
}
|
|
5485
5580
|
const idempotencyKey = `agent-step-${createHash('sha256')
|
|
5486
|
-
.update(`${executionId}:${stepId}:${agentProfileId}:${String(
|
|
5581
|
+
.update(`${executionId}:${stepId}:${agentProfileId}:${String(normalizedEvidenceCommentId || '')}`)
|
|
5487
5582
|
.digest('hex')
|
|
5488
5583
|
.slice(0, 32)}`;
|
|
5489
5584
|
let result;
|
|
@@ -5505,7 +5600,7 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
5505
5600
|
}).completeStep({
|
|
5506
5601
|
executionId,
|
|
5507
5602
|
expectedStepId: stepId,
|
|
5508
|
-
evidenceCommentId,
|
|
5603
|
+
evidenceCommentId: normalizedEvidenceCommentId,
|
|
5509
5604
|
})
|
|
5510
5605
|
: executionService.completeCurrentStep({
|
|
5511
5606
|
workspaceId: ACTIVE_WORKSPACE_ID,
|
|
@@ -5513,7 +5608,7 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
5513
5608
|
actorId: agentProfileId,
|
|
5514
5609
|
actorType: 'agent',
|
|
5515
5610
|
expectedStepId: stepId,
|
|
5516
|
-
evidenceCommentId,
|
|
5611
|
+
evidenceCommentId: normalizedEvidenceCommentId,
|
|
5517
5612
|
idempotencyKey,
|
|
5518
5613
|
});
|
|
5519
5614
|
}
|
|
@@ -6170,12 +6265,14 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
6170
6265
|
const { taskId } = args;
|
|
6171
6266
|
const { id: resolvedTaskId } = resolveTaskByIdentifierOrThrow(taskId);
|
|
6172
6267
|
const checklist = core.listChecklistItems(resolvedTaskId, ACTIVE_WORKSPACE_ID);
|
|
6268
|
+
const detailRevision = core.getTaskDetailRevision(resolvedTaskId, ACTIVE_WORKSPACE_ID);
|
|
6173
6269
|
return {
|
|
6174
6270
|
content: [{
|
|
6175
6271
|
type: "text",
|
|
6176
6272
|
text: JSON.stringify({
|
|
6177
6273
|
taskId: resolvedTaskId,
|
|
6178
6274
|
...(buildTaskUrl({ id: resolvedTaskId }) ? { url: buildTaskUrl({ id: resolvedTaskId }) } : {}),
|
|
6275
|
+
detailRevision,
|
|
6179
6276
|
items: checklist,
|
|
6180
6277
|
}, null, 2),
|
|
6181
6278
|
}],
|
|
@@ -6245,6 +6342,49 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
6245
6342
|
}],
|
|
6246
6343
|
};
|
|
6247
6344
|
}
|
|
6345
|
+
case "update_task_checklist_item": {
|
|
6346
|
+
const { taskId, itemId, text, done, order, expectedDetailRevision, idempotencyKey: rawIdempotencyKey, } = args;
|
|
6347
|
+
const idempotencyKey = normalizeExplicitIdempotencyKey(rawIdempotencyKey);
|
|
6348
|
+
const operationId = idempotencyKey
|
|
6349
|
+
? stableExplicitMutationId('operation', 'update_task_checklist_item', idempotencyKey)
|
|
6350
|
+
: requireStableMcpRequestId('operation', 'task-checklist-update');
|
|
6351
|
+
let result;
|
|
6352
|
+
try {
|
|
6353
|
+
result = taskChecklistCommandService.update({
|
|
6354
|
+
taskId,
|
|
6355
|
+
itemId,
|
|
6356
|
+
text,
|
|
6357
|
+
done,
|
|
6358
|
+
order,
|
|
6359
|
+
expectedDetailRevision,
|
|
6360
|
+
operationId,
|
|
6361
|
+
requireDurableIdempotency: Boolean(idempotencyKey),
|
|
6362
|
+
});
|
|
6363
|
+
}
|
|
6364
|
+
catch (error) {
|
|
6365
|
+
rethrowChecklistCommandError(error);
|
|
6366
|
+
}
|
|
6367
|
+
const detailRevision = core.getTaskDetailRevision(result.taskId, ACTIVE_WORKSPACE_ID);
|
|
6368
|
+
recordMcpWriteAudit('update_task_checklist_item', {
|
|
6369
|
+
taskId: result.taskId,
|
|
6370
|
+
itemId: result.item.id,
|
|
6371
|
+
});
|
|
6372
|
+
await notifyResourceMutation({
|
|
6373
|
+
includeTasks: true,
|
|
6374
|
+
taskIds: [result.taskId],
|
|
6375
|
+
});
|
|
6376
|
+
return {
|
|
6377
|
+
content: [{
|
|
6378
|
+
type: "text",
|
|
6379
|
+
text: JSON.stringify({
|
|
6380
|
+
taskId: result.taskId,
|
|
6381
|
+
...(buildTaskUrl({ id: result.taskId }) ? { url: buildTaskUrl({ id: result.taskId }) } : {}),
|
|
6382
|
+
detailRevision,
|
|
6383
|
+
item: result.item,
|
|
6384
|
+
}, null, 2),
|
|
6385
|
+
}],
|
|
6386
|
+
};
|
|
6387
|
+
}
|
|
6248
6388
|
case "get_task_attachments": {
|
|
6249
6389
|
const { id, taskId, attachmentId } = args;
|
|
6250
6390
|
const taskIdentifier = taskId ?? id;
|
|
@@ -6978,14 +7118,40 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
6978
7118
|
};
|
|
6979
7119
|
}
|
|
6980
7120
|
case "review_document": {
|
|
6981
|
-
const { id, documentId, sessionId, title, comments, prompt } = args;
|
|
7121
|
+
const { id, documentId, sessionId, title, comments, prompt, parentCommentId, threadCommentId, threadStatus, } = args;
|
|
6982
7122
|
const asset = resolveDocumentAssetByIdentifierOrThrow(documentId ?? id);
|
|
6983
7123
|
const normalizedComments = Array.isArray(comments)
|
|
6984
7124
|
? comments
|
|
6985
7125
|
: (typeof prompt === 'string' && prompt.trim()
|
|
6986
7126
|
? [{ body: prompt.trim() }]
|
|
6987
7127
|
: []);
|
|
6988
|
-
|
|
7128
|
+
const normalizedSessionId = typeof sessionId === 'string' ? sessionId.trim() : '';
|
|
7129
|
+
const normalizedParentCommentId = typeof parentCommentId === 'string' ? parentCommentId.trim() : '';
|
|
7130
|
+
const normalizedThreadCommentId = typeof threadCommentId === 'string' ? threadCommentId.trim() : '';
|
|
7131
|
+
const hasThreadStatus = threadStatus !== undefined;
|
|
7132
|
+
const hasThreadUpdate = Boolean(normalizedThreadCommentId) || hasThreadStatus;
|
|
7133
|
+
const hasCommentsArgument = Object.prototype.hasOwnProperty.call(args, 'comments');
|
|
7134
|
+
const hasPromptArgument = Object.prototype.hasOwnProperty.call(args, 'prompt');
|
|
7135
|
+
const hasTitleArgument = Object.prototype.hasOwnProperty.call(args, 'title');
|
|
7136
|
+
if (hasThreadUpdate && (!normalizedThreadCommentId || (threadStatus !== 'open' && threadStatus !== 'resolved'))) {
|
|
7137
|
+
throw new McpPublicError('threadCommentId and threadStatus are required together');
|
|
7138
|
+
}
|
|
7139
|
+
if ((normalizedParentCommentId || hasThreadUpdate) && !normalizedSessionId) {
|
|
7140
|
+
throw new McpPublicError('sessionId is required for reply and thread-status updates');
|
|
7141
|
+
}
|
|
7142
|
+
if (hasThreadUpdate && (normalizedParentCommentId || hasCommentsArgument || hasPromptArgument || hasTitleArgument)) {
|
|
7143
|
+
throw new McpPublicError('Thread-status updates cannot be combined with comments, replies, or a session title');
|
|
7144
|
+
}
|
|
7145
|
+
if (normalizedParentCommentId && hasTitleArgument) {
|
|
7146
|
+
throw new McpPublicError('Replies cannot set a session title');
|
|
7147
|
+
}
|
|
7148
|
+
if (hasCommentsArgument && hasPromptArgument) {
|
|
7149
|
+
throw new McpPublicError('comments and prompt cannot be combined');
|
|
7150
|
+
}
|
|
7151
|
+
if (normalizedParentCommentId && normalizedComments.length !== 1) {
|
|
7152
|
+
throw new McpPublicError('Replies require exactly one comment or prompt');
|
|
7153
|
+
}
|
|
7154
|
+
if (!hasThreadUpdate && normalizedComments.length === 0) {
|
|
6989
7155
|
throw new McpPublicError('comments array is required');
|
|
6990
7156
|
}
|
|
6991
7157
|
for (const comment of normalizedComments) {
|
|
@@ -6997,13 +7163,115 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
6997
7163
|
throw new McpPublicError(anchorError);
|
|
6998
7164
|
}
|
|
6999
7165
|
}
|
|
7166
|
+
if (normalizedParentCommentId && normalizedComments[0]?.anchor !== undefined && normalizedComments[0]?.anchor !== null) {
|
|
7167
|
+
throw new McpPublicError('Replies cannot have anchors');
|
|
7168
|
+
}
|
|
7169
|
+
if (hasThreadUpdate) {
|
|
7170
|
+
const existingSession = core.getDocumentReviewSession({
|
|
7171
|
+
workspaceId: ACTIVE_WORKSPACE_ID,
|
|
7172
|
+
sessionId: normalizedSessionId,
|
|
7173
|
+
});
|
|
7174
|
+
if (!existingSession) {
|
|
7175
|
+
throw new McpPublicError(`Document review session ${normalizedSessionId} not found.`, 'MCP_NOT_FOUND', 404);
|
|
7176
|
+
}
|
|
7177
|
+
if (existingSession.assetId !== asset.assetId) {
|
|
7178
|
+
throw new McpPublicError(`Document review session ${normalizedSessionId} is not linked to document ${getDocumentReferenceLabel(asset) || asset.assetId}.`, 'MCP_ATTACHMENT_CONFLICT', 409);
|
|
7179
|
+
}
|
|
7180
|
+
const updatedSession = core.updateDocumentReviewThreadStatus({
|
|
7181
|
+
workspaceId: ACTIVE_WORKSPACE_ID,
|
|
7182
|
+
sessionId: normalizedSessionId,
|
|
7183
|
+
commentId: normalizedThreadCommentId,
|
|
7184
|
+
status: threadStatus,
|
|
7185
|
+
actorId: getActiveMcpActorRef(),
|
|
7186
|
+
});
|
|
7187
|
+
const updatedThread = updatedSession.comments.find((entry) => entry.id === normalizedThreadCommentId) || null;
|
|
7188
|
+
const sessionSummary = buildDocumentReviewSessionSummary(updatedSession);
|
|
7189
|
+
recordMcpWriteAudit('review_document', {
|
|
7190
|
+
documentAssetId: asset.assetId,
|
|
7191
|
+
sessionId: updatedSession.id,
|
|
7192
|
+
sessionAction: 'reused',
|
|
7193
|
+
threadCommentId: normalizedThreadCommentId,
|
|
7194
|
+
threadStatus,
|
|
7195
|
+
});
|
|
7196
|
+
return {
|
|
7197
|
+
content: [{
|
|
7198
|
+
type: 'text',
|
|
7199
|
+
text: JSON.stringify({
|
|
7200
|
+
document: {
|
|
7201
|
+
assetId: asset.assetId,
|
|
7202
|
+
referenceLabel: getDocumentReferenceLabel(asset),
|
|
7203
|
+
},
|
|
7204
|
+
sessionId: updatedSession.id,
|
|
7205
|
+
sessionAction: 'reused',
|
|
7206
|
+
postedCommentIds: [],
|
|
7207
|
+
commentCount: 0,
|
|
7208
|
+
thread: buildCompactDocumentReviewComment(updatedThread),
|
|
7209
|
+
unresolvedThreadCount: sessionSummary.unresolvedThreadCount,
|
|
7210
|
+
nextTool: 'get_document_reviews',
|
|
7211
|
+
suggestedArgs: {
|
|
7212
|
+
documentId: getDocumentReferenceLabel(asset) || asset.assetId,
|
|
7213
|
+
sessionId: updatedSession.id,
|
|
7214
|
+
},
|
|
7215
|
+
}, null, 2),
|
|
7216
|
+
}],
|
|
7217
|
+
};
|
|
7218
|
+
}
|
|
7219
|
+
if (normalizedParentCommentId) {
|
|
7220
|
+
const existingSession = core.getDocumentReviewSession({
|
|
7221
|
+
workspaceId: ACTIVE_WORKSPACE_ID,
|
|
7222
|
+
sessionId: normalizedSessionId,
|
|
7223
|
+
});
|
|
7224
|
+
if (!existingSession) {
|
|
7225
|
+
throw new McpPublicError(`Document review session ${normalizedSessionId} not found.`, 'MCP_NOT_FOUND', 404);
|
|
7226
|
+
}
|
|
7227
|
+
if (existingSession.assetId !== asset.assetId) {
|
|
7228
|
+
throw new McpPublicError(`Document review session ${normalizedSessionId} is not linked to document ${getDocumentReferenceLabel(asset) || asset.assetId}.`, 'MCP_ATTACHMENT_CONFLICT', 409);
|
|
7229
|
+
}
|
|
7230
|
+
const repliedSession = core.addDocumentReviewReply({
|
|
7231
|
+
workspaceId: ACTIVE_WORKSPACE_ID,
|
|
7232
|
+
sessionId: normalizedSessionId,
|
|
7233
|
+
parentCommentId: normalizedParentCommentId,
|
|
7234
|
+
body: normalizedComments[0].body,
|
|
7235
|
+
actorId: getActiveMcpActorRef(),
|
|
7236
|
+
});
|
|
7237
|
+
const postedReply = repliedSession.comments.at(-1) || null;
|
|
7238
|
+
recordMcpWriteAudit('review_document', {
|
|
7239
|
+
documentAssetId: asset.assetId,
|
|
7240
|
+
sessionId: repliedSession.id,
|
|
7241
|
+
sessionAction: 'reused',
|
|
7242
|
+
parentCommentId: normalizedParentCommentId,
|
|
7243
|
+
commentCount: 1,
|
|
7244
|
+
});
|
|
7245
|
+
return {
|
|
7246
|
+
content: [{
|
|
7247
|
+
type: 'text',
|
|
7248
|
+
text: JSON.stringify({
|
|
7249
|
+
document: {
|
|
7250
|
+
assetId: asset.assetId,
|
|
7251
|
+
referenceLabel: getDocumentReferenceLabel(asset),
|
|
7252
|
+
},
|
|
7253
|
+
sessionId: repliedSession.id,
|
|
7254
|
+
sessionAction: 'reused',
|
|
7255
|
+
postedCommentIds: postedReply ? [postedReply.id] : [],
|
|
7256
|
+
commentCount: postedReply ? 1 : 0,
|
|
7257
|
+
reply: buildCompactDocumentReviewComment(postedReply),
|
|
7258
|
+
nextTool: 'get_document_reviews',
|
|
7259
|
+
suggestedArgs: {
|
|
7260
|
+
documentId: getDocumentReferenceLabel(asset) || asset.assetId,
|
|
7261
|
+
sessionId: repliedSession.id,
|
|
7262
|
+
},
|
|
7263
|
+
}, null, 2),
|
|
7264
|
+
}],
|
|
7265
|
+
};
|
|
7266
|
+
}
|
|
7000
7267
|
let commandResult;
|
|
7001
7268
|
try {
|
|
7002
7269
|
commandResult = documentReviewCommandService.review({
|
|
7003
7270
|
workspaceId: ACTIVE_WORKSPACE_ID,
|
|
7004
7271
|
assetId: asset.assetId,
|
|
7272
|
+
documentVersion: asset.version,
|
|
7005
7273
|
documentLabel: getDocumentReferenceLabel(asset) || asset.assetId,
|
|
7006
|
-
sessionId:
|
|
7274
|
+
sessionId: normalizedSessionId || null,
|
|
7007
7275
|
title: typeof title === 'string' ? title : null,
|
|
7008
7276
|
comments: normalizedComments,
|
|
7009
7277
|
actorId: getActiveMcpActorRef(),
|
|
@@ -7029,6 +7297,7 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
7029
7297
|
},
|
|
7030
7298
|
sessionId: currentSession.id,
|
|
7031
7299
|
sessionAction,
|
|
7300
|
+
documentVersion: currentSession.documentVersion,
|
|
7032
7301
|
postedCommentIds,
|
|
7033
7302
|
commentCount: postedCommentIds.length,
|
|
7034
7303
|
nextTool: 'get_document_reviews',
|
|
@@ -7353,13 +7622,6 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
7353
7622
|
actorRef: getActiveMcpActorRef(),
|
|
7354
7623
|
provisionalLocalReference: shouldUseProvisionalTaskReferences(runtimeMode)
|
|
7355
7624
|
}), 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
7625
|
recordMcpWriteAudit('create_task', {
|
|
7364
7626
|
taskId: task.task?.id || null,
|
|
7365
7627
|
title: task.task?.title || null,
|
|
@@ -7478,6 +7740,9 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
7478
7740
|
const inputId = args.id;
|
|
7479
7741
|
const { id, task: existingTask } = resolveTaskByIdentifierOrThrow(inputId);
|
|
7480
7742
|
const prepared = taskRootCommandPreparationService.prepareUpdate(args);
|
|
7743
|
+
if (prepared.updates.status === 'review' && existingTask.status !== 'review') {
|
|
7744
|
+
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);
|
|
7745
|
+
}
|
|
7481
7746
|
const updated = mutateTaskThroughStatusBoundary({ task: existingTask, updates: prepared.updates });
|
|
7482
7747
|
if (!updated) {
|
|
7483
7748
|
throw new Error(`Task ${id} not found`);
|
|
@@ -7516,13 +7781,13 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
7516
7781
|
}
|
|
7517
7782
|
case "finish_task": {
|
|
7518
7783
|
try {
|
|
7519
|
-
const { id: inputId, outcome, comment } = args;
|
|
7784
|
+
const { id: inputId, outcome, comment, reviewer } = args;
|
|
7520
7785
|
const normalizedOutcome = String(outcome || '').trim().toLowerCase();
|
|
7521
7786
|
if (normalizedOutcome !== 'done' && normalizedOutcome !== 'review') {
|
|
7522
7787
|
throw new McpPublicError("outcome must be 'done' or 'review'");
|
|
7523
7788
|
}
|
|
7524
7789
|
const { id, task: existingTask } = resolveTaskByIdentifierOrThrow(inputId);
|
|
7525
|
-
const result = taskLifecycleCommandService.finish(existingTask, { outcome: normalizedOutcome, comment });
|
|
7790
|
+
const result = taskLifecycleCommandService.finish(existingTask, { outcome: normalizedOutcome, comment, reviewer });
|
|
7526
7791
|
recordMcpWriteAudit('finish_task', {
|
|
7527
7792
|
taskId: id,
|
|
7528
7793
|
outcome: normalizedOutcome,
|
|
@@ -7906,6 +8171,14 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
7906
8171
|
update.complexity = resolveNumberOption('complexity', update.complexity, COMPLEXITY_OPTIONS);
|
|
7907
8172
|
}
|
|
7908
8173
|
const preview = core.bulkUpdateFieldsPreview(resolvedList, ACTIVE_WORKSPACE_ID);
|
|
8174
|
+
for (const item of preview.toApply) {
|
|
8175
|
+
if (item.fields.status !== 'review')
|
|
8176
|
+
continue;
|
|
8177
|
+
const existingTask = core.getTask(item.id, ACTIVE_WORKSPACE_ID);
|
|
8178
|
+
if (existingTask?.status !== 'review') {
|
|
8179
|
+
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);
|
|
8180
|
+
}
|
|
8181
|
+
}
|
|
7909
8182
|
const forceStatusBoundary = (durableTaskMutationRouter.enabled
|
|
7910
8183
|
&& preview.toApply.some((item) => Object.prototype.hasOwnProperty.call(item.fields, 'status')));
|
|
7911
8184
|
const durableBatch = forceStatusBoundary || durableTaskRootMutationRouter.metadataEnabled;
|
|
@@ -8029,8 +8302,8 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
8029
8302
|
};
|
|
8030
8303
|
const toolHandlers = new Map(registeredTools.map((tool) => [tool.name, tool.handler]));
|
|
8031
8304
|
const mcpInputValidator = createMcpInputValidator();
|
|
8032
|
-
|
|
8033
|
-
const { name, arguments: args } = resolveMcpToolCallCompatibility(
|
|
8305
|
+
const callTool = async (params, context = {}) => {
|
|
8306
|
+
const { name, arguments: args } = resolveMcpToolCallCompatibility(params.name, params.arguments);
|
|
8034
8307
|
const toolStartedAtMs = Date.now();
|
|
8035
8308
|
let preparationMs = 0;
|
|
8036
8309
|
let validationMs = 0;
|
|
@@ -8073,11 +8346,11 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
8073
8346
|
}
|
|
8074
8347
|
});
|
|
8075
8348
|
let result;
|
|
8076
|
-
if (
|
|
8349
|
+
if (context.requestId === undefined || context.requestId === null) {
|
|
8077
8350
|
result = await execute();
|
|
8078
8351
|
}
|
|
8079
8352
|
else {
|
|
8080
|
-
const transportSessionId = String(
|
|
8353
|
+
const transportSessionId = String(context.sessionId || '').trim();
|
|
8081
8354
|
const requestIdentity = operationIdentityScope
|
|
8082
8355
|
? fingerprintWorkspaceSyncPayload({
|
|
8083
8356
|
kind: 'shared-mcp-request',
|
|
@@ -8086,18 +8359,18 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
8086
8359
|
|| options.auth?.mcpConnectionId
|
|
8087
8360
|
|| options.auth?.mcpClientId
|
|
8088
8361
|
|| 'mcp',
|
|
8089
|
-
requestId: { type: typeof
|
|
8362
|
+
requestId: { type: typeof context.requestId, value: context.requestId },
|
|
8090
8363
|
tool: name,
|
|
8091
8364
|
})
|
|
8092
8365
|
: [
|
|
8093
8366
|
...(runtimeMode === 'local' || !transportSessionId ? [runtimeRequestNamespace] : []),
|
|
8094
8367
|
String(transportSessionId || options.auth?.mcpConnectionId || options.auth?.mcpClientId || 'mcp'),
|
|
8095
|
-
String(
|
|
8368
|
+
String(context.requestId),
|
|
8096
8369
|
name,
|
|
8097
8370
|
].join(':');
|
|
8098
8371
|
const logicalCloudCreateIdentity = [
|
|
8099
8372
|
String(transportSessionId || options.auth?.mcpConnectionId || options.auth?.mcpClientId || 'mcp'),
|
|
8100
|
-
String(
|
|
8373
|
+
String(context.requestId),
|
|
8101
8374
|
name,
|
|
8102
8375
|
].join(':');
|
|
8103
8376
|
result = await cloudCreateRequestIdentity.run(logicalCloudCreateIdentity, () => mcpRequestIdentity.run(requestIdentity, execute));
|
|
@@ -8116,14 +8389,14 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
8116
8389
|
responseBytes = measureToolResultBytes(result);
|
|
8117
8390
|
return result;
|
|
8118
8391
|
}
|
|
8119
|
-
const result = buildUnexpectedToolErrorResult(auditRequestId ||
|
|
8392
|
+
const result = buildUnexpectedToolErrorResult(auditRequestId || context.requestId);
|
|
8120
8393
|
responseBytes = measureToolResultBytes(result);
|
|
8121
8394
|
return result;
|
|
8122
8395
|
}
|
|
8123
8396
|
finally {
|
|
8124
8397
|
try {
|
|
8125
8398
|
options.onToolCallTiming?.({
|
|
8126
|
-
requestId: String(auditRequestId ||
|
|
8399
|
+
requestId: String(auditRequestId || context.requestId || '').trim() || null,
|
|
8127
8400
|
toolName: name,
|
|
8128
8401
|
isWrite: isMcpWriteToolName(name),
|
|
8129
8402
|
outcome: timingOutcome,
|
|
@@ -8139,7 +8412,11 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
8139
8412
|
// Observability must never change tool behavior.
|
|
8140
8413
|
}
|
|
8141
8414
|
}
|
|
8142
|
-
}
|
|
8415
|
+
};
|
|
8416
|
+
server.setRequestHandler('tools/call', (request, ctx) => callTool(request.params, {
|
|
8417
|
+
requestId: ctx.mcpReq.id,
|
|
8418
|
+
sessionId: ctx.sessionId,
|
|
8419
|
+
}));
|
|
8143
8420
|
return {
|
|
8144
8421
|
server,
|
|
8145
8422
|
core,
|
|
@@ -8149,6 +8426,16 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
8149
8426
|
tenantId,
|
|
8150
8427
|
version: MCP_SERVER_VERSION,
|
|
8151
8428
|
toolProfile: activeToolProfile,
|
|
8429
|
+
listTools,
|
|
8430
|
+
callTool,
|
|
8431
|
+
};
|
|
8432
|
+
}
|
|
8433
|
+
export async function connectMcpRuntimeToStdio(runtime, transport = new StdioServerTransport()) {
|
|
8434
|
+
await runtime.server.connect(transport);
|
|
8435
|
+
return {
|
|
8436
|
+
...runtime,
|
|
8437
|
+
transport,
|
|
8438
|
+
close: () => runtime.server.close(),
|
|
8152
8439
|
};
|
|
8153
8440
|
}
|
|
8154
8441
|
export async function startTaskforceMcpStdioServer(options = {}) {
|
|
@@ -8164,18 +8451,18 @@ export async function startTaskforceMcpStdioServer(options = {}) {
|
|
|
8164
8451
|
projectRoot,
|
|
8165
8452
|
tenantId,
|
|
8166
8453
|
core,
|
|
8454
|
+
resourceSubscriptionMode: options.resourceSubscriptionMode ?? 'legacy-long-lived',
|
|
8167
8455
|
auth: {
|
|
8168
8456
|
...envAuth,
|
|
8169
8457
|
...(options.auth || {}),
|
|
8170
8458
|
},
|
|
8171
8459
|
});
|
|
8172
|
-
const
|
|
8173
|
-
await runtime.server.connect(transport);
|
|
8460
|
+
const connected = await connectMcpRuntimeToStdio(runtime);
|
|
8174
8461
|
const close = createTaskforceMcpStdioClose({
|
|
8175
|
-
closeServer:
|
|
8462
|
+
closeServer: connected.close,
|
|
8176
8463
|
...(ownsCore ? { closeOwnedCore: () => core.close() } : {}),
|
|
8177
8464
|
});
|
|
8178
|
-
return { ...runtime, transport, close };
|
|
8465
|
+
return { ...runtime, transport: connected.transport, close };
|
|
8179
8466
|
}
|
|
8180
8467
|
catch (error) {
|
|
8181
8468
|
try {
|