@taskforcehq/taskforce 0.3.300 → 0.3.302
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 +19 -0
- package/dist/Taskforce.module.css +26 -2
- package/dist/TaskforceCore.filter-persistence.test.js +1 -1
- package/dist/TaskforceCore.js +13 -24
- package/dist/TaskforceCore.test.js +167 -152
- 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/ui/ReferenceBadgeButton.js +1 -1
- package/dist/components/views/PlansPage.js +9 -8
- package/dist/components/views/StandaloneLayout.js +490 -207
- package/dist/components/views/panels/FilterToolbar.d.ts +2 -0
- package/dist/components/views/panels/FilterToolbarControls.d.ts +1 -0
- package/dist/components/views/panels/FilterToolbarControls.js +1 -1
- package/dist/components/views/panels/PlanningDrawer.js +19 -2
- package/dist/components/views/standalone/modals/AccountHubModal.d.ts +43 -0
- package/dist/components/views/standalone/modals/AccountHubModal.js +22 -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/SyncReconciliationService.d.ts +2 -0
- package/dist/core/SyncReconciliationService.js +3 -0
- package/dist/core/TaskAuditTimeline.test.js +40 -0
- package/dist/core/Taskforce.d.ts +49 -0
- package/dist/core/Taskforce.ids.test.js +133 -0
- package/dist/core/Taskforce.js +241 -78
- package/dist/core/UserProfileAvatarDrafts.test.d.ts +1 -0
- package/dist/core/UserProfileAvatarDrafts.test.js +102 -0
- package/dist/core/taskReferencePolicy.d.ts +28 -0
- package/dist/core/taskReferencePolicy.js +189 -0
- package/dist/core/types.d.ts +2 -0
- package/dist/hooks/tasks/useTaskFormActions.js +3 -0
- package/dist/hooks/useTaskData.js +16 -11
- package/dist/hooks/useTaskData.test.js +127 -0
- package/dist/hooks/useTaskforce.d.ts +5 -0
- package/dist/hooks/useTaskforce.js +63 -15
- 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 +45 -23
- package/dist/mcp/runtime.test.js +56 -3
- package/dist/migrations/taskSchemaMigrations.js +53 -1
- package/dist/qaOpen.test.d.ts +1 -0
- package/dist/qaOpen.test.js +56 -0
- package/dist/server/index.cookieProxy.test.js +1 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +15 -1
- package/dist/server/index.test.js +14 -1
- package/dist/server/routes/admin.js +25 -22
- package/dist/server/routes/auth.d.ts +5 -0
- package/dist/server/routes/auth.js +350 -16
- package/dist/server/routes/billing.js +11 -1
- package/dist/server/routes/billing.test.js +32 -2
- package/dist/server/routes/documents.js +6 -1
- package/dist/server/routes/shared.d.ts +1 -1
- package/dist/server/routes/shared.js +11 -3
- package/dist/server/routes/sync.integration.test.js +130 -0
- package/dist/server/routes/sync.js +226 -1924
- package/dist/server/routes/tasks.js +18 -4
- package/dist/server/routes.js +26 -19
- package/dist/server/routes.test.js +352 -6
- package/dist/shared/runtimeContract.d.ts +1 -1
- 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 +88 -0
- package/dist/sync/contentSyncState.js +743 -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/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 +28 -0
- package/dist/sync/workspacePullFeed.js +301 -0
- package/dist/sync/workspacePullFeed.test.d.ts +1 -0
- package/dist/sync/workspacePullFeed.test.js +166 -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-TVmCgizS.js → AgentsModule-JG5jc3he.js} +1 -1
- package/dist/ui/assets/{AnnotatedAttachmentWorkspace-CAyhnPeR.js → AnnotatedAttachmentWorkspace-Dvi02Y7q.js} +1 -1
- package/dist/ui/assets/{DocumentWorkspace-BOCw5e4D.js → DocumentWorkspace-iys3zfca.js} +2 -2
- package/dist/ui/assets/{InitiativesModule-CN0r02Oi.js → InitiativesModule-DJvLJI3A.js} +1 -1
- package/dist/ui/assets/PlansPage-BMPlpFpw.js +1 -0
- package/dist/ui/assets/TaskSettings-Bqd4cCzW.js +8 -0
- package/dist/ui/assets/{TaskSettings-BwB9NtmJ.css → TaskSettings-CnIBL_Eb.css} +1 -1
- package/dist/ui/assets/{WorkflowsModule-CY9R2zPB.js → WorkflowsModule-BguHeQaV.js} +1 -1
- package/dist/ui/assets/index-MXeWoebC.css +1 -0
- package/dist/ui/assets/index-YJ4k5QNa.js +6 -0
- package/dist/ui/assets/{vendor-icons-QZyhEwgT.js → vendor-icons-C8EED3Oh.js} +1 -1
- package/dist/ui/index.html +3 -3
- package/dist/utils/billingStatusCache.d.ts +21 -0
- package/dist/utils/billingStatusCache.js +70 -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 -1
- package/scripts/deploy-prod.sh +41 -0
- package/scripts/deploy-staging.sh +23 -0
- 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-FcQSNLZd.js +0 -1
- package/dist/ui/assets/TaskSettings-Cw5zYD1L.js +0 -8
- package/dist/ui/assets/index-Bzqy5QGm.js +0 -6
- package/dist/ui/assets/index-DxRiI3tY.css +0 -1
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { describe, expect, it } from 'vitest';
|
|
4
|
+
// @ts-ignore - JS helper module without generated .d.ts; covered by focused tests.
|
|
5
|
+
import { assertQaProjectRootSafe, matchExpectedWorkspace, parseEnvFileContents, parseQaArgs, resolveExpectedWorkspace, resolveQaPaths } from '../scripts/qa-open-lib.mjs';
|
|
6
|
+
describe('qa open helper library', () => {
|
|
7
|
+
it('derives a stable QA root layout for an agent', () => {
|
|
8
|
+
const homeDir = path.join(os.tmpdir(), 'qa-open-test-home');
|
|
9
|
+
const paths = resolveQaPaths({ agentId: 'Codex Main', homeDir });
|
|
10
|
+
expect(paths.agentId).toBe('codex-main');
|
|
11
|
+
expect(paths.root).toContain(path.join('.taskforce', 'qa', 'codex-main'));
|
|
12
|
+
expect(paths.projectRoot).toContain(path.join('.taskforce', 'qa', 'codex-main', 'project'));
|
|
13
|
+
expect(paths.playwrightStorageState).toContain(path.join('.taskforce', 'qa', 'codex-main', 'playwright-auth.json'));
|
|
14
|
+
});
|
|
15
|
+
it('parses env files with comments, export statements, and quoted values', () => {
|
|
16
|
+
const env = parseEnvFileContents(`
|
|
17
|
+
# comment
|
|
18
|
+
export TASKFORCE_E2E_EMAIL="codex@example.com"
|
|
19
|
+
TASKFORCE_E2E_PASSWORD='secret'
|
|
20
|
+
TASKFORCE_QA_EXPECTED_WORKSPACE_SLUG=codex-qa
|
|
21
|
+
`);
|
|
22
|
+
expect(env.TASKFORCE_E2E_EMAIL).toBe('codex@example.com');
|
|
23
|
+
expect(env.TASKFORCE_E2E_PASSWORD).toBe('secret');
|
|
24
|
+
expect(env.TASKFORCE_QA_EXPECTED_WORKSPACE_SLUG).toBe('codex-qa');
|
|
25
|
+
});
|
|
26
|
+
it('rejects QA roots inside the repository', () => {
|
|
27
|
+
const repoRoot = '/repo/taskforce';
|
|
28
|
+
expect(() => assertQaProjectRootSafe('/repo/taskforce', repoRoot)).toThrow(/inside the repository/i);
|
|
29
|
+
expect(() => assertQaProjectRootSafe('/repo/taskforce/tmp/qa', repoRoot)).toThrow(/inside the repository/i);
|
|
30
|
+
expect(() => assertQaProjectRootSafe('/tmp/taskforce-qa', repoRoot)).not.toThrow();
|
|
31
|
+
});
|
|
32
|
+
it('matches expected workspace by slug against the current workspace id', () => {
|
|
33
|
+
const match = matchExpectedWorkspace({
|
|
34
|
+
currentWorkspaceId: 'workspace-2',
|
|
35
|
+
workspaces: [
|
|
36
|
+
{ id: 'workspace-1', slug: 'alpha' },
|
|
37
|
+
{ id: 'workspace-2', slug: 'beta' }
|
|
38
|
+
]
|
|
39
|
+
}, { workspaceId: null, workspaceSlug: 'beta' });
|
|
40
|
+
expect(match.ok).toBe(true);
|
|
41
|
+
});
|
|
42
|
+
it('builds args and expected workspace from env', () => {
|
|
43
|
+
const parsed = parseQaArgs([], {
|
|
44
|
+
TASKFORCE_QA_AGENT: 'Claude QA',
|
|
45
|
+
TASKFORCE_QA_MODE: 'staging',
|
|
46
|
+
TASKFORCE_QA_PORT: '5199'
|
|
47
|
+
});
|
|
48
|
+
expect(parsed.agentId).toBe('claude-qa');
|
|
49
|
+
expect(parsed.mode).toBe('staging');
|
|
50
|
+
expect(parsed.preferredPort).toBe(5199);
|
|
51
|
+
const expected = resolveExpectedWorkspace({
|
|
52
|
+
TASKFORCE_QA_EXPECTED_WORKSPACE_ID: 'workspace-123'
|
|
53
|
+
});
|
|
54
|
+
expect(expected).toEqual({ workspaceId: 'workspace-123', workspaceSlug: null });
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -22,6 +22,7 @@ describe('proxy cookie rewrite helpers', () => {
|
|
|
22
22
|
expect(shouldProxyCloudPath('/api/taskforce/public/site-config-script')).toBe(true);
|
|
23
23
|
expect(shouldProxyCloudPath('/api/taskforce/version')).toBe(true);
|
|
24
24
|
expect(shouldProxyCloudPath('/api/taskforce/account/entitlements')).toBe(true);
|
|
25
|
+
expect(shouldProxyCloudPath('/api/taskforce/account/team-management-access')).toBe(true);
|
|
25
26
|
expect(shouldProxyCloudPath('/api/taskforce/admin/mcp-audit-logs')).toBe(true);
|
|
26
27
|
expect(shouldProxyCloudPath('/api/taskforce/billing/status')).toBe(true);
|
|
27
28
|
expect(shouldProxyCloudPath('/api/taskforce/billing/checkout-session')).toBe(true);
|
package/dist/server/index.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ interface AuthorizedRequestAccess extends RequestAccessContext {
|
|
|
22
22
|
export declare function shouldProxyCloudPath(pathname: string): boolean;
|
|
23
23
|
export declare function resolveCloudProxyUpstreamBaseUrl(req: http.IncomingMessage, fallbackBaseUrl: string): string;
|
|
24
24
|
export declare function resolveAuthorizedWorkspaceAccess(core: Pick<TaskforceCore, 'resolveUserAccess' | 'getSystemRole'>, access: AuthorizedRequestAccess, requestedWorkspaceId: string): AuthorizedRequestAccess;
|
|
25
|
+
export declare function resolveEffectiveRequestUserId(accessUserId: string, explicitUserId: string): string;
|
|
25
26
|
export declare function resolveMaxPayloadBytesForPath(pathname: string, defaultMaxBytes: number): number;
|
|
26
27
|
export declare function shouldRewriteSetCookieForLocalDevHost(hostHeader: string | undefined): boolean;
|
|
27
28
|
export declare function writeJsonErrorIfPossible(res: http.ServerResponse, statusCode: number, payload: Record<string, unknown>): boolean;
|
package/dist/server/index.js
CHANGED
|
@@ -145,6 +145,17 @@ export function resolveAuthorizedWorkspaceAccess(core, access, requestedWorkspac
|
|
|
145
145
|
}
|
|
146
146
|
return access;
|
|
147
147
|
}
|
|
148
|
+
export function resolveEffectiveRequestUserId(accessUserId, explicitUserId) {
|
|
149
|
+
const normalizedAccessUserId = String(accessUserId || '').trim();
|
|
150
|
+
if (normalizedAccessUserId && normalizedAccessUserId !== 'anonymous') {
|
|
151
|
+
return normalizedAccessUserId;
|
|
152
|
+
}
|
|
153
|
+
const normalizedExplicitUserId = String(explicitUserId || '').trim();
|
|
154
|
+
if (normalizedExplicitUserId && normalizedExplicitUserId !== 'anonymous') {
|
|
155
|
+
return normalizedExplicitUserId;
|
|
156
|
+
}
|
|
157
|
+
return 'anonymous';
|
|
158
|
+
}
|
|
148
159
|
export function resolveMaxPayloadBytesForPath(pathname, defaultMaxBytes) {
|
|
149
160
|
if (pathname.startsWith('/api/taskforce/sync/')) {
|
|
150
161
|
// Sync routes (especially applying local changes) often include large binary attachments
|
|
@@ -677,7 +688,10 @@ export function createStandaloneServer(options) {
|
|
|
677
688
|
req.headers['x-taskforce-role'] = access.role;
|
|
678
689
|
req.headers['x-taskforce-system-role'] = access.systemRole;
|
|
679
690
|
req.headers['x-taskforce-workspace-id'] = access.workspaceId;
|
|
680
|
-
req.headers['x-taskforce-user-id']
|
|
691
|
+
const explicitRequestUserId = Array.isArray(req.headers['x-taskforce-user-id'])
|
|
692
|
+
? String(req.headers['x-taskforce-user-id'][0] || '')
|
|
693
|
+
: String(req.headers['x-taskforce-user-id'] || '');
|
|
694
|
+
req.headers['x-taskforce-user-id'] = resolveEffectiveRequestUserId(access.userId, explicitRequestUserId);
|
|
681
695
|
if (isCollaborationPolicyEnabled() && isMutation && access.role === 'read-only') {
|
|
682
696
|
res.writeHead(403, { 'Content-Type': 'application/json' });
|
|
683
697
|
res.end(JSON.stringify({ error: 'Forbidden: read-only role cannot mutate data.' }));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import { ensureBillingWebhookAuthExclusion, ensurePublicSiteConfigAuthExclusion, isBillingWebhookPath, resolveAuthorizedWorkspaceAccess, shouldApplyAuthRateLimitForPath, shouldProxyCloudPath, writeJsonErrorIfPossible } from './index.js';
|
|
2
|
+
import { ensureBillingWebhookAuthExclusion, ensurePublicSiteConfigAuthExclusion, isBillingWebhookPath, resolveEffectiveRequestUserId, resolveAuthorizedWorkspaceAccess, shouldApplyAuthRateLimitForPath, shouldProxyCloudPath, writeJsonErrorIfPossible } from './index.js';
|
|
3
3
|
describe('server index helper policies', () => {
|
|
4
4
|
it('adds webhook path to auth exclusions without duplicates', () => {
|
|
5
5
|
const base = ['/api/taskforce/health', '/api/taskforce/auth'];
|
|
@@ -86,6 +86,7 @@ describe('shouldProxyCloudPath', () => {
|
|
|
86
86
|
expect(shouldProxyCloudPath('/api/taskforce/admin/users')).toBe(true);
|
|
87
87
|
expect(shouldProxyCloudPath('/api/taskforce/billing/plans')).toBe(true);
|
|
88
88
|
expect(shouldProxyCloudPath('/api/taskforce/auth/login')).toBe(true);
|
|
89
|
+
expect(shouldProxyCloudPath('/api/taskforce/account/team-management-access')).toBe(false);
|
|
89
90
|
expect(shouldProxyCloudPath('/api/taskforce/public/site-config')).toBe(true);
|
|
90
91
|
expect(shouldProxyCloudPath('/api/taskforce/public/site-config-script')).toBe(true);
|
|
91
92
|
});
|
|
@@ -148,3 +149,15 @@ describe('resolveAuthorizedWorkspaceAccess', () => {
|
|
|
148
149
|
expect(next.workspaceId).toBe('workspace-personal');
|
|
149
150
|
});
|
|
150
151
|
});
|
|
152
|
+
describe('resolveEffectiveRequestUserId', () => {
|
|
153
|
+
it('prefers the authenticated access user when present', () => {
|
|
154
|
+
expect(resolveEffectiveRequestUserId('user-authenticated', 'user-explicit')).toBe('user-authenticated');
|
|
155
|
+
});
|
|
156
|
+
it('preserves an explicit local actor header when auth access is anonymous', () => {
|
|
157
|
+
expect(resolveEffectiveRequestUserId('anonymous', 'user-local-actor')).toBe('user-local-actor');
|
|
158
|
+
expect(resolveEffectiveRequestUserId('', 'user-local-actor')).toBe('user-local-actor');
|
|
159
|
+
});
|
|
160
|
+
it('falls back to anonymous when neither source has a user id', () => {
|
|
161
|
+
expect(resolveEffectiveRequestUserId('anonymous', '')).toBe('anonymous');
|
|
162
|
+
});
|
|
163
|
+
});
|
|
@@ -59,6 +59,7 @@ import { normalizeStorageIntegrityScheduleSettings, resolveStorageIntegritySched
|
|
|
59
59
|
import { resolveVirusScanConfigFromEnv } from '../../security/virusScan.js';
|
|
60
60
|
import { applyPrefixedRateLimitHeaders } from '../rateLimit.js';
|
|
61
61
|
import { createTaskforceMcpServer, isMcpWriteToolName } from '../../mcp/runtime.js';
|
|
62
|
+
import { parseAiProfileBootstrapHeaders } from '../../mcp/aiProfileBootstrap.js';
|
|
62
63
|
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
63
64
|
import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
|
|
64
65
|
import { randomUUID } from 'crypto';
|
|
@@ -81,6 +82,20 @@ export function registerAdminRoutes(deps) {
|
|
|
81
82
|
const globalSettings = core.getGlobalSettings();
|
|
82
83
|
return resolveEffectiveEmailConfig(process.env, globalSettings.email || null);
|
|
83
84
|
};
|
|
85
|
+
const resolveBooleanSetting = (value, fallback) => {
|
|
86
|
+
if (typeof value === 'boolean')
|
|
87
|
+
return value;
|
|
88
|
+
if (typeof value === 'number')
|
|
89
|
+
return value !== 0;
|
|
90
|
+
const normalized = String(value || '').trim().toLowerCase();
|
|
91
|
+
if (!normalized)
|
|
92
|
+
return fallback;
|
|
93
|
+
if (['1', 'true', 'yes', 'on'].includes(normalized))
|
|
94
|
+
return true;
|
|
95
|
+
if (['0', 'false', 'no', 'off'].includes(normalized))
|
|
96
|
+
return false;
|
|
97
|
+
return fallback;
|
|
98
|
+
};
|
|
84
99
|
const getAuthBehavior = () => {
|
|
85
100
|
const globalSettings = core.getGlobalSettings();
|
|
86
101
|
const authSettings = globalSettings.auth || {};
|
|
@@ -88,10 +103,10 @@ export function registerAdminRoutes(deps) {
|
|
|
88
103
|
const authRateLimitWindowMsRaw = Number(authSettings.authRateLimitWindowMs);
|
|
89
104
|
const signupSettings = core.getSignupMonetizationSettings();
|
|
90
105
|
return {
|
|
91
|
-
allowSelfRegistration: authSettings.allowSelfRegistration
|
|
92
|
-
requireVerifiedEmail: authSettings.requireVerifiedEmail
|
|
93
|
-
defaultNewUserBetaAccess: authSettings.defaultNewUserBetaAccess
|
|
94
|
-
authRateLimitEnabled: authSettings.authRateLimitEnabled
|
|
106
|
+
allowSelfRegistration: resolveBooleanSetting(authSettings.allowSelfRegistration, true),
|
|
107
|
+
requireVerifiedEmail: resolveBooleanSetting(authSettings.requireVerifiedEmail, true),
|
|
108
|
+
defaultNewUserBetaAccess: resolveBooleanSetting(authSettings.defaultNewUserBetaAccess, false),
|
|
109
|
+
authRateLimitEnabled: resolveBooleanSetting(authSettings.authRateLimitEnabled, true),
|
|
95
110
|
authRateLimitMaxRequests: Number.isFinite(authRateLimitMaxRequestsRaw) && authRateLimitMaxRequestsRaw >= 1
|
|
96
111
|
? Math.floor(authRateLimitMaxRequestsRaw)
|
|
97
112
|
: 10,
|
|
@@ -106,8 +121,8 @@ export function registerAdminRoutes(deps) {
|
|
|
106
121
|
const globalSettings = core.getGlobalSettings();
|
|
107
122
|
const siteSettings = globalSettings.site || {};
|
|
108
123
|
return {
|
|
109
|
-
showRunTaskforceLocally: siteSettings.showRunTaskforceLocally
|
|
110
|
-
pricingPageEnabled: siteSettings.pricingPageEnabled
|
|
124
|
+
showRunTaskforceLocally: resolveBooleanSetting(siteSettings.showRunTaskforceLocally, true),
|
|
125
|
+
pricingPageEnabled: resolveBooleanSetting(siteSettings.pricingPageEnabled, true)
|
|
111
126
|
};
|
|
112
127
|
};
|
|
113
128
|
const resolveEffectiveVirusScanSettings = () => {
|
|
@@ -264,13 +279,7 @@ export function registerAdminRoutes(deps) {
|
|
|
264
279
|
? authorization.slice(7).trim()
|
|
265
280
|
: '';
|
|
266
281
|
const requestedWorkspaceId = requestHeader(req, 'x-taskforce-workspace-id', '').trim();
|
|
267
|
-
const
|
|
268
|
-
const aiProfileName = requestHeader(req, 'x-taskforce-ai-name', '').trim() || null;
|
|
269
|
-
const aiProfileDescription = requestHeader(req, 'x-taskforce-ai-description', '').trim() || null;
|
|
270
|
-
const aiProfileRole = requestHeader(req, 'x-taskforce-ai-role', '').trim() || null;
|
|
271
|
-
const aiProfileProvider = requestHeader(req, 'x-taskforce-ai-provider', '').trim() || null;
|
|
272
|
-
const aiProfileModel = requestHeader(req, 'x-taskforce-ai-model', '').trim() || null;
|
|
273
|
-
const aiProfileSurfaceType = requestHeader(req, 'x-taskforce-ai-surface-type', '').trim() || null;
|
|
282
|
+
const bootstrap = parseAiProfileBootstrapHeaders(req.headers);
|
|
274
283
|
if (bearerToken) {
|
|
275
284
|
const tokenAuth = core.authenticateMcpAccessToken(bearerToken);
|
|
276
285
|
const oauthAuth = tokenAuth ? null : core.authenticateMcpOAuthAccessToken(bearerToken);
|
|
@@ -318,13 +327,7 @@ export function registerAdminRoutes(deps) {
|
|
|
318
327
|
authenticatedViaToken: tokenAuth || null,
|
|
319
328
|
authenticatedViaOAuth: oauthAuth || null,
|
|
320
329
|
userId: null,
|
|
321
|
-
|
|
322
|
-
aiProfileName,
|
|
323
|
-
aiProfileDescription,
|
|
324
|
-
aiProfileRole,
|
|
325
|
-
aiProfileProvider,
|
|
326
|
-
aiProfileModel,
|
|
327
|
-
aiProfileSurfaceType,
|
|
330
|
+
...bootstrap,
|
|
328
331
|
};
|
|
329
332
|
}
|
|
330
333
|
core.addMcpAuditLog({
|
|
@@ -1812,7 +1815,7 @@ export function registerAdminRoutes(deps) {
|
|
|
1812
1815
|
addRoute('OPTIONS', '/mcp', async (_req, res) => {
|
|
1813
1816
|
res.writeHead(204, {
|
|
1814
1817
|
'Access-Control-Allow-Origin': '*',
|
|
1815
|
-
'Access-Control-Allow-Headers': 'authorization, content-type, accept, last-event-id, mcp-protocol-version, mcp-session-id, x-taskforce-workspace-id, x-taskforce-ai-profile-token, x-taskforce-ai-name, x-taskforce-ai-description, x-taskforce-ai-role, x-taskforce-ai-provider, x-taskforce-ai-model, x-taskforce-ai-surface-type',
|
|
1818
|
+
'Access-Control-Allow-Headers': 'authorization, content-type, accept, last-event-id, mcp-protocol-version, mcp-session-id, x-taskforce-workspace-id, x-taskforce-ai-profile-token, x-taskforce-ai-name, x-taskforce-ai-icon, x-taskforce-ai-color, x-taskforce-ai-description, x-taskforce-ai-role, x-taskforce-ai-provider, x-taskforce-ai-model, x-taskforce-ai-surface-type',
|
|
1816
1819
|
'Access-Control-Allow-Methods': 'GET, POST, DELETE, OPTIONS'
|
|
1817
1820
|
});
|
|
1818
1821
|
res.end();
|
|
@@ -1820,7 +1823,7 @@ export function registerAdminRoutes(deps) {
|
|
|
1820
1823
|
addRoute('OPTIONS', '/mcp/', async (_req, res) => {
|
|
1821
1824
|
res.writeHead(204, {
|
|
1822
1825
|
'Access-Control-Allow-Origin': '*',
|
|
1823
|
-
'Access-Control-Allow-Headers': 'authorization, content-type, accept, last-event-id, mcp-protocol-version, mcp-session-id, x-taskforce-workspace-id, x-taskforce-ai-profile-token, x-taskforce-ai-name, x-taskforce-ai-description, x-taskforce-ai-role, x-taskforce-ai-provider, x-taskforce-ai-model, x-taskforce-ai-surface-type',
|
|
1826
|
+
'Access-Control-Allow-Headers': 'authorization, content-type, accept, last-event-id, mcp-protocol-version, mcp-session-id, x-taskforce-workspace-id, x-taskforce-ai-profile-token, x-taskforce-ai-name, x-taskforce-ai-icon, x-taskforce-ai-color, x-taskforce-ai-description, x-taskforce-ai-role, x-taskforce-ai-provider, x-taskforce-ai-model, x-taskforce-ai-surface-type',
|
|
1824
1827
|
'Access-Control-Allow-Methods': 'GET, POST, DELETE, OPTIONS'
|
|
1825
1828
|
});
|
|
1826
1829
|
res.end();
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
* POST /api/taskforce/auth/logout
|
|
22
22
|
* GET /api/taskforce/account/access-status
|
|
23
23
|
* GET /api/taskforce/account/entitlements
|
|
24
|
+
* GET /api/taskforce/account/team-management-access
|
|
24
25
|
* GET /api/taskforce/account/plan-preview
|
|
25
26
|
* GET /api/taskforce/auth/workspace-members
|
|
26
27
|
* GET /api/taskforce/workspace/assignee-options
|
|
@@ -36,6 +37,8 @@
|
|
|
36
37
|
import type { IncomingMessage, ServerResponse } from 'http';
|
|
37
38
|
import type { TaskforceCore } from '../../core/Taskforce.js';
|
|
38
39
|
import type { RouteHandler, RouteContext } from '../routes.js';
|
|
40
|
+
import type { ResolvedObjectStorageConfig } from '../../storage/objectStorage.js';
|
|
41
|
+
import { ObjectStorageClient } from '../../storage/objectStorageClient.js';
|
|
39
42
|
export interface AuthRouteDependencies {
|
|
40
43
|
addRoute: (method: string, path: string, handler: RouteHandler) => void;
|
|
41
44
|
core: TaskforceCore;
|
|
@@ -57,5 +60,7 @@ export interface AuthRouteDependencies {
|
|
|
57
60
|
shouldExposeDevAuthTokens: () => boolean;
|
|
58
61
|
resolveRuntimeConfigBaseUrl: (req: IncomingMessage) => string;
|
|
59
62
|
resolvePublicAuthBaseUrl: (req: IncomingMessage) => string;
|
|
63
|
+
resolveEffectiveObjectStorageConfig: () => ResolvedObjectStorageConfig;
|
|
64
|
+
getObjectStorageClient: () => ObjectStorageClient | null;
|
|
60
65
|
}
|
|
61
66
|
export declare function registerAuthRoutes(deps: AuthRouteDependencies): void;
|