@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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
5
|
+
import { TaskforceCore } from './Taskforce';
|
|
6
|
+
const createdRoots = [];
|
|
7
|
+
const originalHome = process.env.HOME;
|
|
8
|
+
function createProjectRoot(prefix = 'taskforce-list-tasks-slim-') {
|
|
9
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), prefix));
|
|
10
|
+
process.env.HOME = root;
|
|
11
|
+
createdRoots.push(root);
|
|
12
|
+
return root;
|
|
13
|
+
}
|
|
14
|
+
afterEach(() => {
|
|
15
|
+
process.env.HOME = originalHome;
|
|
16
|
+
while (createdRoots.length > 0) {
|
|
17
|
+
const root = createdRoots.pop();
|
|
18
|
+
if (root && fs.existsSync(root)) {
|
|
19
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
describe('TaskforceCore.listTasksSlim', () => {
|
|
24
|
+
it('does not hydrate comments, task events, attachments, or checklist items', () => {
|
|
25
|
+
const projectRoot = createProjectRoot();
|
|
26
|
+
const core = new TaskforceCore({ projectRoot, storagePath: '.taskforce' });
|
|
27
|
+
const task = core.createTask({ title: 'Heavy task' }, { workspaceId: 'default' });
|
|
28
|
+
core.addComment(task.id, 'note from reviewer', 'user', 'default');
|
|
29
|
+
core.replaceChecklistItems(task.id, [{ title: 'step one', isCompleted: false }], 'default');
|
|
30
|
+
const slim = core.listTasksSlim('default');
|
|
31
|
+
const entry = slim.find((t) => t.id === task.id);
|
|
32
|
+
expect(entry).toBeDefined();
|
|
33
|
+
expect(entry).not.toHaveProperty('comments');
|
|
34
|
+
expect(entry).not.toHaveProperty('taskEvents');
|
|
35
|
+
expect(entry).not.toHaveProperty('activity');
|
|
36
|
+
expect(entry).not.toHaveProperty('attachments');
|
|
37
|
+
expect(entry).not.toHaveProperty('checklistItems');
|
|
38
|
+
expect(entry).not.toHaveProperty('description');
|
|
39
|
+
expect(entry).not.toHaveProperty('createdByActor');
|
|
40
|
+
expect(entry).not.toHaveProperty('assigneeActor');
|
|
41
|
+
expect(entry).toMatchObject({
|
|
42
|
+
id: task.id,
|
|
43
|
+
title: 'Heavy task',
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
it('pushes assignee, status, openOnly, type, and priority filters into the query', () => {
|
|
47
|
+
const projectRoot = createProjectRoot();
|
|
48
|
+
const core = new TaskforceCore({ projectRoot, storagePath: '.taskforce' });
|
|
49
|
+
const mine = core.createTask({ title: 'Mine open', status: 'in-progress', assignee: 'user-a', priority: 3, type: 'issue' }, { workspaceId: 'default' });
|
|
50
|
+
core.createTask({ title: 'Other assigned', status: 'task', assignee: 'user-b', priority: 3 }, { workspaceId: 'default' });
|
|
51
|
+
const mineDone = core.createTask({ title: 'Mine done', status: 'done', assignee: 'user-a', priority: 1 }, { workspaceId: 'default' });
|
|
52
|
+
core.createTask({ title: 'Mine unassigned' }, { workspaceId: 'default' });
|
|
53
|
+
const byAssignee = core.listTasksSlim('default', { assignee: 'user-a' }).map((t) => t.id);
|
|
54
|
+
expect(byAssignee).toEqual(expect.arrayContaining([mine.id, mineDone.id]));
|
|
55
|
+
expect(byAssignee).toHaveLength(2);
|
|
56
|
+
const openOnly = core.listTasksSlim('default', { assignee: 'user-a', openOnly: true }).map((t) => t.id);
|
|
57
|
+
expect(openOnly).toEqual([mine.id]);
|
|
58
|
+
const byStatus = core.listTasksSlim('default', { status: 'done' }).map((t) => t.id);
|
|
59
|
+
expect(byStatus).toEqual([mineDone.id]);
|
|
60
|
+
const byType = core.listTasksSlim('default', { type: 'issue' }).map((t) => t.id);
|
|
61
|
+
expect(byType).toEqual([mine.id]);
|
|
62
|
+
const byPriority = core.listTasksSlim('default', { priority: 3 }).map((t) => t.id).sort();
|
|
63
|
+
expect(byPriority).toHaveLength(2);
|
|
64
|
+
const byCategory = core.listTasksSlim('default', { category: 'default' }).map((t) => t.id);
|
|
65
|
+
expect(byCategory).toHaveLength(4);
|
|
66
|
+
});
|
|
67
|
+
it('matches unassigned filter against null, empty-string, and "unassigned" values', () => {
|
|
68
|
+
const projectRoot = createProjectRoot();
|
|
69
|
+
const core = new TaskforceCore({ projectRoot, storagePath: '.taskforce' });
|
|
70
|
+
const unassigned = core.createTask({ title: 'no one' }, { workspaceId: 'default' });
|
|
71
|
+
const assigned = core.createTask({ title: 'someone', assignee: 'user-x' }, { workspaceId: 'default' });
|
|
72
|
+
const db = core.getDatabaseAdapter();
|
|
73
|
+
// Inject a row with assignee stored as empty string to exercise the fallback branch.
|
|
74
|
+
db.prepare(`UPDATE tasks SET assignee = '' WHERE id = ?`).run(unassigned.id);
|
|
75
|
+
const results = core.listTasksSlim('default', { assignee: 'unassigned' }).map((t) => t.id);
|
|
76
|
+
expect(results).toContain(unassigned.id);
|
|
77
|
+
expect(results).not.toContain(assigned.id);
|
|
78
|
+
});
|
|
79
|
+
it('applies sort, order, and limit in SQL', () => {
|
|
80
|
+
const projectRoot = createProjectRoot();
|
|
81
|
+
const core = new TaskforceCore({ projectRoot, storagePath: '.taskforce' });
|
|
82
|
+
const low = core.createTask({ title: 'low', priority: 1 }, { workspaceId: 'default' });
|
|
83
|
+
const mid = core.createTask({ title: 'mid', priority: 2 }, { workspaceId: 'default' });
|
|
84
|
+
const high = core.createTask({ title: 'high', priority: 4 }, { workspaceId: 'default' });
|
|
85
|
+
const byPriorityDesc = core.listTasksSlim('default', { sort: 'priority', order: 'desc' }).map((t) => t.id);
|
|
86
|
+
expect(byPriorityDesc.slice(0, 3)).toEqual([high.id, mid.id, low.id]);
|
|
87
|
+
const limited = core.listTasksSlim('default', { sort: 'priority', order: 'desc', limit: 1 });
|
|
88
|
+
expect(limited).toHaveLength(1);
|
|
89
|
+
expect(limited[0]?.id).toBe(high.id);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
@@ -289,6 +289,82 @@ describe('TaskforceCore MCP auth invalidation', () => {
|
|
|
289
289
|
cleanup();
|
|
290
290
|
}
|
|
291
291
|
});
|
|
292
|
+
it('does not delete active MCP access tokens', () => {
|
|
293
|
+
const { core, cleanup } = makeCore();
|
|
294
|
+
try {
|
|
295
|
+
setupWorkspace(core, 'owner-1', 'workspace-1');
|
|
296
|
+
const issued = core.createMcpAccessToken({
|
|
297
|
+
userId: 'owner-1',
|
|
298
|
+
workspaceId: 'workspace-1',
|
|
299
|
+
name: 'Active Token',
|
|
300
|
+
scopes: ['tasks:read']
|
|
301
|
+
});
|
|
302
|
+
expect(() => core.deleteMcpAccessToken({
|
|
303
|
+
actorUserId: 'owner-1',
|
|
304
|
+
workspaceId: 'workspace-1',
|
|
305
|
+
tokenId: issued.record.id
|
|
306
|
+
})).toThrow('Active MCP tokens must be revoked before deletion');
|
|
307
|
+
expect(core.listMcpAccessTokens({ userId: 'owner-1', workspaceId: 'workspace-1' }).items).toHaveLength(1);
|
|
308
|
+
}
|
|
309
|
+
finally {
|
|
310
|
+
cleanup();
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
it('deletes revoked MCP access token records', () => {
|
|
314
|
+
const { core, cleanup } = makeCore();
|
|
315
|
+
try {
|
|
316
|
+
setupWorkspace(core, 'owner-1', 'workspace-1');
|
|
317
|
+
const issued = core.createMcpAccessToken({
|
|
318
|
+
userId: 'owner-1',
|
|
319
|
+
workspaceId: 'workspace-1',
|
|
320
|
+
name: 'Revoked Token',
|
|
321
|
+
scopes: ['tasks:read']
|
|
322
|
+
});
|
|
323
|
+
core.revokeMcpAccessToken({
|
|
324
|
+
actorUserId: 'owner-1',
|
|
325
|
+
workspaceId: 'workspace-1',
|
|
326
|
+
tokenId: issued.record.id
|
|
327
|
+
});
|
|
328
|
+
expect(core.deleteMcpAccessToken({
|
|
329
|
+
actorUserId: 'owner-1',
|
|
330
|
+
workspaceId: 'workspace-1',
|
|
331
|
+
tokenId: issued.record.id
|
|
332
|
+
})).toBe(true);
|
|
333
|
+
expect(core.listMcpAccessTokens({ userId: 'owner-1', workspaceId: 'workspace-1' }).items).toHaveLength(0);
|
|
334
|
+
expect(core.authenticateMcpAccessToken(issued.token)).toBeNull();
|
|
335
|
+
}
|
|
336
|
+
finally {
|
|
337
|
+
cleanup();
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
it('deletes expired MCP access token records', () => {
|
|
341
|
+
const { core, cleanup } = makeCore();
|
|
342
|
+
try {
|
|
343
|
+
setupWorkspace(core, 'owner-1', 'workspace-1');
|
|
344
|
+
const issued = core.createMcpAccessToken({
|
|
345
|
+
userId: 'owner-1',
|
|
346
|
+
workspaceId: 'workspace-1',
|
|
347
|
+
name: 'Expired Token',
|
|
348
|
+
scopes: ['tasks:read'],
|
|
349
|
+
expiresAt: new Date(Date.now() + 60_000).toISOString()
|
|
350
|
+
});
|
|
351
|
+
core.db.prepare(`
|
|
352
|
+
UPDATE mcp_access_tokens
|
|
353
|
+
SET expires_at = ?
|
|
354
|
+
WHERE tenant_id = ? AND id = ?
|
|
355
|
+
`).run(new Date(Date.now() - 60_000).toISOString(), 'default', issued.record.id);
|
|
356
|
+
expect(core.listMcpAccessTokens({ userId: 'owner-1', workspaceId: 'workspace-1' }).items[0]?.status).toBe('expired');
|
|
357
|
+
expect(core.deleteMcpAccessToken({
|
|
358
|
+
actorUserId: 'owner-1',
|
|
359
|
+
workspaceId: 'workspace-1',
|
|
360
|
+
tokenId: issued.record.id
|
|
361
|
+
})).toBe(true);
|
|
362
|
+
expect(core.listMcpAccessTokens({ userId: 'owner-1', workspaceId: 'workspace-1' }).items).toHaveLength(0);
|
|
363
|
+
}
|
|
364
|
+
finally {
|
|
365
|
+
cleanup();
|
|
366
|
+
}
|
|
367
|
+
});
|
|
292
368
|
it('denies OAuth authentication after the authorized member is disabled', () => {
|
|
293
369
|
const { core, cleanup } = makeCore();
|
|
294
370
|
try {
|
|
@@ -308,6 +384,39 @@ describe('TaskforceCore MCP auth invalidation', () => {
|
|
|
308
384
|
cleanup();
|
|
309
385
|
}
|
|
310
386
|
});
|
|
387
|
+
it('returns persisted AI profile binding on OAuth connector authentication', () => {
|
|
388
|
+
const { core, cleanup } = makeCore();
|
|
389
|
+
try {
|
|
390
|
+
setupWorkspace(core, 'owner-1', 'workspace-1');
|
|
391
|
+
const accessToken = createOauthGrantToken(core, 'owner-1', 'workspace-1');
|
|
392
|
+
const auth = core.authenticateMcpOAuthAccessToken(accessToken);
|
|
393
|
+
expect(auth?.aiProfileToken).toBeFalsy();
|
|
394
|
+
const resolved = core.resolveAiProfile({
|
|
395
|
+
workspaceId: 'workspace-1',
|
|
396
|
+
name: 'Codex Connector',
|
|
397
|
+
icon: 'Code',
|
|
398
|
+
color: '#0ea5e9',
|
|
399
|
+
}, {
|
|
400
|
+
trustedSeatScope: 'cloud_metered',
|
|
401
|
+
});
|
|
402
|
+
expect(core.bindMcpOAuthConnectorGrantAiProfile({
|
|
403
|
+
grantId: auth.grantId,
|
|
404
|
+
workspaceId: 'workspace-1',
|
|
405
|
+
profileId: resolved.profile.id,
|
|
406
|
+
profileToken: resolved.profile.profileToken,
|
|
407
|
+
profileName: resolved.profile.name,
|
|
408
|
+
})).toBe(true);
|
|
409
|
+
expect(core.authenticateMcpOAuthAccessToken(accessToken)).toEqual(expect.objectContaining({
|
|
410
|
+
grantId: auth.grantId,
|
|
411
|
+
aiProfileId: resolved.profile.id,
|
|
412
|
+
aiProfileToken: resolved.profile.profileToken,
|
|
413
|
+
aiProfileName: 'Codex Connector',
|
|
414
|
+
}));
|
|
415
|
+
}
|
|
416
|
+
finally {
|
|
417
|
+
cleanup();
|
|
418
|
+
}
|
|
419
|
+
});
|
|
311
420
|
it('denies OAuth authentication after account access is suspended', () => {
|
|
312
421
|
const { core, cleanup } = makeCore();
|
|
313
422
|
try {
|
|
@@ -24,7 +24,7 @@ function seedPlans(core) {
|
|
|
24
24
|
billing: {
|
|
25
25
|
onboardingPolicy: {
|
|
26
26
|
mode: 'auto_grant_free',
|
|
27
|
-
|
|
27
|
+
planId: 'starter'
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
});
|
|
@@ -44,7 +44,7 @@ describe('TaskforceCore user profile avatar drafts', () => {
|
|
|
44
44
|
try {
|
|
45
45
|
const created = core.registerPasswordUser({
|
|
46
46
|
email: 'avatar-user@example.com',
|
|
47
|
-
password: '
|
|
47
|
+
password: 'ValidPassphrase123!'
|
|
48
48
|
});
|
|
49
49
|
const updated = core.updateUserProfile(created.userId, {
|
|
50
50
|
displayName: 'Avatar User',
|
|
@@ -62,13 +62,40 @@ describe('TaskforceCore user profile avatar drafts', () => {
|
|
|
62
62
|
fs.rmSync(projectRoot, { recursive: true, force: true });
|
|
63
63
|
}
|
|
64
64
|
});
|
|
65
|
+
it('exposes cloud-owned user avatarUrl on live workspace member records', () => {
|
|
66
|
+
const projectRoot = makeProjectRoot();
|
|
67
|
+
const core = openCore(projectRoot);
|
|
68
|
+
try {
|
|
69
|
+
core.createWorkspace({ workspaceId: 'workspace-1', name: 'Workspace 1' });
|
|
70
|
+
const created = core.registerPasswordUser({
|
|
71
|
+
email: 'member-avatar@example.com',
|
|
72
|
+
password: 'ValidPassphrase123!',
|
|
73
|
+
workspaceId: 'workspace-1'
|
|
74
|
+
});
|
|
75
|
+
const avatarUrl = `/api/taskforce/context/${encodeURIComponent(`users/${created.userId}/profile/avatar/headshot.webp`)}`;
|
|
76
|
+
core.updateUserProfile(created.userId, {
|
|
77
|
+
displayName: 'Member Avatar',
|
|
78
|
+
avatarUrl
|
|
79
|
+
});
|
|
80
|
+
const members = core.listWorkspaceUsers('workspace-1');
|
|
81
|
+
expect(members.find((member) => member.userId === created.userId)).toEqual(expect.objectContaining({
|
|
82
|
+
userId: created.userId,
|
|
83
|
+
displayName: 'Member Avatar',
|
|
84
|
+
avatarUrl
|
|
85
|
+
}));
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
core.close();
|
|
89
|
+
fs.rmSync(projectRoot, { recursive: true, force: true });
|
|
90
|
+
}
|
|
91
|
+
});
|
|
65
92
|
it('tracks, finalizes, discards, and cleans up stale avatar upload drafts', () => {
|
|
66
93
|
const projectRoot = makeProjectRoot();
|
|
67
94
|
const core = openCore(projectRoot);
|
|
68
95
|
try {
|
|
69
96
|
const created = core.registerPasswordUser({
|
|
70
97
|
email: 'draft-user@example.com',
|
|
71
|
-
password: '
|
|
98
|
+
password: 'ValidPassphrase123!'
|
|
72
99
|
});
|
|
73
100
|
const draft = core.createUserAvatarUploadDraft({
|
|
74
101
|
userId: created.userId,
|
|
@@ -55,11 +55,6 @@ export function deleteWorkspaceService(deps, input) {
|
|
|
55
55
|
const result = deps.db.prepare(sql).run(...params);
|
|
56
56
|
counts[tableName] = Number(result?.changes || 0);
|
|
57
57
|
};
|
|
58
|
-
deps.db.prepare(`
|
|
59
|
-
UPDATE tasks
|
|
60
|
-
SET parent_task_id = NULL
|
|
61
|
-
WHERE tenant_id = ? AND workspace_id = ? AND parent_task_id IS NOT NULL
|
|
62
|
-
`).run(deps.tenantId, normalizedWorkspaceId);
|
|
63
58
|
runDelete('comments', 'DELETE FROM comments WHERE tenant_id = ? AND workspace_id = ?', deps.tenantId, normalizedWorkspaceId);
|
|
64
59
|
runDelete('task_events', 'DELETE FROM task_events WHERE tenant_id = ? AND workspace_id = ?', deps.tenantId, normalizedWorkspaceId);
|
|
65
60
|
runDelete('deleted_tasks', 'DELETE FROM deleted_tasks WHERE tenant_id = ? AND workspace_id = ?', deps.tenantId, normalizedWorkspaceId);
|
|
@@ -124,10 +124,11 @@ describe('TaskforceCore workspace permission invariants', () => {
|
|
|
124
124
|
cleanup();
|
|
125
125
|
}
|
|
126
126
|
});
|
|
127
|
-
it('marks deactivated
|
|
127
|
+
it('marks deactivated workspace memberships as disabled without disabling the global account', () => {
|
|
128
128
|
const { core, cleanup } = makeCore();
|
|
129
129
|
try {
|
|
130
130
|
core.createWorkspace({ workspaceId: 'workspace-1', name: 'Workspace 1' });
|
|
131
|
+
core.createWorkspace({ workspaceId: 'workspace-home', name: 'Workspace Home' });
|
|
131
132
|
core.ensureBootstrapUserAccess({
|
|
132
133
|
userId: 'owner-1',
|
|
133
134
|
workspaceId: 'workspace-1',
|
|
@@ -140,9 +141,32 @@ describe('TaskforceCore workspace permission invariants', () => {
|
|
|
140
141
|
role: 'member',
|
|
141
142
|
email: 'member@example.com'
|
|
142
143
|
});
|
|
144
|
+
core.ensureBootstrapUserAccess({
|
|
145
|
+
userId: 'member-1',
|
|
146
|
+
workspaceId: 'workspace-home',
|
|
147
|
+
role: 'owner',
|
|
148
|
+
email: 'member@example.com'
|
|
149
|
+
});
|
|
143
150
|
expect(core.setWorkspaceUserDisabled('member-1', 'workspace-1', true)).toBe(true);
|
|
144
151
|
const access = core.resolveUserAccess('member-1', 'workspace-1', 'member');
|
|
145
152
|
expect(access?.disabled).toBe(true);
|
|
153
|
+
expect(access?.accountDisabled).toBe(false);
|
|
154
|
+
expect(access?.workspaceDisabled).toBe(true);
|
|
155
|
+
expect(core.resolveUserAccess('member-1', 'workspace-home', 'owner')).toEqual(expect.objectContaining({
|
|
156
|
+
role: 'owner',
|
|
157
|
+
disabled: false,
|
|
158
|
+
accountDisabled: false,
|
|
159
|
+
workspaceDisabled: false
|
|
160
|
+
}));
|
|
161
|
+
expect(core.listUserWorkspaces('member-1').map((workspace) => workspace.id)).toEqual(['workspace-home']);
|
|
162
|
+
expect(core.listWorkspaceUsers('workspace-1').find((user) => user.userId === 'member-1')).toEqual(expect.objectContaining({
|
|
163
|
+
status: 'disabled',
|
|
164
|
+
disabled: true
|
|
165
|
+
}));
|
|
166
|
+
const row = core.db.prepare(`
|
|
167
|
+
SELECT is_disabled FROM users WHERE tenant_id = ? AND id = ? LIMIT 1
|
|
168
|
+
`).get('default', 'member-1');
|
|
169
|
+
expect(Boolean(row?.is_disabled)).toBe(false);
|
|
146
170
|
}
|
|
147
171
|
finally {
|
|
148
172
|
cleanup();
|
|
@@ -31,7 +31,7 @@ function openCore(projectRoot) {
|
|
|
31
31
|
core.updatePlanVersionFeatures({
|
|
32
32
|
planVersionId: 'free-v1',
|
|
33
33
|
features: [
|
|
34
|
-
{ featureKey: 'workspace.
|
|
34
|
+
{ featureKey: 'workspace.workspaces', access: 'enabled' }
|
|
35
35
|
]
|
|
36
36
|
});
|
|
37
37
|
core.upsertPlanCatalog({ planId: 'team-5', displayName: 'Team 5' });
|
|
@@ -71,17 +71,17 @@ describe('TaskforceCore account-level plan mode and invite revoke', () => {
|
|
|
71
71
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
72
72
|
`).run('workspace-u1-second', 'default', 'workspace-u1-second', 'Second U1 Workspace', now, now);
|
|
73
73
|
db.prepare(`
|
|
74
|
-
INSERT INTO users (id, tenant_id, email, display_name,
|
|
75
|
-
VALUES (?, ?, ?, ?,
|
|
76
|
-
`).run('u1', 'default', 'u1@example.com', 'U1',
|
|
74
|
+
INSERT INTO users (id, tenant_id, email, display_name, is_disabled, created_at, updated_at)
|
|
75
|
+
VALUES (?, ?, ?, ?, 0, ?, ?)
|
|
76
|
+
`).run('u1', 'default', 'u1@example.com', 'U1', now, now);
|
|
77
77
|
db.prepare(`
|
|
78
|
-
INSERT INTO users (id, tenant_id, email, display_name,
|
|
79
|
-
VALUES (?, ?, ?, ?,
|
|
80
|
-
`).run('u2', 'default', 'u2@example.com', 'U2',
|
|
78
|
+
INSERT INTO users (id, tenant_id, email, display_name, is_disabled, created_at, updated_at)
|
|
79
|
+
VALUES (?, ?, ?, ?, 0, ?, ?)
|
|
80
|
+
`).run('u2', 'default', 'u2@example.com', 'U2', now, now);
|
|
81
81
|
db.prepare(`
|
|
82
|
-
INSERT INTO users (id, tenant_id, email, display_name,
|
|
83
|
-
VALUES (?, ?, ?, ?,
|
|
84
|
-
`).run('u3', 'default', 'u3@example.com', 'U3',
|
|
82
|
+
INSERT INTO users (id, tenant_id, email, display_name, is_disabled, created_at, updated_at)
|
|
83
|
+
VALUES (?, ?, ?, ?, 0, ?, ?)
|
|
84
|
+
`).run('u3', 'default', 'u3@example.com', 'U3', now, now);
|
|
85
85
|
db.prepare(`
|
|
86
86
|
INSERT INTO workspace_memberships (id, tenant_id, workspace_id, user_id, role, status, created_at, updated_at)
|
|
87
87
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
@@ -153,7 +153,7 @@ describe('TaskforceCore account-level plan mode and invite revoke', () => {
|
|
|
153
153
|
});
|
|
154
154
|
core.ensurePasswordUser({
|
|
155
155
|
email: 'existing@example.com',
|
|
156
|
-
password: '
|
|
156
|
+
password: 'HarborLanternOrbit!2026',
|
|
157
157
|
workspaceId: 'workspace-invite',
|
|
158
158
|
role: 'member'
|
|
159
159
|
});
|
|
@@ -190,7 +190,7 @@ describe('TaskforceCore account-level plan mode and invite revoke', () => {
|
|
|
190
190
|
core.setUserAccountPlanMode('owner-user', 'team');
|
|
191
191
|
const existing = core.ensurePasswordUser({
|
|
192
192
|
email: 'existing@example.com',
|
|
193
|
-
password: '
|
|
193
|
+
password: 'HarborLanternOrbit!2026',
|
|
194
194
|
workspaceId: 'workspace-invite',
|
|
195
195
|
role: 'member'
|
|
196
196
|
});
|
|
@@ -202,7 +202,8 @@ describe('TaskforceCore account-level plan mode and invite revoke', () => {
|
|
|
202
202
|
WHERE tenant_id = ? AND user_id = ? AND workspace_id = ?
|
|
203
203
|
`).run('default', existing.userId, 'workspace-invite');
|
|
204
204
|
const before = db.prepare(`
|
|
205
|
-
SELECT password_hash FROM
|
|
205
|
+
SELECT password_hash FROM user_auth_identities
|
|
206
|
+
WHERE tenant_id = ? AND user_id = ? AND provider = 'password' LIMIT 1
|
|
206
207
|
`).get('default', existing.userId);
|
|
207
208
|
const invite = core.requestInviteAcceptance({ userId: existing.userId, workspaceId: 'workspace-invite' });
|
|
208
209
|
const accepted = core.joinInviteWithAuthenticatedUser({
|
|
@@ -210,7 +211,8 @@ describe('TaskforceCore account-level plan mode and invite revoke', () => {
|
|
|
210
211
|
userId: existing.userId
|
|
211
212
|
});
|
|
212
213
|
const after = db.prepare(`
|
|
213
|
-
SELECT password_hash FROM
|
|
214
|
+
SELECT password_hash FROM user_auth_identities
|
|
215
|
+
WHERE tenant_id = ? AND user_id = ? AND provider = 'password' LIMIT 1
|
|
214
216
|
`).get('default', existing.userId);
|
|
215
217
|
const membership = db.prepare(`
|
|
216
218
|
SELECT status FROM workspace_memberships WHERE tenant_id = ? AND user_id = ? AND workspace_id = ? LIMIT 1
|
|
@@ -233,7 +235,7 @@ describe('TaskforceCore account-level plan mode and invite revoke', () => {
|
|
|
233
235
|
billing: {
|
|
234
236
|
onboardingPolicy: {
|
|
235
237
|
mode: 'auto_grant_free',
|
|
236
|
-
|
|
238
|
+
planId: 'free'
|
|
237
239
|
}
|
|
238
240
|
}
|
|
239
241
|
});
|
|
@@ -261,7 +263,7 @@ describe('TaskforceCore account-level plan mode and invite revoke', () => {
|
|
|
261
263
|
const invite = core.requestInviteAcceptance({ userId: 'invited-user', workspaceId: 'workspace-invite' });
|
|
262
264
|
const accepted = core.acceptInviteWithToken({
|
|
263
265
|
token: String(invite.token),
|
|
264
|
-
password: '
|
|
266
|
+
password: 'LanternHarborOrbit!2026'
|
|
265
267
|
});
|
|
266
268
|
expect(accepted.workspaceId).toBe('workspace-invite');
|
|
267
269
|
expect(core.hasAccountEntitlement('invited-user')).toBe(true);
|
|
@@ -279,4 +281,103 @@ describe('TaskforceCore account-level plan mode and invite revoke', () => {
|
|
|
279
281
|
fs.rmSync(projectRoot, { recursive: true, force: true });
|
|
280
282
|
}
|
|
281
283
|
});
|
|
284
|
+
it('grants the free personal entitlement to newly accepted invited accounts even without explicit self-serve onboarding policy', () => {
|
|
285
|
+
const projectRoot = makeProjectRoot();
|
|
286
|
+
const core = openCore(projectRoot);
|
|
287
|
+
try {
|
|
288
|
+
core.createWorkspace({ workspaceId: 'workspace-invite', name: 'Invite Workspace' });
|
|
289
|
+
core.ensureBootstrapUserAccess({
|
|
290
|
+
userId: 'owner-user',
|
|
291
|
+
workspaceId: 'workspace-invite',
|
|
292
|
+
role: 'owner',
|
|
293
|
+
email: 'owner@example.com'
|
|
294
|
+
});
|
|
295
|
+
core.setUserAccountPlanMode('owner-user', 'team');
|
|
296
|
+
core.ensureBootstrapUserAccess({
|
|
297
|
+
userId: 'invited-user',
|
|
298
|
+
workspaceId: 'workspace-invite',
|
|
299
|
+
role: 'member',
|
|
300
|
+
email: 'invited-no-policy@example.com'
|
|
301
|
+
});
|
|
302
|
+
core.setWorkspaceUserDisabled('invited-user', 'workspace-invite', true);
|
|
303
|
+
const db = core.db;
|
|
304
|
+
db.prepare(`
|
|
305
|
+
UPDATE workspace_memberships
|
|
306
|
+
SET status = 'invited'
|
|
307
|
+
WHERE tenant_id = ? AND user_id = ? AND workspace_id = ?
|
|
308
|
+
`).run('default', 'invited-user', 'workspace-invite');
|
|
309
|
+
const invite = core.requestInviteAcceptance({ userId: 'invited-user', workspaceId: 'workspace-invite' });
|
|
310
|
+
const accepted = core.acceptInviteWithToken({
|
|
311
|
+
token: String(invite.token),
|
|
312
|
+
password: 'LanternHarborOrbit!2026'
|
|
313
|
+
});
|
|
314
|
+
expect(accepted.workspaceId).toBe('workspace-invite');
|
|
315
|
+
expect(core.hasAccountEntitlement('invited-user')).toBe(true);
|
|
316
|
+
expect(core.getAccountEntitlement('invited-user')).toEqual(expect.objectContaining({
|
|
317
|
+
planVersionId: 'free-v1',
|
|
318
|
+
state: 'active'
|
|
319
|
+
}));
|
|
320
|
+
expect(core.getAccountAccessStatus('invited-user')).toEqual(expect.objectContaining({
|
|
321
|
+
gate: 'ok',
|
|
322
|
+
canAccessApp: true
|
|
323
|
+
}));
|
|
324
|
+
}
|
|
325
|
+
finally {
|
|
326
|
+
core.close();
|
|
327
|
+
fs.rmSync(projectRoot, { recursive: true, force: true });
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
it('reactivates blocked placeholder entitlements when a new invited user accepts a reused seat', () => {
|
|
331
|
+
const projectRoot = makeProjectRoot();
|
|
332
|
+
const core = openCore(projectRoot);
|
|
333
|
+
try {
|
|
334
|
+
core.createWorkspace({ workspaceId: 'workspace-invite', name: 'Invite Workspace' });
|
|
335
|
+
core.ensureBootstrapUserAccess({
|
|
336
|
+
userId: 'owner-user',
|
|
337
|
+
workspaceId: 'workspace-invite',
|
|
338
|
+
role: 'owner',
|
|
339
|
+
email: 'owner@example.com'
|
|
340
|
+
});
|
|
341
|
+
core.setUserAccountPlanMode('owner-user', 'team');
|
|
342
|
+
core.ensureBootstrapUserAccess({
|
|
343
|
+
userId: 'invited-user',
|
|
344
|
+
workspaceId: 'workspace-invite',
|
|
345
|
+
role: 'member',
|
|
346
|
+
email: 'invited@example.com'
|
|
347
|
+
});
|
|
348
|
+
core.setWorkspaceUserDisabled('invited-user', 'workspace-invite', true);
|
|
349
|
+
const db = core.db;
|
|
350
|
+
db.prepare(`
|
|
351
|
+
UPDATE workspace_memberships
|
|
352
|
+
SET status = 'invited'
|
|
353
|
+
WHERE tenant_id = ? AND user_id = ? AND workspace_id = ?
|
|
354
|
+
`).run('default', 'invited-user', 'workspace-invite');
|
|
355
|
+
core.updateAccountEntitlement({
|
|
356
|
+
accountId: 'invited-user',
|
|
357
|
+
planVersionId: 'free-v1',
|
|
358
|
+
entitlementState: 'canceled',
|
|
359
|
+
actorUserId: 'system-admin',
|
|
360
|
+
actorRole: 'system_admin',
|
|
361
|
+
reason: 'invite-reaccept-regression'
|
|
362
|
+
});
|
|
363
|
+
const invite = core.requestInviteAcceptance({ userId: 'invited-user', workspaceId: 'workspace-invite' });
|
|
364
|
+
const accepted = core.acceptInviteWithToken({
|
|
365
|
+
token: String(invite.token),
|
|
366
|
+
password: 'LanternHarborOrbit!2026'
|
|
367
|
+
});
|
|
368
|
+
expect(accepted.workspaceId).toBe('workspace-invite');
|
|
369
|
+
expect(core.getAccountEntitlement('invited-user')).toEqual(expect.objectContaining({
|
|
370
|
+
planVersionId: 'free-v1',
|
|
371
|
+
state: 'active'
|
|
372
|
+
}));
|
|
373
|
+
expect(core.getAccountAccessStatus('invited-user')).toEqual(expect.objectContaining({
|
|
374
|
+
gate: 'ok',
|
|
375
|
+
canAccessApp: true
|
|
376
|
+
}));
|
|
377
|
+
}
|
|
378
|
+
finally {
|
|
379
|
+
core.close();
|
|
380
|
+
fs.rmSync(projectRoot, { recursive: true, force: true });
|
|
381
|
+
}
|
|
382
|
+
});
|
|
282
383
|
});
|
package/dist/core/shared.d.ts
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import type { McpAccessTokenScope, PlanFeatureCatalogItem } from './types.js';
|
|
18
18
|
export declare const DOCUMENT_CLOUD_STORAGE_FEATURE_KEY = "context.uploads";
|
|
19
|
-
export declare const WORKSPACES_FEATURE_KEY = "workspace.
|
|
19
|
+
export declare const WORKSPACES_FEATURE_KEY = "workspace.workspaces";
|
|
20
20
|
export declare const AI_PROFILES_FEATURE_KEY = "collaboration.ai_profiles";
|
|
21
21
|
export declare const DOCUMENT_CLOUD_STORAGE_LIMIT_CONFIG_KEY = "storageLimitMb";
|
|
22
22
|
export declare const WORKSPACES_LIMIT_CONFIG_KEY = "maxWorkspaces";
|
package/dist/core/shared.js
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
import { createHash, pbkdf2Sync, randomBytes, timingSafeEqual } from 'crypto';
|
|
18
18
|
// === SECTION: Constants ===
|
|
19
19
|
export const DOCUMENT_CLOUD_STORAGE_FEATURE_KEY = 'context.uploads';
|
|
20
|
-
export const WORKSPACES_FEATURE_KEY = 'workspace.
|
|
20
|
+
export const WORKSPACES_FEATURE_KEY = 'workspace.workspaces';
|
|
21
21
|
export const AI_PROFILES_FEATURE_KEY = 'collaboration.ai_profiles';
|
|
22
22
|
export const DOCUMENT_CLOUD_STORAGE_LIMIT_CONFIG_KEY = 'storageLimitMb';
|
|
23
23
|
export const WORKSPACES_LIMIT_CONFIG_KEY = 'maxWorkspaces';
|
|
@@ -32,6 +32,7 @@ export const DEFAULT_PLAN_FEATURE_CATALOG = [
|
|
|
32
32
|
featureKey: 'collaboration.team_management',
|
|
33
33
|
label: 'Team Management',
|
|
34
34
|
description: 'Allow managing members, invites, roles, and collaboration settings.',
|
|
35
|
+
publicDisplayOrder: 40,
|
|
35
36
|
allowedAccessModes: ['enabled', 'disabled'],
|
|
36
37
|
configTemplate: {}
|
|
37
38
|
},
|
|
@@ -39,6 +40,7 @@ export const DEFAULT_PLAN_FEATURE_CATALOG = [
|
|
|
39
40
|
featureKey: DOCUMENT_CLOUD_STORAGE_FEATURE_KEY,
|
|
40
41
|
label: 'Document Cloud Storage',
|
|
41
42
|
description: 'Allow cloud document storage with an optional storage allowance in MB.',
|
|
43
|
+
publicDisplayOrder: 30,
|
|
42
44
|
allowedAccessModes: ['enabled', 'disabled'],
|
|
43
45
|
configTemplate: {
|
|
44
46
|
[DOCUMENT_CLOUD_STORAGE_LIMIT_CONFIG_KEY]: 1024
|
|
@@ -48,6 +50,7 @@ export const DEFAULT_PLAN_FEATURE_CATALOG = [
|
|
|
48
50
|
featureKey: WORKSPACES_FEATURE_KEY,
|
|
49
51
|
label: 'Workspaces',
|
|
50
52
|
description: 'Allow multiple workspaces with a configurable workspace limit.',
|
|
53
|
+
publicDisplayOrder: 10,
|
|
51
54
|
allowedAccessModes: ['enabled', 'disabled'],
|
|
52
55
|
configTemplate: {
|
|
53
56
|
[WORKSPACES_LIMIT_CONFIG_KEY]: 1
|
|
@@ -57,6 +60,7 @@ export const DEFAULT_PLAN_FEATURE_CATALOG = [
|
|
|
57
60
|
featureKey: AI_PROFILES_FEATURE_KEY,
|
|
58
61
|
label: 'AI Profiles',
|
|
59
62
|
description: 'Allow registered AI collaborator profiles with an optional per-workspace limit.',
|
|
63
|
+
publicDisplayOrder: 20,
|
|
60
64
|
allowedAccessModes: ['enabled', 'limited', 'disabled'],
|
|
61
65
|
configTemplate: {
|
|
62
66
|
[AI_PROFILES_LIMIT_CONFIG_KEY]: 1
|