@taskforcehq/taskforce 0.3.305 → 0.3.307
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 +603 -107
- package/dist/TaskforceCore.js +216 -43
- package/dist/TaskforceCore.test.js +611 -28
- package/dist/assets/fonts/CourierPrime-Bold.woff2 +0 -0
- package/dist/assets/fonts/CourierPrime-BoldItalic.woff2 +0 -0
- package/dist/assets/fonts/CourierPrime-Italic.woff2 +0 -0
- package/dist/assets/fonts/CourierPrime-Regular.woff2 +0 -0
- package/dist/assets/fonts/Noir_medium.woff2 +0 -0
- package/dist/assets/fonts/Noir_regular.woff2 +0 -0
- package/dist/assets/fonts/RussoOne-Regular.woff2 +0 -0
- package/dist/assets/fonts/SpecialElite-Regular.woff2 +0 -0
- package/dist/compat/workspaceSyncCompat.js +46 -2
- package/dist/compat/workspaceSyncCompat.test.js +38 -1
- package/dist/components/activity/EntityActivityTimeline.d.ts +34 -0
- package/dist/components/activity/EntityActivityTimeline.js +81 -0
- package/dist/components/context/ContextAttachmentManager.d.ts +14 -0
- package/dist/components/context/ContextAttachmentManager.js +561 -0
- package/dist/components/features/AgentsModule.d.ts +14 -1
- package/dist/components/features/AgentsModule.js +366 -18
- package/dist/components/features/AgentsModule.test.js +507 -8
- 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 +7 -1
- package/dist/components/features/DocumentViewer.js +62 -4
- package/dist/components/features/DocumentWorkspace.d.ts +10 -2
- package/dist/components/features/DocumentWorkspace.js +15 -4
- package/dist/components/features/DocumentWorkspace.test.js +51 -1
- 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/features/documentWorkspaceModel.d.ts +1 -1
- package/dist/components/task/TaskActionHeader.js +11 -5
- package/dist/components/task/TaskActionHeader.test.js +10 -0
- package/dist/components/task/TaskCard.js +24 -29
- package/dist/components/task/TaskCard.test.js +38 -3
- package/dist/components/task/TaskContextUpload.js +4 -526
- package/dist/components/task/TaskContextUpload.test.js +3 -3
- package/dist/components/task/TaskForm.js +61 -116
- package/dist/components/task/TaskForm.test.js +110 -8
- package/dist/components/task/TaskKanban.d.ts +2 -1
- package/dist/components/task/TaskKanban.js +94 -21
- package/dist/components/task/TaskKanban.test.js +36 -0
- package/dist/components/task/TaskList.js +5 -1
- package/dist/components/task/TaskList.test.js +4 -0
- package/dist/components/ui/EditableAvatarButton.d.ts +18 -0
- package/dist/components/ui/EditableAvatarButton.js +18 -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 +9 -1
- package/dist/components/views/PlanComparisonPage.js +78 -14
- package/dist/components/views/PlanComparisonPage.test.js +257 -0
- package/dist/components/views/PlansPage.js +127 -36
- package/dist/components/views/PlansPage.test.js +294 -12
- package/dist/components/views/StandaloneLayout.js +529 -592
- package/dist/components/views/WidgetView.js +10 -8
- package/dist/components/views/panels/PlanningDrawer.d.ts +25 -5
- package/dist/components/views/panels/PlanningDrawer.js +270 -55
- package/dist/components/views/panels/PlanningDrawer.test.d.ts +1 -0
- package/dist/components/views/panels/PlanningDrawer.test.js +529 -0
- package/dist/components/views/planningScope.d.ts +20 -0
- package/dist/components/views/planningScope.js +25 -0
- package/dist/components/views/planningScope.test.d.ts +1 -0
- package/dist/components/views/planningScope.test.js +60 -0
- package/dist/components/views/standalone/modals/AccountHubModal.d.ts +26 -1
- package/dist/components/views/standalone/modals/AccountHubModal.js +76 -2
- package/dist/components/views/standalone/modals/AccountHubModal.test.js +20 -3
- package/dist/components/views/standalone/modals/AvatarImageManagerModal.d.ts +20 -0
- package/dist/components/views/standalone/modals/AvatarImageManagerModal.js +127 -0
- package/dist/components/views/standalone/modals/EditProfileModal.d.ts +2 -9
- package/dist/components/views/standalone/modals/EditProfileModal.js +3 -2
- package/dist/components/views/standalone/modals/SyncEnableWarningModal.d.ts +9 -0
- package/dist/components/views/standalone/modals/SyncEnableWarningModal.js +6 -0
- package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.d.ts +1 -0
- package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.js +24 -0
- package/dist/components/views/standalone/modals/SyncStatusModal.d.ts +2 -1
- package/dist/components/views/standalone/modals/SyncStatusModal.js +2 -2
- package/dist/config/envSchema.js +1 -0
- package/dist/core/AiProfileService.d.ts +46 -2
- package/dist/core/AiProfileService.js +1073 -82
- package/dist/core/AiProfileService.test.js +19 -1
- package/dist/core/AiProfiles.test.js +1249 -44
- package/dist/core/AttachmentLinkService.d.ts +3 -0
- package/dist/core/AttachmentLinkService.js +110 -23
- package/dist/core/AuthIdentityService.d.ts +107 -0
- package/dist/core/AuthIdentityService.js +284 -0
- package/dist/core/AuthTokenService.d.ts +4 -0
- package/dist/core/AuthTokenService.js +34 -6
- package/dist/core/AuthTokenService.test.js +3 -3
- package/dist/core/EntitlementsPolicy.test.js +2 -2
- package/dist/core/GlobalSettingsService.js +127 -6
- package/dist/core/McpTokenService.d.ts +12 -0
- package/dist/core/McpTokenService.js +44 -1
- package/dist/core/PlanEntitlementService.d.ts +23 -2
- package/dist/core/PlanEntitlementService.js +343 -57
- package/dist/core/PlanFeatureCatalog.test.d.ts +1 -0
- package/dist/core/PlanFeatureCatalog.test.js +84 -0
- package/dist/core/PlanVersionPolicy.test.js +35 -2
- package/dist/core/PlanningEntities.test.js +418 -4
- package/dist/core/SignupMonetizationSettings.test.js +199 -27
- package/dist/core/SyncReconciliationService.js +2 -65
- package/dist/core/SystemAdmin.test.js +42 -42
- 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/TaskAttachmentsCanonical.test.js +51 -1
- package/dist/core/TaskAuditTimeline.test.js +96 -0
- package/dist/core/Taskforce.d.ts +415 -40
- package/dist/core/Taskforce.ids.test.js +58 -0
- package/dist/core/Taskforce.js +1543 -266
- package/dist/core/Taskforce.listTasksSlim.test.d.ts +1 -0
- package/dist/core/Taskforce.listTasksSlim.test.js +91 -0
- package/dist/core/Taskforce.mcpAuth.test.js +109 -0
- package/dist/core/UserProfileAvatarDrafts.test.js +30 -3
- package/dist/core/WorkspaceLifecycleService.js +0 -5
- package/dist/core/WorkspacePermissions.test.js +25 -1
- package/dist/core/WorkspacePlanMode.test.js +117 -16
- package/dist/core/shared.d.ts +1 -1
- package/dist/core/shared.js +5 -1
- package/dist/core/types.d.ts +75 -2
- package/dist/hooks/auth/useTaskforceAuthBootstrap.js +28 -2
- 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/bootstrap.js +2 -0
- package/dist/hooks/sync/controlPlane.d.ts +37 -0
- package/dist/hooks/sync/controlPlane.js +78 -0
- package/dist/hooks/sync/controlPlane.test.d.ts +1 -0
- package/dist/hooks/sync/controlPlane.test.js +121 -0
- package/dist/hooks/sync/lifecyclePolicy.d.ts +45 -0
- package/dist/hooks/sync/lifecyclePolicy.js +93 -0
- package/dist/hooks/sync/lifecyclePolicy.test.d.ts +1 -0
- package/dist/hooks/sync/lifecyclePolicy.test.js +124 -0
- package/dist/hooks/sync/orchestratorShared.d.ts +13 -4
- package/dist/hooks/sync/orchestratorShared.js +129 -48
- package/dist/hooks/sync/orchestratorShared.test.js +50 -1
- package/dist/hooks/sync/pullLifecycle.d.ts +31 -0
- package/dist/hooks/sync/pullLifecycle.js +24 -0
- package/dist/hooks/sync/pullLifecycle.test.d.ts +1 -0
- package/dist/hooks/sync/pullLifecycle.test.js +80 -0
- package/dist/hooks/sync/recovery.d.ts +16 -2
- package/dist/hooks/sync/recovery.js +179 -53
- package/dist/hooks/sync/recovery.test.d.ts +1 -0
- package/dist/hooks/sync/recovery.test.js +292 -0
- package/dist/hooks/sync/transfers.d.ts +16 -3
- package/dist/hooks/sync/transfers.js +210 -66
- package/dist/hooks/sync/transfers.test.d.ts +1 -0
- package/dist/hooks/sync/transfers.test.js +928 -0
- package/dist/hooks/sync/useRecentSyncEvents.d.ts +21 -0
- package/dist/hooks/sync/useRecentSyncEvents.js +92 -0
- package/dist/hooks/sync/useRecentSyncEvents.test.d.ts +1 -0
- package/dist/hooks/sync/useRecentSyncEvents.test.js +124 -0
- package/dist/hooks/sync/useSyncStatusActions.d.ts +30 -0
- package/dist/hooks/sync/useSyncStatusActions.js +88 -0
- package/dist/hooks/sync/useSyncStatusActions.test.d.ts +1 -0
- package/dist/hooks/sync/useSyncStatusActions.test.js +133 -0
- package/dist/hooks/sync/useSyncStatusControls.d.ts +25 -0
- package/dist/hooks/sync/useSyncStatusControls.js +60 -0
- package/dist/hooks/sync/useSyncStatusControls.test.d.ts +1 -0
- package/dist/hooks/sync/useSyncStatusControls.test.js +88 -0
- package/dist/hooks/useFilterSort.js +13 -13
- package/dist/hooks/useFilterSort.test.js +87 -1
- package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +12 -0
- package/dist/hooks/useSyncOrchestrator.d.ts +9 -2
- package/dist/hooks/useSyncOrchestrator.js +409 -183
- package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +407 -0
- package/dist/hooks/useTaskData.js +8 -3
- package/dist/hooks/useTaskData.test.js +45 -0
- package/dist/hooks/useTaskforce.d.ts +145 -52
- package/dist/hooks/useTaskforce.js +592 -253
- package/dist/hooks/useTaskforce.runtime-routing.test.d.ts +1 -0
- package/dist/hooks/useTaskforce.runtime-routing.test.js +246 -0
- package/dist/hooks/useTaskforce.sync-behavior.test.js +2468 -201
- package/dist/hooks/useWorkspaceSyncController.d.ts +1 -0
- package/dist/hooks/useWorkspaceSyncController.js +13 -2
- package/dist/hooks/useWorkspaceSyncController.test.js +48 -0
- package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.d.ts +16 -0
- package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +328 -40
- package/dist/localization/locales/en-US.d.ts +0 -1
- package/dist/localization/locales/en-US.js +0 -1
- package/dist/localization/locales/es-419.js +0 -1
- package/dist/localization/locales/pt-BR.js +0 -1
- 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 +116 -10
- package/dist/mcp/runtime.d.ts +3 -0
- package/dist/mcp/runtime.js +1099 -185
- package/dist/mcp/runtime.test.js +1491 -140
- 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.d.ts +1 -1
- package/dist/migrations/taskSchemaMigrations.js +192 -61
- package/dist/migrations/taskSchemaMigrations.test.js +15 -0
- package/dist/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
- package/dist/resources/templates/workflows/collaborate.yaml +1 -1
- package/dist/resources/templates/workflows/evaluate.yaml +2 -2
- package/dist/resources/templates/workflows/plan.yaml +1 -1
- package/dist/resources/templates/workflows/review.yaml +2 -2
- 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 +69 -10
- package/dist/server/auth/providers/apple.d.ts +33 -0
- package/dist/server/auth/providers/apple.js +82 -0
- package/dist/server/auth/providers/appleClientSecret.d.ts +37 -0
- package/dist/server/auth/providers/appleClientSecret.js +65 -0
- package/dist/server/auth/providers/github.d.ts +26 -0
- package/dist/server/auth/providers/github.js +86 -0
- package/dist/server/auth/providers/google.d.ts +21 -0
- package/dist/server/auth/providers/google.js +56 -0
- package/dist/server/auth/providers/types.d.ts +21 -0
- package/dist/server/auth/providers/types.js +1 -0
- package/dist/server/auth.d.ts +2 -0
- package/dist/server/auth.js +6 -3
- package/dist/server/documentReviewRoutes.test.js +36 -3
- package/dist/server/index.cookieProxy.test.js +1 -0
- package/dist/server/index.d.ts +12 -0
- package/dist/server/index.js +124 -9
- package/dist/server/index.rateLimit.test.js +3 -0
- package/dist/server/index.test.js +111 -3
- package/dist/server/routes/admin.d.ts +3 -0
- package/dist/server/routes/admin.js +459 -28
- package/dist/server/routes/annotatedAttachments.js +51 -0
- package/dist/server/routes/auth.d.ts +26 -2
- package/dist/server/routes/auth.js +1170 -71
- package/dist/server/routes/authSupport.d.ts +5 -1
- package/dist/server/routes/authSupport.js +13 -2
- package/dist/server/routes/billing.js +372 -35
- package/dist/server/routes/billing.test.js +595 -12
- package/dist/server/routes/documents.d.ts +1 -0
- package/dist/server/routes/documents.js +182 -70
- package/dist/server/routes/shared.d.ts +28 -2
- package/dist/server/routes/shared.js +69 -14
- package/dist/server/routes/sync.integration.test.js +658 -39
- package/dist/server/routes/sync.js +74 -608
- package/dist/server/routes/syncAuxRoutes.d.ts +15 -0
- package/dist/server/routes/syncAuxRoutes.js +91 -0
- package/dist/server/routes/syncAuxRoutes.test.d.ts +1 -0
- package/dist/server/routes/syncAuxRoutes.test.js +158 -0
- package/dist/server/routes/syncPullApplyRoutes.d.ts +36 -0
- package/dist/server/routes/syncPullApplyRoutes.js +204 -0
- package/dist/server/routes/syncPushRoutes.d.ts +24 -0
- package/dist/server/routes/syncPushRoutes.js +212 -0
- package/dist/server/routes/syncRouteGuards.d.ts +36 -0
- package/dist/server/routes/syncRouteGuards.js +67 -0
- package/dist/server/routes/syncRouteGuards.test.d.ts +1 -0
- package/dist/server/routes/syncRouteGuards.test.js +94 -0
- package/dist/server/routes/syncRouteTypes.d.ts +13 -0
- package/dist/server/routes/syncRouteTypes.js +1 -0
- package/dist/server/routes/syncSnapshotRoutes.d.ts +66 -0
- package/dist/server/routes/syncSnapshotRoutes.js +182 -0
- package/dist/server/routes/tasks.js +55 -10
- package/dist/server/routes/workspaces.js +36 -5
- package/dist/server/routes.js +147 -11
- package/dist/server/routes.test.js +2704 -183
- package/dist/services/workflowExportSnapshots.test.js +2 -0
- package/dist/shared/aiProfileSeatScope.d.ts +5 -0
- package/dist/shared/aiProfileSeatScope.js +21 -0
- package/dist/shared/aiProfileSurfaceType.d.ts +1 -1
- package/dist/shared/aiProfileSurfaceType.js +10 -8
- package/dist/shared/passwordPolicy.d.ts +13 -0
- package/dist/shared/passwordPolicy.js +84 -0
- package/dist/shared/passwordPolicy.test.d.ts +1 -0
- package/dist/shared/passwordPolicy.test.js +34 -0
- 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/storage/workspaceAssetStore.d.ts +15 -3
- package/dist/storage/workspaceAssetStore.js +132 -44
- package/dist/storage/workspaceAssetStore.test.js +93 -6
- package/dist/styles/fonts.css +70 -0
- package/dist/sync/collaborationSyncPayload.d.ts +6 -1
- package/dist/sync/collaborationSyncPayload.js +19 -11
- package/dist/sync/collaborationSyncPayload.test.js +14 -1
- 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 +9 -9
- package/dist/sync/contentSyncState.js +248 -107
- package/dist/sync/planningSyncPayload.js +5 -0
- package/dist/sync/planningSyncPayload.test.js +24 -0
- package/dist/sync/syncApplyHandlers.d.ts +11 -4
- package/dist/sync/syncApplyHandlers.js +115 -42
- package/dist/sync/syncApplyHandlers.test.js +251 -4
- package/dist/sync/syncFieldSemantics.d.ts +12 -0
- package/dist/sync/syncFieldSemantics.js +55 -0
- package/dist/sync/syncResourceAdapters.d.ts +46 -0
- package/dist/sync/syncResourceAdapters.js +79 -0
- package/dist/sync/syncService.d.ts +6 -0
- package/dist/sync/syncService.js +65 -1
- package/dist/sync/syncService.test.js +96 -3
- package/dist/sync/taskSyncChangeKey.d.ts +2 -0
- package/dist/sync/taskSyncChangeKey.js +143 -0
- package/dist/sync/taskSyncPayload.js +3 -8
- package/dist/sync/workspacePullFeed.d.ts +4 -0
- package/dist/sync/workspacePullFeed.js +132 -72
- package/dist/sync/workspacePullFeed.test.js +92 -0
- package/dist/sync/workspaceRepair.js +5 -2
- package/dist/sync/workspaceSyncModel.d.ts +73 -6
- package/dist/sync/workspaceSyncModel.js +342 -73
- package/dist/sync/workspaceSyncModel.test.js +559 -14
- package/dist/sync/workspaceSyncState.d.ts +17 -0
- package/dist/sync/workspaceSyncState.js +2 -1
- package/dist/sync/workspaceSyncSurface.js +3 -8
- package/dist/types.d.ts +50 -2
- package/dist/ui/assets/AgentsModule-2y82_3DO.js +1 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BTLZZCiQ.js +3 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BVKew-mH.css +1 -0
- package/dist/ui/assets/ContextAttachmentManager-D2epuNnG.js +3 -0
- package/dist/ui/assets/CourierPrime-Bold-BuLj_dpw.woff2 +0 -0
- package/dist/ui/assets/CourierPrime-BoldItalic-BrK2pUkZ.woff2 +0 -0
- package/dist/ui/assets/CourierPrime-Italic-DFUZK5Ey.woff2 +0 -0
- package/dist/ui/assets/CourierPrime-Regular-BsKphzVf.woff2 +0 -0
- package/dist/ui/assets/DocumentWorkspace-D4rJKXzd.css +1 -0
- package/dist/ui/assets/DocumentWorkspace-sVa-3Do6.js +252 -0
- package/dist/ui/assets/EntityActivityTimeline-DyqvvhuF.css +1 -0
- package/dist/ui/assets/EntityActivityTimeline-Zods27y_.js +1 -0
- package/dist/ui/assets/{InitiativesModule-Dhm7M8e7.js → InitiativesModule-D4XseTwW.js} +1 -1
- package/dist/ui/assets/Noir_medium-bxQwKGzB.woff2 +0 -0
- package/dist/ui/assets/Noir_regular-ojf2kxlG.woff2 +0 -0
- package/dist/ui/assets/PlansPage-D5AcbO0L.js +1 -0
- package/dist/ui/assets/PlansPage-Dvqsz5zc.css +1 -0
- package/dist/ui/assets/RussoOne-Regular-Cu_qq_qC.woff2 +0 -0
- package/dist/ui/assets/SpecialElite-Regular-Di6gSvAS.woff2 +0 -0
- package/dist/ui/assets/TaskContextUpload-uC5qx4Bv.js +1 -0
- package/dist/ui/assets/TaskSettings-CqvPAsTv.js +9 -0
- package/dist/ui/assets/{WorkflowsModule-BcS4afRn.js → WorkflowsModule-oOA9bcdK.js} +4 -4
- package/dist/ui/assets/documentReferences-DPZuTgHh.js +1 -0
- package/dist/ui/assets/index-607WPo_X.js +4 -0
- package/dist/ui/assets/index-CYyodXsg.css +1 -0
- package/dist/ui/assets/{vendor-icons-BSUaRwF8.js → vendor-icons-B32hGuF2.js} +1 -1
- package/dist/ui/fonts/CourierPrime-Bold.ttf +0 -0
- package/dist/ui/fonts/CourierPrime-Bold.woff2 +0 -0
- package/dist/ui/fonts/CourierPrime-BoldItalic.ttf +0 -0
- package/dist/ui/fonts/CourierPrime-BoldItalic.woff2 +0 -0
- package/dist/ui/fonts/CourierPrime-Italic.ttf +0 -0
- package/dist/ui/fonts/CourierPrime-Italic.woff2 +0 -0
- package/dist/ui/fonts/CourierPrime-Regular.ttf +0 -0
- package/dist/ui/fonts/CourierPrime-Regular.woff2 +0 -0
- package/dist/ui/fonts/Noir_medium.otf +0 -0
- package/dist/ui/fonts/Noir_medium.woff2 +0 -0
- package/dist/ui/fonts/Noir_regular.otf +0 -0
- package/dist/ui/fonts/Noir_regular.woff2 +0 -0
- package/dist/ui/fonts/RussoOne-Regular.woff2 +0 -0
- package/dist/ui/fonts/SpecialElite-Regular.ttf +0 -0
- package/dist/ui/fonts/SpecialElite-Regular.woff2 +0 -0
- package/dist/ui/index.html +3 -3
- package/dist/ui/product/agent manager.png +0 -0
- package/dist/ui/product/agent_manager_02.png +0 -0
- package/dist/utils/accountProfileSummaryCache.d.ts +5 -0
- package/dist/utils/aiProfileEvents.d.ts +7 -0
- package/dist/utils/aiProfileEvents.js +6 -0
- package/dist/utils/assignees.d.ts +8 -0
- package/dist/utils/assignees.js +10 -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/avatarUpload.d.ts +27 -0
- package/dist/utils/avatarUpload.js +132 -0
- package/dist/utils/avatarUpload.test.d.ts +1 -0
- package/dist/utils/avatarUpload.test.js +40 -0
- package/dist/utils/bootstrapTrace.d.ts +7 -0
- package/dist/utils/bootstrapTrace.js +29 -0
- package/dist/utils/commercialLifecyclePresentation.js +3 -0
- package/dist/utils/contextAssetEvents.d.ts +2 -0
- package/dist/utils/contextFiles.d.ts +3 -1
- package/dist/utils/contextFiles.js +2 -1
- package/dist/utils/syncEventDetails.d.ts +3 -0
- package/dist/utils/syncEventDetails.js +64 -0
- package/dist/utils/syncEventDetails.test.d.ts +1 -0
- package/dist/utils/syncEventDetails.test.js +23 -0
- package/dist/utils/syncEventPresentation.d.ts +15 -0
- package/dist/utils/syncEventPresentation.js +129 -0
- package/dist/utils/syncEventPresentation.test.d.ts +1 -0
- package/dist/utils/syncEventPresentation.test.js +64 -0
- package/dist/utils/syncStatusPresentation.d.ts +72 -0
- package/dist/utils/syncStatusPresentation.js +217 -0
- package/dist/utils/syncStatusPresentation.test.d.ts +1 -0
- package/dist/utils/syncStatusPresentation.test.js +164 -0
- package/dist/utils/taskActivity.d.ts +9 -1
- package/dist/utils/taskActivity.js +290 -22
- package/dist/utils/taskActivity.test.js +141 -8
- 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/dist/utils/workspaceSyncPresentation.d.ts +4 -0
- package/dist/utils/workspaceSyncPresentation.js +68 -2
- package/dist/utils/workspaceSyncPresentation.test.js +36 -1
- package/package.json +3 -2
- package/scripts/export-sqlite-to-postgres.mjs +7 -9
- package/scripts/run-e2e-realtime.sh +17 -3
- package/scripts/run-smoke.sh +17 -5
- package/scripts/run-soak.sh +17 -5
- package/src/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
- package/src/resources/templates/workflows/collaborate.yaml +1 -1
- package/src/resources/templates/workflows/evaluate.yaml +2 -2
- package/src/resources/templates/workflows/plan.yaml +1 -1
- package/src/resources/templates/workflows/review.yaml +2 -2
- package/dist/ui/assets/AgentsModule-N2MnQBZk.js +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BG6P_GVW.js +0 -3
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BaS2VwIr.css +0 -1
- package/dist/ui/assets/DocumentWorkspace-B3nV_Gc5.css +0 -1
- package/dist/ui/assets/DocumentWorkspace-DRbDMwh8.js +0 -252
- package/dist/ui/assets/PlansPage-C2dd2n1X.css +0 -1
- package/dist/ui/assets/PlansPage-Cq0zXj3I.js +0 -1
- package/dist/ui/assets/RussoOne-Regular-C3BxZIj7.ttf +0 -0
- package/dist/ui/assets/TaskSettings-ln0aF7xc.js +0 -9
- package/dist/ui/assets/index-C2-OXZV7.css +0 -1
- package/dist/ui/assets/index-DcSI5F86.js +0 -6
- package/scripts/migrate-planning-model.ts +0 -233
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* GET /api/taskforce/context-metadata
|
|
16
16
|
* POST /api/taskforce/context/purge-expired
|
|
17
17
|
* GET /api/taskforce/documents
|
|
18
|
+
* POST /api/taskforce/documents/:assetId/attach
|
|
18
19
|
* DELETE /api/taskforce/documents/:assetId
|
|
19
20
|
* PATCH /api/taskforce/documents/:assetId
|
|
20
21
|
* POST /api/taskforce/documents/save
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* GET /api/taskforce/context-metadata
|
|
16
16
|
* POST /api/taskforce/context/purge-expired
|
|
17
17
|
* GET /api/taskforce/documents
|
|
18
|
+
* POST /api/taskforce/documents/:assetId/attach
|
|
18
19
|
* DELETE /api/taskforce/documents/:assetId
|
|
19
20
|
* PATCH /api/taskforce/documents/:assetId
|
|
20
21
|
* POST /api/taskforce/documents/save
|
|
@@ -30,6 +31,75 @@ import { parsePlan } from '../../utils/planParser.js';
|
|
|
30
31
|
import { getCanonicalDocumentName, getReadableDocumentName, isGeneratedDocumentName } from '../../utils/documentNames.js';
|
|
31
32
|
import { requestRuntimeMode } from './shared.js';
|
|
32
33
|
import { parseJsonBody } from './primitives.js';
|
|
34
|
+
import { resolveDeploymentConfig } from '../../config/deployment.js';
|
|
35
|
+
function isUserProfileAvatarPath(relativePath) {
|
|
36
|
+
return /^users\/[^/]+\/profile\/avatar\/[^/]+$/i.test(String(relativePath || '').replace(/\\/g, '/'));
|
|
37
|
+
}
|
|
38
|
+
function isAiProfileAvatarPath(relativePath) {
|
|
39
|
+
return /^workspaces\/[^/]+\/assets\/images\/ai-profiles\/[^/]+\/avatar\/[^/]+$/i.test(String(relativePath || '').replace(/\\/g, '/'));
|
|
40
|
+
}
|
|
41
|
+
function resolveRequestOrigin(req) {
|
|
42
|
+
const host = String(req.headers.host || '').trim();
|
|
43
|
+
if (!host)
|
|
44
|
+
return '';
|
|
45
|
+
const proto = String(req.headers['x-forwarded-proto'] || '').trim().toLowerCase() === 'https'
|
|
46
|
+
? 'https'
|
|
47
|
+
: (req.socket?.encrypted ? 'https' : 'http');
|
|
48
|
+
return `${proto}://${host.replace(/\/+$/, '')}`;
|
|
49
|
+
}
|
|
50
|
+
async function proxyCloudUserProfileAvatar(req, res, relativePath, contentTypeForExt) {
|
|
51
|
+
if (!isUserProfileAvatarPath(relativePath))
|
|
52
|
+
return false;
|
|
53
|
+
const deployment = resolveDeploymentConfig(process.env);
|
|
54
|
+
const cloudBaseUrl = String(deployment.cloudBaseUrl || deployment.cloudAuthBaseUrl || '').trim().replace(/\/+$/, '');
|
|
55
|
+
if (!cloudBaseUrl)
|
|
56
|
+
return false;
|
|
57
|
+
if (cloudBaseUrl === resolveRequestOrigin(req))
|
|
58
|
+
return false;
|
|
59
|
+
const requestUrl = new URL(req.url || '', 'http://localhost');
|
|
60
|
+
const upstreamUrl = `${cloudBaseUrl}/api/taskforce/context/${encodeURIComponent(relativePath)}${requestUrl.search || ''}`;
|
|
61
|
+
const headers = new Headers();
|
|
62
|
+
const cookie = String(req.headers.cookie || '').trim();
|
|
63
|
+
const accept = String(req.headers.accept || '').trim();
|
|
64
|
+
const userAgent = String(req.headers['user-agent'] || '').trim();
|
|
65
|
+
if (cookie)
|
|
66
|
+
headers.set('cookie', cookie);
|
|
67
|
+
if (accept)
|
|
68
|
+
headers.set('accept', accept);
|
|
69
|
+
if (userAgent)
|
|
70
|
+
headers.set('user-agent', userAgent);
|
|
71
|
+
headers.set('x-taskforce-origin-runtime', 'local-proxy');
|
|
72
|
+
const cfClientId = String(process.env.TASKFORCE_CF_ACCESS_CLIENT_ID || process.env.CF_ACCESS_CLIENT_ID || '').trim();
|
|
73
|
+
const cfClientSecret = String(process.env.TASKFORCE_CF_ACCESS_CLIENT_SECRET || process.env.CF_ACCESS_CLIENT_SECRET || '').trim();
|
|
74
|
+
if (cfClientId && cfClientSecret) {
|
|
75
|
+
headers.set('CF-Access-Client-Id', cfClientId);
|
|
76
|
+
headers.set('CF-Access-Client-Secret', cfClientSecret);
|
|
77
|
+
}
|
|
78
|
+
try {
|
|
79
|
+
const upstream = await fetch(upstreamUrl, {
|
|
80
|
+
method: 'GET',
|
|
81
|
+
headers
|
|
82
|
+
});
|
|
83
|
+
if (upstream.status === 404)
|
|
84
|
+
return false;
|
|
85
|
+
const outgoingHeaders = {};
|
|
86
|
+
for (const [key, value] of upstream.headers.entries()) {
|
|
87
|
+
const name = key.toLowerCase();
|
|
88
|
+
if (name === 'set-cookie' || name === 'content-length' || name === 'transfer-encoding')
|
|
89
|
+
continue;
|
|
90
|
+
outgoingHeaders[key] = value;
|
|
91
|
+
}
|
|
92
|
+
if (!outgoingHeaders['content-type']) {
|
|
93
|
+
outgoingHeaders['Content-Type'] = contentTypeForExt(path.extname(relativePath).toLowerCase());
|
|
94
|
+
}
|
|
95
|
+
res.writeHead(upstream.status, outgoingHeaders);
|
|
96
|
+
res.end(Buffer.from(await upstream.arrayBuffer()));
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
33
103
|
export function registerDocumentRoutes(deps) {
|
|
34
104
|
const { addRoute, core, context, requestWorkspaceId, ensureAdminRole, resolveEffectiveObjectStorageConfig, getObjectStorageClient, resolveStorageWorkspaceId, ensureContextUploadAllowed, parseStorageFolderSegments, buildCanonicalWorkspaceAssetRelativePath, inferAssetKindFromPath, appendStorageTelemetry, scanAndRecordDocument, buildTaskAttachmentPayload, workspaceAssetStore, taskAssetStore, normalizeDocumentPathInput, getAssetMetadata, getCanonicalAssetMetadata, documentRetentionDays, appendDocumentPurgeHistory, markAssetDeleted, isAssetDeleted, clearAssetDeleted, ensureWithinDir, sanitizeDownloadFilename, contentTypeForExt, inferInlineDocumentFromPath, resolveCanonicalDocumentRead, inferWorkspaceIdFromStoragePath, inferTaskIdFromStoragePath, } = deps;
|
|
35
105
|
const removeDocumentAttachmentFromTaskAttachments = (attachmentsRaw, asset) => {
|
|
@@ -396,9 +466,22 @@ export function registerDocumentRoutes(deps) {
|
|
|
396
466
|
return;
|
|
397
467
|
}
|
|
398
468
|
if (objectStorageClient && normalizedRelative && resolvedObjectStorage.provider === 'r2' && resolvedObjectStorage.r2) {
|
|
399
|
-
|
|
469
|
+
const shouldProxyInlineUserAvatar = isUserProfileAvatarPath(normalizedRelative);
|
|
470
|
+
const shouldProxyInlineAiAvatar = isAiProfileAvatarPath(normalizedRelative);
|
|
471
|
+
if (shouldProxyInlineDocument || shouldProxyInlineUserAvatar || shouldProxyInlineAiAvatar) {
|
|
400
472
|
const object = await objectStorageClient.getObject(normalizedRelative);
|
|
401
473
|
if (!object) {
|
|
474
|
+
if (shouldProxyInlineUserAvatar && await proxyCloudUserProfileAvatar(req, res, normalizedRelative, contentTypeForExt)) {
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
if (shouldProxyInlineAiAvatar && filePath && fs.existsSync(filePath)) {
|
|
478
|
+
res.writeHead(200, {
|
|
479
|
+
'Content-Type': contentTypeForExt(ext),
|
|
480
|
+
'Content-Disposition': contentDisposition
|
|
481
|
+
});
|
|
482
|
+
res.end(fs.readFileSync(filePath));
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
402
485
|
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
403
486
|
res.end('Context file not found');
|
|
404
487
|
return;
|
|
@@ -423,6 +506,9 @@ export function registerDocumentRoutes(deps) {
|
|
|
423
506
|
res.end(fs.readFileSync(filePath));
|
|
424
507
|
return;
|
|
425
508
|
}
|
|
509
|
+
if (normalizedRelative && await proxyCloudUserProfileAvatar(req, res, normalizedRelative, contentTypeForExt)) {
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
426
512
|
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
427
513
|
res.end('Context file not found');
|
|
428
514
|
});
|
|
@@ -590,9 +676,6 @@ export function registerDocumentRoutes(deps) {
|
|
|
590
676
|
});
|
|
591
677
|
addRoute('GET', '/api/taskforce/documents', async (req, res) => {
|
|
592
678
|
const workspaceId = requestWorkspaceId(req);
|
|
593
|
-
const { basePath, projectRoot } = core.getPaths();
|
|
594
|
-
const planningDocsDir = path.join(basePath, 'docs');
|
|
595
|
-
const runtimeMode = context.authConfig?.runtimeMode === 'cloud' ? 'cloud' : 'local';
|
|
596
679
|
function inferDocType(filename) {
|
|
597
680
|
const base = path.basename(filename, path.extname(filename)).toLowerCase();
|
|
598
681
|
if (base.includes('implementation-plan') || base.includes('implementation_plan'))
|
|
@@ -630,12 +713,9 @@ export function registerDocumentRoutes(deps) {
|
|
|
630
713
|
: (taskId ? 1 : 0);
|
|
631
714
|
const attachmentState = input.attachmentState === 'attached'
|
|
632
715
|
|| input.attachmentState === 'unattached'
|
|
633
|
-
|| input.attachmentState === 'standalone'
|
|
634
716
|
? (attachmentCount > 0 || taskId
|
|
635
717
|
? 'attached'
|
|
636
|
-
:
|
|
637
|
-
? 'standalone'
|
|
638
|
-
: 'unattached')
|
|
718
|
+
: 'unattached')
|
|
639
719
|
: (attachmentCount > 0 || taskId ? 'attached' : 'unattached');
|
|
640
720
|
return {
|
|
641
721
|
id: input.id,
|
|
@@ -658,12 +738,6 @@ export function registerDocumentRoutes(deps) {
|
|
|
658
738
|
attachmentState
|
|
659
739
|
};
|
|
660
740
|
}
|
|
661
|
-
function safeRelative(fullPath) {
|
|
662
|
-
const rel = path.relative(projectRoot, fullPath);
|
|
663
|
-
if (rel.startsWith('..'))
|
|
664
|
-
return null;
|
|
665
|
-
return rel;
|
|
666
|
-
}
|
|
667
741
|
const documents = [];
|
|
668
742
|
const seenDocumentPaths = new Set();
|
|
669
743
|
const pushDocument = (doc) => {
|
|
@@ -674,6 +748,9 @@ export function registerDocumentRoutes(deps) {
|
|
|
674
748
|
seenDocumentPaths.add(key);
|
|
675
749
|
documents.push(normalizedDoc);
|
|
676
750
|
};
|
|
751
|
+
// Shared document listing is canonical-document-only. Raw files under
|
|
752
|
+
// .taskforce/docs are intentionally excluded because they are not
|
|
753
|
+
// workspace-scoped managed documents.
|
|
677
754
|
const canonicalDocuments = workspaceAssetStore?.listAllByWorkspace(workspaceId, {
|
|
678
755
|
includeDeleted: false,
|
|
679
756
|
kind: 'document'
|
|
@@ -689,8 +766,11 @@ export function registerDocumentRoutes(deps) {
|
|
|
689
766
|
});
|
|
690
767
|
const activeLinks = (workspaceAssetStore?.listLinksForAsset(asset.assetId, workspaceId) || [])
|
|
691
768
|
.filter((link) => !link.deletedAt)
|
|
769
|
+
.filter((link) => link.targetType !== 'task' || (!!link.taskId && !!core.getTask(link.taskId, workspaceId)));
|
|
770
|
+
const activeTaskLinks = activeLinks
|
|
771
|
+
.filter((link) => link.targetType === 'task' && !!link.taskId)
|
|
692
772
|
.filter((link) => !!core.getTask(link.taskId, workspaceId));
|
|
693
|
-
const firstLink =
|
|
773
|
+
const firstLink = activeTaskLinks[0] || null;
|
|
694
774
|
const repairedLogicalName = isGeneratedDocumentName(asset.logicalName || null, asset.assetId || null)
|
|
695
775
|
? (String(firstLink?.displayName || '').trim()
|
|
696
776
|
|| repairedReadableName)
|
|
@@ -742,58 +822,6 @@ export function registerDocumentRoutes(deps) {
|
|
|
742
822
|
attachmentState: activeLinks.length > 0 ? 'attached' : 'unattached',
|
|
743
823
|
});
|
|
744
824
|
}
|
|
745
|
-
if (runtimeMode !== 'cloud') {
|
|
746
|
-
const walkMarkdownFiles = (dir, visitor) => {
|
|
747
|
-
let entries = [];
|
|
748
|
-
try {
|
|
749
|
-
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
750
|
-
}
|
|
751
|
-
catch {
|
|
752
|
-
return;
|
|
753
|
-
}
|
|
754
|
-
for (const entry of entries) {
|
|
755
|
-
const fullPath = path.join(dir, entry.name);
|
|
756
|
-
if (entry.isDirectory()) {
|
|
757
|
-
walkMarkdownFiles(fullPath, visitor);
|
|
758
|
-
continue;
|
|
759
|
-
}
|
|
760
|
-
if (!entry.isFile() || path.extname(entry.name).toLowerCase() !== '.md') {
|
|
761
|
-
continue;
|
|
762
|
-
}
|
|
763
|
-
let stat;
|
|
764
|
-
try {
|
|
765
|
-
stat = fs.statSync(fullPath);
|
|
766
|
-
}
|
|
767
|
-
catch {
|
|
768
|
-
continue;
|
|
769
|
-
}
|
|
770
|
-
const relativePath = safeRelative(fullPath);
|
|
771
|
-
if (!relativePath)
|
|
772
|
-
continue;
|
|
773
|
-
visitor({ relativePath, entryName: entry.name, stat });
|
|
774
|
-
}
|
|
775
|
-
};
|
|
776
|
-
walkMarkdownFiles(planningDocsDir, ({ relativePath, entryName, stat }) => {
|
|
777
|
-
pushDocument({
|
|
778
|
-
id: relativePath,
|
|
779
|
-
assetId: null,
|
|
780
|
-
referenceNumber: null,
|
|
781
|
-
referenceLabel: null,
|
|
782
|
-
fsPath: relativePath,
|
|
783
|
-
apiUrl: `/api/taskforce/context-link?path=${encodeURIComponent(relativePath)}`,
|
|
784
|
-
taskId: null,
|
|
785
|
-
displayName: inferTitle(entryName),
|
|
786
|
-
originalFilename: entryName,
|
|
787
|
-
title: inferTitle(entryName),
|
|
788
|
-
docType: 'planning',
|
|
789
|
-
sizeBytes: stat.size,
|
|
790
|
-
updatedAt: stat.mtime.toISOString(),
|
|
791
|
-
editable: true,
|
|
792
|
-
attachmentCount: 0,
|
|
793
|
-
attachmentState: 'standalone',
|
|
794
|
-
});
|
|
795
|
-
});
|
|
796
|
-
}
|
|
797
825
|
documents.sort((a, b) => {
|
|
798
826
|
if (!a.updatedAt && !b.updatedAt)
|
|
799
827
|
return 0;
|
|
@@ -806,6 +834,87 @@ export function registerDocumentRoutes(deps) {
|
|
|
806
834
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
807
835
|
res.end(JSON.stringify({ documents }));
|
|
808
836
|
});
|
|
837
|
+
addRoute('POST', '/api/taskforce/documents/:assetId/attach', async (req, res, params) => {
|
|
838
|
+
const workspaceId = requestWorkspaceId(req);
|
|
839
|
+
const assetId = String(params.assetId || '').trim();
|
|
840
|
+
const body = await parseJsonBody(req);
|
|
841
|
+
const targetType = String(body?.targetType || 'task').trim();
|
|
842
|
+
const targetId = String(body?.targetId || '').trim();
|
|
843
|
+
if (!workspaceAssetStore || !assetId) {
|
|
844
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
845
|
+
res.end(JSON.stringify({ error: 'Document not found.' }));
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
if (!targetId) {
|
|
849
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
850
|
+
res.end(JSON.stringify({ error: 'Missing required targetId.' }));
|
|
851
|
+
return;
|
|
852
|
+
}
|
|
853
|
+
if (targetType !== 'task') {
|
|
854
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
855
|
+
res.end(JSON.stringify({ error: 'Only task attachments are supported from the document manager right now.' }));
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
const asset = workspaceAssetStore.get(assetId, workspaceId);
|
|
859
|
+
if (!asset || asset.kind !== 'document' || asset.deletedAt) {
|
|
860
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
861
|
+
res.end(JSON.stringify({ error: 'Document not found.' }));
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
const task = core.getTask(targetId, workspaceId);
|
|
865
|
+
if (!task) {
|
|
866
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
867
|
+
res.end(JSON.stringify({ error: 'Task not found.' }));
|
|
868
|
+
return;
|
|
869
|
+
}
|
|
870
|
+
const existingLinks = workspaceAssetStore.listLinksForTarget('task', targetId, workspaceId)
|
|
871
|
+
.filter((link) => !link.deletedAt);
|
|
872
|
+
const alreadyAttached = existingLinks.some((link) => link.assetId === asset.assetId && link.role === 'attachment');
|
|
873
|
+
if (alreadyAttached) {
|
|
874
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
875
|
+
res.end(JSON.stringify({
|
|
876
|
+
success: true,
|
|
877
|
+
alreadyAttached: true,
|
|
878
|
+
targetType: 'task',
|
|
879
|
+
targetId,
|
|
880
|
+
attachmentCount: existingLinks.length,
|
|
881
|
+
}));
|
|
882
|
+
return;
|
|
883
|
+
}
|
|
884
|
+
const attachedAt = new Date().toISOString();
|
|
885
|
+
const payload = buildTaskAttachmentPayload(asset.storageKey, {
|
|
886
|
+
caption: getCanonicalDocumentName({
|
|
887
|
+
assetId: asset.assetId,
|
|
888
|
+
fsPath: asset.storageKey,
|
|
889
|
+
logicalName: asset.logicalName || null,
|
|
890
|
+
title: asset.logicalName || asset.originalFilename,
|
|
891
|
+
originalFilename: asset.originalFilename,
|
|
892
|
+
}),
|
|
893
|
+
assetId: asset.assetId,
|
|
894
|
+
taskId: targetId,
|
|
895
|
+
timestamp: attachedAt,
|
|
896
|
+
});
|
|
897
|
+
if (!payload) {
|
|
898
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
899
|
+
res.end(JSON.stringify({ error: 'Failed to build attachment payload for this document.' }));
|
|
900
|
+
return;
|
|
901
|
+
}
|
|
902
|
+
core.updateTask(targetId, {
|
|
903
|
+
attachments: [...(Array.isArray(task.attachments) ? task.attachments : []), payload],
|
|
904
|
+
}, workspaceId, {
|
|
905
|
+
actorRef: 'user',
|
|
906
|
+
saveSource: 'manual',
|
|
907
|
+
});
|
|
908
|
+
core.notifyDocumentMetadataMutation(workspaceId, [asset.storageKey], 'upsert');
|
|
909
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
910
|
+
res.end(JSON.stringify({
|
|
911
|
+
success: true,
|
|
912
|
+
attached: true,
|
|
913
|
+
alreadyAttached: false,
|
|
914
|
+
targetType: 'task',
|
|
915
|
+
targetId,
|
|
916
|
+
}));
|
|
917
|
+
});
|
|
809
918
|
addRoute('DELETE', '/api/taskforce/documents/:assetId', async (req, res, params) => {
|
|
810
919
|
const workspaceId = requestWorkspaceId(req);
|
|
811
920
|
const assetId = String(params.assetId || '').trim();
|
|
@@ -824,6 +933,7 @@ export function registerDocumentRoutes(deps) {
|
|
|
824
933
|
}
|
|
825
934
|
const activeLinks = workspaceAssetStore.listLinksForAsset(asset.assetId, workspaceId)
|
|
826
935
|
.filter((link) => !link.deletedAt)
|
|
936
|
+
.filter((link) => link.targetType === 'task' && !!link.taskId)
|
|
827
937
|
.filter((link) => !!core.getTask(link.taskId, workspaceId));
|
|
828
938
|
if (activeLinks.length > 0) {
|
|
829
939
|
if (!forceDetach) {
|
|
@@ -836,11 +946,12 @@ export function registerDocumentRoutes(deps) {
|
|
|
836
946
|
return;
|
|
837
947
|
}
|
|
838
948
|
for (const link of activeLinks) {
|
|
839
|
-
const
|
|
949
|
+
const taskId = link.taskId;
|
|
950
|
+
const task = core.getTask(taskId, workspaceId);
|
|
840
951
|
if (!task)
|
|
841
952
|
continue;
|
|
842
953
|
const updatedAttachments = removeDocumentAttachmentFromTaskAttachments(task.attachments, asset);
|
|
843
|
-
core.updateTask(
|
|
954
|
+
core.updateTask(taskId, { attachments: updatedAttachments }, workspaceId, {
|
|
844
955
|
actorRef: 'user',
|
|
845
956
|
saveSource: 'manual'
|
|
846
957
|
});
|
|
@@ -855,7 +966,8 @@ export function registerDocumentRoutes(deps) {
|
|
|
855
966
|
workspaceAssetStore.deleteLink({
|
|
856
967
|
workspaceId,
|
|
857
968
|
assetId: asset.assetId,
|
|
858
|
-
|
|
969
|
+
targetType: link.targetType,
|
|
970
|
+
targetId: link.targetId,
|
|
859
971
|
role: link.role
|
|
860
972
|
});
|
|
861
973
|
}
|
|
@@ -10,7 +10,32 @@ import { TaskforceCore } from '../../core/Taskforce.js';
|
|
|
10
10
|
import type { McpAccessTokenAuthResult, McpOAuthAccessTokenAuthResult, McpAccessTokenScope } from '../../core/Taskforce.js';
|
|
11
11
|
import type { RouteContext } from './primitives.js';
|
|
12
12
|
import type { AiProfileBootstrapConfig } from '../../mcp/aiProfileBootstrap.js';
|
|
13
|
+
import type { AiProfileSeatScope } from '../../shared/aiProfileSeatScope.js';
|
|
13
14
|
export declare function resolveErrorStatusCode(error: unknown, fallback?: number): number;
|
|
15
|
+
export declare const BOOTSTRAP_ROUTE_SLOW_THRESHOLD_MS = 1500;
|
|
16
|
+
export declare const BOOTSTRAP_ROUTE_SEVERE_THRESHOLD_MS = 5000;
|
|
17
|
+
export type ServerTimingMetric = {
|
|
18
|
+
name: string;
|
|
19
|
+
durationMs: number;
|
|
20
|
+
};
|
|
21
|
+
export declare function getRouteTimingNow(): number;
|
|
22
|
+
export declare function buildServerTimingMetric(name: string, durationMs: number): string;
|
|
23
|
+
export declare function setServerTimingHeader(res: ServerResponse, metrics: ServerTimingMetric[]): void;
|
|
24
|
+
export declare function serializeJsonWithTiming(payload: unknown, startedAt?: number): {
|
|
25
|
+
body: string;
|
|
26
|
+
byteLength: number;
|
|
27
|
+
durationMs: number;
|
|
28
|
+
};
|
|
29
|
+
export declare function requestBootstrapTraceId(req: IncomingMessage): string;
|
|
30
|
+
export declare function logSlowBootstrapRoute(input: {
|
|
31
|
+
route: string;
|
|
32
|
+
workspaceId: string;
|
|
33
|
+
durationMs: number;
|
|
34
|
+
traceId?: string | null;
|
|
35
|
+
thresholdMs?: number;
|
|
36
|
+
severeThresholdMs?: number;
|
|
37
|
+
details?: Record<string, unknown>;
|
|
38
|
+
}): void;
|
|
14
39
|
export declare function buildCloudMcpRuntimeAuth(input: {
|
|
15
40
|
req: IncomingMessage;
|
|
16
41
|
auth: {
|
|
@@ -34,6 +59,7 @@ export declare function buildCloudMcpRuntimeAuth(input: {
|
|
|
34
59
|
aiProfileProvider?: AiProfileBootstrapConfig['aiProfileProvider'];
|
|
35
60
|
aiProfileModel?: AiProfileBootstrapConfig['aiProfileModel'];
|
|
36
61
|
aiProfileSurfaceType?: AiProfileBootstrapConfig['aiProfileSurfaceType'];
|
|
62
|
+
aiProfileSeatScope?: AiProfileSeatScope | null;
|
|
37
63
|
actorType?: 'local' | 'user' | 'token' | 'oauth';
|
|
38
64
|
requestId?: string | null;
|
|
39
65
|
ip?: string | null;
|
|
@@ -51,7 +77,7 @@ export declare function makeResolveAuthenticatedUserId(core: TaskforceCore, cont
|
|
|
51
77
|
export declare function makeResolveAuthenticatedMutationUserId(core: TaskforceCore, context: RouteContext, requestWorkspaceId: (req: IncomingMessage) => string): (req: IncomingMessage) => string;
|
|
52
78
|
export declare function makeEnsureAppAccess(core: TaskforceCore, context: RouteContext): (req: IncomingMessage, res: ServerResponse) => boolean;
|
|
53
79
|
export declare function makeEnsureAdminRole(core: TaskforceCore, context: RouteContext): (req: IncomingMessage) => boolean;
|
|
54
|
-
export declare function makeEnsureAuthenticatedUser(): (req: IncomingMessage) => boolean;
|
|
80
|
+
export declare function makeEnsureAuthenticatedUser(authConfig?: RouteContext['authConfig']): (req: IncomingMessage) => boolean;
|
|
55
81
|
export declare function ensureOwnerRole(req: IncomingMessage): boolean;
|
|
56
82
|
export declare function ensureWorkspaceAdminRole(req: IncomingMessage): boolean;
|
|
57
83
|
export declare function makeResolveAdminRequestActor(core: TaskforceCore, context: RouteContext): (req: IncomingMessage) => {
|
|
@@ -60,6 +86,6 @@ export declare function makeResolveAdminRequestActor(core: TaskforceCore, contex
|
|
|
60
86
|
systemRole: "system_admin" | "user";
|
|
61
87
|
};
|
|
62
88
|
export declare function makeAuditAdminAction(core: TaskforceCore, context: RouteContext): (req: IncomingMessage, action: string, details: Record<string, unknown>) => void;
|
|
63
|
-
export declare function makeAuditAuthAction(core: TaskforceCore, requestWorkspaceId: (req: IncomingMessage) => string, context: RouteContext): (req: IncomingMessage, action: string, details: Record<string, unknown
|
|
89
|
+
export declare function makeAuditAuthAction(core: TaskforceCore, requestWorkspaceId: (req: IncomingMessage) => string, context: RouteContext): (req: IncomingMessage, action: string, details: Record<string, unknown>, workspaceIdOverride?: string | null) => void;
|
|
64
90
|
export declare function makeRequireCloudRuntime(context: RouteContext): (res: ServerResponse, feature: string) => boolean;
|
|
65
91
|
export declare function makeEnsureCloudPlanData(context: RouteContext): (req: IncomingMessage, res: ServerResponse) => boolean;
|
|
@@ -17,6 +17,57 @@ export function resolveErrorStatusCode(error, fallback = 400) {
|
|
|
17
17
|
}
|
|
18
18
|
return fallback;
|
|
19
19
|
}
|
|
20
|
+
// === SECTION: Route timing helpers ===
|
|
21
|
+
export const BOOTSTRAP_ROUTE_SLOW_THRESHOLD_MS = 1500;
|
|
22
|
+
export const BOOTSTRAP_ROUTE_SEVERE_THRESHOLD_MS = 5000;
|
|
23
|
+
function sanitizeServerTimingMetricName(name) {
|
|
24
|
+
return String(name || 'taskforce-route')
|
|
25
|
+
.trim()
|
|
26
|
+
.replace(/[^A-Za-z0-9_-]+/g, '-')
|
|
27
|
+
.replace(/^-+|-+$/g, '')
|
|
28
|
+
|| 'taskforce-route';
|
|
29
|
+
}
|
|
30
|
+
export function getRouteTimingNow() {
|
|
31
|
+
return Date.now();
|
|
32
|
+
}
|
|
33
|
+
export function buildServerTimingMetric(name, durationMs) {
|
|
34
|
+
return `${sanitizeServerTimingMetricName(name)};dur=${Math.max(0, Math.round(durationMs))}`;
|
|
35
|
+
}
|
|
36
|
+
export function setServerTimingHeader(res, metrics) {
|
|
37
|
+
const value = metrics
|
|
38
|
+
.filter((metric) => String(metric.name || '').trim().length > 0)
|
|
39
|
+
.map((metric) => buildServerTimingMetric(metric.name, metric.durationMs))
|
|
40
|
+
.join(', ');
|
|
41
|
+
if (value)
|
|
42
|
+
res.setHeader('Server-Timing', value);
|
|
43
|
+
}
|
|
44
|
+
export function serializeJsonWithTiming(payload, startedAt = getRouteTimingNow()) {
|
|
45
|
+
const body = JSON.stringify(payload);
|
|
46
|
+
return {
|
|
47
|
+
body,
|
|
48
|
+
byteLength: Buffer.byteLength(body, 'utf8'),
|
|
49
|
+
durationMs: Math.max(0, getRouteTimingNow() - startedAt),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export function requestBootstrapTraceId(req) {
|
|
53
|
+
return requestHeader(req, 'x-taskforce-bootstrap-trace-id', '').trim();
|
|
54
|
+
}
|
|
55
|
+
export function logSlowBootstrapRoute(input) {
|
|
56
|
+
const thresholdMs = Number(input.thresholdMs) > 0 ? Number(input.thresholdMs) : BOOTSTRAP_ROUTE_SLOW_THRESHOLD_MS;
|
|
57
|
+
const severeThresholdMs = Number(input.severeThresholdMs) > 0 ? Number(input.severeThresholdMs) : BOOTSTRAP_ROUTE_SEVERE_THRESHOLD_MS;
|
|
58
|
+
const durationMs = Math.max(0, Math.round(input.durationMs));
|
|
59
|
+
if (durationMs < thresholdMs)
|
|
60
|
+
return;
|
|
61
|
+
const payload = {
|
|
62
|
+
route: input.route,
|
|
63
|
+
workspaceId: String(input.workspaceId || '').trim() || 'default',
|
|
64
|
+
traceId: String(input.traceId || '').trim() || null,
|
|
65
|
+
durationMs,
|
|
66
|
+
severity: durationMs >= severeThresholdMs ? 'high' : 'warning',
|
|
67
|
+
...(input.details || {}),
|
|
68
|
+
};
|
|
69
|
+
console.warn('[Taskforce Bootstrap Timing]', payload);
|
|
70
|
+
}
|
|
20
71
|
export function buildCloudMcpRuntimeAuth(input) {
|
|
21
72
|
const { req, auth, requestHeader, requestId, authScopes } = input;
|
|
22
73
|
const actorType = auth.authenticatedViaToken
|
|
@@ -37,6 +88,7 @@ export function buildCloudMcpRuntimeAuth(input) {
|
|
|
37
88
|
aiProfileProvider: auth.aiProfileProvider,
|
|
38
89
|
aiProfileModel: auth.aiProfileModel,
|
|
39
90
|
aiProfileSurfaceType: auth.aiProfileSurfaceType,
|
|
91
|
+
aiProfileSeatScope: 'cloud_metered',
|
|
40
92
|
actorType,
|
|
41
93
|
requestId: String(requestId || req.headers['x-request-id'] || req.headers['x-railway-request-id'] || '').trim() || undefined,
|
|
42
94
|
ip: req.socket?.remoteAddress || null,
|
|
@@ -164,16 +216,6 @@ export function makeResolveAuthenticatedMutationUserId(core, context, requestWor
|
|
|
164
216
|
const explicitUserId = String(requestUserId(req) || '').trim();
|
|
165
217
|
if (explicitUserId && explicitUserId !== 'anonymous')
|
|
166
218
|
return explicitUserId;
|
|
167
|
-
if (requestRuntimeMode(req) === 'local') {
|
|
168
|
-
const workspaceId = String(requestWorkspaceId(req) || '').trim() || 'default';
|
|
169
|
-
const fallbackUser = core.listWorkspaceUsers(workspaceId).find((user) => {
|
|
170
|
-
const status = String(user.status || '').trim().toLowerCase();
|
|
171
|
-
return status === 'active' && user.disabled !== true;
|
|
172
|
-
});
|
|
173
|
-
const fallbackUserId = String(fallbackUser?.userId || '').trim();
|
|
174
|
-
if (fallbackUserId)
|
|
175
|
-
return fallbackUserId;
|
|
176
|
-
}
|
|
177
219
|
throw new TaskforceRuleError('Authenticated user required for mutation attribution.', 401, 'MUTATION_AUTH_REQUIRED');
|
|
178
220
|
};
|
|
179
221
|
}
|
|
@@ -216,8 +258,14 @@ export function makeEnsureAdminRole(core, context) {
|
|
|
216
258
|
return actor.authenticated && actor.systemRole === 'system_admin';
|
|
217
259
|
};
|
|
218
260
|
}
|
|
219
|
-
export function makeEnsureAuthenticatedUser() {
|
|
261
|
+
export function makeEnsureAuthenticatedUser(authConfig) {
|
|
220
262
|
return function ensureAuthenticatedUser(req) {
|
|
263
|
+
if (authConfig?.enabled) {
|
|
264
|
+
const access = resolveRequestAccess(req, authConfig);
|
|
265
|
+
if (access.authenticated && access.userId && access.userId !== 'anonymous') {
|
|
266
|
+
return true;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
221
269
|
const userId = String(requestUserId(req) || '').trim();
|
|
222
270
|
return userId.length > 0 && userId !== 'anonymous';
|
|
223
271
|
};
|
|
@@ -286,21 +334,28 @@ export function makeAuditAdminAction(core, context) {
|
|
|
286
334
|
};
|
|
287
335
|
}
|
|
288
336
|
export function makeAuditAuthAction(core, requestWorkspaceId, context) {
|
|
289
|
-
return function auditAuthAction(req, action, details) {
|
|
337
|
+
return function auditAuthAction(req, action, details, workspaceIdOverride) {
|
|
290
338
|
const authConfig = context.authConfig;
|
|
291
339
|
const resolvedAccess = authConfig?.enabled ? resolveRequestAccess(req, authConfig) : null;
|
|
292
340
|
const actorUserId = resolvedAccess?.authenticated && resolvedAccess.userId && resolvedAccess.userId !== 'anonymous'
|
|
293
341
|
? resolvedAccess.userId
|
|
294
342
|
: requestUserId(req);
|
|
295
|
-
|
|
343
|
+
let actorRole = resolvedAccess?.authenticated
|
|
296
344
|
? String(resolvedAccess.role || '').trim().toLowerCase() || requestRole(req)
|
|
297
345
|
: requestRole(req);
|
|
346
|
+
const workspaceId = String(workspaceIdOverride || requestWorkspaceId(req) || '').trim() || 'default';
|
|
347
|
+
if (workspaceIdOverride && actorUserId && actorUserId !== 'anonymous') {
|
|
348
|
+
const membership = core.listWorkspaceUsers(workspaceId).find((user) => String(user.userId || '').trim() === actorUserId);
|
|
349
|
+
const role = String(membership?.role || '').trim().toLowerCase();
|
|
350
|
+
if (role)
|
|
351
|
+
actorRole = role;
|
|
352
|
+
}
|
|
298
353
|
const payload = {
|
|
299
354
|
ts: new Date().toISOString(),
|
|
300
355
|
action,
|
|
301
356
|
actorUserId,
|
|
302
357
|
actorRole,
|
|
303
|
-
workspaceId
|
|
358
|
+
workspaceId,
|
|
304
359
|
details
|
|
305
360
|
};
|
|
306
361
|
try {
|