@taskforcehq/taskforce 0.3.301 → 0.3.303
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 +37 -2
- package/dist/TaskforceCore.filter-persistence.test.js +1 -1
- package/dist/TaskforceCore.js +72 -33
- package/dist/TaskforceCore.test.js +848 -130
- package/dist/components/features/TaskSettings.js +14 -82
- package/dist/components/features/TaskSettings.test.js +33 -70
- package/dist/components/features/settings/TaxonomyLibraryManager.js +8 -2
- package/dist/components/features/settings/TaxonomyLibraryManager.test.js +1 -1
- package/dist/components/task/TaskActionHeader.js +6 -3
- package/dist/components/task/TaskCard.js +6 -3
- package/dist/components/task/TaskForm.js +2 -2
- package/dist/components/task/TaskForm.test.js +41 -2
- package/dist/components/task/TaskKanban.test.js +17 -0
- package/dist/components/ui/ReferenceBadgeButton.js +1 -1
- package/dist/components/views/PlansPage.d.ts +3 -1
- package/dist/components/views/PlansPage.js +109 -49
- package/dist/components/views/PlansPage.test.d.ts +1 -0
- package/dist/components/views/PlansPage.test.js +100 -0
- package/dist/components/views/StandaloneLayout.d.ts +1 -0
- package/dist/components/views/StandaloneLayout.js +473 -256
- package/dist/components/views/panels/PlanningDrawer.js +18 -1
- package/dist/components/views/standalone/modals/AccountHubModal.d.ts +48 -0
- package/dist/components/views/standalone/modals/AccountHubModal.js +36 -0
- package/dist/components/views/standalone/modals/AccountHubModal.test.d.ts +1 -0
- package/dist/components/views/standalone/modals/AccountHubModal.test.js +26 -0
- package/dist/components/views/standalone/modals/CreateWorkspaceConfirmModal.d.ts +9 -0
- package/dist/components/views/standalone/modals/CreateWorkspaceConfirmModal.js +8 -0
- package/dist/components/views/standalone/modals/EditProfileModal.d.ts +26 -0
- package/dist/components/views/standalone/modals/EditProfileModal.js +10 -0
- package/dist/components/views/standalone/modals/HelpModal.d.ts +9 -0
- package/dist/components/views/standalone/modals/HelpModal.js +8 -0
- package/dist/components/views/standalone/modals/ScheduleWarningModal.d.ts +13 -0
- package/dist/components/views/standalone/modals/ScheduleWarningModal.js +6 -0
- package/dist/components/views/standalone/modals/SyncStatusModal.d.ts +61 -0
- package/dist/components/views/standalone/modals/SyncStatusModal.js +38 -0
- package/dist/components/views/standalone/modals/TeamManagementModal.d.ts +64 -0
- package/dist/components/views/standalone/modals/TeamManagementModal.js +10 -0
- package/dist/components/views/standalone/modals/types.d.ts +2 -0
- package/dist/components/views/standalone/modals/types.js +1 -0
- package/dist/components/views/teamManagementAccess.d.ts +1 -1
- package/dist/components/views/teamManagementAccess.js +2 -2
- package/dist/components/views/teamManagementAccess.test.js +3 -3
- package/dist/config/deployment.js +2 -2
- package/dist/config/deployment.test.js +5 -3
- package/dist/core/AiProfileService.js +7 -2
- package/dist/core/AiProfiles.test.js +19 -0
- package/dist/core/EntitlementsPolicy.test.js +2 -2
- package/dist/core/GlobalSettingsService.js +78 -18
- package/dist/core/PlanEntitlementService.d.ts +29 -5
- package/dist/core/PlanEntitlementService.js +297 -219
- package/dist/core/SignupMonetizationSettings.test.js +173 -49
- package/dist/core/SyncReconciliationService.d.ts +2 -0
- package/dist/core/SyncReconciliationService.js +3 -0
- package/dist/core/SystemAdmin.test.js +186 -96
- package/dist/core/TaskAuditTimeline.test.js +40 -0
- package/dist/core/Taskforce.d.ts +100 -10
- package/dist/core/Taskforce.ids.test.js +133 -0
- package/dist/core/Taskforce.js +459 -127
- package/dist/core/Taskforce.mcpAuth.test.js +0 -2
- package/dist/core/UserProfileAvatarDrafts.test.d.ts +1 -0
- package/dist/core/UserProfileAvatarDrafts.test.js +111 -0
- package/dist/core/taskReferencePolicy.d.ts +28 -0
- package/dist/core/taskReferencePolicy.js +189 -0
- package/dist/core/types.d.ts +13 -12
- package/dist/hooks/tasks/useTaskFormActions.js +3 -0
- package/dist/hooks/useSyncOrchestrator.js +17 -3
- package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +97 -5
- package/dist/hooks/useTaskData.js +3 -2
- package/dist/hooks/useTaskData.test.js +66 -0
- package/dist/hooks/useTaskforce.d.ts +8 -0
- package/dist/hooks/useTaskforce.js +72 -19
- package/dist/hooks/useTaskforce.sync-behavior.test.js +185 -6
- package/dist/mcp/aiProfileBootstrap.d.ts +29 -0
- package/dist/mcp/aiProfileBootstrap.js +80 -0
- package/dist/mcp/aiProfileBootstrap.test.d.ts +1 -0
- package/dist/mcp/aiProfileBootstrap.test.js +68 -0
- package/dist/mcp/clientIntegrations.d.ts +2 -8
- package/dist/mcp/clientIntegrations.js +21 -40
- package/dist/mcp/clientIntegrations.test.js +28 -2
- package/dist/mcp/clientProfileDefaults.d.ts +12 -0
- package/dist/mcp/clientProfileDefaults.js +37 -0
- package/dist/mcp/runtime.d.ts +10 -7
- package/dist/mcp/runtime.js +131 -48
- package/dist/mcp/runtime.test.js +321 -83
- package/dist/migrations/billingSchemaParity.test.js +3 -0
- package/dist/migrations/taskSchemaMigrations.js +68 -1
- package/dist/qaOpen.test.d.ts +1 -0
- package/dist/qaOpen.test.js +56 -0
- package/dist/server/index.cookieProxy.test.js +2 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +17 -1
- package/dist/server/index.test.js +15 -1
- package/dist/server/mockStripe.d.ts +1 -0
- package/dist/server/mockStripe.js +2 -0
- package/dist/server/routes/admin.js +105 -45
- package/dist/server/routes/auth.d.ts +6 -0
- package/dist/server/routes/auth.js +505 -30
- package/dist/server/routes/billing.js +517 -24
- package/dist/server/routes/billing.test.js +967 -45
- package/dist/server/routes/documents.js +6 -1
- package/dist/server/routes/shared.d.ts +1 -1
- package/dist/server/routes/shared.js +16 -6
- package/dist/server/routes/sync.integration.test.js +290 -0
- package/dist/server/routes/sync.js +234 -1922
- package/dist/server/routes/tasks.js +18 -4
- package/dist/server/routes.js +29 -22
- package/dist/server/routes.test.js +639 -82
- package/dist/shared/runtimeContract.d.ts +1 -1
- package/dist/sync/cloudSyncApi.d.ts +1 -0
- package/dist/sync/collaborationSyncPayload.d.ts +17 -0
- package/dist/sync/collaborationSyncPayload.js +131 -0
- package/dist/sync/collaborationSyncPayload.test.d.ts +1 -0
- package/dist/sync/collaborationSyncPayload.test.js +104 -0
- package/dist/sync/collaborationSyncState.d.ts +15 -0
- package/dist/sync/collaborationSyncState.js +60 -0
- package/dist/sync/contentSyncPayload.d.ts +45 -0
- package/dist/sync/contentSyncPayload.js +104 -0
- package/dist/sync/contentSyncPayload.test.d.ts +1 -0
- package/dist/sync/contentSyncPayload.test.js +104 -0
- package/dist/sync/contentSyncState.d.ts +98 -0
- package/dist/sync/contentSyncState.js +1004 -0
- package/dist/sync/planningSyncPayload.d.ts +9 -0
- package/dist/sync/planningSyncPayload.js +82 -0
- package/dist/sync/planningSyncPayload.test.d.ts +1 -0
- package/dist/sync/planningSyncPayload.test.js +68 -0
- package/dist/sync/syncApplyHandlers.d.ts +83 -0
- package/dist/sync/syncApplyHandlers.js +445 -0
- package/dist/sync/syncService.d.ts +1 -0
- package/dist/sync/syncService.js +21 -8
- package/dist/sync/taskSyncPayload.d.ts +33 -0
- package/dist/sync/taskSyncPayload.js +126 -0
- package/dist/sync/taskSyncPayload.test.d.ts +1 -0
- package/dist/sync/taskSyncPayload.test.js +54 -0
- package/dist/sync/workspacePullFeed.d.ts +38 -0
- package/dist/sync/workspacePullFeed.js +349 -0
- package/dist/sync/workspacePullFeed.test.d.ts +1 -0
- package/dist/sync/workspacePullFeed.test.js +278 -0
- package/dist/sync/workspaceSyncModel.d.ts +4 -1
- package/dist/sync/workspaceSyncModel.js +9 -2
- package/dist/sync/workspaceSyncModel.test.js +29 -0
- package/dist/test/setup.js +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/ui/assets/{AgentsModule-Bdq3T1Ts.js → AgentsModule-CpsTmrIW.js} +1 -1
- package/dist/ui/assets/{AnnotatedAttachmentWorkspace-jKUVo-PJ.js → AnnotatedAttachmentWorkspace-C_TmXZwA.js} +1 -1
- package/dist/ui/assets/{DocumentWorkspace-DuQa-uIC.js → DocumentWorkspace-C3GyzrWm.js} +2 -2
- package/dist/ui/assets/{InitiativesModule-C8Pi2VTk.js → InitiativesModule-4-Rh2K2n.js} +1 -1
- package/dist/ui/assets/PlansPage-BP7AYOqr.js +1 -0
- package/dist/ui/assets/TaskSettings-BOC5F6Ag.js +8 -0
- package/dist/ui/assets/{TaskSettings-BwB9NtmJ.css → TaskSettings-CnIBL_Eb.css} +1 -1
- package/dist/ui/assets/{WorkflowsModule-b6TLuHwJ.js → WorkflowsModule-CGk9s3NJ.js} +1 -1
- package/dist/ui/assets/index-CLIMgR6g.js +6 -0
- package/dist/ui/assets/index-DneETxcu.css +1 -0
- package/dist/ui/assets/{vendor-icons-QZyhEwgT.js → vendor-icons-pWocEipT.js} +1 -1
- package/dist/ui/index.html +3 -3
- package/dist/utils/accountProfileSummaryCache.d.ts +31 -0
- package/dist/utils/accountProfileSummaryCache.js +97 -0
- package/dist/utils/accountProfileSummaryCache.test.d.ts +1 -0
- package/dist/utils/accountProfileSummaryCache.test.js +63 -0
- package/dist/utils/taskActivity.js +17 -4
- package/dist/utils/taskActivity.test.js +27 -0
- package/dist/utils/taskNormalization.js +10 -2
- package/dist/utils/taskReferences.d.ts +11 -1
- package/dist/utils/taskReferences.js +33 -1
- package/package.json +4 -3
- package/scripts/qa-open-lib.mjs +175 -0
- package/scripts/qa-open-lib.mjs.d.ts +49 -0
- package/scripts/qa-open.mjs +352 -0
- package/dist/ui/assets/PlansPage-B6BDECSi.js +0 -1
- package/dist/ui/assets/TaskSettings-DUJgRTPU.js +0 -8
- package/dist/ui/assets/index-BiiF1cLQ.css +0 -1
- package/dist/ui/assets/index-xBWLPOEb.js +0 -6
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { IncomingHttpHeaders } from 'http';
|
|
2
|
+
import type { ResolveAiProfileInput } from '../core/Taskforce.js';
|
|
3
|
+
import { type AiProfileSurfaceType } from '../shared/aiProfileSurfaceType.js';
|
|
4
|
+
export interface AiProfileBootstrapConfig {
|
|
5
|
+
aiProfileToken?: string | null;
|
|
6
|
+
aiProfileName?: string | null;
|
|
7
|
+
aiProfileIcon?: string | null;
|
|
8
|
+
aiProfileColor?: string | null;
|
|
9
|
+
aiProfileDescription?: string | null;
|
|
10
|
+
aiProfileRole?: string | null;
|
|
11
|
+
aiProfileProvider?: string | null;
|
|
12
|
+
aiProfileModel?: string | null;
|
|
13
|
+
aiProfileSurfaceType?: AiProfileSurfaceType | null;
|
|
14
|
+
}
|
|
15
|
+
export declare const AI_PROFILE_BOOTSTRAP_HEADER_NAMES: {
|
|
16
|
+
readonly aiProfileToken: "X-Taskforce-AI-Profile-Token";
|
|
17
|
+
readonly aiProfileName: "X-Taskforce-AI-Name";
|
|
18
|
+
readonly aiProfileIcon: "X-Taskforce-AI-Icon";
|
|
19
|
+
readonly aiProfileColor: "X-Taskforce-AI-Color";
|
|
20
|
+
readonly aiProfileDescription: "X-Taskforce-AI-Description";
|
|
21
|
+
readonly aiProfileRole: "X-Taskforce-AI-Role";
|
|
22
|
+
readonly aiProfileProvider: "X-Taskforce-AI-Provider";
|
|
23
|
+
readonly aiProfileModel: "X-Taskforce-AI-Model";
|
|
24
|
+
readonly aiProfileSurfaceType: "X-Taskforce-AI-Surface-Type";
|
|
25
|
+
};
|
|
26
|
+
export declare function normalizeAiProfileBootstrapConfig(input: AiProfileBootstrapConfig): AiProfileBootstrapConfig;
|
|
27
|
+
export declare function buildAiProfileBootstrapHeaders(input: AiProfileBootstrapConfig): Record<string, string>;
|
|
28
|
+
export declare function parseAiProfileBootstrapHeaders(headers: IncomingHttpHeaders | Record<string, string | string[] | undefined>): Required<AiProfileBootstrapConfig>;
|
|
29
|
+
export declare function buildResolveAiProfileInputFromBootstrap(workspaceId: string, bootstrap: AiProfileBootstrapConfig, includeToken?: boolean): Pick<ResolveAiProfileInput, 'workspaceId' | 'name' | 'profileToken' | 'icon' | 'color' | 'description' | 'role' | 'provider' | 'model' | 'surfaceType'> | null;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { parseAiProfileSurfaceType } from '../shared/aiProfileSurfaceType.js';
|
|
2
|
+
export const AI_PROFILE_BOOTSTRAP_HEADER_NAMES = {
|
|
3
|
+
aiProfileToken: 'X-Taskforce-AI-Profile-Token',
|
|
4
|
+
aiProfileName: 'X-Taskforce-AI-Name',
|
|
5
|
+
aiProfileIcon: 'X-Taskforce-AI-Icon',
|
|
6
|
+
aiProfileColor: 'X-Taskforce-AI-Color',
|
|
7
|
+
aiProfileDescription: 'X-Taskforce-AI-Description',
|
|
8
|
+
aiProfileRole: 'X-Taskforce-AI-Role',
|
|
9
|
+
aiProfileProvider: 'X-Taskforce-AI-Provider',
|
|
10
|
+
aiProfileModel: 'X-Taskforce-AI-Model',
|
|
11
|
+
aiProfileSurfaceType: 'X-Taskforce-AI-Surface-Type',
|
|
12
|
+
};
|
|
13
|
+
function normalizeBootstrapValue(value) {
|
|
14
|
+
const normalized = String(value || '').trim();
|
|
15
|
+
return normalized || null;
|
|
16
|
+
}
|
|
17
|
+
function normalizeBootstrapSurfaceType(value) {
|
|
18
|
+
if (value === null || value === undefined)
|
|
19
|
+
return null;
|
|
20
|
+
return parseAiProfileSurfaceType(value);
|
|
21
|
+
}
|
|
22
|
+
export function normalizeAiProfileBootstrapConfig(input) {
|
|
23
|
+
return {
|
|
24
|
+
aiProfileToken: normalizeBootstrapValue(input.aiProfileToken),
|
|
25
|
+
aiProfileName: normalizeBootstrapValue(input.aiProfileName),
|
|
26
|
+
aiProfileIcon: normalizeBootstrapValue(input.aiProfileIcon),
|
|
27
|
+
aiProfileColor: normalizeBootstrapValue(input.aiProfileColor),
|
|
28
|
+
aiProfileDescription: normalizeBootstrapValue(input.aiProfileDescription),
|
|
29
|
+
aiProfileRole: normalizeBootstrapValue(input.aiProfileRole),
|
|
30
|
+
aiProfileProvider: normalizeBootstrapValue(input.aiProfileProvider),
|
|
31
|
+
aiProfileModel: normalizeBootstrapValue(input.aiProfileModel),
|
|
32
|
+
aiProfileSurfaceType: normalizeBootstrapSurfaceType(input.aiProfileSurfaceType),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export function buildAiProfileBootstrapHeaders(input) {
|
|
36
|
+
const normalized = normalizeAiProfileBootstrapConfig(input);
|
|
37
|
+
const headers = {};
|
|
38
|
+
for (const [key, headerName] of Object.entries(AI_PROFILE_BOOTSTRAP_HEADER_NAMES)) {
|
|
39
|
+
const value = normalized[key];
|
|
40
|
+
if (value)
|
|
41
|
+
headers[headerName] = value;
|
|
42
|
+
}
|
|
43
|
+
return headers;
|
|
44
|
+
}
|
|
45
|
+
export function parseAiProfileBootstrapHeaders(headers) {
|
|
46
|
+
const readHeader = (headerName) => {
|
|
47
|
+
const value = headers[headerName] ?? headers[headerName.toLowerCase()];
|
|
48
|
+
if (Array.isArray(value))
|
|
49
|
+
return normalizeBootstrapValue(value[0]);
|
|
50
|
+
return normalizeBootstrapValue(value);
|
|
51
|
+
};
|
|
52
|
+
return {
|
|
53
|
+
aiProfileToken: readHeader(AI_PROFILE_BOOTSTRAP_HEADER_NAMES.aiProfileToken),
|
|
54
|
+
aiProfileName: readHeader(AI_PROFILE_BOOTSTRAP_HEADER_NAMES.aiProfileName),
|
|
55
|
+
aiProfileIcon: readHeader(AI_PROFILE_BOOTSTRAP_HEADER_NAMES.aiProfileIcon),
|
|
56
|
+
aiProfileColor: readHeader(AI_PROFILE_BOOTSTRAP_HEADER_NAMES.aiProfileColor),
|
|
57
|
+
aiProfileDescription: readHeader(AI_PROFILE_BOOTSTRAP_HEADER_NAMES.aiProfileDescription),
|
|
58
|
+
aiProfileRole: readHeader(AI_PROFILE_BOOTSTRAP_HEADER_NAMES.aiProfileRole),
|
|
59
|
+
aiProfileProvider: readHeader(AI_PROFILE_BOOTSTRAP_HEADER_NAMES.aiProfileProvider),
|
|
60
|
+
aiProfileModel: readHeader(AI_PROFILE_BOOTSTRAP_HEADER_NAMES.aiProfileModel),
|
|
61
|
+
aiProfileSurfaceType: normalizeBootstrapSurfaceType(readHeader(AI_PROFILE_BOOTSTRAP_HEADER_NAMES.aiProfileSurfaceType)),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
export function buildResolveAiProfileInputFromBootstrap(workspaceId, bootstrap, includeToken = true) {
|
|
65
|
+
const normalized = normalizeAiProfileBootstrapConfig(bootstrap);
|
|
66
|
+
if (!normalized.aiProfileName)
|
|
67
|
+
return null;
|
|
68
|
+
return {
|
|
69
|
+
workspaceId,
|
|
70
|
+
name: normalized.aiProfileName,
|
|
71
|
+
...(includeToken && normalized.aiProfileToken ? { profileToken: normalized.aiProfileToken } : {}),
|
|
72
|
+
...(normalized.aiProfileIcon ? { icon: normalized.aiProfileIcon } : {}),
|
|
73
|
+
...(normalized.aiProfileColor ? { color: normalized.aiProfileColor } : {}),
|
|
74
|
+
...(normalized.aiProfileDescription ? { description: normalized.aiProfileDescription } : {}),
|
|
75
|
+
...(normalized.aiProfileRole ? { role: normalized.aiProfileRole } : {}),
|
|
76
|
+
...(normalized.aiProfileProvider ? { provider: normalized.aiProfileProvider } : {}),
|
|
77
|
+
...(normalized.aiProfileModel ? { model: normalized.aiProfileModel } : {}),
|
|
78
|
+
...(normalized.aiProfileSurfaceType ? { surfaceType: normalized.aiProfileSurfaceType } : {}),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { AI_PROFILE_BOOTSTRAP_HEADER_NAMES, buildAiProfileBootstrapHeaders, buildResolveAiProfileInputFromBootstrap, parseAiProfileBootstrapHeaders, } from './aiProfileBootstrap';
|
|
3
|
+
describe('aiProfileBootstrap', () => {
|
|
4
|
+
it('builds and parses bootstrap headers from a shared contract', () => {
|
|
5
|
+
const headers = buildAiProfileBootstrapHeaders({
|
|
6
|
+
aiProfileName: 'Automation Codex',
|
|
7
|
+
aiProfileToken: 'tfp_automation_codex',
|
|
8
|
+
aiProfileIcon: 'Code2',
|
|
9
|
+
aiProfileColor: '#10a37f',
|
|
10
|
+
aiProfileDescription: 'OpenAI Codex coding agent connected through MCP.',
|
|
11
|
+
aiProfileRole: 'Coding Agent',
|
|
12
|
+
aiProfileProvider: 'OpenAI',
|
|
13
|
+
aiProfileModel: 'Codex',
|
|
14
|
+
aiProfileSurfaceType: 'coding_tool',
|
|
15
|
+
});
|
|
16
|
+
expect(headers).toEqual({
|
|
17
|
+
[AI_PROFILE_BOOTSTRAP_HEADER_NAMES.aiProfileName]: 'Automation Codex',
|
|
18
|
+
[AI_PROFILE_BOOTSTRAP_HEADER_NAMES.aiProfileToken]: 'tfp_automation_codex',
|
|
19
|
+
[AI_PROFILE_BOOTSTRAP_HEADER_NAMES.aiProfileIcon]: 'Code2',
|
|
20
|
+
[AI_PROFILE_BOOTSTRAP_HEADER_NAMES.aiProfileColor]: '#10a37f',
|
|
21
|
+
[AI_PROFILE_BOOTSTRAP_HEADER_NAMES.aiProfileDescription]: 'OpenAI Codex coding agent connected through MCP.',
|
|
22
|
+
[AI_PROFILE_BOOTSTRAP_HEADER_NAMES.aiProfileRole]: 'Coding Agent',
|
|
23
|
+
[AI_PROFILE_BOOTSTRAP_HEADER_NAMES.aiProfileProvider]: 'OpenAI',
|
|
24
|
+
[AI_PROFILE_BOOTSTRAP_HEADER_NAMES.aiProfileModel]: 'Codex',
|
|
25
|
+
[AI_PROFILE_BOOTSTRAP_HEADER_NAMES.aiProfileSurfaceType]: 'coding_tool',
|
|
26
|
+
});
|
|
27
|
+
expect(parseAiProfileBootstrapHeaders(headers)).toEqual({
|
|
28
|
+
aiProfileName: 'Automation Codex',
|
|
29
|
+
aiProfileToken: 'tfp_automation_codex',
|
|
30
|
+
aiProfileIcon: 'Code2',
|
|
31
|
+
aiProfileColor: '#10a37f',
|
|
32
|
+
aiProfileDescription: 'OpenAI Codex coding agent connected through MCP.',
|
|
33
|
+
aiProfileRole: 'Coding Agent',
|
|
34
|
+
aiProfileProvider: 'OpenAI',
|
|
35
|
+
aiProfileModel: 'Codex',
|
|
36
|
+
aiProfileSurfaceType: 'coding_tool',
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
it('builds resolve_profile input from bootstrap metadata', () => {
|
|
40
|
+
expect(buildResolveAiProfileInputFromBootstrap('workspace-1', {
|
|
41
|
+
aiProfileName: 'Automation Codex',
|
|
42
|
+
aiProfileToken: 'tfp_automation_codex',
|
|
43
|
+
aiProfileIcon: 'Code2',
|
|
44
|
+
aiProfileColor: '#10a37f',
|
|
45
|
+
aiProfileDescription: 'OpenAI Codex coding agent connected through MCP.',
|
|
46
|
+
aiProfileRole: 'Coding Agent',
|
|
47
|
+
aiProfileProvider: 'OpenAI',
|
|
48
|
+
aiProfileModel: 'Codex',
|
|
49
|
+
aiProfileSurfaceType: 'coding_tool',
|
|
50
|
+
})).toEqual({
|
|
51
|
+
workspaceId: 'workspace-1',
|
|
52
|
+
name: 'Automation Codex',
|
|
53
|
+
profileToken: 'tfp_automation_codex',
|
|
54
|
+
icon: 'Code2',
|
|
55
|
+
color: '#10a37f',
|
|
56
|
+
description: 'OpenAI Codex coding agent connected through MCP.',
|
|
57
|
+
role: 'Coding Agent',
|
|
58
|
+
provider: 'OpenAI',
|
|
59
|
+
model: 'Codex',
|
|
60
|
+
surfaceType: 'coding_tool',
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
it('returns null resolve input when no bootstrap name is present', () => {
|
|
64
|
+
expect(buildResolveAiProfileInputFromBootstrap('workspace-1', {
|
|
65
|
+
aiProfileToken: 'tfp_automation_codex',
|
|
66
|
+
})).toBeNull();
|
|
67
|
+
});
|
|
68
|
+
});
|
|
@@ -1,21 +1,15 @@
|
|
|
1
|
+
import { type AiProfileBootstrapConfig } from './aiProfileBootstrap.js';
|
|
1
2
|
export type McpClientId = 'cursor' | 'cline' | 'vscode' | 'windsurf' | 'antigravity' | 'openclaw' | 'codex' | 'claude-code' | 'gemini-cli' | 'claude-desktop' | 'chatgpt-desktop';
|
|
2
3
|
export interface McpClientOption {
|
|
3
4
|
id: McpClientId;
|
|
4
5
|
label: string;
|
|
5
6
|
disabled?: boolean;
|
|
6
7
|
}
|
|
7
|
-
export interface BuildCloudMcpClientConfigInput {
|
|
8
|
+
export interface BuildCloudMcpClientConfigInput extends AiProfileBootstrapConfig {
|
|
8
9
|
clientId: McpClientId;
|
|
9
10
|
endpoint: string;
|
|
10
11
|
tokenValue: string;
|
|
11
12
|
serverId: string;
|
|
12
|
-
aiProfileName?: string | null;
|
|
13
|
-
aiProfileToken?: string | null;
|
|
14
|
-
aiProfileDescription?: string | null;
|
|
15
|
-
aiProfileRole?: string | null;
|
|
16
|
-
aiProfileProvider?: string | null;
|
|
17
|
-
aiProfileModel?: string | null;
|
|
18
|
-
aiProfileSurfaceType?: string | null;
|
|
19
13
|
}
|
|
20
14
|
export interface CloudMcpClientIntegration {
|
|
21
15
|
clientId: McpClientId;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { buildAiProfileBootstrapHeaders } from './aiProfileBootstrap.js';
|
|
1
2
|
export const MCP_CLIENT_OPTIONS = [
|
|
2
3
|
{ id: 'cursor', label: 'Cursor' },
|
|
3
4
|
{ id: 'cline', label: 'Cline' },
|
|
@@ -29,38 +30,18 @@ function buildConnectorDetails(clientId, endpoint) {
|
|
|
29
30
|
return endpoint;
|
|
30
31
|
}
|
|
31
32
|
function buildCloudMcpHeaders(input) {
|
|
32
|
-
|
|
33
|
-
Authorization: `Bearer ${input.tokenValue}
|
|
33
|
+
return {
|
|
34
|
+
Authorization: `Bearer ${input.tokenValue}`,
|
|
35
|
+
...buildAiProfileBootstrapHeaders(input),
|
|
34
36
|
};
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
headers['X-Taskforce-AI-Name'] = aiProfileName;
|
|
44
|
-
}
|
|
45
|
-
if (aiProfileToken) {
|
|
46
|
-
headers['X-Taskforce-AI-Profile-Token'] = aiProfileToken;
|
|
47
|
-
}
|
|
48
|
-
if (aiProfileDescription) {
|
|
49
|
-
headers['X-Taskforce-AI-Description'] = aiProfileDescription;
|
|
50
|
-
}
|
|
51
|
-
if (aiProfileRole) {
|
|
52
|
-
headers['X-Taskforce-AI-Role'] = aiProfileRole;
|
|
53
|
-
}
|
|
54
|
-
if (aiProfileProvider) {
|
|
55
|
-
headers['X-Taskforce-AI-Provider'] = aiProfileProvider;
|
|
56
|
-
}
|
|
57
|
-
if (aiProfileModel) {
|
|
58
|
-
headers['X-Taskforce-AI-Model'] = aiProfileModel;
|
|
59
|
-
}
|
|
60
|
-
if (aiProfileSurfaceType) {
|
|
61
|
-
headers['X-Taskforce-AI-Surface-Type'] = aiProfileSurfaceType;
|
|
62
|
-
}
|
|
63
|
-
return headers;
|
|
37
|
+
}
|
|
38
|
+
function buildAutomationBootstrapInstruction(baseInstruction) {
|
|
39
|
+
return `${baseInstruction} Keep the generated AI bootstrap headers intact so Taskforce can bind and restore the same AI profile automatically.`;
|
|
40
|
+
}
|
|
41
|
+
function buildConfigurationInstruction(baseInstruction, options) {
|
|
42
|
+
if (options?.usesGeneratedConfig === false)
|
|
43
|
+
return baseInstruction;
|
|
44
|
+
return buildAutomationBootstrapInstruction(`${baseInstruction} Use the generated config exactly as shown.`);
|
|
64
45
|
}
|
|
65
46
|
export function buildCloudMcpClientIntegration(input) {
|
|
66
47
|
const { clientId, endpoint, tokenValue, serverId } = input;
|
|
@@ -81,7 +62,7 @@ export function buildCloudMcpClientIntegration(input) {
|
|
|
81
62
|
headers
|
|
82
63
|
},
|
|
83
64
|
instructionLabel: 'Cursor Configuration Instructions',
|
|
84
|
-
instructionText: 'Open Cursor settings, find MCP servers, and paste this config.
|
|
65
|
+
instructionText: buildConfigurationInstruction('Open Cursor settings, find MCP servers, and paste this config.')
|
|
85
66
|
};
|
|
86
67
|
case 'cline':
|
|
87
68
|
return {
|
|
@@ -94,7 +75,7 @@ export function buildCloudMcpClientIntegration(input) {
|
|
|
94
75
|
headers
|
|
95
76
|
},
|
|
96
77
|
instructionLabel: 'Cline Configuration Instructions',
|
|
97
|
-
instructionText: 'Open Cline MCP Servers, add a remote server, or paste this into the Cline MCP config with Streamable HTTP selected.
|
|
78
|
+
instructionText: buildConfigurationInstruction('Open Cline MCP Servers, add a remote server, or paste this into the Cline MCP config with Streamable HTTP selected.')
|
|
98
79
|
};
|
|
99
80
|
case 'vscode':
|
|
100
81
|
return {
|
|
@@ -107,7 +88,7 @@ export function buildCloudMcpClientIntegration(input) {
|
|
|
107
88
|
headers
|
|
108
89
|
},
|
|
109
90
|
instructionLabel: 'VS Code Configuration Instructions',
|
|
110
|
-
instructionText: 'Open .vscode/mcp.json or MCP: Open User Configuration and add this server under the servers object.
|
|
91
|
+
instructionText: buildConfigurationInstruction('Open .vscode/mcp.json or MCP: Open User Configuration and add this server under the servers object.')
|
|
111
92
|
};
|
|
112
93
|
case 'windsurf':
|
|
113
94
|
return {
|
|
@@ -119,7 +100,7 @@ export function buildCloudMcpClientIntegration(input) {
|
|
|
119
100
|
headers
|
|
120
101
|
},
|
|
121
102
|
instructionLabel: 'Windsurf Configuration Instructions',
|
|
122
|
-
instructionText: 'Open Windsurf MCP settings, add a server, and paste this config.
|
|
103
|
+
instructionText: buildConfigurationInstruction('Open Windsurf MCP settings, add a server, and paste this config.')
|
|
123
104
|
};
|
|
124
105
|
case 'antigravity':
|
|
125
106
|
return {
|
|
@@ -131,7 +112,7 @@ export function buildCloudMcpClientIntegration(input) {
|
|
|
131
112
|
headers
|
|
132
113
|
},
|
|
133
114
|
instructionLabel: 'Antigravity Configuration Instructions',
|
|
134
|
-
instructionText: 'Open Antigravity MCP settings, view the raw config, and paste this Antigravity-specific configuration.
|
|
115
|
+
instructionText: buildConfigurationInstruction('Open Antigravity MCP settings, view the raw config, and paste this Antigravity-specific configuration.')
|
|
135
116
|
};
|
|
136
117
|
case 'openclaw':
|
|
137
118
|
return {
|
|
@@ -145,7 +126,7 @@ export function buildCloudMcpClientIntegration(input) {
|
|
|
145
126
|
headers
|
|
146
127
|
},
|
|
147
128
|
instructionLabel: 'OpenClaw Configuration Instructions',
|
|
148
|
-
instructionText: 'Open ~/.openclaw/openclaw.json and add this server under mcp.servers.
|
|
129
|
+
instructionText: buildConfigurationInstruction('Open ~/.openclaw/openclaw.json and add this server under mcp.servers.')
|
|
149
130
|
};
|
|
150
131
|
case 'codex':
|
|
151
132
|
return {
|
|
@@ -157,7 +138,7 @@ export function buildCloudMcpClientIntegration(input) {
|
|
|
157
138
|
`http_headers = { ${Object.entries(headers).map(([key, value]) => `${key} = "${value}"`).join(', ')} }`
|
|
158
139
|
].join('\n'),
|
|
159
140
|
instructionLabel: 'Codex Configuration Instructions',
|
|
160
|
-
instructionText: 'Open ~/.codex/config.toml and add this Codex MCP entry.
|
|
141
|
+
instructionText: buildConfigurationInstruction('Open ~/.codex/config.toml and add this Codex MCP entry.')
|
|
161
142
|
};
|
|
162
143
|
case 'claude-code':
|
|
163
144
|
return {
|
|
@@ -165,7 +146,7 @@ export function buildCloudMcpClientIntegration(input) {
|
|
|
165
146
|
kind: 'text',
|
|
166
147
|
renderedText: `claude mcp add --transport http ${serverId} ${endpoint} --header "Authorization: Bearer ${tokenValue}"${extraHeaderFlags}`,
|
|
167
148
|
instructionLabel: 'Claude Code Configuration Instructions',
|
|
168
|
-
instructionText: 'Run this Claude Code command in your terminal to add the remote Taskforce MCP server.
|
|
149
|
+
instructionText: buildConfigurationInstruction('Run this Claude Code command in your terminal to add the remote Taskforce MCP server.')
|
|
169
150
|
};
|
|
170
151
|
case 'gemini-cli':
|
|
171
152
|
return {
|
|
@@ -173,7 +154,7 @@ export function buildCloudMcpClientIntegration(input) {
|
|
|
173
154
|
kind: 'text',
|
|
174
155
|
renderedText: `gemini mcp add ${serverId} ${endpoint} --transport http --header "Authorization: Bearer ${tokenValue}"${extraHeaderFlags}`,
|
|
175
156
|
instructionLabel: 'Gemini CLI Configuration Instructions',
|
|
176
|
-
instructionText: 'Run this Gemini CLI command in your terminal to add the remote Taskforce MCP server. Add --scope user if you want it available across all projects.
|
|
157
|
+
instructionText: buildConfigurationInstruction('Run this Gemini CLI command in your terminal to add the remote Taskforce MCP server. Add --scope user if you want it available across all projects.')
|
|
177
158
|
};
|
|
178
159
|
case 'claude-desktop':
|
|
179
160
|
return {
|
|
@@ -45,6 +45,8 @@ describe('clientIntegrations', () => {
|
|
|
45
45
|
serverId: 'taskforce-workspace-alpha',
|
|
46
46
|
aiProfileName: 'Automation Codex',
|
|
47
47
|
aiProfileToken: 'tfp_automation_codex',
|
|
48
|
+
aiProfileIcon: 'Code2',
|
|
49
|
+
aiProfileColor: '#10a37f',
|
|
48
50
|
aiProfileDescription: 'OpenAI Codex coding agent connected through MCP.',
|
|
49
51
|
aiProfileRole: 'Coding Agent',
|
|
50
52
|
aiProfileProvider: 'OpenAI',
|
|
@@ -57,26 +59,34 @@ describe('clientIntegrations', () => {
|
|
|
57
59
|
tokenValue: '<<GENERATE_TOKEN>>',
|
|
58
60
|
serverId: 'taskforce-workspace-alpha',
|
|
59
61
|
aiProfileName: 'Automation Codex',
|
|
62
|
+
aiProfileIcon: 'Code2',
|
|
63
|
+
aiProfileColor: '#10a37f',
|
|
60
64
|
aiProfileRole: 'Coding Agent',
|
|
61
65
|
});
|
|
62
66
|
expect(codex.renderedText).toContain('X-Taskforce-AI-Name = "Automation Codex"');
|
|
63
67
|
expect(codex.renderedText).toContain('X-Taskforce-AI-Profile-Token = "tfp_automation_codex"');
|
|
68
|
+
expect(codex.renderedText).toContain('X-Taskforce-AI-Icon = "Code2"');
|
|
69
|
+
expect(codex.renderedText).toContain('X-Taskforce-AI-Color = "#10a37f"');
|
|
64
70
|
expect(codex.renderedText).toContain('X-Taskforce-AI-Description = "OpenAI Codex coding agent connected through MCP."');
|
|
65
71
|
expect(codex.renderedText).toContain('X-Taskforce-AI-Role = "Coding Agent"');
|
|
66
72
|
expect(codex.renderedText).toContain('X-Taskforce-AI-Provider = "OpenAI"');
|
|
67
73
|
expect(codex.renderedText).toContain('X-Taskforce-AI-Model = "Codex"');
|
|
68
74
|
expect(codex.renderedText).toContain('X-Taskforce-AI-Surface-Type = "coding_tool"');
|
|
69
|
-
expect(codex.instructionText).toContain('
|
|
75
|
+
expect(codex.instructionText).toContain('Use the generated config exactly as shown.');
|
|
76
|
+
expect(codex.instructionText).toContain('generated AI bootstrap headers');
|
|
70
77
|
expect(vscode.serverConfig).toEqual({
|
|
71
78
|
type: 'http',
|
|
72
79
|
url: 'https://performance-app.taskforcehq.ai/mcp',
|
|
73
80
|
headers: {
|
|
74
81
|
Authorization: 'Bearer <<GENERATE_TOKEN>>',
|
|
75
82
|
'X-Taskforce-AI-Name': 'Automation Codex',
|
|
83
|
+
'X-Taskforce-AI-Icon': 'Code2',
|
|
84
|
+
'X-Taskforce-AI-Color': '#10a37f',
|
|
76
85
|
'X-Taskforce-AI-Role': 'Coding Agent',
|
|
77
86
|
}
|
|
78
87
|
});
|
|
79
|
-
expect(vscode.instructionText).toContain('
|
|
88
|
+
expect(vscode.instructionText).toContain('Use the generated config exactly as shown.');
|
|
89
|
+
expect(vscode.instructionText).toContain('generated AI bootstrap headers');
|
|
80
90
|
});
|
|
81
91
|
it('builds JSON text config for OpenClaw using mcp.servers', () => {
|
|
82
92
|
const integration = buildCloudMcpClientIntegration({
|
|
@@ -97,6 +107,22 @@ describe('clientIntegrations', () => {
|
|
|
97
107
|
});
|
|
98
108
|
expect(integration.instructionText).toContain('~/.openclaw/openclaw.json');
|
|
99
109
|
});
|
|
110
|
+
it('keeps OAuth connector instructions focused on the URL flow instead of generated config language', () => {
|
|
111
|
+
const claudeDesktop = buildCloudMcpClientIntegration({
|
|
112
|
+
clientId: 'claude-desktop',
|
|
113
|
+
endpoint: 'https://performance-app.taskforcehq.ai/mcp',
|
|
114
|
+
tokenValue: '<<GENERATE_TOKEN>>',
|
|
115
|
+
serverId: 'taskforce-workspace-alpha',
|
|
116
|
+
});
|
|
117
|
+
const chatgptDesktop = buildCloudMcpClientIntegration({
|
|
118
|
+
clientId: 'chatgpt-desktop',
|
|
119
|
+
endpoint: 'https://performance-app.taskforcehq.ai/mcp',
|
|
120
|
+
tokenValue: '<<GENERATE_TOKEN>>',
|
|
121
|
+
serverId: 'taskforce-workspace-alpha',
|
|
122
|
+
});
|
|
123
|
+
expect(claudeDesktop.instructionText).not.toContain('generated config exactly as shown');
|
|
124
|
+
expect(chatgptDesktop.instructionText).not.toContain('generated config exactly as shown');
|
|
125
|
+
});
|
|
100
126
|
it('builds command config for Gemini CLI using http transport', () => {
|
|
101
127
|
const integration = buildCloudMcpClientIntegration({
|
|
102
128
|
clientId: 'gemini-cli',
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { McpClientId } from './clientIntegrations.js';
|
|
2
|
+
import type { AiProfileSurfaceType } from '../shared/aiProfileSurfaceType.js';
|
|
3
|
+
export interface AiProfileMetadataDefaults {
|
|
4
|
+
icon: string | null;
|
|
5
|
+
color: string | null;
|
|
6
|
+
description: string | null;
|
|
7
|
+
role: string | null;
|
|
8
|
+
provider: string | null;
|
|
9
|
+
model: string | null;
|
|
10
|
+
surfaceType: AiProfileSurfaceType | null;
|
|
11
|
+
}
|
|
12
|
+
export declare function getDefaultAiProfileMetadataForClient(clientId: McpClientId): AiProfileMetadataDefaults;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const CLIENT_LABELS = {
|
|
2
|
+
cline: 'Cline',
|
|
3
|
+
windsurf: 'Windsurf',
|
|
4
|
+
antigravity: 'Antigravity',
|
|
5
|
+
openclaw: 'OpenClaw',
|
|
6
|
+
};
|
|
7
|
+
export function getDefaultAiProfileMetadataForClient(clientId) {
|
|
8
|
+
switch (clientId) {
|
|
9
|
+
case 'codex':
|
|
10
|
+
return { icon: 'Code2', color: '#10a37f', description: 'OpenAI Codex coding agent connected through MCP.', role: 'Coding Agent', provider: 'OpenAI', model: 'Codex', surfaceType: 'coding_tool' };
|
|
11
|
+
case 'chatgpt-desktop':
|
|
12
|
+
return { icon: 'MessageSquare', color: '#10a37f', description: 'ChatGPT desktop app connected through the Taskforce MCP connector.', role: 'AI Assistant', provider: 'OpenAI', model: 'ChatGPT', surfaceType: 'chat_app' };
|
|
13
|
+
case 'claude-code':
|
|
14
|
+
return { icon: 'Sparkles', color: '#d97706', description: 'Claude Code coding agent connected through MCP.', role: 'Coding Agent', provider: 'Anthropic', model: 'Claude Code', surfaceType: 'coding_tool' };
|
|
15
|
+
case 'claude-desktop':
|
|
16
|
+
return { icon: 'MessageSquareMore', color: '#d97706', description: 'Claude Desktop connected through the Taskforce MCP connector.', role: 'AI Assistant', provider: 'Anthropic', model: 'Claude', surfaceType: 'chat_app' };
|
|
17
|
+
case 'gemini-cli':
|
|
18
|
+
return { icon: 'Gem', color: '#2563eb', description: 'Gemini CLI coding agent connected through MCP.', role: 'Coding Agent', provider: 'Google', model: 'Gemini', surfaceType: 'coding_tool' };
|
|
19
|
+
case 'vscode':
|
|
20
|
+
return { icon: 'Code2', color: '#2563eb', description: 'VS Code MCP-connected coding agent.', role: 'Coding Agent', provider: null, model: null, surfaceType: 'ide' };
|
|
21
|
+
case 'cline':
|
|
22
|
+
case 'windsurf':
|
|
23
|
+
case 'antigravity':
|
|
24
|
+
case 'openclaw':
|
|
25
|
+
return {
|
|
26
|
+
icon: 'Bot',
|
|
27
|
+
color: '#8b5cf6',
|
|
28
|
+
description: `${CLIENT_LABELS[clientId] || 'MCP'} coding agent connected through MCP.`,
|
|
29
|
+
role: 'Coding Agent',
|
|
30
|
+
provider: null,
|
|
31
|
+
model: null,
|
|
32
|
+
surfaceType: 'coding_tool',
|
|
33
|
+
};
|
|
34
|
+
default:
|
|
35
|
+
return { icon: null, color: null, description: null, role: null, provider: null, model: null, surfaceType: null };
|
|
36
|
+
}
|
|
37
|
+
}
|
package/dist/mcp/runtime.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
2
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
3
|
import { McpAccessTokenScope, TaskforceCore } from '../core/Taskforce.js';
|
|
4
|
+
import { type AiProfileBootstrapConfig } from './aiProfileBootstrap.js';
|
|
4
5
|
export interface TaskforceMcpServerOptions {
|
|
5
6
|
projectRoot?: string;
|
|
6
7
|
tenantId?: string;
|
|
@@ -13,13 +14,15 @@ export interface TaskforceMcpServerOptions {
|
|
|
13
14
|
scopes?: McpAccessTokenScope[] | null;
|
|
14
15
|
userId?: string | null;
|
|
15
16
|
tokenId?: string | null;
|
|
16
|
-
aiProfileToken?:
|
|
17
|
-
aiProfileName?:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
aiProfileToken?: AiProfileBootstrapConfig['aiProfileToken'];
|
|
18
|
+
aiProfileName?: AiProfileBootstrapConfig['aiProfileName'];
|
|
19
|
+
aiProfileIcon?: AiProfileBootstrapConfig['aiProfileIcon'];
|
|
20
|
+
aiProfileColor?: AiProfileBootstrapConfig['aiProfileColor'];
|
|
21
|
+
aiProfileDescription?: AiProfileBootstrapConfig['aiProfileDescription'];
|
|
22
|
+
aiProfileRole?: AiProfileBootstrapConfig['aiProfileRole'];
|
|
23
|
+
aiProfileProvider?: AiProfileBootstrapConfig['aiProfileProvider'];
|
|
24
|
+
aiProfileModel?: AiProfileBootstrapConfig['aiProfileModel'];
|
|
25
|
+
aiProfileSurfaceType?: AiProfileBootstrapConfig['aiProfileSurfaceType'];
|
|
23
26
|
actorType?: 'local' | 'user' | 'token' | 'oauth';
|
|
24
27
|
requestId?: string | null;
|
|
25
28
|
ip?: string | null;
|