@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
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
2
|
import { buildWorkspaceSyncPayloadModel, buildWorkspaceSyncSignatureModel } from './workspaceSyncModel';
|
|
3
|
+
import { aiProfileSyncResourceAdapter, taskSyncResourceAdapter } from './syncResourceAdapters';
|
|
3
4
|
describe('workspaceSyncModel', () => {
|
|
4
5
|
describe('buildWorkspaceSyncPayloadModel', () => {
|
|
5
6
|
it('emits document-delete when a previously pushed document path is now missing', () => {
|
|
@@ -20,6 +21,28 @@ describe('workspaceSyncModel', () => {
|
|
|
20
21
|
expect.objectContaining({ op: 'document-delete', path: 'docs/remove.md' })
|
|
21
22
|
]));
|
|
22
23
|
});
|
|
24
|
+
it('does not emit document-delete when a canonical path is still known but missing from the readable snapshot', () => {
|
|
25
|
+
const payload = buildWorkspaceSyncPayloadModel({
|
|
26
|
+
tasks: [],
|
|
27
|
+
archivedTasks: [],
|
|
28
|
+
lastPushedTaskIds: new Set(),
|
|
29
|
+
pendingDeletedTaskIds: new Set(),
|
|
30
|
+
documents: [
|
|
31
|
+
{ path: 'docs/keep.md', updatedAt: '2026-02-01T00:00:00.000Z', content: 'keep' }
|
|
32
|
+
],
|
|
33
|
+
currentDocumentPaths: new Set(['docs/keep.md', 'docs/missing-content.md']),
|
|
34
|
+
lastPushedDocumentPaths: new Set(['docs/keep.md', 'docs/missing-content.md', 'docs/remove.md'])
|
|
35
|
+
});
|
|
36
|
+
expect(Array.from(payload.currentDocumentPaths).sort()).toEqual(['docs/keep.md', 'docs/missing-content.md']);
|
|
37
|
+
expect(Array.from(payload.deleteDocumentPaths).sort()).toEqual(['docs/remove.md']);
|
|
38
|
+
expect(payload.changes).toEqual(expect.arrayContaining([
|
|
39
|
+
expect.objectContaining({ op: 'document-upsert', path: 'docs/keep.md' }),
|
|
40
|
+
expect.objectContaining({ op: 'document-delete', path: 'docs/remove.md' })
|
|
41
|
+
]));
|
|
42
|
+
expect(payload.changes).not.toEqual(expect.arrayContaining([
|
|
43
|
+
expect.objectContaining({ op: 'document-delete', path: 'docs/missing-content.md' })
|
|
44
|
+
]));
|
|
45
|
+
});
|
|
23
46
|
it('emits task-event-upsert changes for new activity events and tracks event watermarks', () => {
|
|
24
47
|
const payload = buildWorkspaceSyncPayloadModel({
|
|
25
48
|
tasks: [],
|
|
@@ -124,6 +147,32 @@ describe('workspaceSyncModel', () => {
|
|
|
124
147
|
['docs/new.md', '2026-02-03T00:00:00.000Z']
|
|
125
148
|
]);
|
|
126
149
|
});
|
|
150
|
+
it('reports send-all diagnostics when a domain has no baseline', () => {
|
|
151
|
+
const payload = buildWorkspaceSyncPayloadModel({
|
|
152
|
+
tasks: [],
|
|
153
|
+
archivedTasks: [],
|
|
154
|
+
lastPushedTaskIds: new Set(),
|
|
155
|
+
pendingDeletedTaskIds: new Set(),
|
|
156
|
+
documents: [
|
|
157
|
+
{ path: 'docs/a.md', updatedAt: '2026-02-01T00:00:00.000Z', content: 'a' },
|
|
158
|
+
{ path: 'docs/b.md', updatedAt: '2026-02-02T00:00:00.000Z', content: 'b' }
|
|
159
|
+
],
|
|
160
|
+
baselineResetReason: 'repair-reset'
|
|
161
|
+
});
|
|
162
|
+
expect(payload.deltaDiagnostics).toEqual(expect.objectContaining({
|
|
163
|
+
totalChanges: 2,
|
|
164
|
+
domains: expect.objectContaining({
|
|
165
|
+
documents: expect.objectContaining({
|
|
166
|
+
mode: 'send-all',
|
|
167
|
+
reason: 'repair-reset',
|
|
168
|
+
currentCount: 2,
|
|
169
|
+
baselineCount: 0,
|
|
170
|
+
changeCount: 2
|
|
171
|
+
})
|
|
172
|
+
})
|
|
173
|
+
}));
|
|
174
|
+
expect(payload.deltaDiagnostics?.byOp['document-upsert']).toBe(2);
|
|
175
|
+
});
|
|
127
176
|
it('preserves canonical document metadata on document-upsert changes', () => {
|
|
128
177
|
const payload = buildWorkspaceSyncPayloadModel({
|
|
129
178
|
tasks: [],
|
|
@@ -196,6 +245,81 @@ describe('workspaceSyncModel', () => {
|
|
|
196
245
|
})
|
|
197
246
|
]));
|
|
198
247
|
});
|
|
248
|
+
it('does not emit asset-delete when a canonical asset path is still known but missing from the readable snapshot', () => {
|
|
249
|
+
const payload = buildWorkspaceSyncPayloadModel({
|
|
250
|
+
tasks: [],
|
|
251
|
+
archivedTasks: [],
|
|
252
|
+
lastPushedTaskIds: new Set(),
|
|
253
|
+
pendingDeletedTaskIds: new Set(),
|
|
254
|
+
assets: [
|
|
255
|
+
{
|
|
256
|
+
path: 'workspaces/default/assets/images/asset-image-1-diagram.png',
|
|
257
|
+
updatedAt: '2026-03-17T12:00:00.000Z',
|
|
258
|
+
contentBase64: 'aW1hZ2UtYnl0ZXM=',
|
|
259
|
+
assetId: 'asset-image-1',
|
|
260
|
+
kind: 'image',
|
|
261
|
+
mimeType: 'image/png',
|
|
262
|
+
taskId: 'task-1',
|
|
263
|
+
originalFilename: 'diagram.png',
|
|
264
|
+
linkRole: 'image'
|
|
265
|
+
}
|
|
266
|
+
],
|
|
267
|
+
currentAssetPaths: new Set([
|
|
268
|
+
'workspaces/default/assets/images/asset-image-1-diagram.png',
|
|
269
|
+
'workspaces/default/assets/files/asset-file-missing.pdf'
|
|
270
|
+
]),
|
|
271
|
+
lastPushedAssetPaths: new Set([
|
|
272
|
+
'workspaces/default/assets/images/asset-image-1-diagram.png',
|
|
273
|
+
'workspaces/default/assets/files/asset-file-missing.pdf',
|
|
274
|
+
'workspaces/default/assets/files/asset-file-old-document.pdf'
|
|
275
|
+
])
|
|
276
|
+
});
|
|
277
|
+
expect(Array.from(payload.currentAssetPaths).sort()).toEqual([
|
|
278
|
+
'workspaces/default/assets/files/asset-file-missing.pdf',
|
|
279
|
+
'workspaces/default/assets/images/asset-image-1-diagram.png'
|
|
280
|
+
]);
|
|
281
|
+
expect(Array.from(payload.deleteAssetPaths)).toEqual(['workspaces/default/assets/files/asset-file-old-document.pdf']);
|
|
282
|
+
expect(payload.changes).not.toEqual(expect.arrayContaining([
|
|
283
|
+
expect.objectContaining({
|
|
284
|
+
op: 'asset-delete',
|
|
285
|
+
path: 'workspaces/default/assets/files/asset-file-missing.pdf'
|
|
286
|
+
})
|
|
287
|
+
]));
|
|
288
|
+
});
|
|
289
|
+
it('emits timestamped task deletes for previously pushed tasks that are now missing', () => {
|
|
290
|
+
const payload = buildWorkspaceSyncPayloadModel({
|
|
291
|
+
tasks: [],
|
|
292
|
+
archivedTasks: [],
|
|
293
|
+
lastPushedTaskIds: new Set(['task-delete-1']),
|
|
294
|
+
pendingDeletedTaskIds: new Set()
|
|
295
|
+
});
|
|
296
|
+
expect(payload.deleteTaskIds).toEqual(new Set(['task-delete-1']));
|
|
297
|
+
expect(payload.changes).toEqual(expect.arrayContaining([
|
|
298
|
+
expect.objectContaining({
|
|
299
|
+
op: 'delete',
|
|
300
|
+
taskId: 'task-delete-1',
|
|
301
|
+
deletedAt: expect.any(String)
|
|
302
|
+
})
|
|
303
|
+
]));
|
|
304
|
+
});
|
|
305
|
+
it('preserves stored task delete watermarks on pending delete changes', () => {
|
|
306
|
+
const payload = buildWorkspaceSyncPayloadModel({
|
|
307
|
+
tasks: [],
|
|
308
|
+
archivedTasks: [],
|
|
309
|
+
lastPushedTaskIds: new Set(),
|
|
310
|
+
pendingDeletedTaskIds: new Set(['task-delete-2']),
|
|
311
|
+
pendingDeletedTaskWatermarks: new Map([
|
|
312
|
+
['task-delete-2', '2026-04-10T11:00:00.000Z']
|
|
313
|
+
])
|
|
314
|
+
});
|
|
315
|
+
expect(payload.changes).toEqual(expect.arrayContaining([
|
|
316
|
+
expect.objectContaining({
|
|
317
|
+
op: 'delete',
|
|
318
|
+
taskId: 'task-delete-2',
|
|
319
|
+
deletedAt: '2026-04-10T11:00:00.000Z'
|
|
320
|
+
})
|
|
321
|
+
]));
|
|
322
|
+
});
|
|
199
323
|
it('orders task upserts deterministically by task id', () => {
|
|
200
324
|
const payload = buildWorkspaceSyncPayloadModel({
|
|
201
325
|
tasks: [
|
|
@@ -243,6 +367,7 @@ describe('workspaceSyncModel', () => {
|
|
|
243
367
|
provider: 'OpenAI',
|
|
244
368
|
model: 'gpt-5.4',
|
|
245
369
|
surfaceType: 'coding_tool',
|
|
370
|
+
rosterStateUpdatedAt: '2026-03-22T10:00:00.000Z',
|
|
246
371
|
createdAt: '2026-03-22T10:00:00.000Z',
|
|
247
372
|
updatedAt: '2026-03-22T10:05:00.000Z',
|
|
248
373
|
lastActiveAt: '2026-03-22T10:05:00.000Z'
|
|
@@ -259,14 +384,49 @@ describe('workspaceSyncModel', () => {
|
|
|
259
384
|
role: 'Implementer',
|
|
260
385
|
provider: 'OpenAI',
|
|
261
386
|
model: 'gpt-5.4',
|
|
262
|
-
surfaceType: 'coding_tool'
|
|
387
|
+
surfaceType: 'coding_tool',
|
|
388
|
+
rosterStateUpdatedAt: '2026-03-22T10:00:00.000Z'
|
|
263
389
|
})
|
|
264
390
|
})
|
|
265
391
|
]));
|
|
266
392
|
expect(Array.from(payload.currentAiProfileIds)).toEqual(['ai-profile-1']);
|
|
267
393
|
expect(payload.currentAiProfileWatermarks.get('ai-profile-1')).toBe('2026-03-22T10:05:00.000Z');
|
|
268
394
|
});
|
|
269
|
-
it('filters unchanged ai profiles when ai
|
|
395
|
+
it('filters unchanged ai profiles when ai change-key state already matches', () => {
|
|
396
|
+
const profile = {
|
|
397
|
+
id: 'ai-profile-1',
|
|
398
|
+
workspaceId: 'ws-1',
|
|
399
|
+
profileToken: 'tfp_test',
|
|
400
|
+
name: 'Codex',
|
|
401
|
+
username: 'codex',
|
|
402
|
+
icon: 'Bot',
|
|
403
|
+
color: '#0ea5e9',
|
|
404
|
+
description: 'Terminal-first coding agent',
|
|
405
|
+
role: 'Implementer',
|
|
406
|
+
provider: 'OpenAI',
|
|
407
|
+
model: 'gpt-5.4',
|
|
408
|
+
surfaceType: 'coding_tool',
|
|
409
|
+
rosterStateUpdatedAt: '2026-03-22T10:00:00.000Z',
|
|
410
|
+
createdAt: '2026-03-22T10:00:00.000Z',
|
|
411
|
+
updatedAt: '2026-03-22T10:05:00.000Z',
|
|
412
|
+
lastActiveAt: '2026-03-22T10:05:00.000Z'
|
|
413
|
+
};
|
|
414
|
+
const payload = buildWorkspaceSyncPayloadModel({
|
|
415
|
+
tasks: [],
|
|
416
|
+
archivedTasks: [],
|
|
417
|
+
lastPushedTaskIds: new Set(),
|
|
418
|
+
pendingDeletedTaskIds: new Set(),
|
|
419
|
+
aiProfiles: [profile],
|
|
420
|
+
lastPushedAiProfileIds: new Set(['ai-profile-1']),
|
|
421
|
+
lastPushedAiProfileWatermarks: new Map([['ai-profile-1', '2026-03-22T10:05:00.000Z']]),
|
|
422
|
+
lastPushedAiProfileChangeKeys: new Map([
|
|
423
|
+
['ai-profile-1', aiProfileSyncResourceAdapter.getChangeKey(profile)]
|
|
424
|
+
])
|
|
425
|
+
});
|
|
426
|
+
expect(payload.changes.some((change) => change.op === 'ai-profile-upsert')).toBe(false);
|
|
427
|
+
expect(Array.from(payload.currentAiProfileIds)).toEqual(['ai-profile-1']);
|
|
428
|
+
});
|
|
429
|
+
it('resends ai profiles when a legacy watermark did not include avatar fields', () => {
|
|
270
430
|
const payload = buildWorkspaceSyncPayloadModel({
|
|
271
431
|
tasks: [],
|
|
272
432
|
archivedTasks: [],
|
|
@@ -281,11 +441,14 @@ describe('workspaceSyncModel', () => {
|
|
|
281
441
|
username: 'codex',
|
|
282
442
|
icon: 'Bot',
|
|
283
443
|
color: '#0ea5e9',
|
|
444
|
+
avatarUrl: '/api/taskforce/context/workspaces%2Fws-1%2Fassets%2Fimages%2Fai-profiles%2Fai-profile-1%2Favatar%2Favatar.webp',
|
|
445
|
+
avatarSourceUrl: '/api/taskforce/context/workspaces%2Fws-1%2Fassets%2Fimages%2Fai-profiles%2Fai-profile-1%2Favatar%2Fsource.webp',
|
|
284
446
|
description: 'Terminal-first coding agent',
|
|
285
447
|
role: 'Implementer',
|
|
286
448
|
provider: 'OpenAI',
|
|
287
449
|
model: 'gpt-5.4',
|
|
288
450
|
surfaceType: 'coding_tool',
|
|
451
|
+
rosterStateUpdatedAt: '2026-03-22T10:00:00.000Z',
|
|
289
452
|
createdAt: '2026-03-22T10:00:00.000Z',
|
|
290
453
|
updatedAt: '2026-03-22T10:05:00.000Z',
|
|
291
454
|
lastActiveAt: '2026-03-22T10:05:00.000Z'
|
|
@@ -294,8 +457,82 @@ describe('workspaceSyncModel', () => {
|
|
|
294
457
|
lastPushedAiProfileIds: new Set(['ai-profile-1']),
|
|
295
458
|
lastPushedAiProfileWatermarks: new Map([['ai-profile-1', '2026-03-22T10:05:00.000Z']])
|
|
296
459
|
});
|
|
297
|
-
expect(payload.changes.
|
|
298
|
-
|
|
460
|
+
expect(payload.changes).toEqual(expect.arrayContaining([
|
|
461
|
+
expect.objectContaining({
|
|
462
|
+
op: 'ai-profile-upsert',
|
|
463
|
+
profile: expect.objectContaining({
|
|
464
|
+
id: 'ai-profile-1',
|
|
465
|
+
avatarUrl: expect.stringContaining('/api/taskforce/context/'),
|
|
466
|
+
avatarSourceUrl: expect.stringContaining('/api/taskforce/context/')
|
|
467
|
+
})
|
|
468
|
+
})
|
|
469
|
+
]));
|
|
470
|
+
expect(payload.currentAiProfileWatermarks.get('ai-profile-1')).toBe('2026-03-22T10:05:00.000Z');
|
|
471
|
+
expect(payload.currentAiProfileChangeKeys?.get('ai-profile-1')).toBe(aiProfileSyncResourceAdapter.getChangeKey({
|
|
472
|
+
id: 'ai-profile-1',
|
|
473
|
+
workspaceId: 'ws-1',
|
|
474
|
+
profileToken: 'tfp_test',
|
|
475
|
+
name: 'Codex',
|
|
476
|
+
username: 'codex',
|
|
477
|
+
icon: 'Bot',
|
|
478
|
+
color: '#0ea5e9',
|
|
479
|
+
avatarUrl: '/api/taskforce/context/workspaces%2Fws-1%2Fassets%2Fimages%2Fai-profiles%2Fai-profile-1%2Favatar%2Favatar.webp',
|
|
480
|
+
avatarSourceUrl: '/api/taskforce/context/workspaces%2Fws-1%2Fassets%2Fimages%2Fai-profiles%2Fai-profile-1%2Favatar%2Fsource.webp',
|
|
481
|
+
description: 'Terminal-first coding agent',
|
|
482
|
+
role: 'Implementer',
|
|
483
|
+
provider: 'OpenAI',
|
|
484
|
+
model: 'gpt-5.4',
|
|
485
|
+
surfaceType: 'coding_tool',
|
|
486
|
+
rosterStateUpdatedAt: '2026-03-22T10:00:00.000Z',
|
|
487
|
+
createdAt: '2026-03-22T10:00:00.000Z',
|
|
488
|
+
updatedAt: '2026-03-22T10:05:00.000Z',
|
|
489
|
+
lastActiveAt: '2026-03-22T10:05:00.000Z'
|
|
490
|
+
}));
|
|
491
|
+
});
|
|
492
|
+
it('resends ai profiles when lifecycle state advances beyond metadata updatedAt', () => {
|
|
493
|
+
const payload = buildWorkspaceSyncPayloadModel({
|
|
494
|
+
tasks: [],
|
|
495
|
+
archivedTasks: [],
|
|
496
|
+
lastPushedTaskIds: new Set(),
|
|
497
|
+
pendingDeletedTaskIds: new Set(),
|
|
498
|
+
aiProfiles: [
|
|
499
|
+
{
|
|
500
|
+
id: 'ai-profile-1',
|
|
501
|
+
workspaceId: 'ws-1',
|
|
502
|
+
profileToken: 'tfp_test',
|
|
503
|
+
name: 'Codex',
|
|
504
|
+
username: 'codex',
|
|
505
|
+
icon: 'Bot',
|
|
506
|
+
color: '#0ea5e9',
|
|
507
|
+
description: 'Terminal-first coding agent',
|
|
508
|
+
role: 'Implementer',
|
|
509
|
+
provider: 'OpenAI',
|
|
510
|
+
model: 'gpt-5.4',
|
|
511
|
+
surfaceType: 'coding_tool',
|
|
512
|
+
archivedAt: '2026-03-22T10:10:00.000Z',
|
|
513
|
+
archivedBy: 'owner-1',
|
|
514
|
+
archivedReason: 'manual_archive',
|
|
515
|
+
rosterStateUpdatedAt: '2026-03-22T10:10:00.000Z',
|
|
516
|
+
createdAt: '2026-03-22T10:00:00.000Z',
|
|
517
|
+
updatedAt: '2026-03-22T10:05:00.000Z',
|
|
518
|
+
lastActiveAt: '2026-03-22T10:05:00.000Z'
|
|
519
|
+
}
|
|
520
|
+
],
|
|
521
|
+
lastPushedAiProfileIds: new Set(['ai-profile-1']),
|
|
522
|
+
lastPushedAiProfileWatermarks: new Map([['ai-profile-1', '2026-03-22T10:05:00.000Z']])
|
|
523
|
+
});
|
|
524
|
+
expect(payload.changes).toEqual(expect.arrayContaining([
|
|
525
|
+
expect.objectContaining({
|
|
526
|
+
op: 'ai-profile-upsert',
|
|
527
|
+
profile: expect.objectContaining({
|
|
528
|
+
id: 'ai-profile-1',
|
|
529
|
+
archivedAt: '2026-03-22T10:10:00.000Z',
|
|
530
|
+
rosterStateUpdatedAt: '2026-03-22T10:10:00.000Z',
|
|
531
|
+
updatedAt: '2026-03-22T10:05:00.000Z'
|
|
532
|
+
})
|
|
533
|
+
})
|
|
534
|
+
]));
|
|
535
|
+
expect(payload.currentAiProfileWatermarks.get('ai-profile-1')).toBe('2026-03-22T10:10:00.000Z');
|
|
299
536
|
});
|
|
300
537
|
it('emits initiative and workstream upserts and tracks their watermarks', () => {
|
|
301
538
|
const payload = buildWorkspaceSyncPayloadModel({
|
|
@@ -802,15 +1039,16 @@ describe('workspaceSyncModel', () => {
|
|
|
802
1039
|
});
|
|
803
1040
|
});
|
|
804
1041
|
describe('dirty task watermarks', () => {
|
|
805
|
-
it('
|
|
1042
|
+
it('resends once when a legacy watermark-only task baseline exists', () => {
|
|
1043
|
+
const task = {
|
|
1044
|
+
id: 'task-1',
|
|
1045
|
+
title: 'Task 1',
|
|
1046
|
+
status: 'in-progress',
|
|
1047
|
+
createdAt: '2026-03-16T10:00:00.000Z',
|
|
1048
|
+
updatedAt: '2026-03-16T10:05:00.000Z'
|
|
1049
|
+
};
|
|
806
1050
|
const payload = buildWorkspaceSyncPayloadModel({
|
|
807
|
-
tasks: [
|
|
808
|
-
id: 'task-1',
|
|
809
|
-
title: 'Task 1',
|
|
810
|
-
status: 'in-progress',
|
|
811
|
-
createdAt: '2026-03-16T10:00:00.000Z',
|
|
812
|
-
updatedAt: '2026-03-16T10:05:00.000Z'
|
|
813
|
-
}],
|
|
1051
|
+
tasks: [task],
|
|
814
1052
|
archivedTasks: [],
|
|
815
1053
|
lastPushedTaskIds: new Set(['task-1']),
|
|
816
1054
|
pendingDeletedTaskIds: new Set(),
|
|
@@ -829,6 +1067,81 @@ describe('workspaceSyncModel', () => {
|
|
|
829
1067
|
})
|
|
830
1068
|
]));
|
|
831
1069
|
expect(payload.pushedWatermarks.get('task-1')).toBe('2026-03-16T10:05:00.000Z');
|
|
1070
|
+
expect(payload.pushedTaskChangeKeys.get('task-1')).toBe(taskSyncResourceAdapter.getChangeKey({ ...task, isArchived: false }));
|
|
1071
|
+
});
|
|
1072
|
+
it('does not resend a task when only updatedAt changes but the replicated change key matches', () => {
|
|
1073
|
+
const task = {
|
|
1074
|
+
id: 'task-1',
|
|
1075
|
+
title: 'Task 1',
|
|
1076
|
+
status: 'in-progress',
|
|
1077
|
+
createdAt: '2026-03-16T10:00:00.000Z',
|
|
1078
|
+
updatedAt: '2026-03-16T10:05:00.000Z'
|
|
1079
|
+
};
|
|
1080
|
+
const payload = buildWorkspaceSyncPayloadModel({
|
|
1081
|
+
tasks: [task],
|
|
1082
|
+
archivedTasks: [],
|
|
1083
|
+
lastPushedTaskIds: new Set(['task-1']),
|
|
1084
|
+
pendingDeletedTaskIds: new Set(),
|
|
1085
|
+
lastPushedWatermarks: new Map([
|
|
1086
|
+
['task-1', '2026-03-16T10:00:00.000Z']
|
|
1087
|
+
]),
|
|
1088
|
+
lastPushedTaskChangeKeys: new Map([
|
|
1089
|
+
['task-1', taskSyncResourceAdapter.getChangeKey({ ...task, isArchived: false })]
|
|
1090
|
+
])
|
|
1091
|
+
});
|
|
1092
|
+
expect(payload.changes.some((change) => change.op === 'upsert' && change.task.id === 'task-1')).toBe(false);
|
|
1093
|
+
expect(payload.currentTaskWatermarks.get('task-1')).toBe('2026-03-16T10:05:00.000Z');
|
|
1094
|
+
});
|
|
1095
|
+
it('treats comment and attachment changes as replicated task-state changes', () => {
|
|
1096
|
+
const task = {
|
|
1097
|
+
id: 'task-1',
|
|
1098
|
+
title: 'Task 1',
|
|
1099
|
+
status: 'task',
|
|
1100
|
+
createdAt: '2026-03-16T10:00:00.000Z',
|
|
1101
|
+
updatedAt: '2026-03-16T10:05:00.000Z',
|
|
1102
|
+
comments: [{
|
|
1103
|
+
id: 'comment-1',
|
|
1104
|
+
author: 'ai-profile-1',
|
|
1105
|
+
text: 'Shipped',
|
|
1106
|
+
timestamp: '2026-03-16T10:05:00.000Z'
|
|
1107
|
+
}],
|
|
1108
|
+
attachments: [{
|
|
1109
|
+
path: 'workspaces/ws-1/assets/files/asset-1.txt',
|
|
1110
|
+
caption: 'Spec',
|
|
1111
|
+
timestamp: '2026-03-16T10:05:00.000Z'
|
|
1112
|
+
}]
|
|
1113
|
+
};
|
|
1114
|
+
const previousTask = {
|
|
1115
|
+
...task,
|
|
1116
|
+
comments: [],
|
|
1117
|
+
attachments: []
|
|
1118
|
+
};
|
|
1119
|
+
const payload = buildWorkspaceSyncPayloadModel({
|
|
1120
|
+
tasks: [task],
|
|
1121
|
+
archivedTasks: [],
|
|
1122
|
+
lastPushedTaskIds: new Set(['task-1']),
|
|
1123
|
+
pendingDeletedTaskIds: new Set(),
|
|
1124
|
+
lastPushedWatermarks: new Map([
|
|
1125
|
+
['task-1', '2026-03-16T10:05:00.000Z']
|
|
1126
|
+
]),
|
|
1127
|
+
lastPushedTaskChangeKeys: new Map([
|
|
1128
|
+
['task-1', taskSyncResourceAdapter.getChangeKey({ ...previousTask, isArchived: false })]
|
|
1129
|
+
])
|
|
1130
|
+
});
|
|
1131
|
+
expect(payload.changes).toEqual(expect.arrayContaining([
|
|
1132
|
+
expect.objectContaining({
|
|
1133
|
+
op: 'upsert',
|
|
1134
|
+
task: expect.objectContaining({
|
|
1135
|
+
id: 'task-1',
|
|
1136
|
+
comments: expect.arrayContaining([
|
|
1137
|
+
expect.objectContaining({ id: 'comment-1' })
|
|
1138
|
+
]),
|
|
1139
|
+
attachments: expect.arrayContaining([
|
|
1140
|
+
expect.objectContaining({ path: 'workspaces/ws-1/assets/files/asset-1.txt' })
|
|
1141
|
+
])
|
|
1142
|
+
})
|
|
1143
|
+
})
|
|
1144
|
+
]));
|
|
832
1145
|
});
|
|
833
1146
|
it('keeps provisional local-reference tasks dirty until a canonical reference is assigned', () => {
|
|
834
1147
|
const payload = buildWorkspaceSyncPayloadModel({
|
|
@@ -1,12 +1,31 @@
|
|
|
1
1
|
export type WorkspaceSyncPhase = 'idle' | 'provision-local' | 'attach-cloud' | 'active' | 'error';
|
|
2
|
+
export type WorkspaceSyncSetupIntent = 'attach-cloud-import' | null;
|
|
3
|
+
export interface WorkspaceSyncPushBaselineSnapshot {
|
|
4
|
+
taskIds?: string[];
|
|
5
|
+
taskWatermarks: Array<[string, string]>;
|
|
6
|
+
taskChangeKeys?: Array<[string, string]>;
|
|
7
|
+
initiativeWatermarks: Array<[string, string]>;
|
|
8
|
+
workstreamWatermarks: Array<[string, string]>;
|
|
9
|
+
aiProfileWatermarks: Array<[string, string]>;
|
|
10
|
+
aiProfileChangeKeys?: Array<[string, string]>;
|
|
11
|
+
documentWatermarks: Array<[string, string]>;
|
|
12
|
+
assetWatermarks: Array<[string, string]>;
|
|
13
|
+
documentReviewSessionWatermarks: Array<[string, string]>;
|
|
14
|
+
documentReviewCommentWatermarks: Array<[string, string]>;
|
|
15
|
+
annotatedAttachmentSessionWatermarks: Array<[string, string]>;
|
|
16
|
+
taskEventWatermarks: Array<[string, string]>;
|
|
17
|
+
taxonomyStateFingerprint: string;
|
|
18
|
+
}
|
|
2
19
|
export interface WorkspaceSyncStateV2 {
|
|
3
20
|
version: 2;
|
|
4
21
|
enabled: boolean;
|
|
5
22
|
phase: WorkspaceSyncPhase;
|
|
23
|
+
setupIntent?: WorkspaceSyncSetupIntent;
|
|
6
24
|
pullCursor: string | null;
|
|
7
25
|
lastPullAt: string | null;
|
|
8
26
|
lastPushAt: string | null;
|
|
9
27
|
lastSyncedAt: string | null;
|
|
10
28
|
lastErrorMessage: string | null;
|
|
29
|
+
pushBaseline?: WorkspaceSyncPushBaselineSnapshot | null;
|
|
11
30
|
}
|
|
12
31
|
export declare function createDefaultWorkspaceSyncState(): WorkspaceSyncStateV2;
|
|
@@ -3,10 +3,12 @@ export function createDefaultWorkspaceSyncState() {
|
|
|
3
3
|
version: 2,
|
|
4
4
|
enabled: false,
|
|
5
5
|
phase: 'idle',
|
|
6
|
+
setupIntent: null,
|
|
6
7
|
pullCursor: null,
|
|
7
8
|
lastPullAt: null,
|
|
8
9
|
lastPushAt: null,
|
|
9
10
|
lastSyncedAt: null,
|
|
10
|
-
lastErrorMessage: null
|
|
11
|
+
lastErrorMessage: null,
|
|
12
|
+
pushBaseline: null
|
|
11
13
|
};
|
|
12
14
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { taskSyncResourceAdapter } from './syncResourceAdapters.js';
|
|
1
2
|
export function compareWorkspaceMutationOrdering(incomingWatermark, existingWatermark, incomingTieBreak, existingTieBreak) {
|
|
2
3
|
const incomingMs = Date.parse(String(incomingWatermark || '').trim());
|
|
3
4
|
const existingMs = Date.parse(String(existingWatermark || '').trim());
|
|
@@ -18,16 +19,10 @@ export function compareWorkspaceMutationOrdering(incomingWatermark, existingWate
|
|
|
18
19
|
return String(incomingTieBreak || '').localeCompare(String(existingTieBreak || ''));
|
|
19
20
|
}
|
|
20
21
|
export function getTaskMutationWatermark(task) {
|
|
21
|
-
return
|
|
22
|
+
return taskSyncResourceAdapter.getWatermark(task || {});
|
|
22
23
|
}
|
|
23
24
|
export function getTaskMutationTieBreak(task, archived) {
|
|
24
|
-
|
|
25
|
-
return JSON.stringify({
|
|
26
|
-
id: String(source.id || ''),
|
|
27
|
-
title: String(source.title || ''),
|
|
28
|
-
status: String(source.status || ''),
|
|
29
|
-
archived: archived ? 1 : 0
|
|
30
|
-
});
|
|
25
|
+
return taskSyncResourceAdapter.getChangeKey({ ...(task || {}), isArchived: archived });
|
|
31
26
|
}
|
|
32
27
|
export function getDocumentMutationWatermark(document) {
|
|
33
28
|
return String(document?.updatedAt || '').trim();
|
package/dist/types.d.ts
CHANGED
|
@@ -143,6 +143,23 @@ export interface WorkstreamItem {
|
|
|
143
143
|
order?: number | null;
|
|
144
144
|
isArchived?: boolean;
|
|
145
145
|
}
|
|
146
|
+
export interface PlanningBootstrapTaskPreview {
|
|
147
|
+
id: string;
|
|
148
|
+
referenceNumber?: number | null;
|
|
149
|
+
title: string;
|
|
150
|
+
status?: string | null;
|
|
151
|
+
}
|
|
152
|
+
export interface PlanningBootstrapWorkstreamTaskSummary {
|
|
153
|
+
workstreamId: string;
|
|
154
|
+
taskCount: number;
|
|
155
|
+
completedTaskCount: number;
|
|
156
|
+
tasks: PlanningBootstrapTaskPreview[];
|
|
157
|
+
}
|
|
158
|
+
export interface PlanningBootstrapPayload {
|
|
159
|
+
initiatives: InitiativeItem[];
|
|
160
|
+
workstreams: WorkstreamItem[];
|
|
161
|
+
workstreamTaskSummaries: PlanningBootstrapWorkstreamTaskSummary[];
|
|
162
|
+
}
|
|
146
163
|
export interface ChecklistItem {
|
|
147
164
|
id: string;
|
|
148
165
|
taskId: string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as c,j as e}from"./vendor-react-CKJs5o3c.js";import{u as se,p as oe,v as ne,w as ce,x as _,y as de,z as pe,t as r,E as fe,B as me,C as K}from"./index-C6k75jr8.js";import{h as ue,B as V,k as U,b as he,$ as ve,a3 as ge}from"./vendor-icons-DuEd_65c.js";import"./vendor-markdown-BUxTU7dS.js";import"./vendor-dnd-DRzYolkg.js";import"./vendor-router-BbWMxlnO.js";function J(d){return!d||typeof d!="object"?null:{used:Math.max(0,Number(d.used||0)),limit:d.limit===null||d.limit===void 0?null:Math.max(0,Number(d.limit||0)),remaining:d.remaining===null||d.remaining===void 0?null:Math.max(0,Number(d.remaining||0))}}function W(d,P){const x=P?.variant==="inline"?`${r.aiProfileSeatScopeIcon} ${r.aiProfileSeatScopeIconInline}`:P?.variant==="detail"?`${r.aiProfileSeatScopeIcon} ${r.aiProfileSeatScopeIconDetail}`:r.aiProfileSeatScopeIcon;return d==="cloud_metered"?e.jsx("span",{className:`${x} ${r.aiProfileSeatScopeIconCloud}`,title:"Cloud MCP","aria-label":"Cloud MCP",children:e.jsx(ve,{size:20})}):d==="local_unmetered"?e.jsx("span",{className:`${x} ${r.aiProfileSeatScopeIconLocal}`,title:"Local MCP","aria-label":"Local MCP",children:e.jsx(ge,{size:20})}):null}function Ie({workspaceId:d,cloudAuthConfigured:P=!1,authSessionResolved:x=!1,isAuthenticated:Y=!1,cloudAiProfileSeatUsage:q=null}){const[S,L]=c.useState([]),[Q,X]=c.useState(null),[M,$]=c.useState(!1),[f,j]=c.useState(null),[I,v]=c.useState(null),[N,A]=c.useState(null),[g,b]=c.useState(null),[E,T]=c.useState(null),[B,D]=c.useState(!1),[Z,m]=c.useState(null),w=c.useCallback(async()=>{if(d){$(!0);try{const a=`/api/taskforce/workspace/assignee-options?workspaceId=${encodeURIComponent(d)}`,i=await fetch(a,{credentials:"include"}),t=i.ok?await i.json().catch(()=>({})):{},s=J(t?.aiProfileSeatUsage),n=Array.isArray(t?.assignees)?t.assignees.filter(l=>l.kind==="agent").map(l=>({id:String(l.value||""),name:String(l.label||l.value||"Unknown Agent"),username:String(l.username||l.value||""),icon:String(l.icon||"Bot"),color:String(l.color||"#6B7280"),avatarUrl:typeof l.avatarUrl=="string"?l.avatarUrl:null,avatarSourceUrl:typeof l.avatarSourceUrl=="string"?l.avatarSourceUrl:null,kind:String(l.kind||"agent"),description:typeof l.description=="string"?l.description:null,role:typeof l.role=="string"?l.role:null,provider:typeof l.provider=="string"?l.provider:null,model:typeof l.model=="string"?l.model:null,surfaceType:oe(l.surfaceType),seatScope:se(l.seatScope),archivedAt:typeof l.archivedAt=="string"?l.archivedAt:null,createdAt:String(l.createdAt||""),updatedAt:String(l.updatedAt||l.createdAt||""),lastActiveAt:typeof l.lastActiveAt=="string"?l.lastActiveAt:null})):[];L(n),X(s),A(l=>l&&!n.some(h=>h.id===l.profileId)?null:l)}finally{$(!1)}}},[d]);c.useEffect(()=>{w()},[w]);const k=c.useMemo(()=>{const a=new Map;for(const i of S){const t=ne(i.surfaceType);a.has(t)||a.set(t,new Map);const s=a.get(t),n=i.name.toLowerCase();s.has(n)||s.set(n,[]),s.get(n).push(i)}return ce.map(i=>({section:i,label:_(i),groups:Array.from(a.get(i)?.entries()||[]).map(([t,s])=>({groupId:`${i}:${t}`,section:i,sectionLabel:_(i),profiles:s,primaryProfile:s[0]}))})).filter(i=>i.groups.length>0)},[S]),u=c.useMemo(()=>k.flatMap(a=>a.groups),[k]),o=c.useMemo(()=>u.find(a=>a.groupId===g)||u[0]||null,[u,g]),p=c.useMemo(()=>S.find(a=>a.id===E)||null,[S,E]);c.useEffect(()=>{if(!u.length){g!==null&&b(null);return}(!g||!u.some(a=>a.groupId===g))&&b(u[0].groupId)},[u,g]);const ee=async(a,i)=>{v(null),A(null);try{const t=await fetch("/api/taskforce/workspace/ai-profiles/merge",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({keepId:a,mergeId:i})}),s=await t.json().catch(()=>({}));if(!t.ok){v({type:"error",message:String(s?.error||"Failed to merge AI profiles.")});return}j(null),v({type:"success",message:"AI profiles merged."}),await w()}catch{v({type:"error",message:"Failed to merge AI profiles."})}},G=async a=>{if(window.confirm(`Remove ${a.name} from the active roster? This frees an AI profile seat and preserves task and comment history.`)){A(null),v(null);try{const t=await fetch("/api/taskforce/workspace/ai-profiles/archive",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({profileId:a.id,reason:"manual_archive"})}),s=await t.json().catch(()=>({}));if(!t.ok){A({profileId:a.id,message:String(s?.error||"Failed to remove AI profile from roster.")});return}(f?.keepId===a.id||f?.mergeId===a.id)&&j(null),v({type:"success",message:"AI profile removed from active roster."}),await w()}catch{A({profileId:a.id,message:"Failed to remove AI profile from roster."})}}},ae=a=>new Promise((i,t)=>{const s=new FileReader;s.onload=()=>i(String(s.result||"")),s.onerror=()=>t(new Error("Failed to read image file.")),s.readAsDataURL(a)}),re=a=>{const i=String(a?.id||"").trim();i&&L(t=>t.map(s=>s.id===i?{...s,avatarUrl:typeof a.avatarUrl=="string"?a.avatarUrl:null,avatarSourceUrl:typeof a.avatarSourceUrl=="string"?a.avatarSourceUrl:null,updatedAt:typeof a.updatedAt=="string"?a.updatedAt:s.updatedAt}:s))},F=async(a,i,t)=>{const s=await fetch("/api/taskforce/workspace/ai-profiles/avatar",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({profileId:a,avatarUrl:i,...t!==void 0?{avatarSourceUrl:t}:{}})}),n=await s.json().catch(()=>({}));if(!s.ok||!n?.profile)throw new Error(String(n?.error||"Failed to update AI profile avatar."));re(n.profile)},z=async(a,i,t)=>{const s=await ae(a),n=await fetch("/api/taskforce/context-upload",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({workspaceId:d,file:s,originalName:`${t}-${a.name}`,folderPath:`ai-profiles/${i.id}/avatar`})}),l=await n.json().catch(()=>({})),h=typeof l?.path=="string"?l.path:"";if(!n.ok||!h)throw new Error(String(l?.error||"Failed to upload AI profile photo."));return h},ie=async(a,i)=>{if(!p)return!1;if(!a.type.startsWith("image/"))return m("AI profile photo must be an image file."),!1;D(!0),m(null);try{const t=await K(a,{maxBytes:5242880});if(t.exceededLimit)throw new Error(a.type==="image/gif"?"Animated GIF AI profile photos must be 5 MB or smaller.":"AI profile photo must be 5 MB or smaller.");const s=t.file,n=await z(s,p,"cropped");let l;if(i){const h=await K(i,{maxBytes:5242880});if(h.exceededLimit)throw new Error(i.type==="image/gif"?"Animated GIF AI profile photos must be 5 MB or smaller.":"AI profile source photo must be 5 MB or smaller.");l=i.type==="image/gif"?n:await z(h.file,p,"source")}return await F(p.id,n,l),!0}catch(t){return m(String(t?.message||"Failed to update AI profile photo.")),!1}finally{D(!1)}},te=async()=>{if(p){D(!0),m(null);try{await F(p.id,null,null)}catch(a){m(String(a?.message||"Failed to remove AI profile photo."))}finally{D(!1)}}},y=a=>{const i=String(a||"").trim();if(!i)return"Unknown";const t=Date.parse(i);return Number.isFinite(t)?new Date(t).toLocaleString(void 0,{dateStyle:"medium",timeStyle:"short"}):i},H=c.useMemo(()=>{if(!o)return{attributes:[],dates:[]};const a=o.primaryProfile,i=t=>t||"Not set";return{attributes:[{label:"Category",value:a.surfaceType?de(a.surfaceType):""},{label:"Connection",value:a.seatScope?pe(a.seatScope):""},{label:"Provider",value:a.provider||""},{label:"Model",value:a.model||""}].map(t=>({...t,value:i(t.value)})),dates:[{label:"Recruited",value:y(a.createdAt)},{label:"Last updated",value:y(a.updatedAt)},{label:"Last active",value:y(a.lastActiveAt)},{label:"Status",value:a.archivedAt?"Retired":"Active"}].map(t=>({...t,value:i(t.value)}))}},[o]),le=!!o&&o.profiles.length>1,O=P&&x&&!Y,C=P?J(q):Q,R=O?"Log into account for Cloud agents":C?`${C.used}/${C.limit===null?"Unlimited":C.limit}`:null;return e.jsxs("section",{className:r.agentsModuleRoot,children:[e.jsx("div",{className:r.agentsModuleContent,children:e.jsx("div",{className:`${r.settingGroup} ${r.agentsModuleGroup}`,children:e.jsxs("div",{children:[e.jsx("h4",{className:r.settingSubTitle,children:"Registered AI Profiles"}),e.jsx("p",{className:`${r.settingsHint} ${r.marginBottom12}`,children:"AI agents register profiles when connecting via MCP. Merge duplicates created when a token was lost, or remove inactive profiles from the active roster to free seats while preserving history."}),R&&e.jsx("div",{className:r.aiProfileSeatSummary,children:O?R:`Registered Cloud Agents: ${R}`}),M&&e.jsxs("div",{className:r.settingsHint,children:[e.jsx(ue,{size:13,className:r.spinner})," Loading profiles…"]}),!M&&S.length===0&&e.jsx("div",{className:r.settingsHint,children:"No AI profiles registered yet."}),!M&&k.length>0&&e.jsxs("div",{className:r.aiProfilesExplorer,children:[e.jsx("div",{className:`${r.aiProfilesListPane} tf-scrollbar tf-scrollbar--track-transparent`,children:e.jsx("div",{className:r.aiProfilesList,children:k.map(a=>e.jsxs("div",{className:r.aiProfilesSection,children:[e.jsx("div",{className:r.aiProfilesSectionHeader,children:a.label}),a.groups.map(i=>{const t=o?.groupId===i.groupId,s=i.primaryProfile;return e.jsxs("div",{role:"button",tabIndex:0,className:`${r.aiProfileGroup} ${i.profiles.length>1?r.aiProfileGroupDuplicate:""} ${t?r.aiProfileGroupSelected:""}`,onClick:()=>b(i.groupId),onKeyDown:n=>{n.key!=="Enter"&&n.key!==" "||(n.preventDefault(),b(i.groupId))},"aria-pressed":t,children:[W(s.seatScope),e.jsxs("div",{className:r.aiProfileGroupHeader,children:[e.jsx("span",{className:r.aiProfileGroupAvatar,style:{color:s.color},children:s.avatarUrl?e.jsx("img",{src:s.avatarUrl,alt:""}):e.jsx(V,{size:22})}),e.jsxs("span",{className:r.aiProfileGroupIdentity,children:[e.jsx("span",{className:r.aiProfileName,children:s.name}),e.jsxs("span",{className:r.aiProfileHandle,children:["@",s.username]}),e.jsx("span",{className:r.aiProfileRole,children:s.role||"Role not set"}),i.profiles.length>1&&e.jsxs("span",{className:r.aiProfileDuplicateBadge,children:[e.jsx(U,{size:11})," ",i.profiles.length," duplicates"]})]})]})]},i.groupId)})]},a.section))})}),o&&e.jsx("div",{className:r.aiProfileDetailPane,children:e.jsxs("div",{className:r.aiProfileDetailCard,children:[W(o.primaryProfile.seatScope,{variant:"detail"}),e.jsxs("div",{className:r.aiProfileDetailHero,children:[e.jsx(fe,{label:"Edit AI profile photo",imageUrl:o.primaryProfile.avatarUrl,fallback:e.jsx(V,{size:38}),accentColor:o.primaryProfile.color,size:176,width:153,height:207,radius:6,editBadgeSize:28,editIconSize:14,className:r.aiProfileDetailAvatar,onClick:()=>{m(null),T(o.primaryProfile.id)}}),e.jsxs("div",{className:r.aiProfileDetailHeading,children:[e.jsx("div",{className:r.aiProfileDetailTitleRow,children:e.jsx("h5",{className:r.aiProfileDetailTitle,children:o.primaryProfile.name})}),e.jsxs("div",{className:r.aiProfileDetailMetaRow,children:[e.jsxs("span",{className:r.aiProfileDetailHandle,children:["@",o.primaryProfile.username]}),o.profiles.length>1&&e.jsxs("span",{className:r.aiProfileDetailLinkedCount,children:[o.profiles.length," linked"]})]}),e.jsxs("div",{className:r.aiProfileDetailRole,children:["Role: ",o.primaryProfile.role||"Not set"]}),o.primaryProfile.description&&e.jsx("div",{className:r.aiProfileDetailDescription,children:o.primaryProfile.description})]})]}),e.jsxs("div",{className:r.aiProfileDetailDataList,children:[e.jsx("div",{className:r.aiProfileDetailDataGroup,children:H.attributes.map(a=>e.jsxs("div",{className:r.aiProfileDetailDataRow,children:[e.jsx("span",{className:r.aiProfileDetailDataLabel,children:a.label}),e.jsx("span",{className:r.aiProfileDetailDataValue,children:a.value})]},a.label))}),e.jsx("div",{className:`${r.aiProfileDetailDataGroup} ${r.aiProfileDetailDateGroup}`,children:H.dates.map(a=>e.jsxs("div",{className:r.aiProfileDetailDataRow,children:[e.jsx("span",{className:r.aiProfileDetailDataLabel,children:a.label}),a.label==="Status"?e.jsx("span",{className:r.aiProfileDetailDataValue,children:e.jsxs("select",{className:r.aiProfileStatusSelect,"aria-label":"Agent roster status",value:o.primaryProfile.archivedAt?"retired":"active",onChange:i=>{i.target.value==="retire"&&G(o.primaryProfile)},children:[e.jsx("option",{value:"active",children:"Active"}),o.primaryProfile.archivedAt?e.jsx("option",{value:"retired",children:"Retired"}):e.jsx("option",{value:"retire",children:"Retire from roster"})]})}):e.jsx("span",{className:r.aiProfileDetailDataValue,children:a.value})]},a.label))})]}),le?e.jsxs("div",{className:r.aiProfileInstanceSection,children:[e.jsxs("div",{className:r.aiProfileInstanceSectionHeader,children:[e.jsx("span",{children:"Profile instances"}),e.jsx("span",{className:r.settingsHint,children:"Choose a keeper here if duplicates need to be merged."})]}),e.jsx("div",{className:r.aiProfileInstanceList,children:o.profiles.map(a=>e.jsxs("div",{className:r.aiProfileInstanceCard,children:[e.jsxs("div",{className:r.aiProfileInstanceTopRow,children:[e.jsxs("div",{children:[e.jsxs("div",{className:r.aiProfileInstanceName,children:["@",a.username]}),e.jsx("div",{className:r.aiProfileIdChip,children:a.id})]}),f?.keepId===a.id&&e.jsx("span",{className:r.aiProfileKeepBadge,children:"Keeping"})]}),e.jsxs("div",{className:r.aiProfileInstanceMeta,children:[e.jsxs("span",{children:["Created ",y(a.createdAt)]}),e.jsxs("span",{children:["Updated ",y(a.updatedAt)]})]}),f?.keepId!==a.id&&e.jsx("button",{className:r.secondaryHeaderBtn,title:"Keep this profile, merge others into it",onClick:()=>{const i=o.profiles.find(t=>t.id!==a.id)?.id;i&&j({keepId:a.id,mergeId:i})},children:"Keep this"}),N?.profileId===a.id&&e.jsxs("div",{className:r.aiProfileInlineError,role:"alert",children:[e.jsx(U,{size:12}),e.jsx("span",{children:N.message})]}),e.jsx("button",{className:r.aiProfileDangerTextButton,title:"Remove this profile from the active roster",onClick:()=>{G(a)},children:"Remove from roster"})]},a.id))}),f&&o.profiles.some(a=>a.id===f.keepId)&&e.jsxs("div",{className:r.aiProfileMergeActions,children:[e.jsx("button",{className:r.dangerBtn,onClick:()=>{ee(f.keepId,f.mergeId)},children:"Merge duplicates"}),e.jsx("button",{className:r.secondaryHeaderBtn,onClick:()=>j(null),children:"Cancel"})]})]}):e.jsxs("div",{className:r.aiProfileIdFooter,children:[e.jsx("div",{className:r.aiProfileIdFooterValue,children:o.primaryProfile.id}),N?.profileId===o.primaryProfile.id&&e.jsxs("div",{className:r.aiProfileInlineError,role:"alert",children:[e.jsx(U,{size:12}),e.jsx("span",{children:N.message})]})]})]})})]}),I&&e.jsxs("div",{className:`${I.type==="success"?r.successMessage:r.errorMessage} ${r.marginTop12}`,children:[I.type==="success"?e.jsx(he,{size:14}):e.jsx(U,{size:14}),I.message]})]})})}),e.jsx(me,{isOpen:!!p,theme:"dark",title:"Edit AI Profile Photo",currentImageUrl:p?.avatarUrl||"",editorImageUrl:p?.avatarSourceUrl||"",fallbackInitial:(p?.name||"AI").charAt(0).toUpperCase(),accept:"image/png,image/jpeg,image/webp,image/gif",busy:B,hasPendingImage:!1,canRemove:!!p?.avatarUrl,error:Z,notice:null,onClose:()=>{B||(T(null),m(null))},onApplyImage:ie,onRemoveImage:te})]})}export{Ie as AgentsModule};
|