@taskforcehq/taskforce 0.3.306 → 0.3.308
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 +0 -2
- package/dist/Taskforce.module.css +317 -27
- package/dist/TaskforceCore.js +1 -0
- package/dist/TaskforceCore.test.js +178 -0
- package/dist/components/activity/EntityActivityTimeline.d.ts +34 -0
- package/dist/components/activity/EntityActivityTimeline.js +81 -0
- package/dist/components/context/ContextAttachmentManager.js +15 -3
- package/dist/components/features/AgentsModule.d.ts +5 -1
- package/dist/components/features/AgentsModule.js +142 -39
- package/dist/components/features/AgentsModule.test.js +260 -11
- package/dist/components/features/AnnotatedAttachmentWorkspace.d.ts +3 -1
- package/dist/components/features/AnnotatedAttachmentWorkspace.js +118 -4
- package/dist/components/features/AnnotatedAttachmentWorkspace.test.js +52 -0
- package/dist/components/features/DocumentIndex.d.ts +2 -2
- package/dist/components/features/DocumentIndex.js +3 -4
- package/dist/components/features/DocumentViewer.d.ts +3 -1
- package/dist/components/features/DocumentViewer.js +6 -5
- package/dist/components/features/DocumentWorkspace.d.ts +10 -2
- package/dist/components/features/DocumentWorkspace.js +15 -4
- package/dist/components/features/DocumentWorkspace.test.js +20 -3
- package/dist/components/features/TaskSettings.d.ts +2 -0
- package/dist/components/features/TaskSettings.js +83 -78
- package/dist/components/features/TaskSettings.test.js +171 -82
- package/dist/components/task/TaskActionHeader.js +11 -5
- package/dist/components/task/TaskActionHeader.test.js +10 -0
- package/dist/components/task/TaskCard.js +6 -2
- package/dist/components/task/TaskContextUpload.test.js +3 -3
- package/dist/components/task/TaskForm.js +14 -64
- package/dist/components/task/TaskKanban.js +0 -8
- package/dist/components/task/TaskList.js +5 -1
- package/dist/components/task/TaskList.test.js +4 -0
- package/dist/components/ui/HierarchyActionBadge.d.ts +10 -0
- package/dist/components/ui/HierarchyActionBadge.js +5 -0
- package/dist/components/views/AppShellHeader.d.ts +3 -1
- package/dist/components/views/AppShellHeader.js +27 -11
- package/dist/components/views/AppShellHeader.test.js +18 -1
- package/dist/components/views/PlanComparisonPage.d.ts +20 -15
- package/dist/components/views/PlanComparisonPage.js +221 -82
- package/dist/components/views/PlanComparisonPage.test.js +268 -14
- package/dist/components/views/PlansPage.js +16 -10
- package/dist/components/views/PlansPage.test.js +4 -2
- package/dist/components/views/StandaloneLayout.js +256 -69
- package/dist/components/views/WidgetView.js +10 -8
- package/dist/components/views/panels/PlanningDrawer.d.ts +19 -6
- package/dist/components/views/panels/PlanningDrawer.js +259 -51
- package/dist/components/views/panels/PlanningDrawer.test.js +392 -4
- package/dist/config/envSchema.js +1 -0
- package/dist/core/AiProfileService.d.ts +7 -0
- package/dist/core/AiProfileService.js +460 -35
- package/dist/core/AiProfiles.test.js +648 -2
- package/dist/core/AttachmentLinkService.d.ts +3 -0
- package/dist/core/AttachmentLinkService.js +58 -13
- package/dist/core/GlobalSettingsService.js +30 -0
- package/dist/core/GlobalSettingsService.test.d.ts +1 -0
- package/dist/core/GlobalSettingsService.test.js +45 -0
- package/dist/core/McpTokenService.d.ts +12 -0
- package/dist/core/McpTokenService.js +44 -1
- package/dist/core/PlanEntitlementService.d.ts +20 -0
- package/dist/core/PlanEntitlementService.js +215 -19
- package/dist/core/PlanFeatureCatalog.test.js +55 -0
- package/dist/core/PlanningEntities.test.js +366 -4
- package/dist/core/TaskActivityService.d.ts +28 -1
- package/dist/core/TaskActivityService.js +227 -46
- package/dist/core/TaskActivitySync.test.d.ts +1 -0
- package/dist/core/TaskActivitySync.test.js +90 -0
- package/dist/core/TaskAuditTimeline.test.js +96 -0
- package/dist/core/Taskforce.d.ts +204 -26
- package/dist/core/Taskforce.ids.test.js +58 -0
- package/dist/core/Taskforce.js +781 -71
- package/dist/core/Taskforce.mcpAuth.test.js +109 -0
- package/dist/core/types.d.ts +10 -0
- package/dist/hooks/auth/useTaskforceAuthBootstrap.js +2 -1
- package/dist/hooks/bootstrapTimeouts.d.ts +4 -0
- package/dist/hooks/bootstrapTimeouts.js +8 -0
- package/dist/hooks/bootstrapTimeouts.test.d.ts +1 -0
- package/dist/hooks/bootstrapTimeouts.test.js +12 -0
- package/dist/hooks/sync/orchestratorShared.d.ts +3 -3
- package/dist/hooks/sync/orchestratorShared.js +61 -1
- package/dist/hooks/sync/recovery.js +8 -0
- package/dist/hooks/sync/recovery.test.js +5 -5
- package/dist/hooks/sync/transfers.d.ts +2 -1
- package/dist/hooks/sync/transfers.js +36 -9
- package/dist/hooks/sync/transfers.test.js +534 -2
- package/dist/hooks/useFilterSort.js +13 -13
- package/dist/hooks/useFilterSort.test.js +87 -1
- package/dist/hooks/useSyncOrchestrator.js +50 -5
- package/dist/hooks/useTaskforce.d.ts +85 -50
- package/dist/hooks/useTaskforce.js +44 -14
- package/dist/hooks/useTaskforce.runtime-routing.test.js +94 -0
- package/dist/hooks/useTaskforce.sync-behavior.test.js +99 -0
- package/dist/hooks/useWorkspaceSyncController.js +7 -1
- package/dist/hooks/useWorkspaceSyncController.test.js +48 -0
- package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +14 -7
- package/dist/mcp/canonicalAssetHelpers.d.ts +16 -4
- package/dist/mcp/canonicalAssetHelpers.js +18 -10
- package/dist/mcp/canonicalAssetHelpers.test.d.ts +1 -0
- package/dist/mcp/canonicalAssetHelpers.test.js +67 -0
- package/dist/mcp/clientIntegrations.d.ts +1 -0
- package/dist/mcp/clientIntegrations.js +25 -0
- package/dist/mcp/clientIntegrations.test.js +14 -3
- package/dist/mcp/clientProfileDefaults.js +3 -3
- package/dist/mcp/collaborationRegistrar.js +7 -7
- package/dist/mcp/documentAssetRegistrar.js +113 -7
- package/dist/mcp/runtime.d.ts +1 -0
- package/dist/mcp/runtime.js +969 -122
- package/dist/mcp/runtime.test.js +1083 -11
- package/dist/mcp/taskAttachmentTypes.d.ts +1 -1
- package/dist/mcp/taskPlanningRegistrar.js +48 -0
- package/dist/mcp/toolRegistry.d.ts +56 -0
- package/dist/mcp/toolRegistry.js +8 -0
- package/dist/mcp/toolRegistry.test.js +4 -0
- package/dist/migrations/taskSchemaMigrations.js +58 -15
- package/dist/server/aiProfileAvatarAssets.d.ts +49 -0
- package/dist/server/aiProfileAvatarAssets.js +319 -0
- package/dist/server/aiProfileAvatarAssets.test.d.ts +1 -0
- package/dist/server/aiProfileAvatarAssets.test.js +213 -0
- package/dist/server/annotatedAttachmentsRoutes.test.js +66 -7
- package/dist/server/index.js +4 -0
- package/dist/server/index.test.js +6 -1
- package/dist/server/routes/admin.js +328 -9
- package/dist/server/routes/annotatedAttachments.js +51 -0
- package/dist/server/routes/auth.d.ts +11 -0
- package/dist/server/routes/auth.js +189 -27
- package/dist/server/routes/authSupport.d.ts +5 -0
- package/dist/server/routes/authSupport.js +13 -1
- package/dist/server/routes/billing.d.ts +1 -0
- package/dist/server/routes/billing.js +116 -63
- package/dist/server/routes/billing.test.js +162 -11
- package/dist/server/routes/documents.js +10 -0
- package/dist/server/routes/shared.js +0 -10
- package/dist/server/routes/sync.integration.test.js +221 -0
- package/dist/server/routes/sync.js +13 -3
- package/dist/server/routes/syncSnapshotRoutes.js +2 -0
- package/dist/server/routes/tasks.js +12 -9
- package/dist/server/routes.js +87 -8
- package/dist/server/routes.test.js +972 -23
- package/dist/shared/aiProfileSurfaceType.d.ts +1 -1
- package/dist/shared/aiProfileSurfaceType.js +10 -8
- package/dist/storage/objectStorage.d.ts +1 -0
- package/dist/storage/objectStorage.js +2 -1
- package/dist/storage/objectStorageClient.d.ts +1 -0
- package/dist/storage/objectStorageClient.js +41 -8
- package/dist/storage/objectStorageClient.test.js +26 -1
- package/dist/storage/objectStorageConfig.js +3 -1
- package/dist/storage/objectStorageConfig.test.js +13 -1
- package/dist/sync/collaborationSyncPayload.js +2 -0
- package/dist/sync/collaborationSyncPayload.test.js +1 -0
- package/dist/sync/collaborationSyncState.d.ts +3 -3
- package/dist/sync/collaborationSyncState.js +19 -12
- package/dist/sync/contentSyncPayload.d.ts +5 -1
- package/dist/sync/contentSyncPayload.js +9 -0
- package/dist/sync/contentSyncPayload.test.js +39 -0
- package/dist/sync/contentSyncState.d.ts +5 -1
- package/dist/sync/contentSyncState.js +231 -37
- package/dist/sync/planningSyncPayload.js +5 -0
- package/dist/sync/planningSyncPayload.test.js +24 -0
- package/dist/sync/syncApplyHandlers.d.ts +4 -4
- package/dist/sync/syncApplyHandlers.js +89 -31
- package/dist/sync/syncApplyHandlers.test.js +184 -4
- package/dist/sync/syncResourceAdapters.d.ts +2 -0
- package/dist/sync/syncResourceAdapters.js +2 -0
- package/dist/sync/syncService.d.ts +1 -0
- package/dist/sync/syncService.js +13 -1
- package/dist/sync/syncService.test.js +39 -0
- package/dist/sync/workspacePullFeed.d.ts +4 -0
- package/dist/sync/workspacePullFeed.js +129 -70
- package/dist/sync/workspacePullFeed.test.js +49 -0
- package/dist/sync/workspaceSyncModel.d.ts +28 -6
- package/dist/sync/workspaceSyncModel.js +159 -45
- package/dist/sync/workspaceSyncModel.test.js +269 -3
- package/dist/types.d.ts +33 -2
- package/dist/ui/agent-logos/ChatGPT.png +0 -0
- package/dist/ui/agent-logos/Gemini CLI.jpeg +0 -0
- package/dist/ui/agent-logos/antigravity.jpeg +0 -0
- package/dist/ui/agent-logos/claude-code.jpeg +0 -0
- package/dist/ui/agent-logos/codex.jpeg +0 -0
- package/dist/ui/agent-logos/cursor.png +0 -0
- package/dist/ui/agent-logos/openclaw.jpeg +0 -0
- package/dist/ui/agent-logos/windsurf.png +0 -0
- package/dist/ui/assets/AgentsModule-BS4Pi_nC.js +1 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BVKew-mH.css +1 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-CCckzWYZ.js +3 -0
- package/dist/ui/assets/ContextAttachmentManager-CfG_ER7C.js +3 -0
- package/dist/ui/assets/DocumentWorkspace-BVaWPA25.js +252 -0
- package/dist/ui/assets/DocumentWorkspace-D4rJKXzd.css +1 -0
- package/dist/ui/assets/EntityActivityTimeline-DSj0ThaK.js +1 -0
- package/dist/ui/assets/EntityActivityTimeline-DyqvvhuF.css +1 -0
- package/dist/ui/assets/{InitiativesModule-9E6ParrY.js → InitiativesModule-AxMkWtxH.js} +1 -1
- package/dist/ui/assets/PlansPage-B_z-D6Nh.css +1 -0
- package/dist/ui/assets/PlansPage-Ndt7mYfo.js +1 -0
- package/dist/ui/assets/TaskContextUpload-Dw4rTF4i.js +1 -0
- package/dist/ui/assets/TaskSettings-f2ga42_V.js +9 -0
- package/dist/ui/assets/{WorkflowsModule-BA7jcEpH.js → WorkflowsModule-E4UL3mov.js} +4 -4
- package/dist/ui/assets/documentReferences-BOUcJm6-.js +1 -0
- package/dist/ui/assets/index-BvAbqx5Q.css +1 -0
- package/dist/ui/assets/index-MAHKvFqp.js +4 -0
- package/dist/ui/assets/{vendor-icons-DuEd_65c.js → vendor-icons-B32hGuF2.js} +1 -1
- package/dist/ui/index.html +3 -3
- package/dist/ui/og-image.png +0 -0
- package/dist/ui/product/agent manager.png +0 -0
- package/dist/ui/product/agent_manager_02.png +0 -0
- package/dist/utils/aiProfileEvents.d.ts +7 -0
- package/dist/utils/aiProfileEvents.js +6 -0
- package/dist/utils/assignees.d.ts +6 -0
- package/dist/utils/assignees.js +8 -1
- package/dist/utils/assignees.test.d.ts +1 -0
- package/dist/utils/assignees.test.js +25 -0
- package/dist/utils/avatarDisplay.d.ts +1 -0
- package/dist/utils/avatarDisplay.js +15 -0
- package/dist/utils/contextFiles.d.ts +3 -1
- package/dist/utils/contextFiles.js +2 -1
- package/dist/utils/taskActivity.d.ts +7 -1
- package/dist/utils/taskActivity.js +63 -1
- package/dist/utils/taskActivity.test.js +23 -1
- package/dist/utils/taskSearch.d.ts +22 -0
- package/dist/utils/taskSearch.js +87 -0
- package/dist/utils/taskSearch.test.d.ts +1 -0
- package/dist/utils/taskSearch.test.js +69 -0
- package/dist/utils/taskUtils.js +10 -3
- package/dist/utils/taskUtils.test.d.ts +1 -0
- package/dist/utils/taskUtils.test.js +19 -0
- package/package.json +1 -1
- package/dist/ui/assets/AgentsModule-DrLawwNl.js +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BaS2VwIr.css +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-Z9_whf7F.js +0 -3
- package/dist/ui/assets/DocumentWorkspace-B03MaSkw.js +0 -252
- package/dist/ui/assets/DocumentWorkspace-Dhdso07p.css +0 -1
- package/dist/ui/assets/PlansPage-CvfnMiWq.css +0 -1
- package/dist/ui/assets/PlansPage-DRXscYxH.js +0 -1
- package/dist/ui/assets/TaskSettings-DZX4jk7e.js +0 -9
- package/dist/ui/assets/index-9eT8e0Lu.css +0 -1
- package/dist/ui/assets/index-C6k75jr8.js +0 -6
|
@@ -38,6 +38,8 @@
|
|
|
38
38
|
* GET /api/taskforce/auth/workspace-members
|
|
39
39
|
* GET /api/taskforce/workspace/assignee-options
|
|
40
40
|
* POST /api/taskforce/workspace/ai-profiles/avatar
|
|
41
|
+
* POST /api/taskforce/workspace/ai-profiles/avatar/upload
|
|
42
|
+
* POST /api/taskforce/workspace/ai-profiles/surface-type
|
|
41
43
|
* GET /api/taskforce/admin/users
|
|
42
44
|
* POST /api/taskforce/admin/users/invite
|
|
43
45
|
* PATCH /api/taskforce/admin/users/:id/role
|
|
@@ -61,9 +63,11 @@ import { resolveRuntimeModeContract } from '../../shared/runtimeContract.js';
|
|
|
61
63
|
import { getRouteTimingNow, logSlowBootstrapRoute, requestBootstrapTraceId, requestHeader, resolveErrorStatusCode, serializeJsonWithTiming, setServerTimingHeader } from './shared.js';
|
|
62
64
|
import { buildAuthFlowBehavior, buildSiteBehavior, getRouteEmailConfig, resolvePublicAuthBaseUrl, resolveRuntimeConfigBaseUrl, shouldExposeDevAuthTokens } from './authSupport.js';
|
|
63
65
|
import { normalizeTaskDataRelativePath } from '../../storage/objectStorageClient.js';
|
|
66
|
+
import { clearAiProfileAvatarAssets, saveAiProfileAvatarAssets } from '../aiProfileAvatarAssets.js';
|
|
67
|
+
const AI_PROFILE_AVATAR_UPLOAD_MAX_JSON_BYTES = 16 * 1024 * 1024;
|
|
64
68
|
// === SECTION: Registration ===
|
|
65
69
|
export function registerAuthRoutes(deps) {
|
|
66
|
-
const { addRoute, core, context, requestWorkspaceId, requestUserId, resolveAuthenticatedUserId, ensureAppAccess, ensureAuthenticatedUser, ensureWorkspaceAdminRole, ensureCloudPlanData, requireCloudRuntime, auditAuthAction, resolveAdminRequestActor, resolveEffectiveObjectStorageConfig, getObjectStorageClient, } = deps;
|
|
70
|
+
const { addRoute, core, context, requestWorkspaceId, requestUserId, resolveAuthenticatedUserId, ensureAppAccess, ensureAuthenticatedUser, ensureWorkspaceAdminRole, ensureCloudPlanData, requireCloudRuntime, auditAuthAction, resolveAdminRequestActor, resolveEffectiveObjectStorageConfig, getObjectStorageClient, workspaceAssetStore, ensureWithinDir, markAssetDeleted, appendStorageTelemetry, } = deps;
|
|
67
71
|
const normalizeTeamWorkspaceRole = (value) => {
|
|
68
72
|
const role = String(value || '').trim().toLowerCase();
|
|
69
73
|
if (role === 'owner' || role === 'admin' || role === 'member' || role === 'read-only')
|
|
@@ -76,6 +80,56 @@ export function registerAuthRoutes(deps) {
|
|
|
76
80
|
const stateAllows = state === 'active' || state === 'trialing' || state === 'grace';
|
|
77
81
|
return teamAllowed && stateAllows ? 'team' : 'personal';
|
|
78
82
|
};
|
|
83
|
+
const serializeAiProfilePublicRecord = (profile) => ({
|
|
84
|
+
id: profile.id,
|
|
85
|
+
workspaceId: profile.workspaceId,
|
|
86
|
+
name: profile.name,
|
|
87
|
+
username: profile.username,
|
|
88
|
+
icon: profile.icon,
|
|
89
|
+
color: profile.color,
|
|
90
|
+
avatarUrl: profile.avatarUrl ?? null,
|
|
91
|
+
avatarSourceUrl: profile.avatarSourceUrl ?? null,
|
|
92
|
+
avatarRevision: profile.avatarRevision ?? 0,
|
|
93
|
+
avatarUpdatedAt: profile.avatarUpdatedAt ?? null,
|
|
94
|
+
description: profile.description ?? null,
|
|
95
|
+
role: profile.role ?? null,
|
|
96
|
+
provider: profile.provider ?? null,
|
|
97
|
+
model: profile.model ?? null,
|
|
98
|
+
surfaceType: profile.surfaceType ?? null,
|
|
99
|
+
seatScope: profile.seatScope ?? null,
|
|
100
|
+
archivedAt: profile.archivedAt ?? null,
|
|
101
|
+
archivedBy: profile.archivedBy ?? null,
|
|
102
|
+
archivedReason: profile.archivedReason ?? null,
|
|
103
|
+
mergedIntoProfileId: profile.mergedIntoProfileId ?? null,
|
|
104
|
+
rosterStateUpdatedAt: profile.rosterStateUpdatedAt ?? null,
|
|
105
|
+
createdAt: profile.createdAt,
|
|
106
|
+
updatedAt: profile.updatedAt,
|
|
107
|
+
lastActiveAt: profile.lastActiveAt ?? null
|
|
108
|
+
});
|
|
109
|
+
const parseAiAvatarDataUrlPayload = (value, fallbackOriginalName) => {
|
|
110
|
+
if (!value || typeof value !== 'object')
|
|
111
|
+
return null;
|
|
112
|
+
const record = value;
|
|
113
|
+
const dataUrl = String(record.dataUrl || record.file || '').trim();
|
|
114
|
+
const dataMatch = dataUrl.match(/^data:([^;]+);base64,(.+)$/);
|
|
115
|
+
if (!dataMatch)
|
|
116
|
+
return null;
|
|
117
|
+
return {
|
|
118
|
+
mimeType: String(record.mimeType || dataMatch[1] || 'application/octet-stream').trim().toLowerCase(),
|
|
119
|
+
originalName: typeof record.originalName === 'string' && record.originalName.trim().length > 0
|
|
120
|
+
? record.originalName.trim()
|
|
121
|
+
: fallbackOriginalName,
|
|
122
|
+
buffer: Buffer.from(dataMatch[2], 'base64')
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
const aiProfileAvatarAssetDeps = {
|
|
126
|
+
core,
|
|
127
|
+
workspaceAssetStore,
|
|
128
|
+
getObjectStorageClient,
|
|
129
|
+
ensureWithinDir,
|
|
130
|
+
markAssetDeleted,
|
|
131
|
+
appendStorageTelemetry,
|
|
132
|
+
};
|
|
79
133
|
const resolveBillingConflictCodeForUser = (userIdRaw, gateRaw) => {
|
|
80
134
|
const userId = String(userIdRaw || '').trim();
|
|
81
135
|
const gate = String(gateRaw || '').trim().toLowerCase();
|
|
@@ -1062,6 +1116,8 @@ export function registerAuthRoutes(deps) {
|
|
|
1062
1116
|
}
|
|
1063
1117
|
const payload = {
|
|
1064
1118
|
authenticated,
|
|
1119
|
+
authRequiredForApi: Boolean(authConfig?.enabled && authConfig.requiredForApi),
|
|
1120
|
+
runtimeMode: authConfig?.runtimeMode || 'local',
|
|
1065
1121
|
userId,
|
|
1066
1122
|
workspaceId,
|
|
1067
1123
|
role,
|
|
@@ -2189,6 +2245,7 @@ export function registerAuthRoutes(deps) {
|
|
|
2189
2245
|
res.end(JSON.stringify({ users }));
|
|
2190
2246
|
});
|
|
2191
2247
|
// GET /api/taskforce/workspace/assignee-options - Read active workspace humans and registered AI collaborators for task assignee selection.
|
|
2248
|
+
// Use ?kind=agent for Agent Manager roster loads that do not need human workspace members.
|
|
2192
2249
|
addRoute('GET', '/api/taskforce/workspace/assignee-options', async (req, res) => {
|
|
2193
2250
|
if (!ensureAppAccess(req, res))
|
|
2194
2251
|
return;
|
|
@@ -2200,26 +2257,30 @@ export function registerAuthRoutes(deps) {
|
|
|
2200
2257
|
const startedAt = getRouteTimingNow();
|
|
2201
2258
|
const wid = requestWorkspaceId(req);
|
|
2202
2259
|
const traceId = requestBootstrapTraceId(req);
|
|
2203
|
-
const
|
|
2204
|
-
const
|
|
2205
|
-
const
|
|
2260
|
+
const reqUrl = new URL(req.url || '/api/taskforce/workspace/assignee-options', 'http://localhost');
|
|
2261
|
+
const kindFilter = String(reqUrl.searchParams.get('kind') || '').trim().toLowerCase();
|
|
2262
|
+
const agentsOnly = kindFilter === 'agent' || kindFilter === 'agents' || kindFilter === 'ai-profile' || kindFilter === 'ai-profiles';
|
|
2206
2263
|
const usersStartedAt = getRouteTimingNow();
|
|
2207
|
-
const activeWorkspaceUsers =
|
|
2208
|
-
|
|
2264
|
+
const activeWorkspaceUsers = agentsOnly
|
|
2265
|
+
? []
|
|
2266
|
+
: core.listWorkspaceUsers(wid)
|
|
2267
|
+
.filter((user) => String(user.status || '').trim().toLowerCase() === 'active' && user.disabled !== true);
|
|
2209
2268
|
const usersLoadedAt = getRouteTimingNow();
|
|
2210
|
-
const workspaceUsers =
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2269
|
+
const workspaceUsers = agentsOnly
|
|
2270
|
+
? []
|
|
2271
|
+
: activeWorkspaceUsers.map((user) => ({
|
|
2272
|
+
value: user.userId,
|
|
2273
|
+
label: String(user.displayName || user.email || user.userId).trim() || user.userId,
|
|
2274
|
+
icon: 'User',
|
|
2275
|
+
color: '#22c55e',
|
|
2276
|
+
kind: 'member',
|
|
2277
|
+
userId: user.userId,
|
|
2278
|
+
email: user.email,
|
|
2279
|
+
displayName: user.displayName ?? null,
|
|
2280
|
+
avatarUrl: user.avatarUrl ?? null,
|
|
2281
|
+
status: user.status,
|
|
2282
|
+
disabled: user.disabled === true
|
|
2283
|
+
}));
|
|
2223
2284
|
const usersMappedAt = getRouteTimingNow();
|
|
2224
2285
|
const aiProfileDiagnostics = { metadataBackfillCount: 0 };
|
|
2225
2286
|
const aiProfilesStartedAt = getRouteTimingNow();
|
|
@@ -2228,12 +2289,13 @@ export function registerAuthRoutes(deps) {
|
|
|
2228
2289
|
.map((profile) => ({
|
|
2229
2290
|
value: profile.id,
|
|
2230
2291
|
label: profile.name,
|
|
2231
|
-
...(includeProfileToken ? { profileToken: profile.profileToken } : {}),
|
|
2232
2292
|
username: profile.username,
|
|
2233
2293
|
icon: profile.icon,
|
|
2234
2294
|
color: profile.color,
|
|
2235
2295
|
avatarUrl: profile.avatarUrl ?? null,
|
|
2236
2296
|
avatarSourceUrl: profile.avatarSourceUrl ?? null,
|
|
2297
|
+
avatarRevision: profile.avatarRevision ?? 0,
|
|
2298
|
+
avatarUpdatedAt: profile.avatarUpdatedAt ?? null,
|
|
2237
2299
|
kind: 'agent',
|
|
2238
2300
|
description: profile.description ?? null,
|
|
2239
2301
|
role: profile.role ?? null,
|
|
@@ -2256,7 +2318,6 @@ export function registerAuthRoutes(deps) {
|
|
|
2256
2318
|
const totalDurationMs = Math.max(0, getRouteTimingNow() - startedAt);
|
|
2257
2319
|
setServerTimingHeader(res, [
|
|
2258
2320
|
{ name: 'assignee-options', durationMs: totalDurationMs },
|
|
2259
|
-
{ name: 'assignee-options-admin-role', durationMs: adminRoleResolvedAt - adminRoleStartedAt },
|
|
2260
2321
|
{ name: 'assignee-options-users', durationMs: usersLoadedAt - usersStartedAt },
|
|
2261
2322
|
{ name: 'assignee-options-users-map', durationMs: usersMappedAt - usersLoadedAt },
|
|
2262
2323
|
{ name: 'assignee-options-ai-profiles', durationMs: aiProfilesLoadedAt - aiProfilesStartedAt },
|
|
@@ -2272,9 +2333,9 @@ export function registerAuthRoutes(deps) {
|
|
|
2272
2333
|
humanAssigneeCount: workspaceUsers.length,
|
|
2273
2334
|
workspaceUserCount: activeWorkspaceUsers.length,
|
|
2274
2335
|
aiProfileCount: aiProfiles.length,
|
|
2336
|
+
agentsOnly,
|
|
2275
2337
|
metadataBackfillCount: aiProfileDiagnostics.metadataBackfillCount,
|
|
2276
2338
|
responseBytes: serialized.byteLength,
|
|
2277
|
-
adminRoleMs: Math.max(0, adminRoleResolvedAt - adminRoleStartedAt),
|
|
2278
2339
|
listWorkspaceUsersMs: Math.max(0, usersLoadedAt - usersStartedAt),
|
|
2279
2340
|
workspaceUsersMapMs: Math.max(0, usersMappedAt - usersLoadedAt),
|
|
2280
2341
|
listAiProfilesMs: Math.max(0, aiProfilesLoadedAt - aiProfilesStartedAt),
|
|
@@ -2285,7 +2346,7 @@ export function registerAuthRoutes(deps) {
|
|
|
2285
2346
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
2286
2347
|
res.end(serialized.body);
|
|
2287
2348
|
});
|
|
2288
|
-
// POST /api/taskforce/workspace/ai-profiles/avatar -
|
|
2349
|
+
// POST /api/taskforce/workspace/ai-profiles/avatar - Clear an AI profile avatar image.
|
|
2289
2350
|
addRoute('POST', '/api/taskforce/workspace/ai-profiles/avatar', async (req, res) => {
|
|
2290
2351
|
if (!ensureWorkspaceAdminRole(req)) {
|
|
2291
2352
|
res.writeHead(403, { 'Content-Type': 'application/json' });
|
|
@@ -2307,9 +2368,19 @@ export function registerAuthRoutes(deps) {
|
|
|
2307
2368
|
return;
|
|
2308
2369
|
}
|
|
2309
2370
|
try {
|
|
2310
|
-
const
|
|
2371
|
+
const shouldClearAvatar = avatarUrl === null && (avatarSourceUrl === null || avatarSourceUrl === undefined);
|
|
2372
|
+
if (!shouldClearAvatar) {
|
|
2373
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
2374
|
+
res.end(JSON.stringify({
|
|
2375
|
+
error: 'AI profile avatar updates must use the stable avatar upload endpoint.',
|
|
2376
|
+
code: 'AI_PROFILE_AVATAR_STABLE_UPLOAD_REQUIRED'
|
|
2377
|
+
}));
|
|
2378
|
+
return;
|
|
2379
|
+
}
|
|
2380
|
+
const result = await clearAiProfileAvatarAssets(aiProfileAvatarAssetDeps, { workspaceId: wid, profileId });
|
|
2381
|
+
const profile = result.profile;
|
|
2311
2382
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
2312
|
-
res.end(JSON.stringify({ success: true, profile }));
|
|
2383
|
+
res.end(JSON.stringify({ success: true, profile: serializeAiProfilePublicRecord(profile) }));
|
|
2313
2384
|
}
|
|
2314
2385
|
catch (err) {
|
|
2315
2386
|
const status = err?.statusCode ?? 500;
|
|
@@ -2317,6 +2388,58 @@ export function registerAuthRoutes(deps) {
|
|
|
2317
2388
|
res.end(JSON.stringify({ error: err?.message ?? 'Failed to update AI profile avatar.' }));
|
|
2318
2389
|
}
|
|
2319
2390
|
});
|
|
2391
|
+
// POST /api/taskforce/workspace/ai-profiles/avatar/upload - Upload stable AI profile avatar slots.
|
|
2392
|
+
addRoute('POST', '/api/taskforce/workspace/ai-profiles/avatar/upload', async (req, res) => {
|
|
2393
|
+
if (!ensureWorkspaceAdminRole(req)) {
|
|
2394
|
+
res.writeHead(403, { 'Content-Type': 'application/json' });
|
|
2395
|
+
res.end(JSON.stringify({ error: 'Forbidden: owner or admin role required.' }));
|
|
2396
|
+
return;
|
|
2397
|
+
}
|
|
2398
|
+
const body = await parseJsonBody(req, AI_PROFILE_AVATAR_UPLOAD_MAX_JSON_BYTES);
|
|
2399
|
+
const wid = requestWorkspaceId(req);
|
|
2400
|
+
const profileId = String(body?.profileId || '').trim();
|
|
2401
|
+
if (!profileId) {
|
|
2402
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
2403
|
+
res.end(JSON.stringify({ error: 'profileId is required.' }));
|
|
2404
|
+
return;
|
|
2405
|
+
}
|
|
2406
|
+
const display = parseAiAvatarDataUrlPayload(body?.displayImage || body?.display, 'display-avatar');
|
|
2407
|
+
if (!display) {
|
|
2408
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
2409
|
+
res.end(JSON.stringify({ error: 'displayImage data URL is required.' }));
|
|
2410
|
+
return;
|
|
2411
|
+
}
|
|
2412
|
+
const source = parseAiAvatarDataUrlPayload(body?.sourceImage || body?.source, 'source-avatar');
|
|
2413
|
+
try {
|
|
2414
|
+
const result = await saveAiProfileAvatarAssets(aiProfileAvatarAssetDeps, {
|
|
2415
|
+
workspaceId: wid,
|
|
2416
|
+
profileId,
|
|
2417
|
+
display,
|
|
2418
|
+
source,
|
|
2419
|
+
actorId: resolveAuthenticatedUserId(req)
|
|
2420
|
+
});
|
|
2421
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
2422
|
+
res.end(JSON.stringify({
|
|
2423
|
+
success: true,
|
|
2424
|
+
profile: serializeAiProfilePublicRecord(result.profile),
|
|
2425
|
+
assets: {
|
|
2426
|
+
display: {
|
|
2427
|
+
assetId: result.displayAsset.assetId,
|
|
2428
|
+
storageKey: result.displayStorageKey,
|
|
2429
|
+
},
|
|
2430
|
+
source: {
|
|
2431
|
+
assetId: result.sourceAsset.assetId,
|
|
2432
|
+
storageKey: result.sourceStorageKey,
|
|
2433
|
+
}
|
|
2434
|
+
}
|
|
2435
|
+
}));
|
|
2436
|
+
}
|
|
2437
|
+
catch (err) {
|
|
2438
|
+
const status = err?.statusCode ?? 500;
|
|
2439
|
+
res.writeHead(status, { 'Content-Type': 'application/json' });
|
|
2440
|
+
res.end(JSON.stringify({ error: err?.message ?? 'Failed to upload AI profile avatar.' }));
|
|
2441
|
+
}
|
|
2442
|
+
});
|
|
2320
2443
|
// POST /api/taskforce/workspace/ai-profiles/merge - Merge a duplicate AI profile into another, reassigning all references.
|
|
2321
2444
|
addRoute('POST', '/api/taskforce/workspace/ai-profiles/merge', async (req, res) => {
|
|
2322
2445
|
if (!ensureWorkspaceAdminRole(req)) {
|
|
@@ -2336,7 +2459,7 @@ export function registerAuthRoutes(deps) {
|
|
|
2336
2459
|
try {
|
|
2337
2460
|
const profile = core.mergeAiProfiles({ workspaceId: wid, keepId, mergeId });
|
|
2338
2461
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
2339
|
-
res.end(JSON.stringify({ profile }));
|
|
2462
|
+
res.end(JSON.stringify({ profile: serializeAiProfilePublicRecord(profile) }));
|
|
2340
2463
|
}
|
|
2341
2464
|
catch (err) {
|
|
2342
2465
|
const status = err?.statusCode ?? 500;
|
|
@@ -2344,6 +2467,45 @@ export function registerAuthRoutes(deps) {
|
|
|
2344
2467
|
res.end(JSON.stringify({ error: err?.message ?? 'Merge failed.' }));
|
|
2345
2468
|
}
|
|
2346
2469
|
});
|
|
2470
|
+
// POST /api/taskforce/workspace/ai-profiles/surface-type - Manually re-categorize an active AI profile.
|
|
2471
|
+
addRoute('POST', '/api/taskforce/workspace/ai-profiles/surface-type', async (req, res) => {
|
|
2472
|
+
if (!ensureWorkspaceAdminRole(req)) {
|
|
2473
|
+
res.writeHead(403, { 'Content-Type': 'application/json' });
|
|
2474
|
+
res.end(JSON.stringify({ error: 'Forbidden: owner or admin role required.' }));
|
|
2475
|
+
return;
|
|
2476
|
+
}
|
|
2477
|
+
const body = await parseJsonBody(req);
|
|
2478
|
+
const wid = requestWorkspaceId(req);
|
|
2479
|
+
const profileId = String(body.profileId || '').trim();
|
|
2480
|
+
const hasSurfaceType = Boolean(body && Object.prototype.hasOwnProperty.call(body, 'surfaceType'));
|
|
2481
|
+
if (!profileId) {
|
|
2482
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
2483
|
+
res.end(JSON.stringify({ error: 'profileId is required.' }));
|
|
2484
|
+
return;
|
|
2485
|
+
}
|
|
2486
|
+
if (!hasSurfaceType) {
|
|
2487
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
2488
|
+
res.end(JSON.stringify({ error: 'surfaceType is required.' }));
|
|
2489
|
+
return;
|
|
2490
|
+
}
|
|
2491
|
+
try {
|
|
2492
|
+
const profile = core.updateAiProfileSurfaceType({
|
|
2493
|
+
workspaceId: wid,
|
|
2494
|
+
profileId,
|
|
2495
|
+
surfaceType: body.surfaceType
|
|
2496
|
+
});
|
|
2497
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
2498
|
+
res.end(JSON.stringify({ success: true, profile: serializeAiProfilePublicRecord(profile) }));
|
|
2499
|
+
}
|
|
2500
|
+
catch (err) {
|
|
2501
|
+
const status = err?.statusCode ?? 500;
|
|
2502
|
+
res.writeHead(status, { 'Content-Type': 'application/json' });
|
|
2503
|
+
res.end(JSON.stringify({
|
|
2504
|
+
error: err?.message ?? 'Failed to update AI profile category.',
|
|
2505
|
+
code: err?.code
|
|
2506
|
+
}));
|
|
2507
|
+
}
|
|
2508
|
+
});
|
|
2347
2509
|
// POST /api/taskforce/workspace/ai-profiles/archive - Remove an AI profile from the active roster without deleting its history.
|
|
2348
2510
|
addRoute('POST', '/api/taskforce/workspace/ai-profiles/archive', async (req, res) => {
|
|
2349
2511
|
if (!ensureWorkspaceAdminRole(req)) {
|
|
@@ -2368,7 +2530,7 @@ export function registerAuthRoutes(deps) {
|
|
|
2368
2530
|
reason
|
|
2369
2531
|
});
|
|
2370
2532
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
2371
|
-
res.end(JSON.stringify({ profile }));
|
|
2533
|
+
res.end(JSON.stringify({ profile: serializeAiProfilePublicRecord(profile) }));
|
|
2372
2534
|
}
|
|
2373
2535
|
catch (err) {
|
|
2374
2536
|
const status = err?.statusCode ?? 500;
|
|
@@ -24,6 +24,11 @@ export declare function buildAuthBehavior(core: TaskforceCore): {
|
|
|
24
24
|
export declare function buildSiteBehavior(core: TaskforceCore): {
|
|
25
25
|
showRunTaskforceLocally: boolean;
|
|
26
26
|
pricingPageEnabled: boolean;
|
|
27
|
+
animatedBackgroundEnabled: boolean;
|
|
28
|
+
siteTheme: string;
|
|
29
|
+
pricingPageTitle: string;
|
|
30
|
+
pricingPageDescription: string;
|
|
31
|
+
pricingPageShowPublicDescriptions: boolean;
|
|
27
32
|
};
|
|
28
33
|
export declare function shouldExposeDevAuthTokens(): boolean;
|
|
29
34
|
export declare function resolveRuntimeConfigBaseUrl(req: IncomingMessage): string;
|
|
@@ -51,9 +51,21 @@ export function buildAuthBehavior(core) {
|
|
|
51
51
|
export function buildSiteBehavior(core) {
|
|
52
52
|
const globalSettings = core.getGlobalSettings();
|
|
53
53
|
const siteSettings = globalSettings.site || {};
|
|
54
|
+
const pricingPageTitle = typeof siteSettings.pricingPageTitle === 'string'
|
|
55
|
+
? (siteSettings.pricingPageTitle.trim() || 'Subscription Plans')
|
|
56
|
+
: 'Subscription Plans';
|
|
57
|
+
const pricingPageDescription = typeof siteSettings.pricingPageDescription === 'string'
|
|
58
|
+
? (siteSettings.pricingPageDescription.trim() || 'Manage your subscription and explore available features. Your current plan is highlighted below.')
|
|
59
|
+
: 'Manage your subscription and explore available features. Your current plan is highlighted below.';
|
|
60
|
+
const siteTheme = siteSettings.siteTheme === 'light' ? 'light' : 'dark';
|
|
54
61
|
return {
|
|
55
62
|
showRunTaskforceLocally: resolveBooleanSetting(siteSettings.showRunTaskforceLocally, true),
|
|
56
|
-
pricingPageEnabled: resolveBooleanSetting(siteSettings.pricingPageEnabled, true)
|
|
63
|
+
pricingPageEnabled: resolveBooleanSetting(siteSettings.pricingPageEnabled, true),
|
|
64
|
+
animatedBackgroundEnabled: resolveBooleanSetting(siteSettings.animatedBackgroundEnabled, false),
|
|
65
|
+
siteTheme,
|
|
66
|
+
pricingPageTitle,
|
|
67
|
+
pricingPageDescription,
|
|
68
|
+
pricingPageShowPublicDescriptions: resolveBooleanSetting(siteSettings.pricingPageShowPublicDescriptions, false)
|
|
57
69
|
};
|
|
58
70
|
}
|
|
59
71
|
export function shouldExposeDevAuthTokens() {
|
|
@@ -3,6 +3,7 @@ import type { TaskforceCore } from '../../core/Taskforce.js';
|
|
|
3
3
|
import { type RouteHandler, type RouteContext } from './primitives.js';
|
|
4
4
|
export type BillingInterval = 'month' | 'year';
|
|
5
5
|
export type BillingPricingType = 'stripe' | 'free';
|
|
6
|
+
export type BillingPricingAudience = 'public' | 'campaign';
|
|
6
7
|
export interface BillingRouteDependencies {
|
|
7
8
|
addRoute: (method: string, path: string, handler: RouteHandler) => void;
|
|
8
9
|
core: TaskforceCore;
|