@taskforcehq/taskforce 0.3.328 → 0.3.329
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 +233 -34
- package/dist/TaskforceCore.js +237 -230
- package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.js +1 -1
- package/dist/cli.js +34 -0
- package/dist/cliCloudTargetGuard.d.ts +5 -0
- package/dist/cliCloudTargetGuard.js +11 -0
- package/dist/components/features/AnnotatedAttachmentWorkspace.js +24 -8
- package/dist/components/features/TaskSettings.d.ts +12 -1
- package/dist/components/features/TaskSettings.js +147 -40
- package/dist/components/features/agentCapabilities/AgentCapabilitiesPrototype.d.ts +1 -1
- package/dist/components/features/planning/PlanningModule.js +2 -5
- package/dist/components/features/planning/PlanningTaskOrderList.d.ts +1 -1
- package/dist/components/features/planning/PlanningTaskOrderList.js +17 -6
- package/dist/components/features/planning/planningTaskArrangement.d.ts +1 -0
- package/dist/components/features/planning/planningTaskArrangement.js +5 -5
- package/dist/components/features/taskforceAgentEditorModel.js +3 -1
- package/dist/components/task/TaskCard.d.ts +5 -0
- package/dist/components/task/TaskCard.js +65 -10
- package/dist/components/task/TaskImageReviews.js +14 -5
- package/dist/components/task/TaskKanban.d.ts +6 -1
- package/dist/components/task/TaskKanban.js +152 -6
- package/dist/components/task/TaskList.d.ts +5 -0
- package/dist/components/task/TaskList.js +3 -3
- package/dist/components/ui/PasswordInput.d.ts +6 -0
- package/dist/components/ui/PasswordInput.js +11 -0
- package/dist/components/ui/TopNoticeLayer.js +1 -1
- package/dist/components/views/AppShellHeader.js +32 -11
- package/dist/components/views/PlanComparisonPage.js +12 -0
- package/dist/components/views/StandaloneLayout.js +7 -31
- package/dist/components/views/WidgetView.js +3 -3
- package/dist/components/views/panels/PlanningDrawer.js +5 -12
- package/dist/components/views/standalone/modals/AccountSettingsModal.js +26 -17
- package/dist/config/envSchema.js +12 -0
- package/dist/config/localServiceRuntimeContract.d.ts +13 -0
- package/dist/config/localServiceRuntimeContract.js +135 -0
- package/dist/core/AiProfileService.js +46 -8
- package/dist/core/DeletedTaskLifecycleService.d.ts +1 -0
- package/dist/core/DeletedTaskLifecycleService.js +37 -6
- package/dist/core/TaskAttachmentLinksDurableMutationService.d.ts +3 -2
- package/dist/core/TaskAttachmentLinksDurableMutationService.js +33 -9
- package/dist/core/Taskforce.d.ts +62 -2
- package/dist/core/Taskforce.js +635 -32
- package/dist/core/types.d.ts +6 -0
- package/dist/hooks/sync/useDurableLocalOutboxDrain.d.ts +1 -1
- package/dist/hooks/sync/useDurableTaskCreateMutation.js +1 -1
- package/dist/hooks/sync/useDurableTaskMetadataMutation.d.ts +1 -0
- package/dist/hooks/sync/useDurableTaskMetadataMutation.js +1 -0
- package/dist/hooks/sync/useDurableTaskStatusMutation.d.ts +1 -0
- package/dist/hooks/tasks/taskHttpMutation.js +1 -0
- package/dist/hooks/tasks/useCloudTaskSearch.d.ts +12 -0
- package/dist/hooks/tasks/useCloudTaskSearch.js +71 -0
- package/dist/hooks/tasks/useTaskDescriptionImageDraftRecovery.d.ts +16 -0
- package/dist/hooks/tasks/useTaskDescriptionImageDraftRecovery.js +197 -0
- package/dist/hooks/tasks/useTaskEditorNavigation.d.ts +16 -3
- package/dist/hooks/tasks/useTaskEditorNavigation.js +72 -13
- package/dist/hooks/tasks/useTaskFormActions.d.ts +6 -0
- package/dist/hooks/tasks/useTaskFormActions.js +65 -12
- package/dist/hooks/ui/useSettingsModel.d.ts +24 -2
- package/dist/hooks/ui/useSettingsModel.js +13 -2
- package/dist/hooks/ui/useSettingsPersistence.d.ts +12 -1
- package/dist/hooks/ui/useSettingsPersistence.js +74 -47
- package/dist/hooks/useFilterSort.d.ts +7 -3
- package/dist/hooks/useFilterSort.js +15 -5
- package/dist/hooks/useTaskData.d.ts +10 -1
- package/dist/hooks/useTaskData.js +216 -7
- package/dist/hooks/useTaskMutations.d.ts +10 -2
- package/dist/hooks/useTaskMutations.js +223 -43
- package/dist/hooks/useTaskforce.d.ts +37 -9
- package/dist/hooks/useTaskforce.js +349 -39
- package/dist/hooks/useUiNotice.d.ts +4 -0
- package/dist/hooks/useUiNotice.js +4 -0
- package/dist/mcp/adminWorkspaceRegistrar.js +3 -3
- package/dist/mcp/documentAssetRegistrar.js +44 -35
- package/dist/mcp/documentHelpers.d.ts +1 -0
- package/dist/mcp/documentHelpers.js +7 -3
- package/dist/mcp/runtime.js +172 -42
- package/dist/mcp/taskPlanningRegistrar.js +41 -38
- package/dist/mcp/toolCallCompatibility.js +38 -1
- package/dist/mcp/toolCatalog.d.ts +1 -0
- package/dist/migrations/taskSchemaMigrations.js +12 -0
- package/dist/runtime/appGateDefinitions.d.ts +30 -6
- package/dist/runtime/appGateDefinitions.js +6 -6
- package/dist/runtime/appGates.d.ts +12 -13
- package/dist/runtime/appGates.js +29 -13
- package/dist/runtime/nodeAppGates.d.ts +8 -0
- package/dist/runtime/nodeAppGates.js +27 -0
- package/dist/server/cloudCollectionRead.d.ts +1 -1
- package/dist/server/cloudCollectionRead.js +2 -2
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.js +15 -3
- package/dist/server/localServiceLease.d.ts +3 -0
- package/dist/server/localServiceLease.js +9 -1
- package/dist/server/localWorkspaceSyncServerRuntime.js +10 -3
- package/dist/server/rateLimit.d.ts +1 -0
- package/dist/server/rateLimit.js +4 -0
- package/dist/server/realtimeSyncWs.js +36 -12
- package/dist/server/routes/admin.js +1 -0
- package/dist/server/routes/agentRoles.js +3 -2
- package/dist/server/routes/agentSkills.js +3 -2
- package/dist/server/routes/agents.js +118 -16
- package/dist/server/routes/annotatedAttachments.js +3 -2
- package/dist/server/routes/auth.js +3 -1
- package/dist/server/routes/durableTaskHttpRouters.d.ts +9 -2
- package/dist/server/routes/localService.js +2 -0
- package/dist/server/routes/primitives.d.ts +2 -0
- package/dist/server/routes/syncAuxRoutes.js +5 -2
- package/dist/server/routes/syncPullApplyRoutes.js +23 -4
- package/dist/server/routes/syncV3FeedRoutes.js +18 -16
- package/dist/server/routes/syncV3LocalCaptureRoutes.js +28 -2
- package/dist/server/routes/syncV3LocalFeedApplyRoutes.d.ts +1 -0
- package/dist/server/routes/syncV3LocalFeedApplyRoutes.js +26 -0
- package/dist/server/routes/syncV3OperationRoutes.js +10 -0
- package/dist/server/routes/tasks.js +103 -11
- package/dist/server/routes/workspaces.js +43 -1
- package/dist/server/workspaceDeletionAdmission.d.ts +23 -0
- package/dist/server/workspaceDeletionAdmission.js +50 -0
- package/dist/service/localServiceCli.js +16 -0
- package/dist/service/localServiceClientLifecycle.js +36 -10
- package/dist/services/codexAppServerModelGateway.d.ts +112 -0
- package/dist/services/codexAppServerModelGateway.js +438 -0
- package/dist/services/taskforceAgentMcpBridge.d.ts +7 -1
- package/dist/services/taskforceAgentMcpBridge.js +23 -3
- package/dist/shared/taskforceAgentDefinition.js +7 -1
- package/dist/shared/taskforceAgentModels.d.ts +1 -0
- package/dist/shared/taskforceAgentModels.js +30 -1
- package/dist/storage/postgresAdapter.d.ts +20 -3
- package/dist/storage/postgresAdapter.js +106 -14
- package/dist/storage/postgresWorker.js +13 -4
- package/dist/storage/postgresWorkerProtocol.d.ts +29 -0
- package/dist/storage/postgresWorkerProtocol.js +30 -0
- package/dist/sync/cloudSyncApi.d.ts +4 -1
- package/dist/sync/cloudSyncApi.js +7 -2
- package/dist/sync/contentSyncState.d.ts +1 -1
- package/dist/sync/coordinator/localSyncExecutionPermitStore.d.ts +1 -0
- package/dist/sync/coordinator/localSyncExecutionPermitStore.js +7 -1
- package/dist/sync/coordinator/localWorkspaceSyncRunner.js +6 -2
- package/dist/sync/engine/workspaceSyncEngineBrowserGatewayRemoteServices.js +20 -2
- package/dist/sync/engine/workspaceSyncEngineLocalServices.d.ts +4 -0
- package/dist/sync/engine/workspaceSyncEngineLocalServices.js +11 -0
- package/dist/sync/engine/workspaceSyncEngineRemoteServices.d.ts +11 -0
- package/dist/sync/engine/workspaceSyncEngineRemoteServices.js +2 -1
- package/dist/sync/engine/workspaceSyncEngineServerRemoteServices.js +31 -4
- package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.d.ts +3 -1
- package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.js +25 -8
- package/dist/sync/engine/workspaceSyncEngineTransfers.d.ts +1 -1
- package/dist/sync/engine/workspaceSyncEngineTransfers.js +8 -3
- package/dist/sync/syncService.d.ts +2 -0
- package/dist/sync/syncService.js +4 -1
- package/dist/sync/v3/combinedFeedCapability.js +4 -0
- package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.d.ts +2 -0
- package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.js +11 -1
- package/dist/sync/v3/durableTaskChecklistMutationRouter.d.ts +2 -0
- package/dist/sync/v3/durableTaskChecklistMutationRouter.js +4 -0
- package/dist/sync/v3/durableTaskHttpBulkMutationRouter.d.ts +1 -0
- package/dist/sync/v3/durableTaskHttpBulkMutationRouter.js +30 -8
- package/dist/sync/v3/durableTaskHttpRootMutationRouter.d.ts +5 -3
- package/dist/sync/v3/durableTaskHttpRootMutationRouter.js +27 -2
- package/dist/sync/v3/localTaskAttachmentLinksOutboxService.d.ts +2 -0
- package/dist/sync/v3/localTaskAttachmentLinksOutboxService.js +47 -7
- package/dist/sync/v3/localTaskCreateOutboxService.js +15 -6
- package/dist/sync/v3/localTaskMetadataClient.d.ts +1 -0
- package/dist/sync/v3/localTaskMetadataClient.js +1 -0
- package/dist/sync/v3/localTaskMetadataOutboxHandler.js +5 -1
- package/dist/sync/v3/localTaskMetadataOutboxService.d.ts +2 -0
- package/dist/sync/v3/localTaskMetadataOutboxService.js +7 -0
- package/dist/sync/v3/localTaskRestoreOutboxService.js +14 -6
- package/dist/sync/v3/localTaskStatusClient.d.ts +1 -0
- package/dist/sync/v3/localTaskStatusClient.js +6 -1
- package/dist/sync/v3/localTaskStatusOutboxService.d.ts +2 -0
- package/dist/sync/v3/localTaskStatusOutboxService.js +54 -13
- package/dist/sync/v3/syncDurabilityStore.d.ts +7 -0
- package/dist/sync/v3/syncDurabilityStore.js +31 -11
- package/dist/sync/v3/taskAttachmentLinksMutationService.d.ts +6 -4
- package/dist/sync/v3/taskAttachmentLinksMutationService.js +19 -10
- package/dist/sync/v3/taskChecklistMutationService.d.ts +4 -2
- package/dist/sync/v3/taskChecklistMutationService.js +4 -0
- package/dist/sync/v3/taskCreateMutationService.d.ts +2 -2
- package/dist/sync/v3/taskCreateMutationService.js +7 -4
- package/dist/sync/v3/taskMetadataMutationService.d.ts +3 -0
- package/dist/sync/v3/taskMetadataMutationService.js +4 -0
- package/dist/sync/v3/taskRestoreMutationService.d.ts +2 -2
- package/dist/sync/v3/taskRestoreMutationService.js +7 -4
- package/dist/sync/v3/taskStatusMutationService.d.ts +2 -0
- package/dist/sync/v3/taskStatusMutationService.js +4 -0
- package/dist/sync/v3/workflowAssignmentSync.d.ts +1 -0
- package/dist/sync/v3/workflowAssignmentSync.js +3 -0
- package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.d.ts +1 -1
- package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.js +13 -3
- package/dist/sync/v3/workspaceSyncV3AttachmentApplyObligationStore.d.ts +11 -0
- package/dist/sync/v3/workspaceSyncV3AttachmentApplyObligationStore.js +27 -10
- package/dist/sync/v3/workspaceSyncV3AttachmentAssetHydration.d.ts +2 -1
- package/dist/sync/v3/workspaceSyncV3AttachmentAssetHydration.js +52 -10
- package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.js +9 -1
- package/dist/sync/v3/workspaceSyncV3CombinedFeedOrchestrator.js +8 -3
- package/dist/sync/v3/workspaceSyncV3CombinedLocalApply.js +51 -10
- package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.d.ts +7 -0
- package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.js +30 -18
- package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.d.ts +9 -4
- package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.js +98 -47
- package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.d.ts +10 -0
- package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.js +58 -21
- package/dist/sync/v3/workspaceSyncV3CombinedWireContract.d.ts +3 -1
- package/dist/sync/v3/workspaceSyncV3CombinedWireContract.js +18 -0
- package/dist/sync/v3/workspaceSyncV3CoverageRegistry.js +6 -0
- package/dist/sync/v3/workspaceSyncV3FeedProfile.d.ts +1 -1
- package/dist/sync/v3/workspaceSyncV3LegacyBoundaryAttestation.d.ts +1 -0
- package/dist/sync/v3/workspaceSyncV3LegacyBoundaryAttestation.js +23 -10
- package/dist/sync/v3/workspaceSyncV3NestedTaskApply.d.ts +3 -0
- package/dist/sync/v3/workspaceSyncV3NestedTaskApply.js +64 -13
- package/dist/sync/v3/workspaceSyncV3NestedTaskCodecs.d.ts +9 -0
- package/dist/sync/v3/workspaceSyncV3NestedTaskCodecs.js +26 -0
- package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.d.ts +15 -5
- package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.js +50 -14
- package/dist/sync/v3/workspaceSyncV3NestedTaskRepairSnapshot.d.ts +2 -1
- package/dist/sync/v3/workspaceSyncV3NestedTaskRepairSnapshot.js +11 -3
- package/dist/sync/v3/workspaceSyncV3OperationProtocol.d.ts +2 -0
- package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.d.ts +2 -0
- package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.js +19 -7
- package/dist/sync/v3/workspaceSyncV3TaskCommentAudit.js +9 -2
- package/dist/sync/v3/workspaceSyncV3TaskCoverCoverage.d.ts +7 -0
- package/dist/sync/v3/workspaceSyncV3TaskCoverCoverage.js +37 -0
- package/dist/sync/v3/workspaceSyncV3TaskCoverWireContract.d.ts +6 -0
- package/dist/sync/v3/workspaceSyncV3TaskCoverWireContract.js +9 -0
- package/dist/sync/workspacePullFeed.js +2 -1
- package/dist/sync/workspaceRepair.d.ts +3 -0
- package/dist/sync/workspaceRepair.js +67 -6
- package/dist/types.d.ts +47 -1
- package/dist/types.js +6 -0
- package/dist/ui/assets/{AiIdentityRosterCard-MZs7lVED.js → AiIdentityRosterCard-BZM4aQnM.js} +1 -1
- package/dist/ui/assets/AiProfilesModule-BbAEWtHH.js +1 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-B68Wg-RV.js +3 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-TzYu7pkG.css +1 -0
- package/dist/ui/assets/{AssetTraySortControl-Kf1pelSy.js → AssetTraySortControl-C8Rztyal.js} +1 -1
- package/dist/ui/assets/{ContextAttachmentManager-B8boOs6Q.js → ContextAttachmentManager-Cj3c7X9y.js} +2 -2
- package/dist/ui/assets/{DocumentWorkspace-DXH4XUsB.js → DocumentWorkspace-B5uvzems.js} +1 -1
- package/dist/ui/assets/{EntityActivityTimeline-BtSTq0ON.js → EntityActivityTimeline-BVFvCB5R.js} +1 -1
- package/dist/ui/assets/PlanningModule-B5DWQOGz.js +1 -0
- package/dist/ui/assets/PlansPage-AY4cGWco.js +1 -0
- package/dist/ui/assets/TaskContextUpload-DZxTVesW.js +1 -0
- package/dist/ui/assets/TaskSettings-BeWAuyZj.js +12 -0
- package/dist/ui/assets/{TaskforceAgentsModule-BazdUwxZ.js → TaskforceAgentsModule-BifCYtjR.js} +6 -6
- package/dist/ui/assets/{WorkflowManagerModule-DWFspC-o.js → WorkflowManagerModule-DEr5di_r.js} +1 -1
- package/dist/ui/assets/index-I5zhdtgt.js +7 -0
- package/dist/ui/assets/index-VRFsx3wz.css +1 -0
- package/dist/ui/assets/{vendor-icons-BkFLXavV.js → vendor-icons-D9Lpw-j4.js} +1 -1
- package/dist/ui/index.html +3 -3
- package/dist/utils/taskActivity.d.ts +3 -2
- package/dist/utils/taskActivity.js +19 -2
- package/dist/utils/taskEditorReconciliation.d.ts +40 -0
- package/dist/utils/taskEditorReconciliation.js +217 -0
- package/dist/utils/taskNormalization.d.ts +1 -0
- package/dist/utils/taskNormalization.js +39 -0
- package/dist/utils/taskSearch.js +2 -2
- package/dist/utils/uiNotice.d.ts +4 -0
- package/package.json +16 -4
- package/dist/ui/assets/AiProfilesModule-C3i0LOxe.js +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-CBRZ8rca.css +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-DVZk5Tln.js +0 -3
- package/dist/ui/assets/PlanningModule-BPVyEa-f.js +0 -1
- package/dist/ui/assets/PlansPage-ChqgxALc.js +0 -1
- package/dist/ui/assets/TaskContextUpload-CB3ol0sN.js +0 -1
- package/dist/ui/assets/TaskSettings-g4ECKNOz.js +0 -12
- package/dist/ui/assets/index-BUplSsv_.js +0 -7
- package/dist/ui/assets/index-gz2EXuoK.css +0 -1
package/dist/mcp/runtime.js
CHANGED
|
@@ -32,7 +32,8 @@ import { WorkspaceSyncContentVersionStore, } from '../sync/engine/workspaceSyncC
|
|
|
32
32
|
import { WorkspaceSyncPublishedContentResolver } from '../sync/engine/workspaceSyncPublishedContentResolver.js';
|
|
33
33
|
import { createWorkspaceSyncServerContentRuntime } from '../sync/engine/workspaceSyncServerContentRuntime.js';
|
|
34
34
|
import { resolveVirusScanConfigFromEnv, scanBufferForThreats } from '../security/virusScan.js';
|
|
35
|
-
import { ANNOTATED_ATTACHMENTS_WORKSPACE_FEATURE_KEY,
|
|
35
|
+
import { ANNOTATED_ATTACHMENTS_WORKSPACE_FEATURE_KEY, } from '../runtime/appGates.js';
|
|
36
|
+
import { resolveNodeAppGateAccess } from '../runtime/nodeAppGates.js';
|
|
36
37
|
import { getDocumentReferenceLabel, parseDocumentReference } from '../utils/documentReferences.js';
|
|
37
38
|
import { getImageReferenceLabel, parseImageReference } from '../utils/imageReferences.js';
|
|
38
39
|
import { inferCanonicalAssetKind, isValidCanonicalDocumentAsset } from '../utils/canonicalAssetKind.js';
|
|
@@ -1208,7 +1209,9 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
1208
1209
|
},
|
|
1209
1210
|
tools: {},
|
|
1210
1211
|
},
|
|
1211
|
-
instructions:
|
|
1212
|
+
instructions: runtimeMode === 'cloud' && options.auth?.actorType === 'token'
|
|
1213
|
+
? `Cloud access-token clients must pass profileToken on every write; obtain it from resolve_profile and keep it private. Use T-, IN-, WS-, I-, and D- references. Link url as [reference](url). For tracked work, prefer start_task and finish_task.`
|
|
1214
|
+
: `Before writes, check get_current_profile; if unbound, use resolve_profile. Keep profileToken private. Use T-, IN-, WS-, I-, and D- references. Link url as [reference](url). For tracked work, prefer start_task and finish_task.`,
|
|
1212
1215
|
});
|
|
1213
1216
|
const TOOL_PERMISSIONS = MCP_TOOL_PERMISSIONS;
|
|
1214
1217
|
const RESOURCE_PERMISSIONS = {
|
|
@@ -1311,9 +1314,10 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
1311
1314
|
function buildBoundedTextContent(content, maxChars) {
|
|
1312
1315
|
const requestedMaxChars = Number(maxChars);
|
|
1313
1316
|
const hasRequestedMaxChars = maxChars !== undefined && maxChars !== null && maxChars !== '';
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
+
if (hasRequestedMaxChars && (!Number.isInteger(requestedMaxChars) || requestedMaxChars < 1)) {
|
|
1318
|
+
throw new McpPublicError('maxChars must be a positive integer');
|
|
1319
|
+
}
|
|
1320
|
+
const resolvedMaxChars = hasRequestedMaxChars ? requestedMaxChars : 200000;
|
|
1317
1321
|
const characters = Array.from(content);
|
|
1318
1322
|
const totalChars = characters.length;
|
|
1319
1323
|
const boundedContent = totalChars > resolvedMaxChars
|
|
@@ -1405,8 +1409,10 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
1405
1409
|
}
|
|
1406
1410
|
const requestedLimit = Number(options?.limit);
|
|
1407
1411
|
const limit = Number.isFinite(requestedLimit)
|
|
1408
|
-
? Math.max(1, Math.min(
|
|
1412
|
+
? Math.max(1, Math.min(51, Math.trunc(requestedLimit)))
|
|
1409
1413
|
: 10;
|
|
1414
|
+
const requestedOffset = Number(options?.offset);
|
|
1415
|
+
const offset = Number.isFinite(requestedOffset) ? Math.max(0, Math.trunc(requestedOffset)) : 0;
|
|
1410
1416
|
const normalize = (value) => typeof value === 'string' ? value.trim().toLowerCase() : '';
|
|
1411
1417
|
const tokenize = (value) => normalize(value).split(/[^a-z0-9]+/i).filter(Boolean);
|
|
1412
1418
|
const allImages = workspaceAssetStore.listAllByWorkspace(ACTIVE_WORKSPACE_ID, { kind: 'image' });
|
|
@@ -1450,8 +1456,10 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
1450
1456
|
return [{ asset, matchedOn: Array.from(matchedOn), score }];
|
|
1451
1457
|
});
|
|
1452
1458
|
return scoredMatches
|
|
1453
|
-
.sort((a, b) => b.score - a.score
|
|
1454
|
-
.
|
|
1459
|
+
.sort((a, b) => b.score - a.score
|
|
1460
|
+
|| String(b.asset.updatedAt || '').localeCompare(String(a.asset.updatedAt || ''))
|
|
1461
|
+
|| a.asset.assetId.localeCompare(b.asset.assetId))
|
|
1462
|
+
.slice(offset, offset + limit);
|
|
1455
1463
|
}
|
|
1456
1464
|
const searchDocumentAssets = documentHelpers.searchDocumentAssets;
|
|
1457
1465
|
function buildImageDescriptor(asset) {
|
|
@@ -1465,7 +1473,9 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
1465
1473
|
sizeBytes: typeof asset.sizeBytes === 'number' ? asset.sizeBytes : null,
|
|
1466
1474
|
...(runtimeMode === 'local' ? { storageKey: asset.storageKey ?? null } : {}),
|
|
1467
1475
|
updatedAt: asset.updatedAt ?? null,
|
|
1468
|
-
|
|
1476
|
+
...(runtimeMode === 'local'
|
|
1477
|
+
? { apiUrl: `/api/taskforce/context/${encodeURIComponent(String(asset.storageKey || '').trim())}` }
|
|
1478
|
+
: {}),
|
|
1469
1479
|
};
|
|
1470
1480
|
return withAttachmentUrl({ ...descriptor, kind: 'image' });
|
|
1471
1481
|
}
|
|
@@ -1518,6 +1528,7 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
1518
1528
|
|| `Image ${normalizedValue} not found in workspace ${ACTIVE_WORKSPACE_ID}. If you only know a keyword, filename, or rough title, call search_images first.`, 'MCP_NOT_FOUND', 404);
|
|
1519
1529
|
}
|
|
1520
1530
|
const auditActorType = options.auth?.actorType || (runtimeMode === 'cloud' ? 'user' : 'local');
|
|
1531
|
+
const requiresExplicitTokenAuthorship = runtimeMode === 'cloud' && auditActorType === 'token';
|
|
1521
1532
|
const auditActorUserId = String(options.auth?.userId || (runtimeMode === 'cloud' ? 'anonymous' : 'local-mcp')).trim() || 'anonymous';
|
|
1522
1533
|
const auditTokenId = options.auth?.tokenId ? String(options.auth.tokenId).trim() : null;
|
|
1523
1534
|
const configuredAiProfileId = options.auth?.aiProfileId ? String(options.auth.aiProfileId).trim() || null : null;
|
|
@@ -1591,7 +1602,7 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
1591
1602
|
const shouldBindOAuthGrant = auditActorType === 'oauth'
|
|
1592
1603
|
&& Boolean(auditTokenId)
|
|
1593
1604
|
&& configuredAiProfileId !== profileId;
|
|
1594
|
-
const shouldApplyClientContext = Boolean((configuredMcpClientId && configuredMcpClientId !== 'general')
|
|
1605
|
+
const shouldApplyClientContext = auditActorType !== 'token' && Boolean((configuredMcpClientId && configuredMcpClientId !== 'general')
|
|
1595
1606
|
|| configuredMcpConnectionId);
|
|
1596
1607
|
if (!shouldBindOAuthGrant && !shouldApplyClientContext)
|
|
1597
1608
|
return;
|
|
@@ -1755,6 +1766,10 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
1755
1766
|
return resolved;
|
|
1756
1767
|
}
|
|
1757
1768
|
function findTrustedBoundProfile(options) {
|
|
1769
|
+
// A generic access token proves workspace/tool authorization, not which AI
|
|
1770
|
+
// is acting. Never use its historical connection row as authorship proof.
|
|
1771
|
+
if (requiresExplicitTokenAuthorship)
|
|
1772
|
+
return null;
|
|
1758
1773
|
const grantProfile = findProfileForConfiguredGrant();
|
|
1759
1774
|
const connectionProfile = findProfileForConfiguredConnection(options);
|
|
1760
1775
|
if (grantProfile && connectionProfile && grantProfile.id !== connectionProfile.id) {
|
|
@@ -1771,6 +1786,19 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
1771
1786
|
}
|
|
1772
1787
|
return profile;
|
|
1773
1788
|
}
|
|
1789
|
+
function assertOAuthProfileClientCompatibility(profile) {
|
|
1790
|
+
if (auditActorType !== 'oauth' || !configuredMcpClientId)
|
|
1791
|
+
return;
|
|
1792
|
+
const connection = profile.providerMetadata?.connection;
|
|
1793
|
+
const storedClientId = connection && typeof connection === 'object' && !Array.isArray(connection)
|
|
1794
|
+
? parseMcpClientId(connection.clientId)
|
|
1795
|
+
: null;
|
|
1796
|
+
const inferredClientId = inferLegacyMcpClientIdFromProfile(profile);
|
|
1797
|
+
const profileClientId = storedClientId || inferredClientId;
|
|
1798
|
+
if (!profileClientId || profileClientId === configuredMcpClientId)
|
|
1799
|
+
return;
|
|
1800
|
+
throw new TaskforceRuleError('The supplied AI profile is not compatible with this OAuth client product.', 409, 'AI_PROFILE_SELECTION_INVALID', { profileId: profile.id, profileClientId, configuredClientId: configuredMcpClientId });
|
|
1801
|
+
}
|
|
1774
1802
|
function listSelectableOAuthProfiles(profileName) {
|
|
1775
1803
|
if (auditActorType !== 'oauth')
|
|
1776
1804
|
return [];
|
|
@@ -2383,6 +2411,8 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
2383
2411
|
function ensureResolvedProfileFromConnection(defaults) {
|
|
2384
2412
|
if (activeAiProfileId)
|
|
2385
2413
|
return;
|
|
2414
|
+
if (requiresExplicitTokenAuthorship)
|
|
2415
|
+
return;
|
|
2386
2416
|
const boundProfile = findTrustedBoundProfile({ repairConnection: false });
|
|
2387
2417
|
if (boundProfile) {
|
|
2388
2418
|
if (configuredAiProfileIdentityAsserted) {
|
|
@@ -2457,6 +2487,25 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
2457
2487
|
throw new TaskforceRuleError('Writes are blocked because this MCP session requested an identity that conflicts with its OAuth-bound profile. Reconnect with the intended profile and retry resolve_profile.', 409, 'AI_PROFILE_BINDING_CONFLICT', { reason: 'session_identity_quarantined', nextTool: 'resolve_profile' });
|
|
2458
2488
|
}
|
|
2459
2489
|
const profileToken = resolveProfileTokenFromArgs(args);
|
|
2490
|
+
if (requiresExplicitTokenAuthorship) {
|
|
2491
|
+
if (!profileToken) {
|
|
2492
|
+
throw new McpPublicError('Cloud access-token clients must pass profileToken on every mutating call. Call resolve_profile to obtain it, keep it private, and retry this write.', 'AI_PROFILE_PROOF_REQUIRED', 401);
|
|
2493
|
+
}
|
|
2494
|
+
const tokenProfile = core.getAiProfileByToken({
|
|
2495
|
+
workspaceId: ACTIVE_WORKSPACE_ID,
|
|
2496
|
+
profileToken,
|
|
2497
|
+
seatScope: configuredAiProfileSeatScope,
|
|
2498
|
+
});
|
|
2499
|
+
if (!tokenProfile) {
|
|
2500
|
+
throw new McpPublicError('Invalid AI profile token. Call resolve_profile again and retry.', 'INVALID_AI_PROFILE_TOKEN', 401);
|
|
2501
|
+
}
|
|
2502
|
+
if (activeAiProfileId && activeAiProfileId !== tokenProfile.id) {
|
|
2503
|
+
failAiProfileBindingConflict('The supplied profile token conflicts with the AI profile already active for this request.', { reason: 'request_token_mismatch', boundProfileId: activeAiProfileId, suppliedProfileId: tokenProfile.id });
|
|
2504
|
+
}
|
|
2505
|
+
if (!activeAiProfileId)
|
|
2506
|
+
activateAiProfile(tokenProfile.id, 'token_lookup');
|
|
2507
|
+
return;
|
|
2508
|
+
}
|
|
2460
2509
|
if (activeAiProfileId) {
|
|
2461
2510
|
if (!profileToken)
|
|
2462
2511
|
return;
|
|
@@ -2491,6 +2540,8 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
2491
2540
|
suppliedProfileId: profile.id,
|
|
2492
2541
|
});
|
|
2493
2542
|
}
|
|
2543
|
+
if (!trustedBoundProfile)
|
|
2544
|
+
assertOAuthProfileClientCompatibility(profile);
|
|
2494
2545
|
if (trustedBoundProfile && configuredAiProfileIdentityAsserted) {
|
|
2495
2546
|
assertRequestedIdentityMatchesBoundProfile(trustedBoundProfile, {
|
|
2496
2547
|
name: configuredAiProfileName,
|
|
@@ -2525,7 +2576,7 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
2525
2576
|
throw new McpPublicError('This tool requires an AI profile. Call resolve_profile first, then retry. If your MCP client is stateless, pass profileToken on mutating calls.', 'AI_PROFILE_REQUIRED');
|
|
2526
2577
|
}
|
|
2527
2578
|
function assertAnnotatedAttachmentReadAccess() {
|
|
2528
|
-
const gate =
|
|
2579
|
+
const gate = resolveNodeAppGateAccess(ANNOTATED_ATTACHMENTS_WORKSPACE_FEATURE_KEY);
|
|
2529
2580
|
if (!gate.allowed) {
|
|
2530
2581
|
throw new TaskforceRuleError('Annotated attachments are unavailable for this workspace.', 403, gate.code || 'ANNOTATED_ATTACHMENTS_UNAVAILABLE');
|
|
2531
2582
|
}
|
|
@@ -3340,6 +3391,17 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
3340
3391
|
offset: Number(normalizedOffset),
|
|
3341
3392
|
};
|
|
3342
3393
|
}
|
|
3394
|
+
function normalizeSearchReadPage(limit, offset, defaultLimit) {
|
|
3395
|
+
const normalizedLimit = limit === undefined ? defaultLimit : limit;
|
|
3396
|
+
const normalizedOffset = offset === undefined ? 0 : offset;
|
|
3397
|
+
if (!Number.isInteger(normalizedLimit) || Number(normalizedLimit) < 1 || Number(normalizedLimit) > 50) {
|
|
3398
|
+
throw new McpPublicError('limit must be an integer from 1 to 50');
|
|
3399
|
+
}
|
|
3400
|
+
if (!Number.isInteger(normalizedOffset) || Number(normalizedOffset) < 0) {
|
|
3401
|
+
throw new McpPublicError('offset must be a non-negative integer');
|
|
3402
|
+
}
|
|
3403
|
+
return { limit: Number(normalizedLimit), offset: Number(normalizedOffset) };
|
|
3404
|
+
}
|
|
3343
3405
|
function buildCompactPlanningHistory(targetType, entity) {
|
|
3344
3406
|
const duplicatedCommentAction = `${targetType}-comment-added`;
|
|
3345
3407
|
const activity = Array.isArray(entity?.activity) ? entity.activity : [];
|
|
@@ -3516,17 +3578,26 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
3516
3578
|
workstreamsByInitiativeId.set(normalizedInitiativeId, current);
|
|
3517
3579
|
}
|
|
3518
3580
|
const taskCountsByWorkstreamId = buildHistoricalTaskCountSnapshot();
|
|
3519
|
-
const
|
|
3520
|
-
.filter((initiative) => matchesInitiativePlanningQuery(initiative, query, workstreamsByInitiativeId.get(initiative.id) || []))
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3581
|
+
const matches = core.listInitiatives(ACTIVE_WORKSPACE_ID)
|
|
3582
|
+
.filter((initiative) => matchesInitiativePlanningQuery(initiative, query, workstreamsByInitiativeId.get(initiative.id) || []));
|
|
3583
|
+
const offset = options?.offset ?? 0;
|
|
3584
|
+
const limit = options?.limit ?? 25;
|
|
3585
|
+
const initiatives = matches.slice(offset, offset + limit).map((initiative) => {
|
|
3586
|
+
const compact = buildInitiativeResourcePayload(initiative, {
|
|
3587
|
+
workstreamsByInitiativeId,
|
|
3588
|
+
taskCountsByWorkstreamId,
|
|
3589
|
+
detail: 'compact',
|
|
3590
|
+
});
|
|
3591
|
+
const { nextDetailOption: _nextDetailOption, ...summary } = compact;
|
|
3592
|
+
return summary;
|
|
3593
|
+
});
|
|
3594
|
+
const pagination = buildPlanningPagination(matches.length, offset, limit, initiatives.length);
|
|
3526
3595
|
return {
|
|
3527
|
-
total:
|
|
3596
|
+
total: matches.length,
|
|
3528
3597
|
...(query ? { query } : {}),
|
|
3529
3598
|
initiatives,
|
|
3599
|
+
pagination,
|
|
3600
|
+
guidance: 'Use get_initiative with the initiative ID or reference for details.',
|
|
3530
3601
|
};
|
|
3531
3602
|
}
|
|
3532
3603
|
function buildWorkstreamsResourcePayload(options) {
|
|
@@ -3536,13 +3607,22 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
3536
3607
|
initiativesById.set(initiative.id, initiative);
|
|
3537
3608
|
}
|
|
3538
3609
|
const taskCountsByWorkstreamId = buildHistoricalTaskCountSnapshot();
|
|
3539
|
-
const
|
|
3540
|
-
.filter((workstream) => matchesWorkstreamPlanningQuery(workstream, query, initiativesById.get(workstream.initiativeId || '')))
|
|
3541
|
-
|
|
3610
|
+
const matches = core.listWorkstreams(ACTIVE_WORKSPACE_ID)
|
|
3611
|
+
.filter((workstream) => matchesWorkstreamPlanningQuery(workstream, query, initiativesById.get(workstream.initiativeId || '')));
|
|
3612
|
+
const offset = options?.offset ?? 0;
|
|
3613
|
+
const limit = options?.limit ?? 25;
|
|
3614
|
+
const workstreams = matches.slice(offset, offset + limit).map((workstream) => {
|
|
3615
|
+
const compact = buildWorkstreamResourcePayload(workstream, { taskCountsByWorkstreamId, detail: 'compact' });
|
|
3616
|
+
const { nextDetailOption: _nextDetailOption, nextTaskTool: _nextTaskTool, suggestedTaskArgs: _suggestedTaskArgs, ...summary } = compact;
|
|
3617
|
+
return summary;
|
|
3618
|
+
});
|
|
3619
|
+
const pagination = buildPlanningPagination(matches.length, offset, limit, workstreams.length);
|
|
3542
3620
|
return {
|
|
3543
|
-
total:
|
|
3621
|
+
total: matches.length,
|
|
3544
3622
|
...(query ? { query } : {}),
|
|
3545
3623
|
workstreams,
|
|
3624
|
+
pagination,
|
|
3625
|
+
guidance: 'Use get_workstream for details or list_tasks with workstreamId for active tasks.',
|
|
3546
3626
|
};
|
|
3547
3627
|
}
|
|
3548
3628
|
function buildPlanningWriteEntitySummary(targetType, entity) {
|
|
@@ -3843,7 +3923,9 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
3843
3923
|
registerAdminWorkspaceTools(registerTool, (name, args) => executeRegisteredTool(name, args));
|
|
3844
3924
|
const mutatingProfileTokenProperty = {
|
|
3845
3925
|
type: 'string',
|
|
3846
|
-
description:
|
|
3926
|
+
description: requiresExplicitTokenAuthorship
|
|
3927
|
+
? 'Required authorship proof for cloud access-token clients; obtain from resolve_profile.'
|
|
3928
|
+
: 'Optional profileToken from resolve_profile for stateless MCP clients.'
|
|
3847
3929
|
};
|
|
3848
3930
|
const nonDestructiveWriteTools = new Set([
|
|
3849
3931
|
'add_annotated_attachment_marker',
|
|
@@ -3876,6 +3958,9 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
3876
3958
|
get priorityDesc() {
|
|
3877
3959
|
return `Priority level: ${getActivePriorities().map((priority) => `${priority.value} (${priority.label})`).join(', ')}`;
|
|
3878
3960
|
},
|
|
3961
|
+
get priorityEnum() {
|
|
3962
|
+
return getActivePriorities().map((priority) => priority.value);
|
|
3963
|
+
},
|
|
3879
3964
|
get typeEnum() {
|
|
3880
3965
|
return getActiveTypes().map((type) => type.value);
|
|
3881
3966
|
},
|
|
@@ -3916,6 +4001,11 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
3916
4001
|
inputSchema: {
|
|
3917
4002
|
...descriptor.inputSchema,
|
|
3918
4003
|
properties,
|
|
4004
|
+
...(requiresExplicitTokenAuthorship
|
|
4005
|
+
&& descriptor.name !== 'resolve_profile'
|
|
4006
|
+
&& isMcpWriteToolName(descriptor.name)
|
|
4007
|
+
? { required: Array.from(new Set([...(descriptor.inputSchema.required || []), 'profileToken'])) }
|
|
4008
|
+
: {}),
|
|
3919
4009
|
additionalProperties: false,
|
|
3920
4010
|
},
|
|
3921
4011
|
annotations: {
|
|
@@ -4992,15 +5082,15 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
4992
5082
|
: resolveWorkstreamByIdentifierOrThrow(workstreamId).id;
|
|
4993
5083
|
const paginated = resolvedWorkstreamId !== undefined || offset !== undefined;
|
|
4994
5084
|
const parsedOffset = offset === undefined ? 0 : Number(offset);
|
|
4995
|
-
if (!Number.
|
|
4996
|
-
throw new McpPublicError('offset must be a non-negative
|
|
4997
|
-
const normalizedOffset =
|
|
5085
|
+
if (!Number.isInteger(parsedOffset) || parsedOffset < 0)
|
|
5086
|
+
throw new McpPublicError('offset must be a non-negative integer');
|
|
5087
|
+
const normalizedOffset = parsedOffset;
|
|
4998
5088
|
const parsedLimit = limit === undefined ? (paginated ? 50 : 0) : Number(limit);
|
|
4999
|
-
if (!Number.
|
|
5000
|
-
throw new McpPublicError('limit must be
|
|
5089
|
+
if (!Number.isInteger(parsedLimit) || parsedLimit < 0 || parsedLimit > 200)
|
|
5090
|
+
throw new McpPublicError('limit must be an integer from 1 to 200');
|
|
5001
5091
|
const normalizedLimit = paginated
|
|
5002
|
-
?
|
|
5003
|
-
:
|
|
5092
|
+
? (parsedLimit || 50)
|
|
5093
|
+
: parsedLimit;
|
|
5004
5094
|
const queriedTasks = core.listTasksSlim(ACTIVE_WORKSPACE_ID, {
|
|
5005
5095
|
category,
|
|
5006
5096
|
status,
|
|
@@ -5087,6 +5177,15 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
5087
5177
|
failAiProfileBindingConflict('The selected AI profile conflicts with the profile already bound to this MCP session or authenticated connection.', { reason: 'selected_profile_mismatch', boundProfileId: alreadyBoundProfile.id, selectedProfileId: explicitlySelectedProfile.id });
|
|
5088
5178
|
}
|
|
5089
5179
|
const boundProfile = alreadyBoundProfile || explicitlySelectedProfile;
|
|
5180
|
+
if (!boundProfile && suppliedProfileToken) {
|
|
5181
|
+
const suppliedProfile = core.getAiProfileByToken({
|
|
5182
|
+
workspaceId: ACTIVE_WORKSPACE_ID,
|
|
5183
|
+
profileToken: suppliedProfileToken,
|
|
5184
|
+
seatScope: configuredAiProfileSeatScope,
|
|
5185
|
+
});
|
|
5186
|
+
if (suppliedProfile)
|
|
5187
|
+
assertOAuthProfileClientCompatibility(suppliedProfile);
|
|
5188
|
+
}
|
|
5090
5189
|
if (boundProfile && suppliedProfileToken) {
|
|
5091
5190
|
const tokenProfile = core.getAiProfileByToken({
|
|
5092
5191
|
workspaceId: ACTIVE_WORKSPACE_ID,
|
|
@@ -5291,10 +5390,19 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
5291
5390
|
};
|
|
5292
5391
|
}
|
|
5293
5392
|
case "search_tasks": {
|
|
5294
|
-
const { query, scope = "all" } = args;
|
|
5295
|
-
const
|
|
5393
|
+
const { query, scope = "all", limit, offset } = args;
|
|
5394
|
+
const page = normalizeSearchReadPage(limit, offset, 25);
|
|
5395
|
+
const queried = core.searchTaskSummaries(query, scope, ACTIVE_WORKSPACE_ID, {
|
|
5396
|
+
limit: page.limit + 1,
|
|
5397
|
+
offset: page.offset,
|
|
5398
|
+
});
|
|
5399
|
+
const hasMore = queried.length > page.limit;
|
|
5400
|
+
const results = hasMore ? queried.slice(0, page.limit) : queried;
|
|
5296
5401
|
return {
|
|
5297
|
-
content: [{
|
|
5402
|
+
content: [{
|
|
5403
|
+
type: "text",
|
|
5404
|
+
text: `${renderTaskTable(results)}\n\nPage: offset ${page.offset}, limit ${page.limit}, returned ${results.length}, hasMore ${hasMore}${hasMore ? `, nextOffset ${page.offset + results.length}` : ''}`,
|
|
5405
|
+
}],
|
|
5298
5406
|
};
|
|
5299
5407
|
}
|
|
5300
5408
|
case "get_task": {
|
|
@@ -5498,9 +5606,10 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
5498
5606
|
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
5499
5607
|
}
|
|
5500
5608
|
case "list_initiatives": {
|
|
5501
|
-
const { query } = args;
|
|
5609
|
+
const { query, limit, offset } = args;
|
|
5610
|
+
const page = normalizePlanningReadPage(limit, offset);
|
|
5502
5611
|
return {
|
|
5503
|
-
content: [{ type: "text", text: JSON.stringify(buildInitiativesResourcePayload({ query }), null, 2) }],
|
|
5612
|
+
content: [{ type: "text", text: JSON.stringify(buildInitiativesResourcePayload({ query, ...page }), null, 2) }],
|
|
5504
5613
|
};
|
|
5505
5614
|
}
|
|
5506
5615
|
case "get_initiative": {
|
|
@@ -5771,9 +5880,10 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
5771
5880
|
};
|
|
5772
5881
|
}
|
|
5773
5882
|
case "list_workstreams": {
|
|
5774
|
-
const { query } = args;
|
|
5883
|
+
const { query, limit, offset } = args;
|
|
5884
|
+
const page = normalizePlanningReadPage(limit, offset);
|
|
5775
5885
|
return {
|
|
5776
|
-
content: [{ type: "text", text: JSON.stringify(buildWorkstreamsResourcePayload({ query }), null, 2) }],
|
|
5886
|
+
content: [{ type: "text", text: JSON.stringify(buildWorkstreamsResourcePayload({ query, ...page }), null, 2) }],
|
|
5777
5887
|
};
|
|
5778
5888
|
}
|
|
5779
5889
|
case "get_workstream": {
|
|
@@ -6190,8 +6300,11 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
6190
6300
|
}
|
|
6191
6301
|
case "search_images": {
|
|
6192
6302
|
assertAnnotatedAttachmentReadAccess();
|
|
6193
|
-
const { query, limit } = args;
|
|
6194
|
-
const
|
|
6303
|
+
const { query, limit, offset } = args;
|
|
6304
|
+
const page = normalizeSearchReadPage(limit, offset, 10);
|
|
6305
|
+
const queried = searchImageAssets(query, { limit: page.limit + 1, offset: page.offset });
|
|
6306
|
+
const hasMore = queried.length > page.limit;
|
|
6307
|
+
const results = (hasMore ? queried.slice(0, page.limit) : queried).map(({ asset, matchedOn, score }) => ({
|
|
6195
6308
|
image: buildImageDescriptor(asset),
|
|
6196
6309
|
matchedOn,
|
|
6197
6310
|
score,
|
|
@@ -6207,6 +6320,13 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
6207
6320
|
workspaceId: ACTIVE_WORKSPACE_ID,
|
|
6208
6321
|
query: typeof query === 'string' ? query.trim() : '',
|
|
6209
6322
|
results,
|
|
6323
|
+
pagination: {
|
|
6324
|
+
offset: page.offset,
|
|
6325
|
+
limit: page.limit,
|
|
6326
|
+
returned: results.length,
|
|
6327
|
+
hasMore,
|
|
6328
|
+
...(hasMore ? { nextOffset: page.offset + results.length } : {}),
|
|
6329
|
+
},
|
|
6210
6330
|
guidance: results.length > 0
|
|
6211
6331
|
? 'After picking a match, call get_image with the suggestedArgs.imageId to inspect linked tasks and image notes.'
|
|
6212
6332
|
: 'No matching canonical images were found. Try an I-123 reference, title keyword, or filename fragment.',
|
|
@@ -6277,8 +6397,11 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
6277
6397
|
};
|
|
6278
6398
|
}
|
|
6279
6399
|
case "search_documents": {
|
|
6280
|
-
const { query, limit } = args;
|
|
6281
|
-
const
|
|
6400
|
+
const { query, limit, offset } = args;
|
|
6401
|
+
const page = normalizeSearchReadPage(limit, offset, 10);
|
|
6402
|
+
const queried = searchDocumentAssets(query, { limit: page.limit + 1, offset: page.offset });
|
|
6403
|
+
const hasMore = queried.length > page.limit;
|
|
6404
|
+
const results = (hasMore ? queried.slice(0, page.limit) : queried).map(({ asset, matchedOn, score }) => ({
|
|
6282
6405
|
document: buildDocumentDescriptor(asset),
|
|
6283
6406
|
matchedOn,
|
|
6284
6407
|
score,
|
|
@@ -6295,6 +6418,13 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
6295
6418
|
workspaceId: ACTIVE_WORKSPACE_ID,
|
|
6296
6419
|
query: typeof query === 'string' ? query.trim() : '',
|
|
6297
6420
|
results,
|
|
6421
|
+
pagination: {
|
|
6422
|
+
offset: page.offset,
|
|
6423
|
+
limit: page.limit,
|
|
6424
|
+
returned: results.length,
|
|
6425
|
+
hasMore,
|
|
6426
|
+
...(hasMore ? { nextOffset: page.offset + results.length } : {}),
|
|
6427
|
+
},
|
|
6298
6428
|
guidance: results.length > 0
|
|
6299
6429
|
? 'After picking a match, call get_document with the suggestedArgs.documentId. Pass includeContent=true when you need the body.'
|
|
6300
6430
|
: 'No matching canonical documents were found. Try a D-123 reference, document id, title keyword, or filename fragment.',
|