@taskforcehq/taskforce 0.3.304 → 0.3.306
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 +140 -247
- package/dist/Taskforce.module.css +295 -89
- package/dist/TaskforceCore.js +378 -111
- package/dist/TaskforceCore.test.js +1221 -107
- 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 +52 -2
- package/dist/compat/workspaceSyncCompat.test.js +38 -1
- package/dist/components/context/ContextAttachmentManager.d.ts +14 -0
- package/dist/components/context/ContextAttachmentManager.js +549 -0
- package/dist/components/features/AgentsModule.d.ts +10 -1
- package/dist/components/features/AgentsModule.js +260 -15
- package/dist/components/features/AgentsModule.test.js +255 -5
- package/dist/components/features/DocumentIndex.d.ts +1 -1
- package/dist/components/features/DocumentIndex.js +1 -1
- package/dist/components/features/DocumentViewer.d.ts +6 -2
- package/dist/components/features/DocumentViewer.js +90 -10
- package/dist/components/features/DocumentWorkspace.d.ts +5 -22
- package/dist/components/features/DocumentWorkspace.js +12 -155
- package/dist/components/features/DocumentWorkspace.test.js +226 -6
- package/dist/components/features/TaskSettings.js +29 -3
- package/dist/components/features/TaskSettings.test.js +42 -1
- package/dist/components/features/documentWorkspaceModel.d.ts +24 -0
- package/dist/components/features/documentWorkspaceModel.js +57 -0
- package/dist/components/features/useDocumentWorkspaceController.d.ts +34 -0
- package/dist/components/features/useDocumentWorkspaceController.js +113 -0
- package/dist/components/task/TaskCard.js +19 -28
- package/dist/components/task/TaskCard.test.js +38 -3
- package/dist/components/task/TaskContextUpload.js +4 -526
- package/dist/components/task/TaskForm.d.ts +8 -8
- package/dist/components/task/TaskForm.js +362 -230
- package/dist/components/task/TaskForm.test.js +558 -381
- package/dist/components/task/TaskKanban.d.ts +2 -1
- package/dist/components/task/TaskKanban.js +96 -14
- package/dist/components/task/TaskKanban.test.js +36 -0
- package/dist/components/ui/EditableAvatarButton.d.ts +18 -0
- package/dist/components/ui/EditableAvatarButton.js +18 -0
- package/dist/components/views/PlanComparisonPage.d.ts +9 -1
- package/dist/components/views/PlanComparisonPage.js +70 -17
- package/dist/components/views/PlanComparisonPage.test.js +289 -41
- package/dist/components/views/PlansPage.js +239 -106
- package/dist/components/views/PlansPage.test.js +593 -42
- package/dist/components/views/StandaloneLayout.js +310 -554
- package/dist/components/views/panels/FilterToolbar.test.js +6 -4
- package/dist/components/views/panels/PlanningDrawer.d.ts +8 -1
- package/dist/components/views/panels/PlanningDrawer.js +18 -11
- package/dist/components/views/panels/PlanningDrawer.test.d.ts +1 -0
- package/dist/components/views/panels/PlanningDrawer.test.js +141 -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 +27 -14
- package/dist/components/views/standalone/modals/AccountHubModal.js +87 -15
- package/dist/components/views/standalone/modals/AccountHubModal.test.js +42 -2
- 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 -1
- package/dist/core/AiProfileService.d.ts +45 -3
- package/dist/core/AiProfileService.js +774 -63
- package/dist/core/AiProfileService.test.js +22 -2
- package/dist/core/AiProfiles.test.js +761 -2
- package/dist/core/AttachmentLinkService.js +57 -15
- 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.d.ts +1 -0
- package/dist/core/AuthTokenService.test.js +78 -0
- package/dist/core/EntitlementsPolicy.test.js +77 -15
- package/dist/core/GlobalSettingsService.js +115 -6
- package/dist/core/PlanEntitlementService.d.ts +30 -3
- package/dist/core/PlanEntitlementService.js +454 -93
- package/dist/core/PlanFeatureCatalog.test.d.ts +1 -0
- package/dist/core/PlanFeatureCatalog.test.js +84 -0
- package/dist/core/PlanVersionPolicy.test.js +54 -28
- package/dist/core/PlanningEntities.test.js +52 -0
- package/dist/core/SignupMonetizationSettings.test.js +241 -44
- package/dist/core/SyncReconciliationService.js +2 -65
- package/dist/core/SystemAdmin.test.js +244 -88
- package/dist/core/TaskAttachmentsCanonical.test.js +51 -1
- package/dist/core/TaskTaxonomyValidation.test.js +53 -0
- package/dist/core/Taskforce.d.ts +228 -14
- package/dist/core/Taskforce.js +814 -201
- package/dist/core/Taskforce.listTasksSlim.test.d.ts +1 -0
- package/dist/core/Taskforce.listTasksSlim.test.js +91 -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 +128 -27
- package/dist/core/shared.d.ts +3 -1
- package/dist/core/shared.js +16 -1
- package/dist/core/types.d.ts +68 -2
- package/dist/hooks/auth/useTaskforceAuthBootstrap.js +26 -1
- package/dist/hooks/sync/auth.js +3 -1
- 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 +10 -1
- package/dist/hooks/sync/orchestratorShared.js +68 -47
- 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 +171 -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 +186 -65
- package/dist/hooks/sync/transfers.test.d.ts +1 -0
- package/dist/hooks/sync/transfers.test.js +396 -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/useSyncOrchestrator.aiProfiles.test.js +12 -0
- package/dist/hooks/useSyncOrchestrator.d.ts +16 -6
- package/dist/hooks/useSyncOrchestrator.js +424 -175
- package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +487 -10
- package/dist/hooks/useTaskData.js +8 -3
- package/dist/hooks/useTaskData.test.js +45 -0
- package/dist/hooks/useTaskMutations.d.ts +2 -1
- package/dist/hooks/useTaskMutations.js +12 -1
- package/dist/hooks/useTaskMutations.test.js +30 -1
- package/dist/hooks/useTaskforce.d.ts +65 -4
- package/dist/hooks/useTaskforce.js +564 -243
- package/dist/hooks/useTaskforce.runtime-routing.test.d.ts +1 -0
- package/dist/hooks/useTaskforce.runtime-routing.test.js +152 -0
- package/dist/hooks/useTaskforce.sync-behavior.test.js +2454 -208
- package/dist/hooks/useWorkspaceSyncController.d.ts +4 -1
- package/dist/hooks/useWorkspaceSyncController.js +17 -2
- package/dist/hooks/useWorkspaceSyncController.test.js +1 -0
- package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.d.ts +16 -0
- package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +316 -35
- 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/adminWorkspaceRegistrar.d.ts +2 -0
- package/dist/mcp/adminWorkspaceRegistrar.js +154 -0
- package/dist/mcp/collaborationRegistrar.d.ts +2 -0
- package/dist/mcp/collaborationRegistrar.js +71 -0
- package/dist/mcp/documentAssetRegistrar.d.ts +2 -0
- package/dist/mcp/documentAssetRegistrar.js +346 -0
- package/dist/mcp/runtime.d.ts +2 -0
- package/dist/mcp/runtime.js +2433 -3534
- package/dist/mcp/runtime.test.js +440 -2
- package/dist/mcp/taskPlanningRegistrar.d.ts +2 -0
- package/dist/mcp/taskPlanningRegistrar.js +418 -0
- package/dist/mcp/toolCatalog.d.ts +35 -0
- package/dist/mcp/toolCatalog.js +3 -0
- package/dist/migrations/taskSchemaMigrations.d.ts +1 -1
- package/dist/migrations/taskSchemaMigrations.js +171 -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/annotatedAttachmentsRoutes.test.js +3 -3
- 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 +120 -9
- package/dist/server/index.rateLimit.test.js +3 -0
- package/dist/server/index.test.js +106 -3
- package/dist/server/routes/admin.d.ts +4 -5
- package/dist/server/routes/admin.js +410 -80
- package/dist/server/routes/annotatedAttachments.d.ts +1 -1
- package/dist/server/routes/annotatedAttachments.js +1 -1
- package/dist/server/routes/auth.d.ts +16 -6
- package/dist/server/routes/auth.js +1015 -118
- package/dist/server/routes/authSupport.d.ts +30 -0
- package/dist/server/routes/authSupport.js +81 -0
- package/dist/server/routes/billing.d.ts +1 -1
- package/dist/server/routes/billing.js +276 -34
- package/dist/server/routes/billing.test.js +760 -52
- package/dist/server/routes/documentReviews.d.ts +1 -1
- package/dist/server/routes/documentReviews.js +1 -1
- package/dist/server/routes/documents.d.ts +5 -2
- package/dist/server/routes/documents.js +242 -74
- package/dist/server/routes/primitives.d.ts +11 -0
- package/dist/server/routes/primitives.js +73 -0
- package/dist/server/routes/resources.d.ts +1 -1
- package/dist/server/routes/resources.js +1 -1
- package/dist/server/routes/shared.d.ts +29 -3
- package/dist/server/routes/shared.js +69 -4
- package/dist/server/routes/sync.d.ts +1 -1
- package/dist/server/routes/sync.integration.test.js +437 -39
- package/dist/server/routes/sync.js +62 -606
- 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 +180 -0
- package/dist/server/routes/tasks.d.ts +1 -1
- package/dist/server/routes/tasks.js +44 -2
- package/dist/server/routes/workspaces.d.ts +1 -1
- package/dist/server/routes/workspaces.js +37 -6
- package/dist/server/routes.d.ts +2 -9
- package/dist/server/routes.js +136 -165
- package/dist/server/routes.test.js +2457 -162
- 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/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/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 +17 -11
- package/dist/sync/collaborationSyncPayload.test.js +13 -1
- package/dist/sync/contentSyncState.d.ts +4 -8
- package/dist/sync/contentSyncState.js +33 -77
- package/dist/sync/syncApplyHandlers.d.ts +7 -0
- package/dist/sync/syncApplyHandlers.js +28 -13
- package/dist/sync/syncApplyHandlers.test.js +72 -3
- package/dist/sync/syncFieldSemantics.d.ts +12 -0
- package/dist/sync/syncFieldSemantics.js +55 -0
- package/dist/sync/syncResourceAdapters.d.ts +44 -0
- package/dist/sync/syncResourceAdapters.js +77 -0
- package/dist/sync/syncService.d.ts +6 -0
- package/dist/sync/syncService.js +60 -0
- package/dist/sync/syncService.test.js +71 -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.js +4 -3
- package/dist/sync/workspacePullFeed.test.js +43 -0
- package/dist/sync/workspaceRepair.js +5 -2
- package/dist/sync/workspaceSyncModel.d.ts +48 -0
- package/dist/sync/workspaceSyncModel.js +195 -31
- package/dist/sync/workspaceSyncModel.test.js +325 -12
- package/dist/sync/workspaceSyncState.d.ts +19 -0
- package/dist/sync/workspaceSyncState.js +3 -1
- package/dist/sync/workspaceSyncSurface.js +3 -8
- package/dist/types.d.ts +17 -0
- package/dist/ui/assets/AgentsModule-DrLawwNl.js +1 -0
- package/dist/ui/assets/{AnnotatedAttachmentWorkspace-BlS-cqnl.js → AnnotatedAttachmentWorkspace-Z9_whf7F.js} +1 -1
- 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-B03MaSkw.js +252 -0
- package/dist/ui/assets/DocumentWorkspace-Dhdso07p.css +1 -0
- package/dist/ui/assets/{InitiativesModule-BjR6iBf9.js → InitiativesModule-9E6ParrY.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-CvfnMiWq.css +1 -0
- package/dist/ui/assets/PlansPage-DRXscYxH.js +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/TaskSettings-DZX4jk7e.js +9 -0
- package/dist/ui/assets/{WorkflowsModule-DnFqdUME.js → WorkflowsModule-BA7jcEpH.js} +1 -1
- package/dist/ui/assets/index-9eT8e0Lu.css +1 -0
- package/dist/ui/assets/index-C6k75jr8.js +6 -0
- package/dist/ui/assets/{vendor-icons-I7ZwG1z_.js → vendor-icons-DuEd_65c.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/utils/accountProfileSummaryCache.d.ts +5 -0
- package/dist/utils/assignees.d.ts +2 -0
- package/dist/utils/assignees.js +2 -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.d.ts +19 -0
- package/dist/utils/commercialLifecyclePresentation.js +199 -0
- package/dist/utils/contextAssetEvents.d.ts +2 -0
- 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 +2 -0
- package/dist/utils/taskActivity.js +228 -22
- package/dist/utils/taskActivity.test.js +119 -8
- 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 +10 -2
- package/scripts/check-cloud-mcp.mjs +83 -0
- package/scripts/export-sqlite-to-postgres.mjs +7 -9
- package/scripts/playwright-auth.sh +5 -1
- package/scripts/run-billing-performance-smoke.sh +24 -0
- 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-BLWVbuKP.js +0 -1
- package/dist/ui/assets/DocumentWorkspace-BH_6DF6x.js +0 -250
- package/dist/ui/assets/DocumentWorkspace-C_8T8oz-.css +0 -1
- package/dist/ui/assets/PlansPage-C2dd2n1X.css +0 -1
- package/dist/ui/assets/PlansPage-CSDQ4sLa.js +0 -1
- package/dist/ui/assets/RussoOne-Regular-C3BxZIj7.ttf +0 -0
- package/dist/ui/assets/TaskSettings-CEDy34Jo.js +0 -9
- package/dist/ui/assets/index-DXUdtH1B.js +0 -6
- package/dist/ui/assets/index-Ii0B0rTO.css +0 -1
- package/scripts/migrate-planning-model.ts +0 -233
|
@@ -16,29 +16,42 @@ function insertFreePriceMapping(core, planVersionId) {
|
|
|
16
16
|
`).run(core.getTenantId(), planVersionId, 'month', `free:${planVersionId}:month`, 'free', 1, 0, null, now, now);
|
|
17
17
|
}
|
|
18
18
|
function seedPlanCatalog(core) {
|
|
19
|
-
core.upsertPlanCatalog({ planId: '
|
|
20
|
-
core.upsertPlanCatalog({ planId: '
|
|
19
|
+
core.upsertPlanCatalog({ planId: 'free', displayName: 'Free', status: 'active' });
|
|
20
|
+
core.upsertPlanCatalog({ planId: 'basic', displayName: 'Basic', status: 'active' });
|
|
21
|
+
core.upsertPlanCatalog({ planId: 'team-5', displayName: 'Team 5', status: 'active' });
|
|
21
22
|
core.updatePlanVersion({
|
|
22
|
-
planId: '
|
|
23
|
+
planId: 'basic',
|
|
24
|
+
versionNumber: 1,
|
|
25
|
+
seatLimit: null
|
|
26
|
+
});
|
|
27
|
+
core.updatePlanVersion({
|
|
28
|
+
planId: 'team-5',
|
|
23
29
|
versionNumber: 1,
|
|
24
30
|
seatLimit: 5
|
|
25
31
|
});
|
|
26
32
|
core.updatePlanVersionFeatures({
|
|
27
|
-
planVersionId: '
|
|
33
|
+
planVersionId: 'free-v1',
|
|
34
|
+
features: [
|
|
35
|
+
{ featureKey: 'workspace.workspaces', access: 'enabled' }
|
|
36
|
+
]
|
|
37
|
+
});
|
|
38
|
+
core.updatePlanVersionFeatures({
|
|
39
|
+
planVersionId: 'basic-v1',
|
|
28
40
|
features: [
|
|
29
|
-
{ featureKey: '
|
|
41
|
+
{ featureKey: 'context.uploads', access: 'enabled' },
|
|
42
|
+
{ featureKey: 'workspace.workspaces', access: 'enabled' }
|
|
30
43
|
]
|
|
31
44
|
});
|
|
32
45
|
core.updatePlanVersionFeatures({
|
|
33
|
-
planVersionId: '
|
|
46
|
+
planVersionId: 'team-5-v1',
|
|
34
47
|
features: [
|
|
35
48
|
{ featureKey: 'collaboration.invites', access: 'enabled' },
|
|
36
49
|
{ featureKey: 'collaboration.team_management', access: 'enabled' },
|
|
37
50
|
{ featureKey: 'context.uploads', access: 'enabled' },
|
|
38
|
-
{ featureKey: 'workspace.
|
|
51
|
+
{ featureKey: 'workspace.workspaces', access: 'enabled' }
|
|
39
52
|
]
|
|
40
53
|
});
|
|
41
|
-
insertFreePriceMapping(core, '
|
|
54
|
+
insertFreePriceMapping(core, 'free-v1');
|
|
42
55
|
}
|
|
43
56
|
function seedPlans(core) {
|
|
44
57
|
seedPlanCatalog(core);
|
|
@@ -46,7 +59,7 @@ function seedPlans(core) {
|
|
|
46
59
|
billing: {
|
|
47
60
|
onboardingPolicy: {
|
|
48
61
|
mode: 'auto_grant_free',
|
|
49
|
-
|
|
62
|
+
planId: 'free'
|
|
50
63
|
}
|
|
51
64
|
}
|
|
52
65
|
});
|
|
@@ -68,7 +81,7 @@ describe('TaskforceCore system admin model', () => {
|
|
|
68
81
|
try {
|
|
69
82
|
const created = core.registerPasswordUser({
|
|
70
83
|
email: 'billing-noworkspace@example.com',
|
|
71
|
-
password: '
|
|
84
|
+
password: 'ValidPassphrase123!'
|
|
72
85
|
});
|
|
73
86
|
const db = core.db;
|
|
74
87
|
const row = db.prepare(`
|
|
@@ -78,7 +91,7 @@ describe('TaskforceCore system admin model', () => {
|
|
|
78
91
|
LIMIT 1
|
|
79
92
|
`).get('default', created.userId);
|
|
80
93
|
expect(row?.user_id).toBe(created.userId);
|
|
81
|
-
expect(row?.tier).toBe('
|
|
94
|
+
expect(row?.tier).toBe('free');
|
|
82
95
|
expect(row?.entitlement_state).toBe('active');
|
|
83
96
|
}
|
|
84
97
|
finally {
|
|
@@ -93,7 +106,7 @@ describe('TaskforceCore system admin model', () => {
|
|
|
93
106
|
core.createWorkspace({ workspaceId: 'workspace-1', name: 'Workspace 1' });
|
|
94
107
|
const created = core.registerPasswordUser({
|
|
95
108
|
email: 'billing-workspace@example.com',
|
|
96
|
-
password: '
|
|
109
|
+
password: 'ValidPassphrase123!',
|
|
97
110
|
workspaceId: 'workspace-1',
|
|
98
111
|
role: 'member'
|
|
99
112
|
});
|
|
@@ -105,7 +118,7 @@ describe('TaskforceCore system admin model', () => {
|
|
|
105
118
|
LIMIT 1
|
|
106
119
|
`).get('default', created.userId);
|
|
107
120
|
expect(row?.user_id).toBe(created.userId);
|
|
108
|
-
expect(row?.tier).toBe('
|
|
121
|
+
expect(row?.tier).toBe('free');
|
|
109
122
|
expect(row?.entitlement_state).toBe('active');
|
|
110
123
|
}
|
|
111
124
|
finally {
|
|
@@ -118,23 +131,23 @@ describe('TaskforceCore system admin model', () => {
|
|
|
118
131
|
const core = openCore(projectRoot, { seedDefaultPlans: true });
|
|
119
132
|
try {
|
|
120
133
|
core.createPlanVersion({
|
|
121
|
-
planId: '
|
|
134
|
+
planId: 'team-5',
|
|
122
135
|
versionNumber: 2,
|
|
123
136
|
isDefault: true,
|
|
124
137
|
seatLimit: 10,
|
|
125
138
|
trialDays: 14
|
|
126
139
|
});
|
|
127
140
|
core.updatePlanVersionFeatures({
|
|
128
|
-
planVersionId: '
|
|
141
|
+
planVersionId: 'team-5-v2',
|
|
129
142
|
features: [
|
|
130
143
|
{ featureKey: 'collaboration.invites', access: 'enabled' },
|
|
131
144
|
{ featureKey: 'collaboration.team_management', access: 'enabled' },
|
|
132
145
|
{ featureKey: 'context.uploads', access: 'enabled' },
|
|
133
|
-
{ featureKey: 'workspace.
|
|
146
|
+
{ featureKey: 'workspace.workspaces', access: 'enabled' }
|
|
134
147
|
]
|
|
135
148
|
});
|
|
136
149
|
core.createPlanVersion({
|
|
137
|
-
planId: '
|
|
150
|
+
planId: 'free',
|
|
138
151
|
versionNumber: 2,
|
|
139
152
|
isDefault: false,
|
|
140
153
|
seatLimit: null
|
|
@@ -143,13 +156,13 @@ describe('TaskforceCore system admin model', () => {
|
|
|
143
156
|
billing: {
|
|
144
157
|
onboardingPolicy: {
|
|
145
158
|
mode: 'auto_start_trial',
|
|
146
|
-
|
|
159
|
+
planId: 'team-5'
|
|
147
160
|
}
|
|
148
161
|
}
|
|
149
162
|
});
|
|
150
163
|
const created = core.registerPasswordUser({
|
|
151
164
|
email: 'configured-signup@example.com',
|
|
152
|
-
password: '
|
|
165
|
+
password: 'ValidPassphrase123!'
|
|
153
166
|
});
|
|
154
167
|
const entitlement = core.getAccountEntitlement(created.userId);
|
|
155
168
|
const db = core.db;
|
|
@@ -159,10 +172,10 @@ describe('TaskforceCore system admin model', () => {
|
|
|
159
172
|
WHERE tenant_id = ? AND user_id = ?
|
|
160
173
|
LIMIT 1
|
|
161
174
|
`).get(core.getTenantId(), created.userId);
|
|
162
|
-
expect(entitlement.planVersionId).toBe('
|
|
163
|
-
expect(entitlement.planId).toBe('
|
|
175
|
+
expect(entitlement.planVersionId).toBe('team-5-v2');
|
|
176
|
+
expect(entitlement.planId).toBe('team-5');
|
|
164
177
|
expect(entitlement.state).toBe('trialing');
|
|
165
|
-
expect(billing?.tier).toBe('
|
|
178
|
+
expect(billing?.tier).toBe('team-5');
|
|
166
179
|
expect(billing?.entitlement_state).toBe('trialing');
|
|
167
180
|
}
|
|
168
181
|
finally {
|
|
@@ -178,13 +191,13 @@ describe('TaskforceCore system admin model', () => {
|
|
|
178
191
|
billing: {
|
|
179
192
|
onboardingPolicy: {
|
|
180
193
|
mode: 'auto_grant_free',
|
|
181
|
-
|
|
194
|
+
planId: 'missing'
|
|
182
195
|
}
|
|
183
196
|
}
|
|
184
197
|
});
|
|
185
198
|
expect(() => core.registerPasswordUser({
|
|
186
199
|
email: 'fallback-signup@example.com',
|
|
187
|
-
password: '
|
|
200
|
+
password: 'ValidPassphrase123!'
|
|
188
201
|
})).toThrowError(/was not found/i);
|
|
189
202
|
}
|
|
190
203
|
finally {
|
|
@@ -200,13 +213,13 @@ describe('TaskforceCore system admin model', () => {
|
|
|
200
213
|
billing: {
|
|
201
214
|
onboardingPolicy: {
|
|
202
215
|
mode: 'require_plan_selection',
|
|
203
|
-
|
|
216
|
+
planId: null
|
|
204
217
|
}
|
|
205
218
|
}
|
|
206
219
|
});
|
|
207
220
|
const created = core.registerPasswordUser({
|
|
208
221
|
email: 'pending-plan@example.com',
|
|
209
|
-
password: '
|
|
222
|
+
password: 'ValidPassphrase123!'
|
|
210
223
|
});
|
|
211
224
|
expect(created.planSelectionRequired).toBe(true);
|
|
212
225
|
expect(core.hasAccountEntitlement(created.userId)).toBe(true);
|
|
@@ -244,7 +257,7 @@ describe('TaskforceCore system admin model', () => {
|
|
|
244
257
|
access = excluded.access,
|
|
245
258
|
config_json = excluded.config_json,
|
|
246
259
|
updated_at = excluded.updated_at
|
|
247
|
-
`).run('default', '
|
|
260
|
+
`).run('default', 'team-5-v1', 'documents.workspace_access', 'enabled', '{}', now, now);
|
|
248
261
|
}
|
|
249
262
|
finally {
|
|
250
263
|
core.close();
|
|
@@ -257,9 +270,9 @@ describe('TaskforceCore system admin model', () => {
|
|
|
257
270
|
FROM plan_feature_matrix
|
|
258
271
|
WHERE tenant_id = ? AND plan_version_id = ? AND feature_key = ?
|
|
259
272
|
LIMIT 1
|
|
260
|
-
`).get('default', '
|
|
273
|
+
`).get('default', 'team-5-v1', 'documents.workspace_access');
|
|
261
274
|
expect(row).toBeUndefined();
|
|
262
|
-
const snapshot = core.listPlanVersions('
|
|
275
|
+
const snapshot = core.listPlanVersions('team-5').find((version) => version.planVersionId === 'team-5-v1');
|
|
263
276
|
expect(snapshot).toBeDefined();
|
|
264
277
|
expect(snapshot.features['documents.workspace_access']).toBeUndefined();
|
|
265
278
|
}
|
|
@@ -268,34 +281,120 @@ describe('TaskforceCore system admin model', () => {
|
|
|
268
281
|
fs.rmSync(projectRoot, { recursive: true, force: true });
|
|
269
282
|
}
|
|
270
283
|
});
|
|
271
|
-
it('
|
|
284
|
+
it('keeps configured auto-grant onboarding plan when registration includes a selected plan version', () => {
|
|
272
285
|
const projectRoot = makeProjectRoot();
|
|
273
286
|
const core = openCore(projectRoot, { seedDefaultPlans: true });
|
|
274
287
|
try {
|
|
275
|
-
core.upsertPlanCatalog({ planId: 'free', displayName: 'Free', status: 'active' });
|
|
276
288
|
core.updatePlanVersion({
|
|
277
|
-
planId: '
|
|
289
|
+
planId: 'basic',
|
|
278
290
|
versionNumber: 1,
|
|
279
|
-
seatLimit:
|
|
291
|
+
seatLimit: null
|
|
280
292
|
});
|
|
281
|
-
insertFreePriceMapping(core, 'free-v1');
|
|
282
|
-
core.upsertPlanCatalog({ planId: 'starter', displayName: 'Starter', status: 'archived' });
|
|
283
293
|
core.updateGlobalSettings({
|
|
284
294
|
billing: {
|
|
285
295
|
onboardingPolicy: {
|
|
286
296
|
mode: 'auto_grant_free',
|
|
287
|
-
|
|
297
|
+
planId: 'free'
|
|
288
298
|
}
|
|
289
299
|
}
|
|
290
300
|
});
|
|
291
301
|
const created = core.registerPasswordUser({
|
|
292
302
|
email: 'selected-plan@example.com',
|
|
293
|
-
password: '
|
|
294
|
-
planVersionId: '
|
|
303
|
+
password: 'ValidPassphrase123!',
|
|
304
|
+
planVersionId: 'basic-v1'
|
|
305
|
+
});
|
|
306
|
+
expect(created.planSelectionRequired).toBe(false);
|
|
307
|
+
expect(core.getAccountEntitlement(created.userId)).toMatchObject({
|
|
308
|
+
planVersionId: 'free-v1',
|
|
309
|
+
planId: 'free',
|
|
310
|
+
state: 'active'
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
finally {
|
|
314
|
+
core.close();
|
|
315
|
+
fs.rmSync(projectRoot, { recursive: true, force: true });
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
it('uses the explicitly selected plan version when onboarding requires plan selection', () => {
|
|
319
|
+
const projectRoot = makeProjectRoot();
|
|
320
|
+
const core = openCore(projectRoot, { seedDefaultPlans: true });
|
|
321
|
+
try {
|
|
322
|
+
core.updatePlanVersion({
|
|
323
|
+
planId: 'basic',
|
|
324
|
+
versionNumber: 1,
|
|
325
|
+
seatLimit: null
|
|
326
|
+
});
|
|
327
|
+
core.updateGlobalSettings({
|
|
328
|
+
billing: {
|
|
329
|
+
onboardingPolicy: {
|
|
330
|
+
mode: 'require_plan_selection',
|
|
331
|
+
planId: null
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
const created = core.registerPasswordUser({
|
|
336
|
+
email: 'selected-plan-required@example.com',
|
|
337
|
+
password: 'ValidPassphrase123!',
|
|
338
|
+
planVersionId: 'basic-v1'
|
|
295
339
|
});
|
|
296
340
|
expect(created.planSelectionRequired).toBe(false);
|
|
297
341
|
expect(core.getAccountEntitlement(created.userId)).toMatchObject({
|
|
342
|
+
planVersionId: 'basic-v1',
|
|
343
|
+
planId: 'basic',
|
|
344
|
+
state: 'checkout_pending'
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
finally {
|
|
348
|
+
core.close();
|
|
349
|
+
fs.rmSync(projectRoot, { recursive: true, force: true });
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
it('auto-heals stranded legacy personal free entitlements onto the active default free version', () => {
|
|
353
|
+
const projectRoot = makeProjectRoot();
|
|
354
|
+
const core = openCore(projectRoot, { seedDefaultPlans: true });
|
|
355
|
+
try {
|
|
356
|
+
core.upsertPlanCatalog({ planId: 'free', displayName: 'Free', status: 'active' });
|
|
357
|
+
insertFreePriceMapping(core, 'free-v1');
|
|
358
|
+
core.createPlanVersion({
|
|
359
|
+
planId: 'free',
|
|
360
|
+
versionNumber: 2,
|
|
361
|
+
isDefault: true,
|
|
362
|
+
seatLimit: 1
|
|
363
|
+
});
|
|
364
|
+
insertFreePriceMapping(core, 'free-v2');
|
|
365
|
+
core.updateGlobalSettings({
|
|
366
|
+
billing: {
|
|
367
|
+
onboardingPolicy: {
|
|
368
|
+
mode: 'require_plan_selection',
|
|
369
|
+
planId: null
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
const created = core.registerPasswordUser({
|
|
374
|
+
email: 'legacy-free@example.com',
|
|
375
|
+
password: 'ValidPassphrase123!',
|
|
376
|
+
planVersionId: 'free-v1'
|
|
377
|
+
});
|
|
378
|
+
core.updateAccountEntitlement({
|
|
379
|
+
accountId: created.userId,
|
|
298
380
|
planVersionId: 'free-v1',
|
|
381
|
+
entitlementState: 'canceled',
|
|
382
|
+
actorUserId: created.userId,
|
|
383
|
+
actorRole: 'user',
|
|
384
|
+
reason: 'legacy-free-v1-canceled'
|
|
385
|
+
});
|
|
386
|
+
expect(core.getAccountAccessStatus(created.userId)).toMatchObject({
|
|
387
|
+
gate: 'ok',
|
|
388
|
+
hasEntitlement: true,
|
|
389
|
+
canAccessApp: true,
|
|
390
|
+
entitlement: {
|
|
391
|
+
planVersionId: 'free-v2',
|
|
392
|
+
planId: 'free',
|
|
393
|
+
state: 'active'
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
expect(core.getAccountEntitlement(created.userId)).toMatchObject({
|
|
397
|
+
planVersionId: 'free-v2',
|
|
299
398
|
planId: 'free',
|
|
300
399
|
state: 'active'
|
|
301
400
|
});
|
|
@@ -305,6 +404,61 @@ describe('TaskforceCore system admin model', () => {
|
|
|
305
404
|
fs.rmSync(projectRoot, { recursive: true, force: true });
|
|
306
405
|
}
|
|
307
406
|
});
|
|
407
|
+
it('does not auto-heal canceled accounts already on the current default free version', () => {
|
|
408
|
+
const projectRoot = makeProjectRoot();
|
|
409
|
+
const core = openCore(projectRoot, { seedDefaultPlans: true });
|
|
410
|
+
try {
|
|
411
|
+
core.upsertPlanCatalog({ planId: 'free', displayName: 'Free', status: 'active' });
|
|
412
|
+
insertFreePriceMapping(core, 'free-v1');
|
|
413
|
+
core.createPlanVersion({
|
|
414
|
+
planId: 'free',
|
|
415
|
+
versionNumber: 2,
|
|
416
|
+
isDefault: true,
|
|
417
|
+
seatLimit: 1
|
|
418
|
+
});
|
|
419
|
+
insertFreePriceMapping(core, 'free-v2');
|
|
420
|
+
core.updateGlobalSettings({
|
|
421
|
+
billing: {
|
|
422
|
+
onboardingPolicy: {
|
|
423
|
+
mode: 'require_plan_selection',
|
|
424
|
+
planId: null
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
const created = core.registerPasswordUser({
|
|
429
|
+
email: 'current-default-free@example.com',
|
|
430
|
+
password: 'ValidPassphrase123!',
|
|
431
|
+
planVersionId: 'free-v2'
|
|
432
|
+
});
|
|
433
|
+
core.updateAccountEntitlement({
|
|
434
|
+
accountId: created.userId,
|
|
435
|
+
planVersionId: 'free-v2',
|
|
436
|
+
entitlementState: 'canceled',
|
|
437
|
+
actorUserId: created.userId,
|
|
438
|
+
actorRole: 'user',
|
|
439
|
+
reason: 'intentional-free-v2-cancel'
|
|
440
|
+
});
|
|
441
|
+
expect(core.getAccountAccessStatus(created.userId)).toMatchObject({
|
|
442
|
+
gate: 'missing_entitlement',
|
|
443
|
+
hasEntitlement: true,
|
|
444
|
+
canAccessApp: false,
|
|
445
|
+
entitlement: {
|
|
446
|
+
planVersionId: 'free-v2',
|
|
447
|
+
planId: 'free',
|
|
448
|
+
state: 'canceled'
|
|
449
|
+
}
|
|
450
|
+
});
|
|
451
|
+
expect(core.getAccountEntitlement(created.userId)).toMatchObject({
|
|
452
|
+
planVersionId: 'free-v2',
|
|
453
|
+
planId: 'free',
|
|
454
|
+
state: 'canceled'
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
finally {
|
|
458
|
+
core.close();
|
|
459
|
+
fs.rmSync(projectRoot, { recursive: true, force: true });
|
|
460
|
+
}
|
|
461
|
+
});
|
|
308
462
|
it('treats accounts without an entitlement or pending-selection marker as missing entitlement', () => {
|
|
309
463
|
const projectRoot = makeProjectRoot();
|
|
310
464
|
const core = openCore(projectRoot, { seedDefaultPlans: true });
|
|
@@ -313,16 +467,16 @@ describe('TaskforceCore system admin model', () => {
|
|
|
313
467
|
billing: {
|
|
314
468
|
onboardingPolicy: {
|
|
315
469
|
mode: 'require_plan_selection',
|
|
316
|
-
|
|
470
|
+
planId: null
|
|
317
471
|
}
|
|
318
472
|
}
|
|
319
473
|
});
|
|
320
474
|
const now = new Date().toISOString();
|
|
321
475
|
const db = core.db;
|
|
322
476
|
db.prepare(`
|
|
323
|
-
INSERT INTO users (id, tenant_id, email, display_name,
|
|
324
|
-
VALUES (?, ?, ?, ?,
|
|
325
|
-
`).run('user-missing-entitlement', 'default', 'broken@example.com', 'Broken',
|
|
477
|
+
INSERT INTO users (id, tenant_id, email, display_name, system_role, beta_access, is_disabled, created_at, updated_at)
|
|
478
|
+
VALUES (?, ?, ?, ?, 'user', 1, 0, ?, ?)
|
|
479
|
+
`).run('user-missing-entitlement', 'default', 'broken@example.com', 'Broken', now, now);
|
|
326
480
|
expect(core.getAccountAccessStatus('user-missing-entitlement')).toMatchObject({
|
|
327
481
|
gate: 'missing_entitlement',
|
|
328
482
|
hasEntitlement: false,
|
|
@@ -344,7 +498,7 @@ describe('TaskforceCore system admin model', () => {
|
|
|
344
498
|
UPDATE plan_versions
|
|
345
499
|
SET is_default = 0
|
|
346
500
|
WHERE tenant_id = ? AND plan_id = ?
|
|
347
|
-
`).run('default', '
|
|
501
|
+
`).run('default', 'free');
|
|
348
502
|
}
|
|
349
503
|
finally {
|
|
350
504
|
initial.close();
|
|
@@ -357,10 +511,10 @@ describe('TaskforceCore system admin model', () => {
|
|
|
357
511
|
FROM plan_versions
|
|
358
512
|
WHERE tenant_id = ? AND plan_id = ? AND plan_version_id = ?
|
|
359
513
|
LIMIT 1
|
|
360
|
-
`).get('default', '
|
|
361
|
-
expect(row?.plan_version_id).toBe('
|
|
514
|
+
`).get('default', 'free', 'free-v1');
|
|
515
|
+
expect(row?.plan_version_id).toBe('free-v1');
|
|
362
516
|
expect(row?.is_default).toBe(1);
|
|
363
|
-
expect(reopened.getRequiredDefaultPlanVersionId('
|
|
517
|
+
expect(reopened.getRequiredDefaultPlanVersionId('free')).toBe('free-v1');
|
|
364
518
|
}
|
|
365
519
|
finally {
|
|
366
520
|
reopened.close();
|
|
@@ -375,7 +529,7 @@ describe('TaskforceCore system admin model', () => {
|
|
|
375
529
|
billing: {
|
|
376
530
|
onboardingPolicy: {
|
|
377
531
|
mode: 'require_plan_selection',
|
|
378
|
-
|
|
532
|
+
planId: null
|
|
379
533
|
}
|
|
380
534
|
}
|
|
381
535
|
});
|
|
@@ -387,7 +541,7 @@ describe('TaskforceCore system admin model', () => {
|
|
|
387
541
|
try {
|
|
388
542
|
expect(reopened.getOnboardingPolicy()).toEqual({
|
|
389
543
|
mode: 'require_plan_selection',
|
|
390
|
-
|
|
544
|
+
planId: null
|
|
391
545
|
});
|
|
392
546
|
}
|
|
393
547
|
finally {
|
|
@@ -405,7 +559,7 @@ describe('TaskforceCore system admin model', () => {
|
|
|
405
559
|
UPDATE plan_versions
|
|
406
560
|
SET seat_limit = NULL, updated_at = ?
|
|
407
561
|
WHERE tenant_id = ? AND plan_version_id = ?
|
|
408
|
-
`).run(now, 'default', '
|
|
562
|
+
`).run(now, 'default', 'team-5-v1');
|
|
409
563
|
db.prepare(`
|
|
410
564
|
INSERT INTO plan_feature_matrix (tenant_id, plan_version_id, feature_key, access, config_json, created_at, updated_at)
|
|
411
565
|
VALUES (?, ?, 'collaboration.seat_limit', 'limited', ?, ?, ?)
|
|
@@ -413,14 +567,14 @@ describe('TaskforceCore system admin model', () => {
|
|
|
413
567
|
access = excluded.access,
|
|
414
568
|
config_json = excluded.config_json,
|
|
415
569
|
updated_at = excluded.updated_at
|
|
416
|
-
`).run('default', '
|
|
570
|
+
`).run('default', 'team-5-v1', JSON.stringify({ seat_limit: 7 }), now, now);
|
|
417
571
|
}
|
|
418
572
|
finally {
|
|
419
573
|
initial.close();
|
|
420
574
|
}
|
|
421
575
|
const reopened = openCore(projectRoot, { seedDefaultPlans: false });
|
|
422
576
|
try {
|
|
423
|
-
const version = reopened.getPlanVersionFeatures('
|
|
577
|
+
const version = reopened.getPlanVersionFeatures('team-5', 'team-5-v1');
|
|
424
578
|
expect(version.seatLimit).toBe(7);
|
|
425
579
|
expect(version.features['collaboration.seat_limit']?.config || {}).toEqual({});
|
|
426
580
|
}
|
|
@@ -436,7 +590,7 @@ describe('TaskforceCore system admin model', () => {
|
|
|
436
590
|
try {
|
|
437
591
|
const created = initial.registerPasswordUser({
|
|
438
592
|
email: 'legacy-billing@example.com',
|
|
439
|
-
password: '
|
|
593
|
+
password: 'ValidPassphrase123!'
|
|
440
594
|
});
|
|
441
595
|
legacyUserId = created.userId;
|
|
442
596
|
const db = initial.db;
|
|
@@ -453,13 +607,15 @@ describe('TaskforceCore system admin model', () => {
|
|
|
453
607
|
const reopened = openCore(projectRoot, { seedDefaultPlans: false });
|
|
454
608
|
try {
|
|
455
609
|
const db = reopened.db;
|
|
610
|
+
const normalizedPersonalVersionId = reopened.getDefaultPlanVersionIdByMode('personal');
|
|
611
|
+
const normalizedBillingMirror = reopened.getBillingMirrorProfileForPlanVersion(normalizedPersonalVersionId);
|
|
456
612
|
const row = db.prepare(`
|
|
457
613
|
SELECT tier, entitlement_state
|
|
458
614
|
FROM user_billing
|
|
459
615
|
WHERE tenant_id = ? AND user_id = ?
|
|
460
616
|
LIMIT 1
|
|
461
617
|
`).get('default', legacyUserId);
|
|
462
|
-
expect(row?.tier).toBe(
|
|
618
|
+
expect(row?.tier).toBe(normalizedBillingMirror.planId);
|
|
463
619
|
expect(row?.entitlement_state).toBe('active');
|
|
464
620
|
}
|
|
465
621
|
finally {
|
|
@@ -490,11 +646,11 @@ describe('TaskforceCore system admin model', () => {
|
|
|
490
646
|
db.prepare(`
|
|
491
647
|
INSERT INTO plan_catalog (plan_id, tenant_id, display_name, status, created_at, updated_at)
|
|
492
648
|
VALUES (?, ?, ?, 'active', ?, ?)
|
|
493
|
-
`).run('
|
|
649
|
+
`).run('agency', 'default', 'Agency', now, now);
|
|
494
650
|
db.prepare(`
|
|
495
651
|
INSERT INTO plan_versions (plan_version_id, tenant_id, plan_id, version_number, is_default, seat_limit, metadata_json, created_at, updated_at)
|
|
496
652
|
VALUES (?, ?, ?, 1, 1, 25, '{}', ?, ?)
|
|
497
|
-
`).run('
|
|
653
|
+
`).run('agency-v1', 'default', 'agency', now, now);
|
|
498
654
|
}
|
|
499
655
|
finally {
|
|
500
656
|
initial.close();
|
|
@@ -502,8 +658,8 @@ describe('TaskforceCore system admin model', () => {
|
|
|
502
658
|
const reopened = openCore(projectRoot, { seedDefaultPlans: false });
|
|
503
659
|
try {
|
|
504
660
|
const plans = reopened.listPlanCatalog();
|
|
505
|
-
expect(plans.map((plan) => plan.planId)).toEqual(['
|
|
506
|
-
expect(reopened.getDefaultPlanVersionIdByMode('personal')).toBe('
|
|
661
|
+
expect(plans.map((plan) => plan.planId)).toEqual(['agency']);
|
|
662
|
+
expect(reopened.getDefaultPlanVersionIdByMode('personal')).toBe('agency-v1');
|
|
507
663
|
}
|
|
508
664
|
finally {
|
|
509
665
|
reopened.close();
|
|
@@ -516,11 +672,11 @@ describe('TaskforceCore system admin model', () => {
|
|
|
516
672
|
try {
|
|
517
673
|
const first = core.registerPasswordUser({
|
|
518
674
|
email: 'first@example.com',
|
|
519
|
-
password: '
|
|
675
|
+
password: 'ValidPassphrase123!'
|
|
520
676
|
});
|
|
521
677
|
const second = core.registerPasswordUser({
|
|
522
678
|
email: 'second@example.com',
|
|
523
|
-
password: '
|
|
679
|
+
password: 'ValidPassphrase123!'
|
|
524
680
|
});
|
|
525
681
|
expect(core.getSystemRole(first.userId)).toBe('system_admin');
|
|
526
682
|
expect(core.getSystemRole(second.userId)).toBe('user');
|
|
@@ -538,11 +694,11 @@ describe('TaskforceCore system admin model', () => {
|
|
|
538
694
|
core.createWorkspace({ workspaceId: 'workspace-1', name: 'Workspace 1' });
|
|
539
695
|
core.registerPasswordUser({
|
|
540
696
|
email: 'bootstrap-admin@example.com',
|
|
541
|
-
password: '
|
|
697
|
+
password: 'ValidPassphrase123!'
|
|
542
698
|
});
|
|
543
699
|
const user = core.registerPasswordUser({
|
|
544
700
|
email: 'beta-off@example.com',
|
|
545
|
-
password: '
|
|
701
|
+
password: 'ValidPassphrase123!',
|
|
546
702
|
workspaceId: 'workspace-1',
|
|
547
703
|
role: 'owner',
|
|
548
704
|
betaAccess: false
|
|
@@ -562,7 +718,7 @@ describe('TaskforceCore system admin model', () => {
|
|
|
562
718
|
try {
|
|
563
719
|
const first = core.registerPasswordUser({
|
|
564
720
|
email: 'first@example.com',
|
|
565
|
-
password: '
|
|
721
|
+
password: 'ValidPassphrase123!'
|
|
566
722
|
});
|
|
567
723
|
expect(() => core.setSystemRole(first.userId, 'user')).toThrowError(/last system admin/i);
|
|
568
724
|
expect(() => core.setUserDisabledGlobal(first.userId, true)).toThrowError(/last system admin/i);
|
|
@@ -578,11 +734,11 @@ describe('TaskforceCore system admin model', () => {
|
|
|
578
734
|
try {
|
|
579
735
|
const first = core.registerPasswordUser({
|
|
580
736
|
email: 'first@example.com',
|
|
581
|
-
password: '
|
|
737
|
+
password: 'ValidPassphrase123!'
|
|
582
738
|
});
|
|
583
739
|
const second = core.registerPasswordUser({
|
|
584
740
|
email: 'second@example.com',
|
|
585
|
-
password: '
|
|
741
|
+
password: 'ValidPassphrase123!'
|
|
586
742
|
});
|
|
587
743
|
core.createWorkspace({ workspaceId: 'workspace-1', name: 'Workspace 1' });
|
|
588
744
|
core.ensureBootstrapUserAccess({
|
|
@@ -606,20 +762,20 @@ describe('TaskforceCore system admin model', () => {
|
|
|
606
762
|
try {
|
|
607
763
|
const admin = core.registerPasswordUser({
|
|
608
764
|
email: 'admin@example.com',
|
|
609
|
-
password: '
|
|
765
|
+
password: 'ValidPassphrase123!'
|
|
610
766
|
});
|
|
611
767
|
const member = core.registerPasswordUser({
|
|
612
768
|
email: 'member@example.com',
|
|
613
|
-
password: '
|
|
769
|
+
password: 'ValidPassphrase123!'
|
|
614
770
|
});
|
|
615
771
|
core.createPlanVersion({
|
|
616
|
-
planId: '
|
|
772
|
+
planId: 'free',
|
|
617
773
|
versionNumber: 2,
|
|
618
774
|
isDefault: true
|
|
619
775
|
});
|
|
620
776
|
core.updateAccountEntitlement({
|
|
621
777
|
accountId: member.userId,
|
|
622
|
-
planVersionId: '
|
|
778
|
+
planVersionId: 'free-v2',
|
|
623
779
|
entitlementState: 'active',
|
|
624
780
|
actorUserId: admin.userId,
|
|
625
781
|
actorRole: 'system_admin'
|
|
@@ -639,11 +795,11 @@ describe('TaskforceCore system admin model', () => {
|
|
|
639
795
|
try {
|
|
640
796
|
const admin = core.registerPasswordUser({
|
|
641
797
|
email: 'admin@example.com',
|
|
642
|
-
password: '
|
|
798
|
+
password: 'ValidPassphrase123!'
|
|
643
799
|
});
|
|
644
800
|
const member = core.registerPasswordUser({
|
|
645
801
|
email: 'member@example.com',
|
|
646
|
-
password: '
|
|
802
|
+
password: 'ValidPassphrase123!'
|
|
647
803
|
});
|
|
648
804
|
const workspaceId = member.workspaceId || 'default';
|
|
649
805
|
const db = core.db;
|
|
@@ -721,11 +877,11 @@ describe('TaskforceCore system admin model', () => {
|
|
|
721
877
|
try {
|
|
722
878
|
const admin = core.registerPasswordUser({
|
|
723
879
|
email: 'admin@example.com',
|
|
724
|
-
password: '
|
|
880
|
+
password: 'ValidPassphrase123!'
|
|
725
881
|
});
|
|
726
882
|
const member = core.registerPasswordUser({
|
|
727
883
|
email: 'member@example.com',
|
|
728
|
-
password: '
|
|
884
|
+
password: 'ValidPassphrase123!'
|
|
729
885
|
});
|
|
730
886
|
const db = core.db;
|
|
731
887
|
const now = new Date().toISOString();
|
|
@@ -741,7 +897,7 @@ describe('TaskforceCore system admin model', () => {
|
|
|
741
897
|
ON CONFLICT (user_id) DO UPDATE SET
|
|
742
898
|
stripe_customer_id = excluded.stripe_customer_id,
|
|
743
899
|
updated_at = excluded.updated_at
|
|
744
|
-
`).run(member.userId, 'default', 'cus_test_123', 'active', '
|
|
900
|
+
`).run(member.userId, 'default', 'cus_test_123', 'active', 'basic', now, now);
|
|
745
901
|
expect(() => core.purgeSystemUser({
|
|
746
902
|
targetUserId: member.userId,
|
|
747
903
|
actorUserId: admin.userId,
|
|
@@ -758,16 +914,16 @@ describe('TaskforceCore system admin model', () => {
|
|
|
758
914
|
const core = openCore(projectRoot, { seedDefaultPlans: true });
|
|
759
915
|
try {
|
|
760
916
|
const plan = core.upsertPlanCatalog({
|
|
761
|
-
planId: '
|
|
762
|
-
displayName: '
|
|
917
|
+
planId: 'agency',
|
|
918
|
+
displayName: 'Agency',
|
|
763
919
|
status: 'active'
|
|
764
920
|
});
|
|
765
|
-
expect(plan.planId).toBe('
|
|
766
|
-
const versions = core.listPlanVersions('
|
|
921
|
+
expect(plan.planId).toBe('agency');
|
|
922
|
+
const versions = core.listPlanVersions('agency');
|
|
767
923
|
expect(versions).toHaveLength(1);
|
|
768
924
|
expect(versions[0]).toMatchObject({
|
|
769
|
-
planVersionId: '
|
|
770
|
-
planId: '
|
|
925
|
+
planVersionId: 'agency-v1',
|
|
926
|
+
planId: 'agency',
|
|
771
927
|
versionNumber: 1,
|
|
772
928
|
isDefault: true,
|
|
773
929
|
seatLimit: null
|
|
@@ -783,24 +939,24 @@ describe('TaskforceCore system admin model', () => {
|
|
|
783
939
|
const core = openCore(projectRoot, { seedDefaultPlans: true });
|
|
784
940
|
try {
|
|
785
941
|
core.upsertPlanCatalog({
|
|
786
|
-
planId: '
|
|
787
|
-
displayName: '
|
|
942
|
+
planId: 'agency',
|
|
943
|
+
displayName: 'Agency',
|
|
788
944
|
status: 'active'
|
|
789
945
|
});
|
|
790
946
|
core.createPlanVersion({
|
|
791
|
-
planId: '
|
|
947
|
+
planId: 'agency',
|
|
792
948
|
versionNumber: 2,
|
|
793
949
|
isDefault: true,
|
|
794
950
|
seatLimit: 25
|
|
795
951
|
});
|
|
796
952
|
core.upsertPlanCatalog({
|
|
797
|
-
planId: '
|
|
798
|
-
displayName: '
|
|
953
|
+
planId: 'agency',
|
|
954
|
+
displayName: 'Agency Plus',
|
|
799
955
|
status: 'archived'
|
|
800
956
|
});
|
|
801
|
-
const versions = core.listPlanVersions('
|
|
802
|
-
expect(versions.map((version) => version.planVersionId)).toEqual(['
|
|
803
|
-
expect(versions.find((version) => version.planVersionId === '
|
|
957
|
+
const versions = core.listPlanVersions('agency');
|
|
958
|
+
expect(versions.map((version) => version.planVersionId)).toEqual(['agency-v2', 'agency-v1']);
|
|
959
|
+
expect(versions.find((version) => version.planVersionId === 'agency-v1')).toMatchObject({
|
|
804
960
|
isDefault: false
|
|
805
961
|
});
|
|
806
962
|
}
|
|
@@ -938,7 +1094,7 @@ describe('TaskforceCore system admin model', () => {
|
|
|
938
1094
|
try {
|
|
939
1095
|
const created = core.registerPasswordUser({
|
|
940
1096
|
email: 'nomembership@example.com',
|
|
941
|
-
password: '
|
|
1097
|
+
password: 'ValidPassphrase123!'
|
|
942
1098
|
});
|
|
943
1099
|
expect(core.resolvePreferredUserWorkspaceId(created.userId)).toBeNull();
|
|
944
1100
|
}
|