@taskforcehq/taskforce 0.3.305 → 0.3.307
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -2
- package/dist/Taskforce.module.css +603 -107
- package/dist/TaskforceCore.js +216 -43
- package/dist/TaskforceCore.test.js +611 -28
- package/dist/assets/fonts/CourierPrime-Bold.woff2 +0 -0
- package/dist/assets/fonts/CourierPrime-BoldItalic.woff2 +0 -0
- package/dist/assets/fonts/CourierPrime-Italic.woff2 +0 -0
- package/dist/assets/fonts/CourierPrime-Regular.woff2 +0 -0
- package/dist/assets/fonts/Noir_medium.woff2 +0 -0
- package/dist/assets/fonts/Noir_regular.woff2 +0 -0
- package/dist/assets/fonts/RussoOne-Regular.woff2 +0 -0
- package/dist/assets/fonts/SpecialElite-Regular.woff2 +0 -0
- package/dist/compat/workspaceSyncCompat.js +46 -2
- package/dist/compat/workspaceSyncCompat.test.js +38 -1
- package/dist/components/activity/EntityActivityTimeline.d.ts +34 -0
- package/dist/components/activity/EntityActivityTimeline.js +81 -0
- package/dist/components/context/ContextAttachmentManager.d.ts +14 -0
- package/dist/components/context/ContextAttachmentManager.js +561 -0
- package/dist/components/features/AgentsModule.d.ts +14 -1
- package/dist/components/features/AgentsModule.js +366 -18
- package/dist/components/features/AgentsModule.test.js +507 -8
- package/dist/components/features/AnnotatedAttachmentWorkspace.d.ts +3 -1
- package/dist/components/features/AnnotatedAttachmentWorkspace.js +118 -4
- package/dist/components/features/AnnotatedAttachmentWorkspace.test.js +52 -0
- package/dist/components/features/DocumentIndex.d.ts +2 -2
- package/dist/components/features/DocumentIndex.js +3 -4
- package/dist/components/features/DocumentViewer.d.ts +7 -1
- package/dist/components/features/DocumentViewer.js +62 -4
- package/dist/components/features/DocumentWorkspace.d.ts +10 -2
- package/dist/components/features/DocumentWorkspace.js +15 -4
- package/dist/components/features/DocumentWorkspace.test.js +51 -1
- package/dist/components/features/TaskSettings.d.ts +2 -0
- package/dist/components/features/TaskSettings.js +83 -78
- package/dist/components/features/TaskSettings.test.js +171 -82
- package/dist/components/features/documentWorkspaceModel.d.ts +1 -1
- package/dist/components/task/TaskActionHeader.js +11 -5
- package/dist/components/task/TaskActionHeader.test.js +10 -0
- package/dist/components/task/TaskCard.js +24 -29
- package/dist/components/task/TaskCard.test.js +38 -3
- package/dist/components/task/TaskContextUpload.js +4 -526
- package/dist/components/task/TaskContextUpload.test.js +3 -3
- package/dist/components/task/TaskForm.js +61 -116
- package/dist/components/task/TaskForm.test.js +110 -8
- package/dist/components/task/TaskKanban.d.ts +2 -1
- package/dist/components/task/TaskKanban.js +94 -21
- package/dist/components/task/TaskKanban.test.js +36 -0
- package/dist/components/task/TaskList.js +5 -1
- package/dist/components/task/TaskList.test.js +4 -0
- package/dist/components/ui/EditableAvatarButton.d.ts +18 -0
- package/dist/components/ui/EditableAvatarButton.js +18 -0
- package/dist/components/ui/HierarchyActionBadge.d.ts +10 -0
- package/dist/components/ui/HierarchyActionBadge.js +5 -0
- package/dist/components/views/AppShellHeader.d.ts +3 -1
- package/dist/components/views/AppShellHeader.js +27 -11
- package/dist/components/views/AppShellHeader.test.js +18 -1
- package/dist/components/views/PlanComparisonPage.d.ts +9 -1
- package/dist/components/views/PlanComparisonPage.js +78 -14
- package/dist/components/views/PlanComparisonPage.test.js +257 -0
- package/dist/components/views/PlansPage.js +127 -36
- package/dist/components/views/PlansPage.test.js +294 -12
- package/dist/components/views/StandaloneLayout.js +529 -592
- package/dist/components/views/WidgetView.js +10 -8
- package/dist/components/views/panels/PlanningDrawer.d.ts +25 -5
- package/dist/components/views/panels/PlanningDrawer.js +270 -55
- package/dist/components/views/panels/PlanningDrawer.test.d.ts +1 -0
- package/dist/components/views/panels/PlanningDrawer.test.js +529 -0
- package/dist/components/views/planningScope.d.ts +20 -0
- package/dist/components/views/planningScope.js +25 -0
- package/dist/components/views/planningScope.test.d.ts +1 -0
- package/dist/components/views/planningScope.test.js +60 -0
- package/dist/components/views/standalone/modals/AccountHubModal.d.ts +26 -1
- package/dist/components/views/standalone/modals/AccountHubModal.js +76 -2
- package/dist/components/views/standalone/modals/AccountHubModal.test.js +20 -3
- package/dist/components/views/standalone/modals/AvatarImageManagerModal.d.ts +20 -0
- package/dist/components/views/standalone/modals/AvatarImageManagerModal.js +127 -0
- package/dist/components/views/standalone/modals/EditProfileModal.d.ts +2 -9
- package/dist/components/views/standalone/modals/EditProfileModal.js +3 -2
- package/dist/components/views/standalone/modals/SyncEnableWarningModal.d.ts +9 -0
- package/dist/components/views/standalone/modals/SyncEnableWarningModal.js +6 -0
- package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.d.ts +1 -0
- package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.js +24 -0
- package/dist/components/views/standalone/modals/SyncStatusModal.d.ts +2 -1
- package/dist/components/views/standalone/modals/SyncStatusModal.js +2 -2
- package/dist/config/envSchema.js +1 -0
- package/dist/core/AiProfileService.d.ts +46 -2
- package/dist/core/AiProfileService.js +1073 -82
- package/dist/core/AiProfileService.test.js +19 -1
- package/dist/core/AiProfiles.test.js +1249 -44
- package/dist/core/AttachmentLinkService.d.ts +3 -0
- package/dist/core/AttachmentLinkService.js +110 -23
- package/dist/core/AuthIdentityService.d.ts +107 -0
- package/dist/core/AuthIdentityService.js +284 -0
- package/dist/core/AuthTokenService.d.ts +4 -0
- package/dist/core/AuthTokenService.js +34 -6
- package/dist/core/AuthTokenService.test.js +3 -3
- package/dist/core/EntitlementsPolicy.test.js +2 -2
- package/dist/core/GlobalSettingsService.js +127 -6
- package/dist/core/McpTokenService.d.ts +12 -0
- package/dist/core/McpTokenService.js +44 -1
- package/dist/core/PlanEntitlementService.d.ts +23 -2
- package/dist/core/PlanEntitlementService.js +343 -57
- package/dist/core/PlanFeatureCatalog.test.d.ts +1 -0
- package/dist/core/PlanFeatureCatalog.test.js +84 -0
- package/dist/core/PlanVersionPolicy.test.js +35 -2
- package/dist/core/PlanningEntities.test.js +418 -4
- package/dist/core/SignupMonetizationSettings.test.js +199 -27
- package/dist/core/SyncReconciliationService.js +2 -65
- package/dist/core/SystemAdmin.test.js +42 -42
- package/dist/core/TaskActivityService.d.ts +28 -1
- package/dist/core/TaskActivityService.js +227 -46
- package/dist/core/TaskActivitySync.test.d.ts +1 -0
- package/dist/core/TaskActivitySync.test.js +90 -0
- package/dist/core/TaskAttachmentsCanonical.test.js +51 -1
- package/dist/core/TaskAuditTimeline.test.js +96 -0
- package/dist/core/Taskforce.d.ts +415 -40
- package/dist/core/Taskforce.ids.test.js +58 -0
- package/dist/core/Taskforce.js +1543 -266
- package/dist/core/Taskforce.listTasksSlim.test.d.ts +1 -0
- package/dist/core/Taskforce.listTasksSlim.test.js +91 -0
- package/dist/core/Taskforce.mcpAuth.test.js +109 -0
- package/dist/core/UserProfileAvatarDrafts.test.js +30 -3
- package/dist/core/WorkspaceLifecycleService.js +0 -5
- package/dist/core/WorkspacePermissions.test.js +25 -1
- package/dist/core/WorkspacePlanMode.test.js +117 -16
- package/dist/core/shared.d.ts +1 -1
- package/dist/core/shared.js +5 -1
- package/dist/core/types.d.ts +75 -2
- package/dist/hooks/auth/useTaskforceAuthBootstrap.js +28 -2
- package/dist/hooks/bootstrapTimeouts.d.ts +4 -0
- package/dist/hooks/bootstrapTimeouts.js +8 -0
- package/dist/hooks/bootstrapTimeouts.test.d.ts +1 -0
- package/dist/hooks/bootstrapTimeouts.test.js +12 -0
- package/dist/hooks/sync/bootstrap.js +2 -0
- package/dist/hooks/sync/controlPlane.d.ts +37 -0
- package/dist/hooks/sync/controlPlane.js +78 -0
- package/dist/hooks/sync/controlPlane.test.d.ts +1 -0
- package/dist/hooks/sync/controlPlane.test.js +121 -0
- package/dist/hooks/sync/lifecyclePolicy.d.ts +45 -0
- package/dist/hooks/sync/lifecyclePolicy.js +93 -0
- package/dist/hooks/sync/lifecyclePolicy.test.d.ts +1 -0
- package/dist/hooks/sync/lifecyclePolicy.test.js +124 -0
- package/dist/hooks/sync/orchestratorShared.d.ts +13 -4
- package/dist/hooks/sync/orchestratorShared.js +129 -48
- package/dist/hooks/sync/orchestratorShared.test.js +50 -1
- package/dist/hooks/sync/pullLifecycle.d.ts +31 -0
- package/dist/hooks/sync/pullLifecycle.js +24 -0
- package/dist/hooks/sync/pullLifecycle.test.d.ts +1 -0
- package/dist/hooks/sync/pullLifecycle.test.js +80 -0
- package/dist/hooks/sync/recovery.d.ts +16 -2
- package/dist/hooks/sync/recovery.js +179 -53
- package/dist/hooks/sync/recovery.test.d.ts +1 -0
- package/dist/hooks/sync/recovery.test.js +292 -0
- package/dist/hooks/sync/transfers.d.ts +16 -3
- package/dist/hooks/sync/transfers.js +210 -66
- package/dist/hooks/sync/transfers.test.d.ts +1 -0
- package/dist/hooks/sync/transfers.test.js +928 -0
- package/dist/hooks/sync/useRecentSyncEvents.d.ts +21 -0
- package/dist/hooks/sync/useRecentSyncEvents.js +92 -0
- package/dist/hooks/sync/useRecentSyncEvents.test.d.ts +1 -0
- package/dist/hooks/sync/useRecentSyncEvents.test.js +124 -0
- package/dist/hooks/sync/useSyncStatusActions.d.ts +30 -0
- package/dist/hooks/sync/useSyncStatusActions.js +88 -0
- package/dist/hooks/sync/useSyncStatusActions.test.d.ts +1 -0
- package/dist/hooks/sync/useSyncStatusActions.test.js +133 -0
- package/dist/hooks/sync/useSyncStatusControls.d.ts +25 -0
- package/dist/hooks/sync/useSyncStatusControls.js +60 -0
- package/dist/hooks/sync/useSyncStatusControls.test.d.ts +1 -0
- package/dist/hooks/sync/useSyncStatusControls.test.js +88 -0
- package/dist/hooks/useFilterSort.js +13 -13
- package/dist/hooks/useFilterSort.test.js +87 -1
- package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +12 -0
- package/dist/hooks/useSyncOrchestrator.d.ts +9 -2
- package/dist/hooks/useSyncOrchestrator.js +409 -183
- package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +407 -0
- package/dist/hooks/useTaskData.js +8 -3
- package/dist/hooks/useTaskData.test.js +45 -0
- package/dist/hooks/useTaskforce.d.ts +145 -52
- package/dist/hooks/useTaskforce.js +592 -253
- package/dist/hooks/useTaskforce.runtime-routing.test.d.ts +1 -0
- package/dist/hooks/useTaskforce.runtime-routing.test.js +246 -0
- package/dist/hooks/useTaskforce.sync-behavior.test.js +2468 -201
- package/dist/hooks/useWorkspaceSyncController.d.ts +1 -0
- package/dist/hooks/useWorkspaceSyncController.js +13 -2
- package/dist/hooks/useWorkspaceSyncController.test.js +48 -0
- package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.d.ts +16 -0
- package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +328 -40
- package/dist/localization/locales/en-US.d.ts +0 -1
- package/dist/localization/locales/en-US.js +0 -1
- package/dist/localization/locales/es-419.js +0 -1
- package/dist/localization/locales/pt-BR.js +0 -1
- package/dist/mcp/canonicalAssetHelpers.d.ts +16 -4
- package/dist/mcp/canonicalAssetHelpers.js +18 -10
- package/dist/mcp/canonicalAssetHelpers.test.d.ts +1 -0
- package/dist/mcp/canonicalAssetHelpers.test.js +67 -0
- package/dist/mcp/clientIntegrations.d.ts +1 -0
- package/dist/mcp/clientIntegrations.js +25 -0
- package/dist/mcp/clientIntegrations.test.js +14 -3
- package/dist/mcp/clientProfileDefaults.js +3 -3
- package/dist/mcp/collaborationRegistrar.js +7 -7
- package/dist/mcp/documentAssetRegistrar.js +116 -10
- package/dist/mcp/runtime.d.ts +3 -0
- package/dist/mcp/runtime.js +1099 -185
- package/dist/mcp/runtime.test.js +1491 -140
- package/dist/mcp/taskAttachmentTypes.d.ts +1 -1
- package/dist/mcp/taskPlanningRegistrar.js +48 -0
- package/dist/mcp/toolRegistry.d.ts +56 -0
- package/dist/mcp/toolRegistry.js +8 -0
- package/dist/mcp/toolRegistry.test.js +4 -0
- package/dist/migrations/taskSchemaMigrations.d.ts +1 -1
- package/dist/migrations/taskSchemaMigrations.js +192 -61
- package/dist/migrations/taskSchemaMigrations.test.js +15 -0
- package/dist/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
- package/dist/resources/templates/workflows/collaborate.yaml +1 -1
- package/dist/resources/templates/workflows/evaluate.yaml +2 -2
- package/dist/resources/templates/workflows/plan.yaml +1 -1
- package/dist/resources/templates/workflows/review.yaml +2 -2
- package/dist/server/aiProfileAvatarAssets.d.ts +49 -0
- package/dist/server/aiProfileAvatarAssets.js +319 -0
- package/dist/server/aiProfileAvatarAssets.test.d.ts +1 -0
- package/dist/server/aiProfileAvatarAssets.test.js +213 -0
- package/dist/server/annotatedAttachmentsRoutes.test.js +69 -10
- package/dist/server/auth/providers/apple.d.ts +33 -0
- package/dist/server/auth/providers/apple.js +82 -0
- package/dist/server/auth/providers/appleClientSecret.d.ts +37 -0
- package/dist/server/auth/providers/appleClientSecret.js +65 -0
- package/dist/server/auth/providers/github.d.ts +26 -0
- package/dist/server/auth/providers/github.js +86 -0
- package/dist/server/auth/providers/google.d.ts +21 -0
- package/dist/server/auth/providers/google.js +56 -0
- package/dist/server/auth/providers/types.d.ts +21 -0
- package/dist/server/auth/providers/types.js +1 -0
- package/dist/server/auth.d.ts +2 -0
- package/dist/server/auth.js +6 -3
- package/dist/server/documentReviewRoutes.test.js +36 -3
- package/dist/server/index.cookieProxy.test.js +1 -0
- package/dist/server/index.d.ts +12 -0
- package/dist/server/index.js +124 -9
- package/dist/server/index.rateLimit.test.js +3 -0
- package/dist/server/index.test.js +111 -3
- package/dist/server/routes/admin.d.ts +3 -0
- package/dist/server/routes/admin.js +459 -28
- package/dist/server/routes/annotatedAttachments.js +51 -0
- package/dist/server/routes/auth.d.ts +26 -2
- package/dist/server/routes/auth.js +1170 -71
- package/dist/server/routes/authSupport.d.ts +5 -1
- package/dist/server/routes/authSupport.js +13 -2
- package/dist/server/routes/billing.js +372 -35
- package/dist/server/routes/billing.test.js +595 -12
- package/dist/server/routes/documents.d.ts +1 -0
- package/dist/server/routes/documents.js +182 -70
- package/dist/server/routes/shared.d.ts +28 -2
- package/dist/server/routes/shared.js +69 -14
- package/dist/server/routes/sync.integration.test.js +658 -39
- package/dist/server/routes/sync.js +74 -608
- package/dist/server/routes/syncAuxRoutes.d.ts +15 -0
- package/dist/server/routes/syncAuxRoutes.js +91 -0
- package/dist/server/routes/syncAuxRoutes.test.d.ts +1 -0
- package/dist/server/routes/syncAuxRoutes.test.js +158 -0
- package/dist/server/routes/syncPullApplyRoutes.d.ts +36 -0
- package/dist/server/routes/syncPullApplyRoutes.js +204 -0
- package/dist/server/routes/syncPushRoutes.d.ts +24 -0
- package/dist/server/routes/syncPushRoutes.js +212 -0
- package/dist/server/routes/syncRouteGuards.d.ts +36 -0
- package/dist/server/routes/syncRouteGuards.js +67 -0
- package/dist/server/routes/syncRouteGuards.test.d.ts +1 -0
- package/dist/server/routes/syncRouteGuards.test.js +94 -0
- package/dist/server/routes/syncRouteTypes.d.ts +13 -0
- package/dist/server/routes/syncRouteTypes.js +1 -0
- package/dist/server/routes/syncSnapshotRoutes.d.ts +66 -0
- package/dist/server/routes/syncSnapshotRoutes.js +182 -0
- package/dist/server/routes/tasks.js +55 -10
- package/dist/server/routes/workspaces.js +36 -5
- package/dist/server/routes.js +147 -11
- package/dist/server/routes.test.js +2704 -183
- package/dist/services/workflowExportSnapshots.test.js +2 -0
- package/dist/shared/aiProfileSeatScope.d.ts +5 -0
- package/dist/shared/aiProfileSeatScope.js +21 -0
- package/dist/shared/aiProfileSurfaceType.d.ts +1 -1
- package/dist/shared/aiProfileSurfaceType.js +10 -8
- package/dist/shared/passwordPolicy.d.ts +13 -0
- package/dist/shared/passwordPolicy.js +84 -0
- package/dist/shared/passwordPolicy.test.d.ts +1 -0
- package/dist/shared/passwordPolicy.test.js +34 -0
- package/dist/storage/objectStorage.d.ts +1 -0
- package/dist/storage/objectStorage.js +2 -1
- package/dist/storage/objectStorageClient.d.ts +1 -0
- package/dist/storage/objectStorageClient.js +41 -8
- package/dist/storage/objectStorageClient.test.js +26 -1
- package/dist/storage/objectStorageConfig.js +3 -1
- package/dist/storage/objectStorageConfig.test.js +13 -1
- package/dist/storage/workspaceAssetStore.d.ts +15 -3
- package/dist/storage/workspaceAssetStore.js +132 -44
- package/dist/storage/workspaceAssetStore.test.js +93 -6
- package/dist/styles/fonts.css +70 -0
- package/dist/sync/collaborationSyncPayload.d.ts +6 -1
- package/dist/sync/collaborationSyncPayload.js +19 -11
- package/dist/sync/collaborationSyncPayload.test.js +14 -1
- package/dist/sync/collaborationSyncState.d.ts +3 -3
- package/dist/sync/collaborationSyncState.js +19 -12
- package/dist/sync/contentSyncPayload.d.ts +5 -1
- package/dist/sync/contentSyncPayload.js +9 -0
- package/dist/sync/contentSyncPayload.test.js +39 -0
- package/dist/sync/contentSyncState.d.ts +9 -9
- package/dist/sync/contentSyncState.js +248 -107
- package/dist/sync/planningSyncPayload.js +5 -0
- package/dist/sync/planningSyncPayload.test.js +24 -0
- package/dist/sync/syncApplyHandlers.d.ts +11 -4
- package/dist/sync/syncApplyHandlers.js +115 -42
- package/dist/sync/syncApplyHandlers.test.js +251 -4
- package/dist/sync/syncFieldSemantics.d.ts +12 -0
- package/dist/sync/syncFieldSemantics.js +55 -0
- package/dist/sync/syncResourceAdapters.d.ts +46 -0
- package/dist/sync/syncResourceAdapters.js +79 -0
- package/dist/sync/syncService.d.ts +6 -0
- package/dist/sync/syncService.js +65 -1
- package/dist/sync/syncService.test.js +96 -3
- package/dist/sync/taskSyncChangeKey.d.ts +2 -0
- package/dist/sync/taskSyncChangeKey.js +143 -0
- package/dist/sync/taskSyncPayload.js +3 -8
- package/dist/sync/workspacePullFeed.d.ts +4 -0
- package/dist/sync/workspacePullFeed.js +132 -72
- package/dist/sync/workspacePullFeed.test.js +92 -0
- package/dist/sync/workspaceRepair.js +5 -2
- package/dist/sync/workspaceSyncModel.d.ts +73 -6
- package/dist/sync/workspaceSyncModel.js +342 -73
- package/dist/sync/workspaceSyncModel.test.js +559 -14
- package/dist/sync/workspaceSyncState.d.ts +17 -0
- package/dist/sync/workspaceSyncState.js +2 -1
- package/dist/sync/workspaceSyncSurface.js +3 -8
- package/dist/types.d.ts +50 -2
- package/dist/ui/assets/AgentsModule-2y82_3DO.js +1 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BTLZZCiQ.js +3 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BVKew-mH.css +1 -0
- package/dist/ui/assets/ContextAttachmentManager-D2epuNnG.js +3 -0
- package/dist/ui/assets/CourierPrime-Bold-BuLj_dpw.woff2 +0 -0
- package/dist/ui/assets/CourierPrime-BoldItalic-BrK2pUkZ.woff2 +0 -0
- package/dist/ui/assets/CourierPrime-Italic-DFUZK5Ey.woff2 +0 -0
- package/dist/ui/assets/CourierPrime-Regular-BsKphzVf.woff2 +0 -0
- package/dist/ui/assets/DocumentWorkspace-D4rJKXzd.css +1 -0
- package/dist/ui/assets/DocumentWorkspace-sVa-3Do6.js +252 -0
- package/dist/ui/assets/EntityActivityTimeline-DyqvvhuF.css +1 -0
- package/dist/ui/assets/EntityActivityTimeline-Zods27y_.js +1 -0
- package/dist/ui/assets/{InitiativesModule-Dhm7M8e7.js → InitiativesModule-D4XseTwW.js} +1 -1
- package/dist/ui/assets/Noir_medium-bxQwKGzB.woff2 +0 -0
- package/dist/ui/assets/Noir_regular-ojf2kxlG.woff2 +0 -0
- package/dist/ui/assets/PlansPage-D5AcbO0L.js +1 -0
- package/dist/ui/assets/PlansPage-Dvqsz5zc.css +1 -0
- package/dist/ui/assets/RussoOne-Regular-Cu_qq_qC.woff2 +0 -0
- package/dist/ui/assets/SpecialElite-Regular-Di6gSvAS.woff2 +0 -0
- package/dist/ui/assets/TaskContextUpload-uC5qx4Bv.js +1 -0
- package/dist/ui/assets/TaskSettings-CqvPAsTv.js +9 -0
- package/dist/ui/assets/{WorkflowsModule-BcS4afRn.js → WorkflowsModule-oOA9bcdK.js} +4 -4
- package/dist/ui/assets/documentReferences-DPZuTgHh.js +1 -0
- package/dist/ui/assets/index-607WPo_X.js +4 -0
- package/dist/ui/assets/index-CYyodXsg.css +1 -0
- package/dist/ui/assets/{vendor-icons-BSUaRwF8.js → vendor-icons-B32hGuF2.js} +1 -1
- package/dist/ui/fonts/CourierPrime-Bold.ttf +0 -0
- package/dist/ui/fonts/CourierPrime-Bold.woff2 +0 -0
- package/dist/ui/fonts/CourierPrime-BoldItalic.ttf +0 -0
- package/dist/ui/fonts/CourierPrime-BoldItalic.woff2 +0 -0
- package/dist/ui/fonts/CourierPrime-Italic.ttf +0 -0
- package/dist/ui/fonts/CourierPrime-Italic.woff2 +0 -0
- package/dist/ui/fonts/CourierPrime-Regular.ttf +0 -0
- package/dist/ui/fonts/CourierPrime-Regular.woff2 +0 -0
- package/dist/ui/fonts/Noir_medium.otf +0 -0
- package/dist/ui/fonts/Noir_medium.woff2 +0 -0
- package/dist/ui/fonts/Noir_regular.otf +0 -0
- package/dist/ui/fonts/Noir_regular.woff2 +0 -0
- package/dist/ui/fonts/RussoOne-Regular.woff2 +0 -0
- package/dist/ui/fonts/SpecialElite-Regular.ttf +0 -0
- package/dist/ui/fonts/SpecialElite-Regular.woff2 +0 -0
- package/dist/ui/index.html +3 -3
- package/dist/ui/product/agent manager.png +0 -0
- package/dist/ui/product/agent_manager_02.png +0 -0
- package/dist/utils/accountProfileSummaryCache.d.ts +5 -0
- package/dist/utils/aiProfileEvents.d.ts +7 -0
- package/dist/utils/aiProfileEvents.js +6 -0
- package/dist/utils/assignees.d.ts +8 -0
- package/dist/utils/assignees.js +10 -1
- package/dist/utils/assignees.test.d.ts +1 -0
- package/dist/utils/assignees.test.js +25 -0
- package/dist/utils/avatarDisplay.d.ts +1 -0
- package/dist/utils/avatarDisplay.js +15 -0
- package/dist/utils/avatarUpload.d.ts +27 -0
- package/dist/utils/avatarUpload.js +132 -0
- package/dist/utils/avatarUpload.test.d.ts +1 -0
- package/dist/utils/avatarUpload.test.js +40 -0
- package/dist/utils/bootstrapTrace.d.ts +7 -0
- package/dist/utils/bootstrapTrace.js +29 -0
- package/dist/utils/commercialLifecyclePresentation.js +3 -0
- package/dist/utils/contextAssetEvents.d.ts +2 -0
- package/dist/utils/contextFiles.d.ts +3 -1
- package/dist/utils/contextFiles.js +2 -1
- package/dist/utils/syncEventDetails.d.ts +3 -0
- package/dist/utils/syncEventDetails.js +64 -0
- package/dist/utils/syncEventDetails.test.d.ts +1 -0
- package/dist/utils/syncEventDetails.test.js +23 -0
- package/dist/utils/syncEventPresentation.d.ts +15 -0
- package/dist/utils/syncEventPresentation.js +129 -0
- package/dist/utils/syncEventPresentation.test.d.ts +1 -0
- package/dist/utils/syncEventPresentation.test.js +64 -0
- package/dist/utils/syncStatusPresentation.d.ts +72 -0
- package/dist/utils/syncStatusPresentation.js +217 -0
- package/dist/utils/syncStatusPresentation.test.d.ts +1 -0
- package/dist/utils/syncStatusPresentation.test.js +164 -0
- package/dist/utils/taskActivity.d.ts +9 -1
- package/dist/utils/taskActivity.js +290 -22
- package/dist/utils/taskActivity.test.js +141 -8
- package/dist/utils/taskSearch.d.ts +22 -0
- package/dist/utils/taskSearch.js +87 -0
- package/dist/utils/taskSearch.test.d.ts +1 -0
- package/dist/utils/taskSearch.test.js +69 -0
- package/dist/utils/taskUtils.js +10 -3
- package/dist/utils/taskUtils.test.d.ts +1 -0
- package/dist/utils/taskUtils.test.js +19 -0
- package/dist/utils/workspaceSyncPresentation.d.ts +4 -0
- package/dist/utils/workspaceSyncPresentation.js +68 -2
- package/dist/utils/workspaceSyncPresentation.test.js +36 -1
- package/package.json +3 -2
- package/scripts/export-sqlite-to-postgres.mjs +7 -9
- package/scripts/run-e2e-realtime.sh +17 -3
- package/scripts/run-smoke.sh +17 -5
- package/scripts/run-soak.sh +17 -5
- package/src/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
- package/src/resources/templates/workflows/collaborate.yaml +1 -1
- package/src/resources/templates/workflows/evaluate.yaml +2 -2
- package/src/resources/templates/workflows/plan.yaml +1 -1
- package/src/resources/templates/workflows/review.yaml +2 -2
- package/dist/ui/assets/AgentsModule-N2MnQBZk.js +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BG6P_GVW.js +0 -3
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BaS2VwIr.css +0 -1
- package/dist/ui/assets/DocumentWorkspace-B3nV_Gc5.css +0 -1
- package/dist/ui/assets/DocumentWorkspace-DRbDMwh8.js +0 -252
- package/dist/ui/assets/PlansPage-C2dd2n1X.css +0 -1
- package/dist/ui/assets/PlansPage-Cq0zXj3I.js +0 -1
- package/dist/ui/assets/RussoOne-Regular-C3BxZIj7.ttf +0 -0
- package/dist/ui/assets/TaskSettings-ln0aF7xc.js +0 -9
- package/dist/ui/assets/index-C2-OXZV7.css +0 -1
- package/dist/ui/assets/index-DcSI5F86.js +0 -6
- package/scripts/migrate-planning-model.ts +0 -233
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import { describe, expect, it, vi, afterEach } from 'vitest';
|
|
4
|
+
import { applyCollaborationSyncChanges, applyContentSyncChanges, applyPlanningSyncChanges, applyPreparedTaskSyncSnapshot, applyTaskActivitySyncChanges, applyTaskSyncDeletes, classifyWorkspaceSyncChanges, prepareTaskSyncSnapshotApply, } from './syncApplyHandlers.js';
|
|
3
5
|
function createCoreFixture(overrides = {}) {
|
|
4
6
|
return {
|
|
5
7
|
resolveTaskIdentifier: vi.fn().mockReturnValue(null),
|
|
6
8
|
getTask: vi.fn().mockReturnValue(null),
|
|
9
|
+
taskExistsForSync: vi.fn().mockReturnValue(true),
|
|
10
|
+
initiativeExistsForSync: vi.fn().mockReturnValue(true),
|
|
11
|
+
workstreamExistsForSync: vi.fn().mockReturnValue(true),
|
|
12
|
+
getTaskEventForSync: vi.fn().mockReturnValue(null),
|
|
13
|
+
getEntityEventForSync: vi.fn().mockReturnValue(null),
|
|
7
14
|
deleteTaskForSync: vi.fn(),
|
|
8
15
|
applyWorkspaceSyncSnapshot: vi.fn().mockReturnValue({
|
|
9
16
|
total: 1,
|
|
@@ -29,6 +36,9 @@ function createCoreFixture(overrides = {}) {
|
|
|
29
36
|
};
|
|
30
37
|
}
|
|
31
38
|
describe('syncApplyHandlers', () => {
|
|
39
|
+
afterEach(() => {
|
|
40
|
+
vi.restoreAllMocks();
|
|
41
|
+
});
|
|
32
42
|
it('classifies task and workstream changes, then prepares and applies the task snapshot pipeline', () => {
|
|
33
43
|
const diagnostics = [];
|
|
34
44
|
const workspaceId = 'workspace-1';
|
|
@@ -87,6 +97,7 @@ describe('syncApplyHandlers', () => {
|
|
|
87
97
|
normalizeWorkspaceSyncDocumentPath: (rawPath) => typeof rawPath === 'string' ? rawPath : null,
|
|
88
98
|
normalizeTaskAssetPath: (rawPath) => typeof rawPath === 'string' ? rawPath : null,
|
|
89
99
|
normalizeIncomingAiProfileSurfaceType: () => null,
|
|
100
|
+
normalizeIncomingAiProfileSeatScope: () => null,
|
|
90
101
|
normalizeTaskEventSyncPayload: () => null,
|
|
91
102
|
recordSyncDiagnostic: (targetWorkspaceId, eventType, message, details) => {
|
|
92
103
|
diagnostics.push({ workspaceId: targetWorkspaceId, eventType, message, details });
|
|
@@ -179,6 +190,84 @@ describe('syncApplyHandlers', () => {
|
|
|
179
190
|
}, workspaceId);
|
|
180
191
|
expect(result).toEqual(expect.objectContaining({ total: 1 }));
|
|
181
192
|
});
|
|
193
|
+
it('preserves planning attachments when applying initiative and workstream sync changes', () => {
|
|
194
|
+
const core = createCoreFixture({
|
|
195
|
+
upsertInitiativeForSync: vi.fn(),
|
|
196
|
+
upsertWorkstreamForSync: vi.fn(),
|
|
197
|
+
updateTaxonomies: vi.fn(),
|
|
198
|
+
});
|
|
199
|
+
applyPlanningSyncChanges({
|
|
200
|
+
core,
|
|
201
|
+
workspaceId: 'workspace-1',
|
|
202
|
+
incomingInitiatives: new Map([
|
|
203
|
+
['initiative-1', {
|
|
204
|
+
id: 'initiative-1',
|
|
205
|
+
referenceNumber: 12,
|
|
206
|
+
referenceLabel: 'I-12',
|
|
207
|
+
title: 'Initiative',
|
|
208
|
+
description: 'Initiative description',
|
|
209
|
+
ownerId: null,
|
|
210
|
+
createdAt: '2026-04-10T09:00:00.000Z',
|
|
211
|
+
updatedAt: '2026-04-10T10:00:00.000Z',
|
|
212
|
+
order: 1,
|
|
213
|
+
attachments: [{
|
|
214
|
+
path: '/api/taskforce/documents/asset-init-doc/content',
|
|
215
|
+
fsPath: 'workspaces/workspace-1/assets/documents/initiative.md',
|
|
216
|
+
assetId: 'asset-init-doc',
|
|
217
|
+
caption: 'Initiative context',
|
|
218
|
+
timestamp: '2026-04-10T10:00:00.000Z'
|
|
219
|
+
}],
|
|
220
|
+
isArchived: false,
|
|
221
|
+
}],
|
|
222
|
+
]),
|
|
223
|
+
incomingWorkstreams: new Map([
|
|
224
|
+
['workstream-1', {
|
|
225
|
+
id: 'workstream-1',
|
|
226
|
+
referenceNumber: 689,
|
|
227
|
+
referenceLabel: 'WS-689',
|
|
228
|
+
initiativeId: 'initiative-1',
|
|
229
|
+
title: 'Security Audit Remediation',
|
|
230
|
+
description: 'Workstream description',
|
|
231
|
+
ownerId: null,
|
|
232
|
+
createdAt: '2026-04-10T09:00:00.000Z',
|
|
233
|
+
updatedAt: '2026-04-10T10:00:00.000Z',
|
|
234
|
+
order: 2,
|
|
235
|
+
attachments: [{
|
|
236
|
+
path: '/api/taskforce/documents/asset-workstream-doc/content',
|
|
237
|
+
fsPath: 'workspaces/workspace-1/assets/documents/security-findings-register.md',
|
|
238
|
+
assetId: 'asset-workstream-doc',
|
|
239
|
+
caption: 'Living security findings register for WS-689',
|
|
240
|
+
timestamp: '2026-04-10T10:00:00.000Z'
|
|
241
|
+
}],
|
|
242
|
+
isArchived: false,
|
|
243
|
+
}],
|
|
244
|
+
]),
|
|
245
|
+
incomingTaxonomies: null,
|
|
246
|
+
incomingTaxonomyState: null,
|
|
247
|
+
incomingTaxonomiesUpdatedAt: '',
|
|
248
|
+
workspaceTaxonomySyncMeta: new Map(),
|
|
249
|
+
recordSyncDiagnostic: vi.fn(),
|
|
250
|
+
});
|
|
251
|
+
expect(core.upsertInitiativeForSync).toHaveBeenCalledWith(expect.objectContaining({
|
|
252
|
+
id: 'initiative-1',
|
|
253
|
+
attachments: [
|
|
254
|
+
expect.objectContaining({
|
|
255
|
+
assetId: 'asset-init-doc',
|
|
256
|
+
caption: 'Initiative context'
|
|
257
|
+
})
|
|
258
|
+
]
|
|
259
|
+
}), 'workspace-1');
|
|
260
|
+
expect(core.upsertWorkstreamForSync).toHaveBeenCalledWith(expect.objectContaining({
|
|
261
|
+
id: 'workstream-1',
|
|
262
|
+
referenceLabel: 'WS-689',
|
|
263
|
+
attachments: [
|
|
264
|
+
expect.objectContaining({
|
|
265
|
+
assetId: 'asset-workstream-doc',
|
|
266
|
+
caption: 'Living security findings register for WS-689'
|
|
267
|
+
})
|
|
268
|
+
]
|
|
269
|
+
}), 'workspace-1');
|
|
270
|
+
});
|
|
182
271
|
it('applies document and asset changes through the content handler helpers', async () => {
|
|
183
272
|
const core = createCoreFixture();
|
|
184
273
|
const writeWorkspaceSyncDocument = vi.fn().mockResolvedValue(undefined);
|
|
@@ -231,7 +320,7 @@ describe('syncApplyHandlers', () => {
|
|
|
231
320
|
expect(core.notifyDocumentMetadataMutation).toHaveBeenNthCalledWith(1, 'workspace-1', ['docs/spec.md', 'assets/proof.png'], 'upsert');
|
|
232
321
|
expect(core.notifyDocumentMetadataMutation).toHaveBeenNthCalledWith(2, 'workspace-1', ['docs/stale.md', 'assets/stale.png'], 'delete');
|
|
233
322
|
});
|
|
234
|
-
it('
|
|
323
|
+
it('allows reference reassignment when metadata drift requires normal sync convergence', async () => {
|
|
235
324
|
const core = createCoreFixture({
|
|
236
325
|
getDocumentWatermark: vi.fn().mockReturnValue(null),
|
|
237
326
|
});
|
|
@@ -280,9 +369,112 @@ describe('syncApplyHandlers', () => {
|
|
|
280
369
|
}),
|
|
281
370
|
recordSyncDiagnostic: vi.fn(),
|
|
282
371
|
});
|
|
283
|
-
expect(writeWorkspaceSyncDocument).toHaveBeenCalledWith('/tmp/taskforce-sync-content', expect.objectContaining({ path: 'docs/spec.md' }), 'workspace-1', { allowReferenceNumberReassignment:
|
|
372
|
+
expect(writeWorkspaceSyncDocument).toHaveBeenCalledWith('/tmp/taskforce-sync-content', expect.objectContaining({ path: 'docs/spec.md' }), 'workspace-1', { allowReferenceNumberReassignment: true });
|
|
284
373
|
expect(writeWorkspaceSyncBinaryAsset).toHaveBeenCalledWith('/tmp/taskforce-sync-content', expect.objectContaining({ path: 'assets/proof.png' }), 'workspace-1', { allowReferenceNumberReassignment: true });
|
|
285
374
|
});
|
|
375
|
+
it('reuses persisted content hashes instead of re-reading unchanged local files while reasserting object storage payloads', async () => {
|
|
376
|
+
const existingDocContent = '# Spec';
|
|
377
|
+
const existingAssetBytes = Buffer.from('png-bytes');
|
|
378
|
+
const core = createCoreFixture({
|
|
379
|
+
getDocumentWatermark: vi.fn().mockReturnValue({
|
|
380
|
+
updatedAt: '2026-04-10T10:00:00.000Z',
|
|
381
|
+
contentHash: createHash('sha256').update(existingDocContent).digest('hex'),
|
|
382
|
+
}),
|
|
383
|
+
});
|
|
384
|
+
const writeWorkspaceSyncDocument = vi.fn().mockResolvedValue(undefined);
|
|
385
|
+
const writeWorkspaceSyncBinaryAsset = vi.fn().mockResolvedValue(undefined);
|
|
386
|
+
const readSpy = vi.spyOn(fs, 'readFileSync').mockImplementation(((targetPath) => {
|
|
387
|
+
const value = String(targetPath);
|
|
388
|
+
if (value.endsWith('spec.md'))
|
|
389
|
+
return existingDocContent;
|
|
390
|
+
return existingAssetBytes;
|
|
391
|
+
}));
|
|
392
|
+
await applyContentSyncChanges({
|
|
393
|
+
core,
|
|
394
|
+
workspaceId: 'workspace-1',
|
|
395
|
+
incomingDocuments: [
|
|
396
|
+
{
|
|
397
|
+
path: 'docs/spec.md',
|
|
398
|
+
updatedAt: '2026-04-10T10:00:00.000Z',
|
|
399
|
+
content: existingDocContent,
|
|
400
|
+
assetId: 'asset-doc-1',
|
|
401
|
+
},
|
|
402
|
+
],
|
|
403
|
+
incomingDocumentDeletes: new Map(),
|
|
404
|
+
incomingAssets: [
|
|
405
|
+
{
|
|
406
|
+
path: 'assets/proof.png',
|
|
407
|
+
updatedAt: '2026-04-10T10:05:00.000Z',
|
|
408
|
+
contentBase64: existingAssetBytes.toString('base64'),
|
|
409
|
+
assetId: 'asset-image-1',
|
|
410
|
+
kind: 'image',
|
|
411
|
+
mimeType: 'image/png',
|
|
412
|
+
},
|
|
413
|
+
],
|
|
414
|
+
incomingAssetDeletes: new Map(),
|
|
415
|
+
basePath: '/tmp/taskforce-sync-content',
|
|
416
|
+
hasObjectStorageClient: () => true,
|
|
417
|
+
hasDocumentSyncMetadataDrift: () => false,
|
|
418
|
+
hasBinaryAssetSyncMetadataDrift: () => false,
|
|
419
|
+
getExistingDocument: () => {
|
|
420
|
+
throw new Error('document fallback should not be used when persisted metadata exists');
|
|
421
|
+
},
|
|
422
|
+
writeWorkspaceSyncDocument,
|
|
423
|
+
deleteWorkspaceSyncDocument: vi.fn(),
|
|
424
|
+
writeWorkspaceSyncBinaryAsset,
|
|
425
|
+
deleteWorkspaceSyncBinaryAsset: vi.fn(),
|
|
426
|
+
getExistingBinaryAsset: () => ({
|
|
427
|
+
updatedAt: '2026-04-10T10:05:00.000Z',
|
|
428
|
+
contentSha256: createHash('sha256').update(existingAssetBytes).digest('hex'),
|
|
429
|
+
}),
|
|
430
|
+
recordSyncDiagnostic: vi.fn(),
|
|
431
|
+
});
|
|
432
|
+
expect(readSpy).not.toHaveBeenCalled();
|
|
433
|
+
expect(writeWorkspaceSyncDocument).toHaveBeenCalledWith('/tmp/taskforce-sync-content', expect.objectContaining({ path: 'docs/spec.md', assetId: 'asset-doc-1' }), 'workspace-1', { allowReferenceNumberReassignment: false });
|
|
434
|
+
expect(writeWorkspaceSyncBinaryAsset).toHaveBeenCalledWith('/tmp/taskforce-sync-content', expect.objectContaining({ path: 'assets/proof.png', assetId: 'asset-image-1' }), 'workspace-1', { allowReferenceNumberReassignment: false });
|
|
435
|
+
});
|
|
436
|
+
it('rejects synced content applies when a binary asset write fails', async () => {
|
|
437
|
+
const core = createCoreFixture();
|
|
438
|
+
const recordSyncDiagnostic = vi.fn();
|
|
439
|
+
await expect(applyContentSyncChanges({
|
|
440
|
+
core,
|
|
441
|
+
workspaceId: 'workspace-1',
|
|
442
|
+
incomingDocuments: [],
|
|
443
|
+
incomingDocumentDeletes: new Map(),
|
|
444
|
+
incomingAssets: [
|
|
445
|
+
{
|
|
446
|
+
path: 'assets/proof.png',
|
|
447
|
+
updatedAt: '2026-04-10T10:05:00.000Z',
|
|
448
|
+
contentBase64: Buffer.from('png-bytes').toString('base64'),
|
|
449
|
+
assetId: 'asset-image-1',
|
|
450
|
+
kind: 'image',
|
|
451
|
+
mimeType: 'image/png',
|
|
452
|
+
},
|
|
453
|
+
],
|
|
454
|
+
incomingAssetDeletes: new Map(),
|
|
455
|
+
basePath: '/tmp/taskforce-sync-content',
|
|
456
|
+
hasObjectStorageClient: () => true,
|
|
457
|
+
hasDocumentSyncMetadataDrift: () => false,
|
|
458
|
+
hasBinaryAssetSyncMetadataDrift: () => false,
|
|
459
|
+
getExistingDocument: () => null,
|
|
460
|
+
writeWorkspaceSyncDocument: vi.fn(),
|
|
461
|
+
deleteWorkspaceSyncDocument: vi.fn(),
|
|
462
|
+
writeWorkspaceSyncBinaryAsset: vi.fn().mockRejectedValue(new Error('R2 write failed')),
|
|
463
|
+
deleteWorkspaceSyncBinaryAsset: vi.fn(),
|
|
464
|
+
getExistingBinaryAsset: () => null,
|
|
465
|
+
recordSyncDiagnostic,
|
|
466
|
+
})).rejects.toMatchObject({
|
|
467
|
+
code: 'SYNC_CONTENT_APPLY_FAILED',
|
|
468
|
+
statusCode: 500,
|
|
469
|
+
});
|
|
470
|
+
expect(recordSyncDiagnostic).toHaveBeenCalledWith('workspace-1', 'apply', 'Failed to apply synced asset change.', expect.objectContaining({
|
|
471
|
+
source: 'assets.apply.write',
|
|
472
|
+
path: 'assets/proof.png',
|
|
473
|
+
assetId: 'asset-image-1',
|
|
474
|
+
kind: 'image',
|
|
475
|
+
error: 'R2 write failed'
|
|
476
|
+
}));
|
|
477
|
+
});
|
|
286
478
|
it('applies collaboration upserts and deletes through the collaboration handlers', () => {
|
|
287
479
|
const core = createCoreFixture();
|
|
288
480
|
applyCollaborationSyncChanges({
|
|
@@ -376,4 +568,59 @@ describe('syncApplyHandlers', () => {
|
|
|
376
568
|
deletedAt: '2026-04-10T11:10:00.000Z',
|
|
377
569
|
});
|
|
378
570
|
});
|
|
571
|
+
it('applies entity events through lean sync lookups instead of hydrated entity activity reads', () => {
|
|
572
|
+
const core = createCoreFixture({
|
|
573
|
+
taskExistsForSync: vi.fn().mockReturnValue(true),
|
|
574
|
+
getEntityEventForSync: vi.fn().mockReturnValue(null),
|
|
575
|
+
listTaskEvents: vi.fn(() => {
|
|
576
|
+
throw new Error('hydrated task activity lookup should not run during sync apply');
|
|
577
|
+
}),
|
|
578
|
+
getTask: vi.fn(() => {
|
|
579
|
+
throw new Error('hydrated task lookup should not run during sync apply');
|
|
580
|
+
}),
|
|
581
|
+
getInitiative: vi.fn(() => {
|
|
582
|
+
throw new Error('hydrated initiative lookup should not run during sync apply');
|
|
583
|
+
}),
|
|
584
|
+
getWorkstream: vi.fn(() => {
|
|
585
|
+
throw new Error('hydrated workstream lookup should not run during sync apply');
|
|
586
|
+
}),
|
|
587
|
+
listEntityEventsForSync: vi.fn(() => {
|
|
588
|
+
throw new Error('hydrated entity event listing should not run during sync apply');
|
|
589
|
+
}),
|
|
590
|
+
upsertEntityEventForSync: vi.fn(),
|
|
591
|
+
});
|
|
592
|
+
applyTaskActivitySyncChanges({
|
|
593
|
+
core,
|
|
594
|
+
workspaceId: 'workspace-1',
|
|
595
|
+
incomingTaskEvents: new Map([
|
|
596
|
+
['task-event-1', {
|
|
597
|
+
id: 'task-event-1',
|
|
598
|
+
taskId: 'task-1',
|
|
599
|
+
entityType: 'task',
|
|
600
|
+
entityId: 'task-1',
|
|
601
|
+
workspaceId: 'workspace-1',
|
|
602
|
+
action: 'task-updated',
|
|
603
|
+
actor: 'user-1',
|
|
604
|
+
actorType: 'human',
|
|
605
|
+
details: { changes: { status: { from: 'task', to: 'review' } } },
|
|
606
|
+
createdAt: '2026-04-10T10:00:00.000Z',
|
|
607
|
+
}],
|
|
608
|
+
]),
|
|
609
|
+
recordSyncDiagnostic: vi.fn(),
|
|
610
|
+
createSyncRouteError: (message, details) => Object.assign(new Error(message), { details }),
|
|
611
|
+
});
|
|
612
|
+
expect(core.taskExistsForSync).toHaveBeenCalledWith('task-1', 'workspace-1');
|
|
613
|
+
expect(core.getEntityEventForSync).toHaveBeenCalledWith({
|
|
614
|
+
workspaceId: 'workspace-1',
|
|
615
|
+
eventId: 'task-event-1',
|
|
616
|
+
});
|
|
617
|
+
expect(core.upsertEntityEventForSync).toHaveBeenCalledWith(expect.objectContaining({
|
|
618
|
+
id: 'task-event-1',
|
|
619
|
+
taskId: 'task-1',
|
|
620
|
+
entityType: 'task',
|
|
621
|
+
entityId: 'task-1',
|
|
622
|
+
workspaceId: 'workspace-1',
|
|
623
|
+
action: 'task-updated',
|
|
624
|
+
}));
|
|
625
|
+
});
|
|
379
626
|
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare function hasOwnSyncField(source: unknown, field: string): boolean;
|
|
2
|
+
export declare function normalizeSyncOptionalString(value: unknown): string | undefined;
|
|
3
|
+
export declare function normalizeSyncNullableString(value: unknown): string | null;
|
|
4
|
+
export declare function normalizeSyncOptionalId(value: unknown): string | undefined;
|
|
5
|
+
export declare function normalizeSyncNullableId(value: unknown): string | null;
|
|
6
|
+
export declare function normalizeSyncNullableIsoString(value: unknown): string | null;
|
|
7
|
+
export declare function normalizeSyncSameOriginAssetUrl(value: unknown): string | null;
|
|
8
|
+
export declare function readSyncOptionalStringField(source: Record<string, unknown>, field: string): string | undefined;
|
|
9
|
+
export declare function readSyncNullableStringField(source: Record<string, unknown>, field: string): string | null | undefined;
|
|
10
|
+
export declare function readSyncNullableIdField(source: Record<string, unknown>, field: string): string | null | undefined;
|
|
11
|
+
export declare function readSyncNullableIsoStringField(source: Record<string, unknown>, field: string): string | null | undefined;
|
|
12
|
+
export declare function readSyncSameOriginAssetUrlField(source: Record<string, unknown>, field: string): string | null | undefined;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export function hasOwnSyncField(source, field) {
|
|
2
|
+
return Boolean(source) && typeof source === 'object' && Object.prototype.hasOwnProperty.call(source, field);
|
|
3
|
+
}
|
|
4
|
+
export function normalizeSyncOptionalString(value) {
|
|
5
|
+
if (value === undefined || value === null)
|
|
6
|
+
return undefined;
|
|
7
|
+
const normalized = String(value).trim();
|
|
8
|
+
return normalized.length > 0 ? normalized : undefined;
|
|
9
|
+
}
|
|
10
|
+
export function normalizeSyncNullableString(value) {
|
|
11
|
+
if (value === undefined || value === null)
|
|
12
|
+
return null;
|
|
13
|
+
const normalized = String(value).trim();
|
|
14
|
+
return normalized.length > 0 ? normalized : null;
|
|
15
|
+
}
|
|
16
|
+
export function normalizeSyncOptionalId(value) {
|
|
17
|
+
return normalizeSyncOptionalString(value);
|
|
18
|
+
}
|
|
19
|
+
export function normalizeSyncNullableId(value) {
|
|
20
|
+
return normalizeSyncNullableString(value);
|
|
21
|
+
}
|
|
22
|
+
export function normalizeSyncNullableIsoString(value) {
|
|
23
|
+
return normalizeSyncNullableString(value);
|
|
24
|
+
}
|
|
25
|
+
export function normalizeSyncSameOriginAssetUrl(value) {
|
|
26
|
+
const normalized = normalizeSyncNullableString(value);
|
|
27
|
+
if (!normalized)
|
|
28
|
+
return null;
|
|
29
|
+
return normalized.startsWith('/api/taskforce/context/') ? normalized : null;
|
|
30
|
+
}
|
|
31
|
+
export function readSyncOptionalStringField(source, field) {
|
|
32
|
+
if (!hasOwnSyncField(source, field))
|
|
33
|
+
return undefined;
|
|
34
|
+
return normalizeSyncOptionalString(source[field]);
|
|
35
|
+
}
|
|
36
|
+
export function readSyncNullableStringField(source, field) {
|
|
37
|
+
if (!hasOwnSyncField(source, field))
|
|
38
|
+
return undefined;
|
|
39
|
+
return normalizeSyncNullableString(source[field]);
|
|
40
|
+
}
|
|
41
|
+
export function readSyncNullableIdField(source, field) {
|
|
42
|
+
if (!hasOwnSyncField(source, field))
|
|
43
|
+
return undefined;
|
|
44
|
+
return normalizeSyncNullableId(source[field]);
|
|
45
|
+
}
|
|
46
|
+
export function readSyncNullableIsoStringField(source, field) {
|
|
47
|
+
if (!hasOwnSyncField(source, field))
|
|
48
|
+
return undefined;
|
|
49
|
+
return normalizeSyncNullableIsoString(source[field]);
|
|
50
|
+
}
|
|
51
|
+
export function readSyncSameOriginAssetUrlField(source, field) {
|
|
52
|
+
if (!hasOwnSyncField(source, field))
|
|
53
|
+
return undefined;
|
|
54
|
+
return normalizeSyncSameOriginAssetUrl(source[field]);
|
|
55
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { TaskItem } from '../types.js';
|
|
2
|
+
export interface SyncAiProfileLike {
|
|
3
|
+
id?: string | null;
|
|
4
|
+
workspaceId?: string | null;
|
|
5
|
+
profileToken?: string | null;
|
|
6
|
+
name?: string | null;
|
|
7
|
+
username?: string | null;
|
|
8
|
+
icon?: string | null;
|
|
9
|
+
color?: string | null;
|
|
10
|
+
avatarUrl?: string | null;
|
|
11
|
+
avatarSourceUrl?: string | null;
|
|
12
|
+
avatarRevision?: number | null;
|
|
13
|
+
avatarUpdatedAt?: string | null;
|
|
14
|
+
description?: string | null;
|
|
15
|
+
role?: string | null;
|
|
16
|
+
provider?: string | null;
|
|
17
|
+
model?: string | null;
|
|
18
|
+
surfaceType?: string | null;
|
|
19
|
+
seatScope?: string | null;
|
|
20
|
+
providerMetadata?: Record<string, unknown> | null;
|
|
21
|
+
archivedAt?: string | null;
|
|
22
|
+
archivedBy?: string | null;
|
|
23
|
+
archivedReason?: string | null;
|
|
24
|
+
mergedIntoProfileId?: string | null;
|
|
25
|
+
rosterStateUpdatedAt?: string | null;
|
|
26
|
+
createdAt?: string | null;
|
|
27
|
+
updatedAt?: string | null;
|
|
28
|
+
lastActiveAt?: string | null;
|
|
29
|
+
}
|
|
30
|
+
export interface SyncResourceAdapter<T> {
|
|
31
|
+
kind: string;
|
|
32
|
+
getId: (resource: T) => string;
|
|
33
|
+
getWatermark: (resource: T) => string;
|
|
34
|
+
getChangeKey: (resource: T) => string;
|
|
35
|
+
}
|
|
36
|
+
export interface SyncResourceBaselineState {
|
|
37
|
+
watermarks?: Map<string, string> | null;
|
|
38
|
+
changeKeys?: Map<string, string> | null;
|
|
39
|
+
}
|
|
40
|
+
export declare function getAiProfileSyncWatermark(profile: Partial<SyncAiProfileLike> | null | undefined): string;
|
|
41
|
+
export declare function getAiProfileSyncChangeKey(profile: Partial<SyncAiProfileLike> | null | undefined): string;
|
|
42
|
+
export declare const taskSyncResourceAdapter: SyncResourceAdapter<Partial<TaskItem> & {
|
|
43
|
+
isArchived?: boolean | null;
|
|
44
|
+
}>;
|
|
45
|
+
export declare const aiProfileSyncResourceAdapter: SyncResourceAdapter<Partial<SyncAiProfileLike>>;
|
|
46
|
+
export declare function shouldSyncResource<T>(adapter: SyncResourceAdapter<T>, resource: T, baseline?: SyncResourceBaselineState | null): boolean;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { buildTaskSyncChangeKey } from './taskSyncChangeKey.js';
|
|
2
|
+
import { normalizeSyncNullableIsoString, normalizeSyncNullableString, normalizeSyncOptionalId, normalizeSyncSameOriginAssetUrl, } from './syncFieldSemantics.js';
|
|
3
|
+
function normalizeSyncTimestampMax(...values) {
|
|
4
|
+
return values.reduce((latest, value) => {
|
|
5
|
+
const normalized = normalizeSyncNullableIsoString(value) || '';
|
|
6
|
+
if (!latest)
|
|
7
|
+
return normalized;
|
|
8
|
+
if (!normalized)
|
|
9
|
+
return latest;
|
|
10
|
+
return normalized > latest ? normalized : latest;
|
|
11
|
+
}, '');
|
|
12
|
+
}
|
|
13
|
+
export function getAiProfileSyncWatermark(profile) {
|
|
14
|
+
const source = profile || {};
|
|
15
|
+
return normalizeSyncTimestampMax(source.createdAt, source.updatedAt, source.lastActiveAt, source.archivedAt, source.rosterStateUpdatedAt);
|
|
16
|
+
}
|
|
17
|
+
export function getAiProfileSyncChangeKey(profile) {
|
|
18
|
+
const source = profile || {};
|
|
19
|
+
return JSON.stringify({
|
|
20
|
+
id: String(source.id || '').trim(),
|
|
21
|
+
workspaceId: String(source.workspaceId || '').trim(),
|
|
22
|
+
profileToken: String(source.profileToken || '').trim(),
|
|
23
|
+
name: String(source.name || '').trim(),
|
|
24
|
+
username: String(source.username || '').trim(),
|
|
25
|
+
icon: String(source.icon || 'Bot').trim() || 'Bot',
|
|
26
|
+
color: String(source.color || '#8b5cf6').trim() || '#8b5cf6',
|
|
27
|
+
avatarUrl: normalizeSyncSameOriginAssetUrl(source.avatarUrl) || '',
|
|
28
|
+
avatarSourceUrl: normalizeSyncSameOriginAssetUrl(source.avatarSourceUrl) || '',
|
|
29
|
+
avatarRevision: Number.isFinite(Number(source.avatarRevision)) ? Math.max(0, Math.floor(Number(source.avatarRevision))) : 0,
|
|
30
|
+
avatarUpdatedAt: normalizeSyncNullableIsoString(source.avatarUpdatedAt) || '',
|
|
31
|
+
description: normalizeSyncNullableString(source.description) || '',
|
|
32
|
+
role: normalizeSyncNullableString(source.role) || '',
|
|
33
|
+
provider: normalizeSyncNullableString(source.provider) || '',
|
|
34
|
+
model: normalizeSyncNullableString(source.model) || '',
|
|
35
|
+
surfaceType: normalizeSyncNullableString(source.surfaceType) || '',
|
|
36
|
+
seatScope: normalizeSyncNullableString(source.seatScope) || '',
|
|
37
|
+
providerMetadata: source.providerMetadata && typeof source.providerMetadata === 'object' && !Array.isArray(source.providerMetadata)
|
|
38
|
+
? source.providerMetadata
|
|
39
|
+
: null,
|
|
40
|
+
archivedAt: normalizeSyncNullableIsoString(source.archivedAt) || '',
|
|
41
|
+
archivedBy: normalizeSyncOptionalId(source.archivedBy) || '',
|
|
42
|
+
archivedReason: normalizeSyncNullableString(source.archivedReason) || '',
|
|
43
|
+
mergedIntoProfileId: normalizeSyncOptionalId(source.mergedIntoProfileId) || '',
|
|
44
|
+
rosterStateUpdatedAt: normalizeSyncNullableIsoString(source.rosterStateUpdatedAt) || '',
|
|
45
|
+
createdAt: normalizeSyncNullableIsoString(source.createdAt) || '',
|
|
46
|
+
updatedAt: normalizeSyncNullableIsoString(source.updatedAt) || '',
|
|
47
|
+
lastActiveAt: normalizeSyncNullableIsoString(source.lastActiveAt) || '',
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
export const taskSyncResourceAdapter = {
|
|
51
|
+
kind: 'task',
|
|
52
|
+
getId: (task) => String(task?.id || '').trim(),
|
|
53
|
+
getWatermark: (task) => String(task?.updatedAt || task?.createdAt || '').trim(),
|
|
54
|
+
getChangeKey: (task) => buildTaskSyncChangeKey(task, Boolean(task?.isArchived))
|
|
55
|
+
};
|
|
56
|
+
export const aiProfileSyncResourceAdapter = {
|
|
57
|
+
kind: 'ai-profile',
|
|
58
|
+
getId: (profile) => String(profile?.id || '').trim(),
|
|
59
|
+
getWatermark: (profile) => getAiProfileSyncWatermark(profile),
|
|
60
|
+
getChangeKey: (profile) => getAiProfileSyncChangeKey(profile)
|
|
61
|
+
};
|
|
62
|
+
export function shouldSyncResource(adapter, resource, baseline) {
|
|
63
|
+
const id = adapter.getId(resource);
|
|
64
|
+
if (!id)
|
|
65
|
+
return false;
|
|
66
|
+
const currentChangeKey = adapter.getChangeKey(resource);
|
|
67
|
+
const previousWatermarks = baseline?.watermarks;
|
|
68
|
+
if (!previousWatermarks || previousWatermarks.size === 0)
|
|
69
|
+
return true;
|
|
70
|
+
if (!previousWatermarks.has(id))
|
|
71
|
+
return true;
|
|
72
|
+
const previousChangeKeys = baseline?.changeKeys;
|
|
73
|
+
const previousChangeKey = previousChangeKeys?.get(id);
|
|
74
|
+
if (typeof previousChangeKey === 'string') {
|
|
75
|
+
return previousChangeKey !== currentChangeKey;
|
|
76
|
+
}
|
|
77
|
+
const previousWatermark = previousWatermarks.get(id) || '';
|
|
78
|
+
return previousWatermark !== currentChangeKey;
|
|
79
|
+
}
|
|
@@ -56,6 +56,8 @@ export interface WorkspacePushSyncResult {
|
|
|
56
56
|
changeCount: number;
|
|
57
57
|
deleteCount: number;
|
|
58
58
|
currentTaskIds: Set<string>;
|
|
59
|
+
currentTaskWatermarks?: Map<string, string>;
|
|
60
|
+
currentTaskChangeKeys?: Map<string, string>;
|
|
59
61
|
deleteTaskIds: Set<string>;
|
|
60
62
|
currentInitiativeIds: Set<string>;
|
|
61
63
|
currentInitiativeWatermarks: Map<string, string>;
|
|
@@ -63,6 +65,7 @@ export interface WorkspacePushSyncResult {
|
|
|
63
65
|
currentWorkstreamWatermarks: Map<string, string>;
|
|
64
66
|
currentAiProfileIds: Set<string>;
|
|
65
67
|
currentAiProfileWatermarks: Map<string, string>;
|
|
68
|
+
currentAiProfileChangeKeys?: Map<string, string>;
|
|
66
69
|
currentDocumentPaths: Set<string>;
|
|
67
70
|
deleteDocumentPaths: Set<string>;
|
|
68
71
|
currentDocumentWatermarks: Map<string, string>;
|
|
@@ -81,6 +84,7 @@ export interface WorkspacePushSyncResult {
|
|
|
81
84
|
currentTaskEventWatermarks: Map<string, string>;
|
|
82
85
|
/** Watermarks for every task upsert that was successfully pushed. */
|
|
83
86
|
pushedWatermarks: Map<string, string>;
|
|
87
|
+
pushedTaskChangeKeys?: Map<string, string>;
|
|
84
88
|
/** Server-emitted realtime mutation event ids for this push apply. */
|
|
85
89
|
emittedEventIds: string[];
|
|
86
90
|
/** Authoritative task snapshots returned immediately by the push route for incoming task upserts. */
|
|
@@ -106,6 +110,7 @@ export interface WorkspacePullSyncResult {
|
|
|
106
110
|
success: boolean;
|
|
107
111
|
kind?: WorkspacePullFailureKind;
|
|
108
112
|
status?: number;
|
|
113
|
+
errorCode?: string;
|
|
109
114
|
retryAfterMs?: number;
|
|
110
115
|
transient?: boolean;
|
|
111
116
|
failures?: string[];
|
|
@@ -121,6 +126,7 @@ export interface WorkspacePullSyncResult {
|
|
|
121
126
|
pulledActiveUpserts: boolean;
|
|
122
127
|
pulledArchivedUpserts: boolean;
|
|
123
128
|
pulledTaskEventUpserts?: boolean;
|
|
129
|
+
pulledPlanningUpserts?: boolean;
|
|
124
130
|
documentDecryptFailures?: string[];
|
|
125
131
|
emittedEventIds?: string[];
|
|
126
132
|
serverDiagnostics?: Record<string, unknown> | null;
|