@taskforcehq/taskforce 0.3.330 → 0.3.333
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -2
- package/dist/components/features/agentCapabilities/AgentCapabilitiesPrototype.d.ts +2 -2
- package/dist/components/features/agentCapabilities/AgentCapabilitiesPrototype.js +2 -2
- package/dist/components/features/planning/PlanningModule.js +15 -3
- package/dist/components/features/planning/planningMetadata.d.ts +10 -0
- package/dist/components/features/planning/planningMetadata.js +8 -0
- package/dist/components/views/StandaloneLayout.js +35 -1
- package/dist/components/views/panels/PlanningDrawer.d.ts +2 -1
- package/dist/components/views/panels/PlanningDrawer.js +12 -8
- package/dist/config/envSchema.js +7 -0
- package/dist/core/McpTokenService.d.ts +2 -0
- package/dist/core/McpTokenService.js +13 -5
- package/dist/core/Taskforce.d.ts +11 -3
- package/dist/core/Taskforce.js +33 -3
- package/dist/core/types.d.ts +1 -0
- package/dist/documentReviews/DocumentReviewCommentStore.d.ts +2 -0
- package/dist/documentReviews/DocumentReviewCommentStore.js +28 -9
- package/dist/mcp/httpProtocolRouting.d.ts +1 -0
- package/dist/mcp/httpProtocolRouting.js +8 -5
- package/dist/mcp/runtime.js +24 -5
- package/dist/mcp/taskPlanningRegistrar.js +2 -2
- package/dist/mcp/toolProfiles.js +1 -0
- package/dist/mcp/toolRegistry.js +8 -8
- package/dist/server/buildInfo.d.ts +1 -0
- package/dist/server/buildInfo.js +5 -1
- package/dist/server/cloudMcpCapacityTelemetry.d.ts +68 -0
- package/dist/server/cloudMcpCapacityTelemetry.js +221 -0
- package/dist/server/localWorkspaceSyncServerRuntime.js +13 -5
- package/dist/server/routes/admin.js +14 -2
- package/dist/server/routes/localService.js +1 -0
- package/dist/server/routes/shared.d.ts +3 -0
- package/dist/server/routes/shared.js +280 -240
- package/dist/server/routes/syncPushRoutes.d.ts +3 -0
- package/dist/server/routes/syncPushRoutes.js +8 -2
- package/dist/service/localServiceCli.d.ts +2 -2
- package/dist/service/localServiceCli.js +4 -3
- package/dist/services/executorPhaseAIssuerCore.d.ts +13 -0
- package/dist/services/executorPhaseAIssuerCore.js +107 -0
- package/dist/services/taskforceAgentMcpBridge.d.ts +1 -1
- package/dist/services/taskforceAgentMcpBridge.js +35 -5
- package/dist/shared/executorPhaseASchemaValidation.js +1 -1
- package/dist/storage/postgresAdapter.js +3 -1
- package/dist/storage/postgresRequestDiagnostics.d.ts +9 -1
- package/dist/storage/postgresRequestDiagnostics.js +15 -2
- package/dist/storage/postgresWorker.js +13 -3
- package/dist/storage/postgresWorkerProtocol.d.ts +6 -0
- package/dist/storage/workflowStore.d.ts +2 -0
- package/dist/storage/workflowStore.js +39 -2
- package/dist/sync/cloudSyncApi.js +4 -2
- package/dist/sync/collaborationSyncState.js +5 -0
- package/dist/sync/coordinator/localWorkspaceSyncRunner.d.ts +3 -1
- package/dist/sync/coordinator/localWorkspaceSyncRunner.js +18 -0
- package/dist/sync/coordinator/localWorkspaceSyncRunnerState.d.ts +1 -0
- package/dist/sync/coordinator/localWorkspaceSyncRunnerState.js +7 -6
- package/dist/sync/engine/workspaceSyncEngineBrowserGatewayRemoteServices.js +2 -2
- package/dist/sync/engine/workspaceSyncEngineLocalApply.d.ts +1 -0
- package/dist/sync/engine/workspaceSyncEnginePushCompletion.d.ts +6 -0
- package/dist/sync/engine/workspaceSyncEnginePushCompletion.js +34 -1
- package/dist/sync/engine/workspaceSyncEngineServerRemoteServices.js +2 -2
- package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.js +4 -1
- package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.d.ts +1 -0
- package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.js +55 -10
- package/dist/sync/syncApplyHandlers.d.ts +1 -0
- package/dist/sync/syncApplyHandlers.js +72 -15
- package/dist/sync/syncService.d.ts +1 -0
- package/dist/sync/syncService.js +5 -2
- package/dist/sync/v3/durableWorkflowRuntimeMutationRouter.d.ts +7 -7
- package/dist/sync/v3/durableWorkflowRuntimeMutationRouter.js +50 -13
- package/dist/sync/v3/localOutboxRecoveryPreparationService.js +8 -2
- package/dist/sync/v3/localTaskCreateOutboxService.d.ts +3 -1
- package/dist/sync/v3/localTaskCreateOutboxService.js +6 -1
- package/dist/sync/v3/localTaskDeleteOutboxService.js +1 -0
- package/dist/sync/v3/localTaskLifecycleOutboxService.d.ts +2 -1
- package/dist/sync/v3/localTaskLifecycleOutboxService.js +5 -1
- package/dist/sync/v3/localTaskMetadataOutboxService.d.ts +2 -1
- package/dist/sync/v3/localTaskMetadataOutboxService.js +6 -2
- package/dist/sync/v3/localTaskStatusOutboxService.d.ts +2 -1
- package/dist/sync/v3/localTaskStatusOutboxService.js +20 -5
- package/dist/sync/v3/syncDurabilityStore.d.ts +2 -1
- package/dist/sync/v3/syncDurabilityStore.js +34 -6
- package/dist/sync/v3/workflowRuntimeMutationService.d.ts +5 -0
- package/dist/sync/v3/workflowRuntimeMutationService.js +124 -71
- package/dist/sync/v3/workspaceSyncV3CombinedLocalApply.js +25 -3
- package/dist/sync/v3/workspaceSyncV3Feed.d.ts +1 -0
- package/dist/sync/v3/workspaceSyncV3Feed.js +6 -1
- package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.d.ts +2 -0
- package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.js +49 -18
- package/dist/sync/v3/workspaceSyncV3WorkflowRuntimeApply.d.ts +1 -0
- package/dist/sync/v3/workspaceSyncV3WorkflowRuntimeApply.js +50 -5
- package/dist/ui/assets/{AiIdentityRosterCard-OcSz1PkK.js → AiIdentityRosterCard-Cfvb9Nuv.js} +1 -1
- package/dist/ui/assets/{AiProfilesModule-ByhYW5Xi.js → AiProfilesModule-0oR70eFG.js} +1 -1
- package/dist/ui/assets/{AnnotatedAttachmentWorkspace-BTM6nIg_.js → AnnotatedAttachmentWorkspace-C33iH_r_.js} +1 -1
- package/dist/ui/assets/{AssetTraySortControl-DabEG8L4.js → AssetTraySortControl-BAqxUtke.js} +1 -1
- package/dist/ui/assets/{ContextAttachmentManager-Coa8yVGM.js → ContextAttachmentManager-BudIbOR9.js} +2 -2
- package/dist/ui/assets/{DocumentWorkspace-BB0qhdix.js → DocumentWorkspace-A8dFQyId.js} +1 -1
- package/dist/ui/assets/{EntityActivityTimeline-CZ8x4UJE.js → EntityActivityTimeline-g7vtdsx1.js} +1 -1
- package/dist/ui/assets/PlanningModule-D-DeQs4F.js +1 -0
- package/dist/ui/assets/{PlansPage-D86pZSSl.js → PlansPage-BWmfGi0Z.js} +1 -1
- package/dist/ui/assets/{TaskContextUpload-BVIkU9yT.js → TaskContextUpload-BA_lQmS9.js} +1 -1
- package/dist/ui/assets/{TaskSettings-Cv1mNhv_.js → TaskSettings-DAlH4YIP.js} +1 -1
- package/dist/ui/assets/{TaskforceAgentsModule-gmH-PD2q.js → TaskforceAgentsModule-DmeCf6pJ.js} +2 -2
- package/dist/ui/assets/{WorkflowManagerModule-DbfnHJ-f.js → WorkflowManagerModule-p08eDOaa.js} +1 -1
- package/dist/ui/assets/index-GHJgcW3j.js +7 -0
- package/dist/ui/index.html +1 -1
- package/package.json +3 -1
- package/dist/ui/assets/PlanningModule-pRPjR7v5.js +0 -1
- package/dist/ui/assets/index-CTsDBaef.js +0 -7
package/dist/core/Taskforce.js
CHANGED
|
@@ -2033,6 +2033,7 @@ export class TaskforceCore {
|
|
|
2033
2033
|
provider TEXT NOT NULL,
|
|
2034
2034
|
client_name TEXT NOT NULL,
|
|
2035
2035
|
redirect_uris_json TEXT NOT NULL,
|
|
2036
|
+
application_type TEXT NOT NULL DEFAULT 'web',
|
|
2036
2037
|
product_client_id TEXT,
|
|
2037
2038
|
status TEXT NOT NULL DEFAULT 'active',
|
|
2038
2039
|
created_at TEXT NOT NULL,
|
|
@@ -2385,6 +2386,9 @@ export class TaskforceCore {
|
|
|
2385
2386
|
if (!mcpOauthClientColumns.some((c) => c.name === 'product_client_id')) {
|
|
2386
2387
|
this.db.exec(`ALTER TABLE mcp_oauth_clients ADD COLUMN product_client_id TEXT`);
|
|
2387
2388
|
}
|
|
2389
|
+
if (!mcpOauthClientColumns.some((c) => c.name === 'application_type')) {
|
|
2390
|
+
this.db.exec(`ALTER TABLE mcp_oauth_clients ADD COLUMN application_type TEXT NOT NULL DEFAULT 'web'`);
|
|
2391
|
+
}
|
|
2388
2392
|
const mcpOauthGrantColumns = this.db.prepare(`PRAGMA table_info(mcp_oauth_connector_grants)`).all();
|
|
2389
2393
|
if (!mcpOauthGrantColumns.some((c) => c.name === 'product_client_id')) {
|
|
2390
2394
|
this.db.exec(`ALTER TABLE mcp_oauth_connector_grants ADD COLUMN product_client_id TEXT`);
|
|
@@ -2405,6 +2409,7 @@ export class TaskforceCore {
|
|
|
2405
2409
|
else {
|
|
2406
2410
|
try {
|
|
2407
2411
|
this.db.exec(`ALTER TABLE mcp_oauth_clients ADD COLUMN IF NOT EXISTS product_client_id TEXT`);
|
|
2412
|
+
this.db.exec(`ALTER TABLE mcp_oauth_clients ADD COLUMN IF NOT EXISTS application_type TEXT NOT NULL DEFAULT 'web'`);
|
|
2408
2413
|
this.db.exec(`ALTER TABLE mcp_oauth_connector_grants ADD COLUMN IF NOT EXISTS product_client_id TEXT`);
|
|
2409
2414
|
this.db.exec(`ALTER TABLE mcp_oauth_connector_grants ADD COLUMN IF NOT EXISTS ai_profile_id TEXT`);
|
|
2410
2415
|
this.db.exec(`ALTER TABLE mcp_oauth_connector_grants ADD COLUMN IF NOT EXISTS ai_profile_token TEXT`);
|
|
@@ -7749,7 +7754,7 @@ export class TaskforceCore {
|
|
|
7749
7754
|
deletedAt: session.deletedAt,
|
|
7750
7755
|
});
|
|
7751
7756
|
}
|
|
7752
|
-
upsertDocumentReviewCommentForSync(comment) {
|
|
7757
|
+
upsertDocumentReviewCommentForSync(comment, options) {
|
|
7753
7758
|
const deps = this.getDocumentReviewServiceDeps();
|
|
7754
7759
|
return deps.commentStore.upsertForSync({
|
|
7755
7760
|
id: comment.id,
|
|
@@ -7769,7 +7774,7 @@ export class TaskforceCore {
|
|
|
7769
7774
|
createdAt: comment.createdAt,
|
|
7770
7775
|
updatedAt: comment.updatedAt,
|
|
7771
7776
|
deletedAt: comment.deletedAt,
|
|
7772
|
-
});
|
|
7777
|
+
}, options);
|
|
7773
7778
|
}
|
|
7774
7779
|
upsertAnnotatedAttachmentSessionForSync(session) {
|
|
7775
7780
|
const deps = this.getAnnotatedAttachmentServiceDeps();
|
|
@@ -9975,7 +9980,7 @@ export class TaskforceCore {
|
|
|
9975
9980
|
return this.getWorkstream(workstreamId, normalizedWorkspaceId) || updated;
|
|
9976
9981
|
})();
|
|
9977
9982
|
}
|
|
9978
|
-
installDurableTaskCreateAuthoritativeForSync(task, workspaceId) {
|
|
9983
|
+
installDurableTaskCreateAuthoritativeForSync(task, workspaceId, options) {
|
|
9979
9984
|
const normalizedWorkspaceId = this.normalizeWorkspaceId(workspaceId);
|
|
9980
9985
|
const taskId = String(task?.id || '').trim();
|
|
9981
9986
|
const createdAt = String(task?.createdAt || '').trim();
|
|
@@ -9993,6 +9998,31 @@ export class TaskforceCore {
|
|
|
9993
9998
|
return this.db.transaction(() => {
|
|
9994
9999
|
const existing = this.getTask(taskId, normalizedWorkspaceId);
|
|
9995
10000
|
if (!existing) {
|
|
10001
|
+
const deleted = options?.preserveDeletedSuccessor
|
|
10002
|
+
? this.getDeletedTask(taskId, normalizedWorkspaceId)
|
|
10003
|
+
: null;
|
|
10004
|
+
if (deleted) {
|
|
10005
|
+
this.relocateTaskReferenceConflict(normalizedWorkspaceId, referenceNumber, taskId, updatedAt);
|
|
10006
|
+
if (this.reserveTaskReferenceNumber(normalizedWorkspaceId, referenceNumber, taskId) !== referenceNumber) {
|
|
10007
|
+
throw new TaskforceRuleError('Authoritative task reference is already in use.', 409, 'WORKSPACE_SYNC_AUTHORITATIVE_RESPONSE_INVALID');
|
|
10008
|
+
}
|
|
10009
|
+
const authoritativeSnapshot = {
|
|
10010
|
+
...deleted.taskSnapshot,
|
|
10011
|
+
referenceNumber,
|
|
10012
|
+
localReferenceNumber: null,
|
|
10013
|
+
referenceLabel: deriveTaskReferenceLabel({ referenceNumber, localReferenceNumber: null }),
|
|
10014
|
+
createdAt,
|
|
10015
|
+
createdBy: task.createdBy,
|
|
10016
|
+
};
|
|
10017
|
+
const updated = this.db.prepare(`
|
|
10018
|
+
UPDATE deleted_tasks SET task_snapshot_json = ?
|
|
10019
|
+
WHERE tenant_id = ? AND workspace_id = ? AND task_id = ?
|
|
10020
|
+
`).run(JSON.stringify(authoritativeSnapshot), this.tenantId, normalizedWorkspaceId, taskId);
|
|
10021
|
+
if (Number(updated.changes || 0) !== 1) {
|
|
10022
|
+
throw new TaskforceRuleError('Captured deleted task history is missing.', 409, 'WORKSPACE_SYNC_AUTHORITATIVE_RESPONSE_INVALID');
|
|
10023
|
+
}
|
|
10024
|
+
return this.getDeletedTask(taskId, normalizedWorkspaceId).taskSnapshot;
|
|
10025
|
+
}
|
|
9996
10026
|
throw new TaskforceRuleError('Task not found.', 404, 'TASK_NOT_FOUND');
|
|
9997
10027
|
}
|
|
9998
10028
|
const mutableCreateFields = [
|
package/dist/core/types.d.ts
CHANGED
|
@@ -77,6 +77,8 @@ export declare class DocumentReviewCommentStore {
|
|
|
77
77
|
threadStatusUpdatedAt?: string | null;
|
|
78
78
|
resolvedAt?: string | null;
|
|
79
79
|
resolvedByActorId?: string | null;
|
|
80
|
+
}, options?: {
|
|
81
|
+
allowAuthoritativeThreadReconciliation?: boolean;
|
|
80
82
|
}): DocumentReviewCommentSyncRecord;
|
|
81
83
|
softDelete(commentIdRaw: string, workspaceIdRaw: string, deletedAtRaw?: string, deletedByActorIdRaw?: string | null): boolean;
|
|
82
84
|
replaceForSession(input: {
|
|
@@ -235,7 +235,7 @@ export class DocumentReviewCommentStore {
|
|
|
235
235
|
: (input.threadStatus === undefined ? existing.threadStatus : input.threadStatus), input.threadStatusUpdatedAt === undefined ? existing.threadStatusUpdatedAt : normalizeNullable(input.threadStatusUpdatedAt), input.resolvedAt === undefined ? existing.resolvedAt : normalizeNullable(input.resolvedAt), input.resolvedByActorId === undefined ? existing.resolvedByActorId : normalizeNullable(input.resolvedByActorId), normalizeId(input.updatedAt) || new Date().toISOString(), input.deletedAt === undefined ? existing.deletedAt : normalizeNullable(input.deletedAt), this.tenantId, normalizeWorkspaceId(input.workspaceId), normalizeId(input.id));
|
|
236
236
|
return this.get(input.id, input.workspaceId, { includeDeleted: true });
|
|
237
237
|
}
|
|
238
|
-
upsertForSync(input) {
|
|
238
|
+
upsertForSync(input, options) {
|
|
239
239
|
const existing = this.get(input.id, input.workspaceId, { includeDeleted: true });
|
|
240
240
|
if (!existing) {
|
|
241
241
|
return this.create(input);
|
|
@@ -248,7 +248,20 @@ export class DocumentReviewCommentStore {
|
|
|
248
248
|
? undefined
|
|
249
249
|
: normalizeNullable(input.parentCommentId);
|
|
250
250
|
if (incomingParentCommentId !== undefined && incomingParentCommentId !== existing.parentCommentId) {
|
|
251
|
-
|
|
251
|
+
if (options?.allowAuthoritativeThreadReconciliation !== true) {
|
|
252
|
+
throw new Error(`Document review comment ${existing.id} cannot move between threads.`);
|
|
253
|
+
}
|
|
254
|
+
const incomingParent = incomingParentCommentId
|
|
255
|
+
? this.get(incomingParentCommentId, input.workspaceId, { includeDeleted: true })
|
|
256
|
+
: null;
|
|
257
|
+
if (existing.parentCommentId
|
|
258
|
+
|| !incomingParent
|
|
259
|
+
|| incomingParent.deletedAt
|
|
260
|
+
|| incomingParent.sessionId !== existing.sessionId
|
|
261
|
+
|| incomingParent.parentCommentId
|
|
262
|
+
|| incomingParent.id === existing.id) {
|
|
263
|
+
throw new Error(`Document review comment ${existing.id} cannot reconcile to an invalid thread root.`);
|
|
264
|
+
}
|
|
252
265
|
}
|
|
253
266
|
const incomingThreadStatusUpdatedAt = input.threadStatusUpdatedAt === undefined
|
|
254
267
|
? undefined
|
|
@@ -283,13 +296,19 @@ export class DocumentReviewCommentStore {
|
|
|
283
296
|
AND id = ?
|
|
284
297
|
`).run(normalizeId(input.sessionId) || existing.sessionId, normalizeId(input.body), input.anchor ? JSON.stringify(input.anchor) : null, normalizeNullable(input.authorActorId), normalizeNullable(input.updatedByActorId), input.deletedByActorId === undefined ? existing.deletedByActorId : normalizeNullable(input.deletedByActorId), nextParentCommentId, nextParentCommentId
|
|
285
298
|
? null
|
|
286
|
-
: (shouldApplyThreadLifecycle ? input.threadStatus : existing.threadStatus),
|
|
287
|
-
?
|
|
288
|
-
:
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
?
|
|
292
|
-
:
|
|
299
|
+
: (shouldApplyThreadLifecycle ? input.threadStatus : existing.threadStatus), nextParentCommentId
|
|
300
|
+
? null
|
|
301
|
+
: shouldApplyThreadLifecycle
|
|
302
|
+
? incomingThreadStatusUpdatedAt
|
|
303
|
+
: existing.threadStatusUpdatedAt, nextParentCommentId
|
|
304
|
+
? null
|
|
305
|
+
: shouldApplyThreadLifecycle
|
|
306
|
+
? normalizeNullable(input.resolvedAt)
|
|
307
|
+
: existing.resolvedAt, nextParentCommentId
|
|
308
|
+
? null
|
|
309
|
+
: shouldApplyThreadLifecycle
|
|
310
|
+
? normalizeNullable(input.resolvedByActorId)
|
|
311
|
+
: existing.resolvedByActorId, normalizePositiveInteger(input.order) ?? existing.order, normalizeId(input.createdAt) || existing.createdAt, normalizeId(input.updatedAt) || existing.updatedAt, existing.deletedAt || (input.deletedAt === undefined
|
|
293
312
|
? null
|
|
294
313
|
: normalizeNullable(input.deletedAt)), this.tenantId, normalizeWorkspaceId(input.workspaceId), normalizeId(input.id));
|
|
295
314
|
return this.get(input.id, input.workspaceId, { includeDeleted: true });
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
2
|
import { type McpServerFactory } from '@modelcontextprotocol/server';
|
|
3
|
+
export declare function createModernMcpHttpHandler(factory: McpServerFactory, onerror?: (error: Error) => void): import("@modelcontextprotocol/server").McpHttpHandler;
|
|
3
4
|
export declare function isModernMcpHttpRequest(req: IncomingMessage, parsedBody: unknown): Promise<boolean>;
|
|
4
5
|
export declare function handleModernMcpHttpRequest(input: {
|
|
5
6
|
req: IncomingMessage;
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { toNodeHandler, toWebRequest } from '@modelcontextprotocol/node';
|
|
2
2
|
import { createMcpHandler, isLegacyRequest, } from '@modelcontextprotocol/server';
|
|
3
|
+
export function createModernMcpHttpHandler(factory, onerror) {
|
|
4
|
+
return createMcpHandler(factory, {
|
|
5
|
+
legacy: 'reject',
|
|
6
|
+
responseMode: 'auto',
|
|
7
|
+
onerror,
|
|
8
|
+
});
|
|
9
|
+
}
|
|
3
10
|
export async function isModernMcpHttpRequest(req, parsedBody) {
|
|
4
11
|
const request = await toWebRequest(req, parsedBody);
|
|
5
12
|
return !(await isLegacyRequest(request, parsedBody));
|
|
6
13
|
}
|
|
7
14
|
export async function handleModernMcpHttpRequest(input) {
|
|
8
|
-
const handler =
|
|
9
|
-
legacy: 'reject',
|
|
10
|
-
responseMode: 'auto',
|
|
11
|
-
onerror: input.onerror,
|
|
12
|
-
});
|
|
15
|
+
const handler = createModernMcpHttpHandler(input.factory, input.onerror);
|
|
13
16
|
try {
|
|
14
17
|
await toNodeHandler(handler, { onerror: input.onerror })(input.req, input.res, input.parsedBody);
|
|
15
18
|
}
|
package/dist/mcp/runtime.js
CHANGED
|
@@ -119,7 +119,10 @@ class ToolProfileHiddenError extends Error {
|
|
|
119
119
|
suggestedTool;
|
|
120
120
|
constructor(name, activeProfile) {
|
|
121
121
|
const requiredProfiles = getMcpToolRequiredProfiles(name);
|
|
122
|
-
const
|
|
122
|
+
const configuredSuccessor = getMcpToolSuccessor(name);
|
|
123
|
+
const suggestedTool = configuredSuccessor && isMcpToolVisibleInProfile(configuredSuccessor.name, activeProfile)
|
|
124
|
+
? configuredSuccessor
|
|
125
|
+
: null;
|
|
123
126
|
const suffix = suggestedTool ? ` Use ${suggestedTool.name} instead.` : ` Request one of these profiles to use it: ${requiredProfiles.join(', ')}.`;
|
|
124
127
|
super(`Tool ${name} is not available in the ${activeProfile} MCP tool profile.${suffix}`);
|
|
125
128
|
this.activeProfile = activeProfile;
|
|
@@ -1884,6 +1887,9 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
1884
1887
|
} : {}),
|
|
1885
1888
|
title: task?.title || null,
|
|
1886
1889
|
status: task?.status || null,
|
|
1890
|
+
isArchived: Boolean(task?.isArchived),
|
|
1891
|
+
completedAt: task?.completedAt || null,
|
|
1892
|
+
canceledReason: task?.canceledReason || null,
|
|
1887
1893
|
category: task?.category || null,
|
|
1888
1894
|
type: task?.type || null,
|
|
1889
1895
|
priority: task?.priority ?? null,
|
|
@@ -5327,6 +5333,7 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
5327
5333
|
const avatarSuggestion = resolved.created
|
|
5328
5334
|
&& !configuredClientBlocksGeneration
|
|
5329
5335
|
&& isAiProfileAvatarGenerationEligible(resolved.profile)
|
|
5336
|
+
&& isMcpToolVisibleInProfile('generate_profile_avatar', activeToolProfile)
|
|
5330
5337
|
? {
|
|
5331
5338
|
avatarSuggestion: {
|
|
5332
5339
|
nextTool: 'generate_profile_avatar',
|
|
@@ -7825,7 +7832,7 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
7825
7832
|
const { id: inputId, status, reason } = args;
|
|
7826
7833
|
const { id, task } = resolveTaskByIdentifierOrThrow(inputId);
|
|
7827
7834
|
const isCancelled = status === 'cancelled';
|
|
7828
|
-
taskLifecycleCommandService.archive(task, { status, reason });
|
|
7835
|
+
const result = taskLifecycleCommandService.archive(task, { status, reason });
|
|
7829
7836
|
recordMcpWriteAudit('archive_task', { taskId: id, status, cancelled: isCancelled });
|
|
7830
7837
|
await notifyResourceMutation({
|
|
7831
7838
|
taskIds: [id],
|
|
@@ -7833,7 +7840,15 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
7833
7840
|
includeStats: true,
|
|
7834
7841
|
});
|
|
7835
7842
|
return {
|
|
7836
|
-
content: [{ type: "text", text:
|
|
7843
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
7844
|
+
task: buildTaskWriteSummary(result.task),
|
|
7845
|
+
archive: {
|
|
7846
|
+
archived: true,
|
|
7847
|
+
status: result.status,
|
|
7848
|
+
cancelled: result.cancelled,
|
|
7849
|
+
reason: isCancelled ? String(reason || '').trim() || null : null,
|
|
7850
|
+
},
|
|
7851
|
+
}, null, 2) }],
|
|
7837
7852
|
};
|
|
7838
7853
|
}
|
|
7839
7854
|
case "get_config": {
|
|
@@ -8056,8 +8071,9 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
8056
8071
|
case "unarchive_task": {
|
|
8057
8072
|
const { id: inputId } = args;
|
|
8058
8073
|
const { id, task: existingTask } = resolveTaskByIdentifierOrThrow(inputId, { notFoundMessage: buildTaskLookupFailureMessage(String(inputId || '').trim()) });
|
|
8074
|
+
let result;
|
|
8059
8075
|
try {
|
|
8060
|
-
taskLifecycleCommandService.unarchive(existingTask);
|
|
8076
|
+
result = taskLifecycleCommandService.unarchive(existingTask);
|
|
8061
8077
|
}
|
|
8062
8078
|
catch (error) {
|
|
8063
8079
|
if (error instanceof TaskLifecycleCommandError && error.code === 'TASK_NOT_FOUND') {
|
|
@@ -8072,7 +8088,10 @@ export function createTaskforceMcpServer(options = {}) {
|
|
|
8072
8088
|
includeStats: true,
|
|
8073
8089
|
});
|
|
8074
8090
|
return {
|
|
8075
|
-
content: [{ type: "text", text:
|
|
8091
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
8092
|
+
task: buildTaskWriteSummary(result.task),
|
|
8093
|
+
unarchive: { unarchived: true },
|
|
8094
|
+
}, null, 2) }],
|
|
8076
8095
|
};
|
|
8077
8096
|
}
|
|
8078
8097
|
case "bulk_archive": {
|
|
@@ -617,7 +617,7 @@ export function registerTaskPlanningTools(registerTool, executeTool) {
|
|
|
617
617
|
},
|
|
618
618
|
}));
|
|
619
619
|
register('archive_task', (context) => ({
|
|
620
|
-
description: context.describeTool('Move a task to history by archiving it. Use status=\'done\' for completed work or status=\'cancelled\' for abandoned work.
|
|
620
|
+
description: context.describeTool('Move a task to history by archiving it. Use status=\'done\' for completed work or status=\'cancelled\' for abandoned work. Returns compact task and archive state so callers can verify the final status and isArchived=true.'),
|
|
621
621
|
inputSchema: {
|
|
622
622
|
properties: {
|
|
623
623
|
id: stringProperty('Task ID or task reference such as T-123.'),
|
|
@@ -628,7 +628,7 @@ export function registerTaskPlanningTools(registerTool, executeTool) {
|
|
|
628
628
|
},
|
|
629
629
|
}));
|
|
630
630
|
register('unarchive_task', (context) => ({
|
|
631
|
-
description: context.describeTool('Restore an archived task to the active task list.'),
|
|
631
|
+
description: context.describeTool('Restore an archived task to the active task list. Returns compact task and unarchive state so callers can verify isArchived=false.'),
|
|
632
632
|
inputSchema: {
|
|
633
633
|
properties: {
|
|
634
634
|
id: stringProperty('Task ID or task reference such as T-123.'),
|
package/dist/mcp/toolProfiles.js
CHANGED
|
@@ -18,6 +18,7 @@ const MANAGED_AGENT_ALLOWED_MUTATING_TOOLS = new Set([
|
|
|
18
18
|
'add_workstream_comment',
|
|
19
19
|
'complete_workflow_step',
|
|
20
20
|
'replace_task_checklist',
|
|
21
|
+
'review_document',
|
|
21
22
|
]);
|
|
22
23
|
export function normalizeMcpToolProfile(value, fallback) {
|
|
23
24
|
const normalized = typeof value === 'string' ? value.trim().toLowerCase() : '';
|
package/dist/mcp/toolRegistry.js
CHANGED
|
@@ -45,8 +45,8 @@ export const MCP_TOOL_REGISTRY = Object.freeze({
|
|
|
45
45
|
add_workstream_comment: defaultTool({ kind: 'scope', scope: 'tasks:write' }, true),
|
|
46
46
|
archive_workstream: extendedTool({ kind: 'scope', scope: 'tasks:write' }, true),
|
|
47
47
|
unarchive_workstream: extendedTool({ kind: 'scope', scope: 'tasks:write' }, true),
|
|
48
|
-
update_task_workstream:
|
|
49
|
-
update_workstream_initiative:
|
|
48
|
+
update_task_workstream: extendedTool({ kind: 'scope', scope: 'tasks:write' }, true, { name: 'update_task' }),
|
|
49
|
+
update_workstream_initiative: extendedTool({ kind: 'scope', scope: 'tasks:write' }, true, { name: 'update_workstream' }),
|
|
50
50
|
get_task_checklist: defaultTool({ kind: 'scope', scope: 'tasks:read' }, false),
|
|
51
51
|
add_task_checklist_item: defaultTool({ kind: 'scope', scope: 'tasks:write' }, true),
|
|
52
52
|
update_task_checklist_item: defaultTool({ kind: 'scope', scope: 'tasks:write' }, true),
|
|
@@ -58,19 +58,19 @@ export const MCP_TOOL_REGISTRY = Object.freeze({
|
|
|
58
58
|
get_initiative_attachments: extendedTool({ kind: 'scope', scope: 'tasks:read' }, false),
|
|
59
59
|
save_initiative_attachment: defaultTool({ kind: 'scope', scope: 'tasks:write' }, true),
|
|
60
60
|
delete_initiative_attachment: extendedTool({ kind: 'scope', scope: 'tasks:write' }, true),
|
|
61
|
-
search_images:
|
|
62
|
-
get_image:
|
|
61
|
+
search_images: extendedTool({ kind: 'scope', scope: 'tasks:read' }, false),
|
|
62
|
+
get_image: extendedTool({ kind: 'scope', scope: 'tasks:read' }, false),
|
|
63
63
|
search_documents: defaultTool({ kind: 'scope', scope: 'tasks:read' }, false),
|
|
64
64
|
get_document: defaultTool({ kind: 'scope', scope: 'tasks:read' }, false),
|
|
65
65
|
update_document: defaultTool({ kind: 'scope', scope: 'tasks:write' }, true),
|
|
66
66
|
link_document: defaultTool({ kind: 'scope', scope: 'tasks:write' }, true),
|
|
67
67
|
rehome_document: defaultTool({ kind: 'scope', scope: 'tasks:write' }, true),
|
|
68
68
|
unlink_document: defaultTool({ kind: 'scope', scope: 'tasks:write' }, true),
|
|
69
|
-
get_image_annotations:
|
|
69
|
+
get_image_annotations: extendedTool({ kind: 'scope', scope: 'tasks:read' }, false),
|
|
70
70
|
create_annotated_attachment_session: extendedTool({ kind: 'scope', scope: 'tasks:write' }, true),
|
|
71
71
|
update_annotated_attachment_session: extendedTool({ kind: 'scope', scope: 'tasks:write' }, true),
|
|
72
72
|
delete_annotated_attachment_session: extendedTool({ kind: 'scope', scope: 'tasks:write' }, true),
|
|
73
|
-
review_image:
|
|
73
|
+
review_image: extendedTool({ kind: 'scope', scope: 'tasks:write' }, true),
|
|
74
74
|
add_annotated_attachment_marker: extendedTool({ kind: 'scope', scope: 'tasks:write' }, true, { name: 'review_image' }),
|
|
75
75
|
bulk_add_annotated_attachment_markers: extendedTool({ kind: 'scope', scope: 'tasks:write' }, true, { name: 'review_image' }),
|
|
76
76
|
update_annotated_attachment_marker: extendedTool({ kind: 'scope', scope: 'tasks:write' }, true),
|
|
@@ -82,14 +82,14 @@ export const MCP_TOOL_REGISTRY = Object.freeze({
|
|
|
82
82
|
review_document: defaultTool({ kind: 'scope', scope: 'tasks:write' }, true),
|
|
83
83
|
add_document_review_comment: extendedTool({ kind: 'scope', scope: 'tasks:write' }, true, { name: 'review_document' }),
|
|
84
84
|
update_document_review_thread: extendedTool({ kind: 'scope', scope: 'tasks:write' }, true),
|
|
85
|
-
update_document_review_comment:
|
|
85
|
+
update_document_review_comment: extendedTool({ kind: 'scope', scope: 'tasks:write' }, true),
|
|
86
86
|
delete_document_review_comment: extendedTool({ kind: 'scope', scope: 'tasks:write' }, true),
|
|
87
87
|
get_schedule_board: defaultTool({ kind: 'scope', scope: 'tasks:read' }, false),
|
|
88
88
|
update_schedule: defaultTool({ kind: 'scope', scope: 'tasks:write' }, true),
|
|
89
89
|
bulk_carryover: extendedTool({ kind: 'scope', scope: 'tasks:write' }, true),
|
|
90
90
|
set_schedule_preferences: fullTool({ kind: 'session-only' }, true),
|
|
91
91
|
resolve_profile: defaultTool({ kind: 'scope', scope: 'tasks:write' }, true),
|
|
92
|
-
generate_profile_avatar:
|
|
92
|
+
generate_profile_avatar: extendedTool({ kind: 'scope', scope: 'tasks:write' }, true),
|
|
93
93
|
create_task: defaultTool({ kind: 'scope', scope: 'tasks:write' }, true),
|
|
94
94
|
start_task: defaultTool({ kind: 'scope', scope: 'tasks:write' }, true),
|
|
95
95
|
reopen_task: defaultTool({ kind: 'scope', scope: 'tasks:write' }, true),
|
package/dist/server/buildInfo.js
CHANGED
|
@@ -88,6 +88,9 @@ export function resolveBuildInfo(env = process.env) {
|
|
|
88
88
|
env.CF_PAGES_URL,
|
|
89
89
|
env.GITHUB_RUN_ID
|
|
90
90
|
]);
|
|
91
|
+
const environmentId = resolveFirstNonEmpty([
|
|
92
|
+
env.RAILWAY_ENVIRONMENT_ID,
|
|
93
|
+
]);
|
|
91
94
|
const version = explicitVersion
|
|
92
95
|
? explicitVersion
|
|
93
96
|
: appendBuildMetadata(packageVersion, [deployId, gitSha, buildTimeToken(buildTime)]);
|
|
@@ -95,6 +98,7 @@ export function resolveBuildInfo(env = process.env) {
|
|
|
95
98
|
version,
|
|
96
99
|
gitSha,
|
|
97
100
|
buildTime,
|
|
98
|
-
deployId
|
|
101
|
+
deployId,
|
|
102
|
+
environmentId,
|
|
99
103
|
};
|
|
100
104
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { ServerResponse } from 'node:http';
|
|
2
|
+
import type { RequestPerformanceDiagnostics } from '../storage/postgresRequestDiagnostics.js';
|
|
3
|
+
export declare const TASKFORCE_CAPACITY_TRACE_HEADER = "x-taskforce-capacity-trace";
|
|
4
|
+
export type CloudMcpRequestClass = 'initialize' | 'discover' | 'tools_list' | 'read' | 'write' | 'other';
|
|
5
|
+
export type CloudMcpOutcome = 'success' | 'rejected' | 'client_error' | 'server_error' | 'timeout_or_abort';
|
|
6
|
+
export type CloudMcpRejectionClass = 'rate_limited' | 'auth_or_scope' | 'protocol' | 'other_client';
|
|
7
|
+
type EventLoopSampler = {
|
|
8
|
+
enable(): void;
|
|
9
|
+
disable?(): void;
|
|
10
|
+
reset(): void;
|
|
11
|
+
percentile(percentile: number): number;
|
|
12
|
+
readonly max: number;
|
|
13
|
+
};
|
|
14
|
+
type CapacityTelemetryOptions = {
|
|
15
|
+
emit?: (payload: Record<string, unknown>) => void;
|
|
16
|
+
eventLoop?: EventLoopSampler;
|
|
17
|
+
now?: () => number;
|
|
18
|
+
cpuUsage?: typeof process.cpuUsage;
|
|
19
|
+
memoryUsage?: typeof process.memoryUsage;
|
|
20
|
+
windowMs?: number;
|
|
21
|
+
maxSamples?: number;
|
|
22
|
+
};
|
|
23
|
+
export declare class CloudMcpCapacityTelemetry {
|
|
24
|
+
private readonly emit;
|
|
25
|
+
private readonly eventLoop;
|
|
26
|
+
private readonly now;
|
|
27
|
+
private readonly cpuUsage;
|
|
28
|
+
private readonly memoryUsage;
|
|
29
|
+
private readonly windowMs;
|
|
30
|
+
private readonly maxSamples;
|
|
31
|
+
private activeRequests;
|
|
32
|
+
private maxActiveRequests;
|
|
33
|
+
private samples;
|
|
34
|
+
private completedRequests;
|
|
35
|
+
private requestClassCounts;
|
|
36
|
+
private outcomeCounts;
|
|
37
|
+
private rejectionCounts;
|
|
38
|
+
private statusClassCounts;
|
|
39
|
+
private windowStartedAt;
|
|
40
|
+
private windowCpuStartedAt;
|
|
41
|
+
private readonly flushTimer;
|
|
42
|
+
constructor(options?: CapacityTelemetryOptions);
|
|
43
|
+
begin(requestClass?: CloudMcpRequestClass): {
|
|
44
|
+
classify: (nextClass: CloudMcpRequestClass) => void;
|
|
45
|
+
setTraceHeaders: (res: ServerResponse, postgres?: RequestPerformanceDiagnostics | null) => void;
|
|
46
|
+
finish: (input: {
|
|
47
|
+
statusCode: number;
|
|
48
|
+
aborted?: boolean;
|
|
49
|
+
postgres?: RequestPerformanceDiagnostics | null;
|
|
50
|
+
}) => void;
|
|
51
|
+
};
|
|
52
|
+
snapshot(): Record<string, unknown>;
|
|
53
|
+
flush(): Record<string, unknown> | null;
|
|
54
|
+
shutdown(): void;
|
|
55
|
+
private flushIfDue;
|
|
56
|
+
private minimumPoolIdle;
|
|
57
|
+
}
|
|
58
|
+
export declare function isCloudMcpCapacityTelemetryEnabled(): boolean;
|
|
59
|
+
export declare function beginCloudMcpCapacityRequest(requestClass?: CloudMcpRequestClass): {
|
|
60
|
+
classify: (nextClass: CloudMcpRequestClass) => void;
|
|
61
|
+
setTraceHeaders: (res: ServerResponse, postgres?: RequestPerformanceDiagnostics | null) => void;
|
|
62
|
+
finish: (input: {
|
|
63
|
+
statusCode: number;
|
|
64
|
+
aborted?: boolean;
|
|
65
|
+
postgres?: RequestPerformanceDiagnostics | null;
|
|
66
|
+
}) => void;
|
|
67
|
+
};
|
|
68
|
+
export {};
|