@taskforcehq/taskforce 0.3.306 → 0.3.308
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 +317 -27
- package/dist/TaskforceCore.js +1 -0
- package/dist/TaskforceCore.test.js +178 -0
- package/dist/components/activity/EntityActivityTimeline.d.ts +34 -0
- package/dist/components/activity/EntityActivityTimeline.js +81 -0
- package/dist/components/context/ContextAttachmentManager.js +15 -3
- package/dist/components/features/AgentsModule.d.ts +5 -1
- package/dist/components/features/AgentsModule.js +142 -39
- package/dist/components/features/AgentsModule.test.js +260 -11
- 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 +3 -1
- package/dist/components/features/DocumentViewer.js +6 -5
- package/dist/components/features/DocumentWorkspace.d.ts +10 -2
- package/dist/components/features/DocumentWorkspace.js +15 -4
- package/dist/components/features/DocumentWorkspace.test.js +20 -3
- 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/task/TaskActionHeader.js +11 -5
- package/dist/components/task/TaskActionHeader.test.js +10 -0
- package/dist/components/task/TaskCard.js +6 -2
- package/dist/components/task/TaskContextUpload.test.js +3 -3
- package/dist/components/task/TaskForm.js +14 -64
- package/dist/components/task/TaskKanban.js +0 -8
- package/dist/components/task/TaskList.js +5 -1
- package/dist/components/task/TaskList.test.js +4 -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 +20 -15
- package/dist/components/views/PlanComparisonPage.js +221 -82
- package/dist/components/views/PlanComparisonPage.test.js +268 -14
- package/dist/components/views/PlansPage.js +16 -10
- package/dist/components/views/PlansPage.test.js +4 -2
- package/dist/components/views/StandaloneLayout.js +256 -69
- package/dist/components/views/WidgetView.js +10 -8
- package/dist/components/views/panels/PlanningDrawer.d.ts +19 -6
- package/dist/components/views/panels/PlanningDrawer.js +259 -51
- package/dist/components/views/panels/PlanningDrawer.test.js +392 -4
- package/dist/config/envSchema.js +1 -0
- package/dist/core/AiProfileService.d.ts +7 -0
- package/dist/core/AiProfileService.js +460 -35
- package/dist/core/AiProfiles.test.js +648 -2
- package/dist/core/AttachmentLinkService.d.ts +3 -0
- package/dist/core/AttachmentLinkService.js +58 -13
- package/dist/core/GlobalSettingsService.js +30 -0
- package/dist/core/GlobalSettingsService.test.d.ts +1 -0
- package/dist/core/GlobalSettingsService.test.js +45 -0
- package/dist/core/McpTokenService.d.ts +12 -0
- package/dist/core/McpTokenService.js +44 -1
- package/dist/core/PlanEntitlementService.d.ts +20 -0
- package/dist/core/PlanEntitlementService.js +215 -19
- package/dist/core/PlanFeatureCatalog.test.js +55 -0
- package/dist/core/PlanningEntities.test.js +366 -4
- 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/TaskAuditTimeline.test.js +96 -0
- package/dist/core/Taskforce.d.ts +204 -26
- package/dist/core/Taskforce.ids.test.js +58 -0
- package/dist/core/Taskforce.js +781 -71
- package/dist/core/Taskforce.mcpAuth.test.js +109 -0
- package/dist/core/types.d.ts +10 -0
- package/dist/hooks/auth/useTaskforceAuthBootstrap.js +2 -1
- 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/orchestratorShared.d.ts +3 -3
- package/dist/hooks/sync/orchestratorShared.js +61 -1
- package/dist/hooks/sync/recovery.js +8 -0
- package/dist/hooks/sync/recovery.test.js +5 -5
- package/dist/hooks/sync/transfers.d.ts +2 -1
- package/dist/hooks/sync/transfers.js +36 -9
- package/dist/hooks/sync/transfers.test.js +534 -2
- package/dist/hooks/useFilterSort.js +13 -13
- package/dist/hooks/useFilterSort.test.js +87 -1
- package/dist/hooks/useSyncOrchestrator.js +50 -5
- package/dist/hooks/useTaskforce.d.ts +85 -50
- package/dist/hooks/useTaskforce.js +44 -14
- package/dist/hooks/useTaskforce.runtime-routing.test.js +94 -0
- package/dist/hooks/useTaskforce.sync-behavior.test.js +99 -0
- package/dist/hooks/useWorkspaceSyncController.js +7 -1
- package/dist/hooks/useWorkspaceSyncController.test.js +48 -0
- package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +14 -7
- 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 +113 -7
- package/dist/mcp/runtime.d.ts +1 -0
- package/dist/mcp/runtime.js +969 -122
- package/dist/mcp/runtime.test.js +1083 -11
- 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.js +58 -15
- 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 +66 -7
- package/dist/server/index.js +4 -0
- package/dist/server/index.test.js +6 -1
- package/dist/server/routes/admin.js +328 -9
- package/dist/server/routes/annotatedAttachments.js +51 -0
- package/dist/server/routes/auth.d.ts +11 -0
- package/dist/server/routes/auth.js +189 -27
- package/dist/server/routes/authSupport.d.ts +5 -0
- package/dist/server/routes/authSupport.js +13 -1
- package/dist/server/routes/billing.d.ts +1 -0
- package/dist/server/routes/billing.js +116 -63
- package/dist/server/routes/billing.test.js +162 -11
- package/dist/server/routes/documents.js +10 -0
- package/dist/server/routes/shared.js +0 -10
- package/dist/server/routes/sync.integration.test.js +221 -0
- package/dist/server/routes/sync.js +13 -3
- package/dist/server/routes/syncSnapshotRoutes.js +2 -0
- package/dist/server/routes/tasks.js +12 -9
- package/dist/server/routes.js +87 -8
- package/dist/server/routes.test.js +972 -23
- package/dist/shared/aiProfileSurfaceType.d.ts +1 -1
- package/dist/shared/aiProfileSurfaceType.js +10 -8
- 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/sync/collaborationSyncPayload.js +2 -0
- package/dist/sync/collaborationSyncPayload.test.js +1 -0
- 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 +5 -1
- package/dist/sync/contentSyncState.js +231 -37
- package/dist/sync/planningSyncPayload.js +5 -0
- package/dist/sync/planningSyncPayload.test.js +24 -0
- package/dist/sync/syncApplyHandlers.d.ts +4 -4
- package/dist/sync/syncApplyHandlers.js +89 -31
- package/dist/sync/syncApplyHandlers.test.js +184 -4
- package/dist/sync/syncResourceAdapters.d.ts +2 -0
- package/dist/sync/syncResourceAdapters.js +2 -0
- package/dist/sync/syncService.d.ts +1 -0
- package/dist/sync/syncService.js +13 -1
- package/dist/sync/syncService.test.js +39 -0
- package/dist/sync/workspacePullFeed.d.ts +4 -0
- package/dist/sync/workspacePullFeed.js +129 -70
- package/dist/sync/workspacePullFeed.test.js +49 -0
- package/dist/sync/workspaceSyncModel.d.ts +28 -6
- package/dist/sync/workspaceSyncModel.js +159 -45
- package/dist/sync/workspaceSyncModel.test.js +269 -3
- package/dist/types.d.ts +33 -2
- package/dist/ui/agent-logos/ChatGPT.png +0 -0
- package/dist/ui/agent-logos/Gemini CLI.jpeg +0 -0
- package/dist/ui/agent-logos/antigravity.jpeg +0 -0
- package/dist/ui/agent-logos/claude-code.jpeg +0 -0
- package/dist/ui/agent-logos/codex.jpeg +0 -0
- package/dist/ui/agent-logos/cursor.png +0 -0
- package/dist/ui/agent-logos/openclaw.jpeg +0 -0
- package/dist/ui/agent-logos/windsurf.png +0 -0
- package/dist/ui/assets/AgentsModule-BS4Pi_nC.js +1 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BVKew-mH.css +1 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-CCckzWYZ.js +3 -0
- package/dist/ui/assets/ContextAttachmentManager-CfG_ER7C.js +3 -0
- package/dist/ui/assets/DocumentWorkspace-BVaWPA25.js +252 -0
- package/dist/ui/assets/DocumentWorkspace-D4rJKXzd.css +1 -0
- package/dist/ui/assets/EntityActivityTimeline-DSj0ThaK.js +1 -0
- package/dist/ui/assets/EntityActivityTimeline-DyqvvhuF.css +1 -0
- package/dist/ui/assets/{InitiativesModule-9E6ParrY.js → InitiativesModule-AxMkWtxH.js} +1 -1
- package/dist/ui/assets/PlansPage-B_z-D6Nh.css +1 -0
- package/dist/ui/assets/PlansPage-Ndt7mYfo.js +1 -0
- package/dist/ui/assets/TaskContextUpload-Dw4rTF4i.js +1 -0
- package/dist/ui/assets/TaskSettings-f2ga42_V.js +9 -0
- package/dist/ui/assets/{WorkflowsModule-BA7jcEpH.js → WorkflowsModule-E4UL3mov.js} +4 -4
- package/dist/ui/assets/documentReferences-BOUcJm6-.js +1 -0
- package/dist/ui/assets/index-BvAbqx5Q.css +1 -0
- package/dist/ui/assets/index-MAHKvFqp.js +4 -0
- package/dist/ui/assets/{vendor-icons-DuEd_65c.js → vendor-icons-B32hGuF2.js} +1 -1
- package/dist/ui/index.html +3 -3
- package/dist/ui/og-image.png +0 -0
- package/dist/ui/product/agent manager.png +0 -0
- package/dist/ui/product/agent_manager_02.png +0 -0
- package/dist/utils/aiProfileEvents.d.ts +7 -0
- package/dist/utils/aiProfileEvents.js +6 -0
- package/dist/utils/assignees.d.ts +6 -0
- package/dist/utils/assignees.js +8 -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/contextFiles.d.ts +3 -1
- package/dist/utils/contextFiles.js +2 -1
- package/dist/utils/taskActivity.d.ts +7 -1
- package/dist/utils/taskActivity.js +63 -1
- package/dist/utils/taskActivity.test.js +23 -1
- 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/package.json +1 -1
- package/dist/ui/assets/AgentsModule-DrLawwNl.js +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-BaS2VwIr.css +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-Z9_whf7F.js +0 -3
- package/dist/ui/assets/DocumentWorkspace-B03MaSkw.js +0 -252
- package/dist/ui/assets/DocumentWorkspace-Dhdso07p.css +0 -1
- package/dist/ui/assets/PlansPage-CvfnMiWq.css +0 -1
- package/dist/ui/assets/PlansPage-DRXscYxH.js +0 -1
- package/dist/ui/assets/TaskSettings-DZX4jk7e.js +0 -9
- package/dist/ui/assets/index-9eT8e0Lu.css +0 -1
- package/dist/ui/assets/index-C6k75jr8.js +0 -6
|
@@ -5,6 +5,31 @@ export async function buildWorkspacePullFeed(input) {
|
|
|
5
5
|
const { core, workspaceId, cursor, pageSize, encodeWorkspaceSyncCursor, contentSyncState, collaborationSyncState } = input;
|
|
6
6
|
const syncCursor = cursor ? { watermark: cursor.u, id: cursor.id } : null;
|
|
7
7
|
const dbFetchLimit = pageSize * 2 + 10;
|
|
8
|
+
const snapshotErrors = [];
|
|
9
|
+
const captureSnapshotError = (domain, error) => {
|
|
10
|
+
snapshotErrors.push({
|
|
11
|
+
domain,
|
|
12
|
+
error: String(error?.message || error || 'Unknown snapshot error')
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
const readSnapshot = (domain, fallback, reader) => {
|
|
16
|
+
try {
|
|
17
|
+
return reader();
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
captureSnapshotError(domain, error);
|
|
21
|
+
return fallback;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const readSnapshotAsync = async (domain, fallback, reader) => {
|
|
25
|
+
try {
|
|
26
|
+
return await reader();
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
captureSnapshotError(domain, error);
|
|
30
|
+
return fallback;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
8
33
|
const taskRows = core.listTasksForSync(workspaceId, syncCursor, dbFetchLimit);
|
|
9
34
|
const upsertEntries = taskRows
|
|
10
35
|
.map((entry) => {
|
|
@@ -28,7 +53,7 @@ export async function buildWorkspacePullFeed(input) {
|
|
|
28
53
|
taskId: String(entry.taskId || '').trim()
|
|
29
54
|
}))
|
|
30
55
|
.filter((entry) => Number.isFinite(Date.parse(entry.watermark)) && entry.sortId.length > 0);
|
|
31
|
-
const taxonomySnapshot = core.getTaxonomiesSyncSnapshot(workspaceId);
|
|
56
|
+
const taxonomySnapshot = readSnapshot('taxonomy', null, () => core.getTaxonomiesSyncSnapshot(workspaceId));
|
|
32
57
|
const taxonomyEntries = (taxonomySnapshot
|
|
33
58
|
&& Array.isArray(taxonomySnapshot.taxonomies)
|
|
34
59
|
&& Number.isFinite(Date.parse(String(taxonomySnapshot.updatedAt || '').trim())))
|
|
@@ -40,7 +65,7 @@ export async function buildWorkspacePullFeed(input) {
|
|
|
40
65
|
...(taxonomySnapshot.taxonomyState ? { taxonomyState: taxonomySnapshot.taxonomyState } : {})
|
|
41
66
|
}]
|
|
42
67
|
: [];
|
|
43
|
-
const initiativeEntries = core.listInitiatives(workspaceId)
|
|
68
|
+
const initiativeEntries = readSnapshot('initiatives', [], () => core.listInitiatives(workspaceId))
|
|
44
69
|
.map((initiative) => ({
|
|
45
70
|
kind: 'initiative',
|
|
46
71
|
watermark: String(initiative.updatedAt || initiative.createdAt || '').trim(),
|
|
@@ -48,7 +73,7 @@ export async function buildWorkspacePullFeed(input) {
|
|
|
48
73
|
initiative
|
|
49
74
|
}))
|
|
50
75
|
.filter((entry) => Number.isFinite(Date.parse(entry.watermark)) && entry.initiative.id.length > 0);
|
|
51
|
-
const workstreamEntries = core.listWorkstreams(workspaceId)
|
|
76
|
+
const workstreamEntries = readSnapshot('workstreams', [], () => core.listWorkstreams(workspaceId))
|
|
52
77
|
.map((workstream) => ({
|
|
53
78
|
kind: 'workstream',
|
|
54
79
|
watermark: String(workstream.updatedAt || workstream.createdAt || '').trim(),
|
|
@@ -56,7 +81,7 @@ export async function buildWorkspacePullFeed(input) {
|
|
|
56
81
|
workstream
|
|
57
82
|
}))
|
|
58
83
|
.filter((entry) => Number.isFinite(Date.parse(entry.watermark)) && entry.workstream.id.length > 0);
|
|
59
|
-
const aiProfileEntries = core.listAiProfiles(workspaceId, { includeArchived: true })
|
|
84
|
+
const aiProfileEntries = readSnapshot('ai-profiles', [], () => core.listAiProfiles(workspaceId, { includeArchived: true }))
|
|
60
85
|
.map((profile) => ({
|
|
61
86
|
kind: 'ai-profile',
|
|
62
87
|
watermark: aiProfileSyncResourceAdapter.getWatermark(profile),
|
|
@@ -65,7 +90,7 @@ export async function buildWorkspacePullFeed(input) {
|
|
|
65
90
|
}))
|
|
66
91
|
.filter((entry) => Number.isFinite(Date.parse(entry.watermark)) && entry.sortId.length > 0);
|
|
67
92
|
const indexStartedAtMs = Date.now();
|
|
68
|
-
const documentIndex = await contentSyncState.listWorkspaceSyncDocumentIndex(core.getPaths().basePath, workspaceId);
|
|
93
|
+
const documentIndex = await readSnapshotAsync('documents.index', [], () => contentSyncState.listWorkspaceSyncDocumentIndex(core.getPaths().basePath, workspaceId));
|
|
69
94
|
const documentEntries = documentIndex
|
|
70
95
|
.map((doc) => ({
|
|
71
96
|
kind: 'document',
|
|
@@ -77,13 +102,15 @@ export async function buildWorkspacePullFeed(input) {
|
|
|
77
102
|
referenceNumber: doc.referenceNumber,
|
|
78
103
|
version: doc.version,
|
|
79
104
|
taskId: doc.taskId,
|
|
105
|
+
linkTargetType: doc.linkTargetType,
|
|
106
|
+
linkTargetId: doc.linkTargetId,
|
|
80
107
|
logicalName: doc.logicalName,
|
|
81
108
|
caption: doc.caption,
|
|
82
109
|
originalFilename: doc.originalFilename,
|
|
83
110
|
linkRole: (doc.linkRole === 'reference' ? 'reference' : 'attachment')
|
|
84
111
|
}))
|
|
85
112
|
.filter((entry) => Number.isFinite(Date.parse(entry.watermark)) && entry.path.length > 0);
|
|
86
|
-
const documentDeleteEntries = contentSyncState.listWorkspaceSyncDocumentDeletesSnapshot(workspaceId)
|
|
113
|
+
const documentDeleteEntries = readSnapshot('documents.deletes', [], () => contentSyncState.listWorkspaceSyncDocumentDeletesSnapshot(workspaceId))
|
|
87
114
|
.map((doc) => ({
|
|
88
115
|
kind: 'document-delete',
|
|
89
116
|
watermark: String(doc.deletedAt || '').trim(),
|
|
@@ -92,7 +119,7 @@ export async function buildWorkspacePullFeed(input) {
|
|
|
92
119
|
assetId: typeof doc.assetId === 'string' && doc.assetId.trim().length > 0 ? doc.assetId.trim() : undefined
|
|
93
120
|
}))
|
|
94
121
|
.filter((entry) => Number.isFinite(Date.parse(entry.watermark)) && entry.path.length > 0);
|
|
95
|
-
const documentReviewSessions = collaborationSyncState.listWorkspaceSyncDocumentReviewSessionsSnapshot(workspaceId);
|
|
122
|
+
const documentReviewSessions = readSnapshot('document-review-sessions', [], () => collaborationSyncState.listWorkspaceSyncDocumentReviewSessionsSnapshot(workspaceId));
|
|
96
123
|
const documentReviewSessionEntries = documentReviewSessions
|
|
97
124
|
.filter((session) => !session.deletedAt)
|
|
98
125
|
.map((session) => ({
|
|
@@ -111,7 +138,7 @@ export async function buildWorkspacePullFeed(input) {
|
|
|
111
138
|
sessionId: String(session.id || '').trim()
|
|
112
139
|
}))
|
|
113
140
|
.filter((entry) => Number.isFinite(Date.parse(entry.watermark)) && entry.sessionId.length > 0);
|
|
114
|
-
const documentReviewComments = collaborationSyncState.listWorkspaceSyncDocumentReviewCommentsSnapshot(workspaceId);
|
|
141
|
+
const documentReviewComments = readSnapshot('document-review-comments', [], () => collaborationSyncState.listWorkspaceSyncDocumentReviewCommentsSnapshot(workspaceId));
|
|
115
142
|
const documentReviewCommentEntries = documentReviewComments
|
|
116
143
|
.filter((comment) => !comment.deletedAt)
|
|
117
144
|
.map((comment) => ({
|
|
@@ -130,7 +157,7 @@ export async function buildWorkspacePullFeed(input) {
|
|
|
130
157
|
commentId: String(comment.id || '').trim()
|
|
131
158
|
}))
|
|
132
159
|
.filter((entry) => Number.isFinite(Date.parse(entry.watermark)) && entry.commentId.length > 0);
|
|
133
|
-
const annotatedAttachmentSessions = collaborationSyncState.listWorkspaceSyncAnnotatedAttachmentSessionsSnapshot(workspaceId);
|
|
160
|
+
const annotatedAttachmentSessions = readSnapshot('annotated-attachment-sessions', [], () => collaborationSyncState.listWorkspaceSyncAnnotatedAttachmentSessionsSnapshot(workspaceId));
|
|
134
161
|
const annotatedAttachmentSessionEntries = annotatedAttachmentSessions
|
|
135
162
|
.filter((session) => !session.deletedAt)
|
|
136
163
|
.map((session) => ({
|
|
@@ -149,15 +176,38 @@ export async function buildWorkspacePullFeed(input) {
|
|
|
149
176
|
sessionId: String(session.id || '').trim()
|
|
150
177
|
}))
|
|
151
178
|
.filter((entry) => Number.isFinite(Date.parse(entry.watermark)) && entry.sessionId.length > 0);
|
|
152
|
-
const taskEventEntries = collaborationSyncState.listWorkspaceSyncTaskEventsSnapshot(workspaceId)
|
|
153
|
-
.map((event) =>
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
event
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
179
|
+
const taskEventEntries = readSnapshot('task-events', [], () => collaborationSyncState.listWorkspaceSyncTaskEventsSnapshot(workspaceId))
|
|
180
|
+
.map((event) => {
|
|
181
|
+
const entityType = event.entityType === 'initiative' || event.entityType === 'workstream'
|
|
182
|
+
? event.entityType
|
|
183
|
+
: 'task';
|
|
184
|
+
const entityId = String(event.entityId || event.taskId || '').trim();
|
|
185
|
+
if (entityType === 'task') {
|
|
186
|
+
return {
|
|
187
|
+
kind: 'task-event',
|
|
188
|
+
watermark: String(event.createdAt || '').trim(),
|
|
189
|
+
sortId: `task-event:${String(event.id || '').trim()}`,
|
|
190
|
+
event: {
|
|
191
|
+
...event,
|
|
192
|
+
entityType: 'task',
|
|
193
|
+
entityId,
|
|
194
|
+
taskId: String(event.taskId || entityId).trim(),
|
|
195
|
+
},
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
kind: 'entity-event',
|
|
200
|
+
watermark: String(event.createdAt || '').trim(),
|
|
201
|
+
sortId: `entity-event:${String(event.id || '').trim()}`,
|
|
202
|
+
event: {
|
|
203
|
+
...event,
|
|
204
|
+
entityType,
|
|
205
|
+
entityId,
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
})
|
|
209
|
+
.filter((entry) => Number.isFinite(Date.parse(entry.watermark)) && entry.event.id.length > 0 && entry.event.entityId.length > 0 && (entry.kind !== 'task-event' || Boolean(entry.event.taskId)));
|
|
210
|
+
const assetIndex = await readSnapshotAsync('assets.index', [], () => contentSyncState.listWorkspaceSyncBinaryAssetIndex(workspaceId));
|
|
161
211
|
const assetEntries = assetIndex
|
|
162
212
|
.map((asset) => ({
|
|
163
213
|
kind: 'asset',
|
|
@@ -169,13 +219,15 @@ export async function buildWorkspacePullFeed(input) {
|
|
|
169
219
|
mimeType: asset.mimeType,
|
|
170
220
|
referenceNumber: asset.referenceNumber,
|
|
171
221
|
taskId: asset.taskId,
|
|
222
|
+
linkTargetType: asset.linkTargetType,
|
|
223
|
+
linkTargetId: asset.linkTargetId,
|
|
172
224
|
logicalName: asset.logicalName,
|
|
173
225
|
caption: asset.caption,
|
|
174
226
|
originalFilename: asset.originalFilename,
|
|
175
227
|
linkRole: asset.linkRole
|
|
176
228
|
}))
|
|
177
229
|
.filter((entry) => Number.isFinite(Date.parse(entry.watermark)) && entry.path.length > 0);
|
|
178
|
-
const assetDeleteEntries = contentSyncState.listWorkspaceSyncBinaryAssetDeletesSnapshot(workspaceId)
|
|
230
|
+
const assetDeleteEntries = readSnapshot('assets.deletes', [], () => contentSyncState.listWorkspaceSyncBinaryAssetDeletesSnapshot(workspaceId))
|
|
179
231
|
.map((asset) => ({
|
|
180
232
|
kind: 'asset-delete',
|
|
181
233
|
watermark: String(asset.deletedAt || '').trim(),
|
|
@@ -218,7 +270,7 @@ export async function buildWorkspacePullFeed(input) {
|
|
|
218
270
|
return String(a.sortId || '').localeCompare(String(b.sortId || ''));
|
|
219
271
|
});
|
|
220
272
|
const page = afterCursor.slice(0, pageSize);
|
|
221
|
-
const workspaceMembers = core.listWorkspaceUsers(workspaceId).map((member) => ({
|
|
273
|
+
const workspaceMembers = readSnapshot('workspace-members', [], () => core.listWorkspaceUsers(workspaceId)).map((member) => ({
|
|
222
274
|
userId: member.userId,
|
|
223
275
|
workspaceId,
|
|
224
276
|
email: member.email,
|
|
@@ -287,55 +339,61 @@ export async function buildWorkspacePullFeed(input) {
|
|
|
287
339
|
? [{ op: 'annotated-attachment-session-delete', sessionId: entry.sessionId, deletedAt: entry.watermark, watermark: entry.watermark }]
|
|
288
340
|
: entry.kind === 'task-event'
|
|
289
341
|
? [{ op: 'task-event-upsert', event: entry.event, watermark: entry.watermark }]
|
|
290
|
-
: entry.kind === '
|
|
291
|
-
?
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
342
|
+
: entry.kind === 'entity-event'
|
|
343
|
+
? [{ op: 'entity-event-upsert', event: entry.event, watermark: entry.watermark }]
|
|
344
|
+
: entry.kind === 'document'
|
|
345
|
+
? (() => {
|
|
346
|
+
const payload = hydratedDocuments.get(entry.path);
|
|
347
|
+
if (!payload)
|
|
348
|
+
return [];
|
|
349
|
+
return [{
|
|
350
|
+
op: 'document-upsert',
|
|
351
|
+
path: entry.path,
|
|
352
|
+
updatedAt: entry.watermark,
|
|
353
|
+
content: payload.content,
|
|
354
|
+
assetId: payload.assetId,
|
|
355
|
+
documentId: payload.documentId,
|
|
356
|
+
referenceNumber: payload.referenceNumber,
|
|
357
|
+
version: payload.version,
|
|
358
|
+
taskId: payload.taskId,
|
|
359
|
+
linkTargetType: payload.linkTargetType,
|
|
360
|
+
linkTargetId: payload.linkTargetId,
|
|
361
|
+
logicalName: payload.logicalName,
|
|
362
|
+
caption: payload.caption,
|
|
363
|
+
originalFilename: payload.originalFilename,
|
|
364
|
+
linkRole: payload.linkRole === 'reference' ? 'reference' : 'attachment',
|
|
365
|
+
watermark: entry.watermark
|
|
366
|
+
}];
|
|
367
|
+
})()
|
|
368
|
+
: entry.kind === 'document-delete'
|
|
369
|
+
? [{ op: 'document-delete', path: entry.path, assetId: entry.assetId, deletedAt: entry.watermark, watermark: entry.watermark }]
|
|
370
|
+
: entry.kind === 'asset'
|
|
371
|
+
? (() => {
|
|
372
|
+
const payload = hydratedAssets.get(entry.path);
|
|
373
|
+
if (!payload)
|
|
374
|
+
return [];
|
|
375
|
+
return [{
|
|
376
|
+
op: 'asset-upsert',
|
|
377
|
+
path: entry.path,
|
|
378
|
+
updatedAt: entry.watermark,
|
|
379
|
+
contentBase64: payload.contentBase64,
|
|
380
|
+
assetId: payload.assetId,
|
|
381
|
+
kind: payload.kind,
|
|
382
|
+
mimeType: payload.mimeType,
|
|
383
|
+
referenceNumber: payload.referenceNumber,
|
|
384
|
+
taskId: payload.taskId,
|
|
385
|
+
linkTargetType: payload.linkTargetType,
|
|
386
|
+
linkTargetId: payload.linkTargetId,
|
|
387
|
+
logicalName: payload.logicalName,
|
|
388
|
+
caption: payload.caption,
|
|
389
|
+
originalFilename: payload.originalFilename,
|
|
390
|
+
linkRole: payload.linkRole,
|
|
391
|
+
watermark: entry.watermark
|
|
392
|
+
}];
|
|
393
|
+
})()
|
|
394
|
+
: entry.kind === 'asset-delete'
|
|
395
|
+
? [{ op: 'asset-delete', path: entry.path, assetId: entry.assetId, deletedAt: entry.watermark, watermark: entry.watermark }]
|
|
396
|
+
: [{ op: 'upsert', task: entry.task, archived: Boolean(entry.archived), watermark: entry.watermark }]));
|
|
339
397
|
const encodeMs = Date.now() - encodeStartedAtMs;
|
|
340
398
|
return {
|
|
341
399
|
workspaceMembers,
|
|
@@ -351,7 +409,8 @@ export async function buildWorkspacePullFeed(input) {
|
|
|
351
409
|
indexMs,
|
|
352
410
|
hydrationMs,
|
|
353
411
|
encodeMs,
|
|
354
|
-
buildMs: Date.now() - buildStartedAtMs
|
|
412
|
+
buildMs: Date.now() - buildStartedAtMs,
|
|
413
|
+
snapshotErrors
|
|
355
414
|
}
|
|
356
415
|
};
|
|
357
416
|
}
|
|
@@ -211,6 +211,55 @@ describe('workspacePullFeed', () => {
|
|
|
211
211
|
expect(result.nextCursor).toBe('2026-04-10T10:05:00.000Z|ai-profile:ai-profile-1');
|
|
212
212
|
expect(result.hasMore).toBe(false);
|
|
213
213
|
});
|
|
214
|
+
it('degrades optional snapshot failures into diagnostics instead of throwing the pull feed', async () => {
|
|
215
|
+
const core = createCoreMock();
|
|
216
|
+
const content = createContentSyncStateMock();
|
|
217
|
+
const collaboration = createCollaborationSyncStateMock();
|
|
218
|
+
core.listTasksForSync = () => [
|
|
219
|
+
{
|
|
220
|
+
archived: false,
|
|
221
|
+
task: {
|
|
222
|
+
id: 'task-1',
|
|
223
|
+
title: 'Still syncs tasks',
|
|
224
|
+
status: 'task',
|
|
225
|
+
category: 'general',
|
|
226
|
+
type: 'task',
|
|
227
|
+
createdAt: '2026-04-10T10:00:00.000Z',
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
];
|
|
231
|
+
core.listWorkspaceUsers = () => {
|
|
232
|
+
throw new Error('workspace members exploded');
|
|
233
|
+
};
|
|
234
|
+
content.listWorkspaceSyncBinaryAssetIndex = async () => {
|
|
235
|
+
throw new Error('asset index exploded');
|
|
236
|
+
};
|
|
237
|
+
collaboration.listWorkspaceSyncDocumentReviewSessionsSnapshot = () => {
|
|
238
|
+
throw new Error('review sessions exploded');
|
|
239
|
+
};
|
|
240
|
+
const result = await buildWorkspacePullFeed({
|
|
241
|
+
core,
|
|
242
|
+
workspaceId: 'workspace-1',
|
|
243
|
+
cursor: null,
|
|
244
|
+
pageSize: 10,
|
|
245
|
+
encodeWorkspaceSyncCursor: encodeCursor,
|
|
246
|
+
contentSyncState: content,
|
|
247
|
+
collaborationSyncState: collaboration,
|
|
248
|
+
});
|
|
249
|
+
expect(result.changes).toEqual([
|
|
250
|
+
expect.objectContaining({
|
|
251
|
+
op: 'upsert',
|
|
252
|
+
task: expect.objectContaining({ id: 'task-1' })
|
|
253
|
+
})
|
|
254
|
+
]);
|
|
255
|
+
expect(result.workspaceMembers).toEqual([]);
|
|
256
|
+
expect(result.diagnostics.assetIndexCount).toBe(0);
|
|
257
|
+
expect(result.diagnostics.snapshotErrors).toEqual(expect.arrayContaining([
|
|
258
|
+
expect.objectContaining({ domain: 'assets.index', error: 'asset index exploded' }),
|
|
259
|
+
expect.objectContaining({ domain: 'document-review-sessions', error: 'review sessions exploded' }),
|
|
260
|
+
expect.objectContaining({ domain: 'workspace-members', error: 'workspace members exploded' }),
|
|
261
|
+
]));
|
|
262
|
+
});
|
|
214
263
|
it('hydrates document and asset payloads only for entries included in the current page', async () => {
|
|
215
264
|
const core = createCoreMock();
|
|
216
265
|
const content = createContentSyncStateMock();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AttachmentItem, EntityEvent, InitiativeItem, TaskItem, WorkstreamItem } from '../types';
|
|
2
2
|
import type { DocumentReviewCommentRecord, DocumentReviewSessionStatus } from '../documentReviews/types.js';
|
|
3
3
|
import type { AnnotatedAttachmentAnnotation } from '../annotatedAttachments/types.js';
|
|
4
4
|
import type { WorkspaceTaxonomyState } from '../shared/taxonomyState.js';
|
|
@@ -6,16 +6,23 @@ import { type AiProfileSurfaceType } from '../shared/aiProfileSurfaceType.js';
|
|
|
6
6
|
import { type AiProfileSeatScope } from '../shared/aiProfileSeatScope.js';
|
|
7
7
|
import { type TaskSyncPayload } from './taskSyncPayload.js';
|
|
8
8
|
export type WorkspaceSyncTaskSnapshot = TaskSyncPayload;
|
|
9
|
-
export interface
|
|
9
|
+
export interface WorkspaceSyncEntityEventSnapshot {
|
|
10
10
|
id: string;
|
|
11
|
-
taskId: string;
|
|
12
11
|
workspaceId: string;
|
|
12
|
+
entityType: 'task' | 'initiative' | 'workstream';
|
|
13
|
+
entityId: string;
|
|
14
|
+
taskId?: string;
|
|
13
15
|
action: string;
|
|
14
16
|
actor: string;
|
|
15
17
|
actorType: 'system' | 'human' | 'ai';
|
|
16
|
-
details?:
|
|
18
|
+
details?: EntityEvent['details'];
|
|
17
19
|
createdAt: string;
|
|
18
20
|
}
|
|
21
|
+
export type WorkspaceSyncTaskEventSnapshot = WorkspaceSyncEntityEventSnapshot & {
|
|
22
|
+
entityType: 'task';
|
|
23
|
+
entityId: string;
|
|
24
|
+
taskId: string;
|
|
25
|
+
};
|
|
19
26
|
export interface WorkspaceSyncAiProfileSnapshot {
|
|
20
27
|
id: string;
|
|
21
28
|
workspaceId: string;
|
|
@@ -26,6 +33,8 @@ export interface WorkspaceSyncAiProfileSnapshot {
|
|
|
26
33
|
color: string;
|
|
27
34
|
avatarUrl?: string | null;
|
|
28
35
|
avatarSourceUrl?: string | null;
|
|
36
|
+
avatarRevision?: number;
|
|
37
|
+
avatarUpdatedAt?: string | null;
|
|
29
38
|
description?: string | null;
|
|
30
39
|
role?: string | null;
|
|
31
40
|
provider?: string | null;
|
|
@@ -105,6 +114,7 @@ export interface WorkspaceSyncInitiativeSnapshot {
|
|
|
105
114
|
createdAt: string;
|
|
106
115
|
updatedAt?: string;
|
|
107
116
|
order?: number | null;
|
|
117
|
+
attachments?: Array<string | AttachmentItem>;
|
|
108
118
|
isArchived?: boolean;
|
|
109
119
|
}
|
|
110
120
|
export interface WorkspaceSyncWorkstreamSnapshot {
|
|
@@ -118,6 +128,7 @@ export interface WorkspaceSyncWorkstreamSnapshot {
|
|
|
118
128
|
createdAt: string;
|
|
119
129
|
updatedAt?: string;
|
|
120
130
|
order?: number | null;
|
|
131
|
+
attachments?: Array<string | AttachmentItem>;
|
|
121
132
|
isArchived?: boolean;
|
|
122
133
|
}
|
|
123
134
|
export type WorkspaceSyncChange = {
|
|
@@ -153,6 +164,8 @@ export type WorkspaceSyncChange = {
|
|
|
153
164
|
referenceNumber?: number | null;
|
|
154
165
|
version?: number | null;
|
|
155
166
|
taskId?: string | null;
|
|
167
|
+
linkTargetType?: 'task' | 'initiative' | 'workstream' | null;
|
|
168
|
+
linkTargetId?: string | null;
|
|
156
169
|
logicalName?: string | null;
|
|
157
170
|
caption?: string | null;
|
|
158
171
|
originalFilename?: string | null;
|
|
@@ -172,6 +185,8 @@ export type WorkspaceSyncChange = {
|
|
|
172
185
|
mimeType: string;
|
|
173
186
|
referenceNumber?: number | null;
|
|
174
187
|
taskId?: string | null;
|
|
188
|
+
linkTargetType?: 'task' | 'initiative' | 'workstream' | null;
|
|
189
|
+
linkTargetId?: string | null;
|
|
175
190
|
logicalName?: string | null;
|
|
176
191
|
caption?: string | null;
|
|
177
192
|
originalFilename?: string | null;
|
|
@@ -202,6 +217,9 @@ export type WorkspaceSyncChange = {
|
|
|
202
217
|
op: 'annotated-attachment-session-delete';
|
|
203
218
|
sessionId: string;
|
|
204
219
|
deletedAt?: string;
|
|
220
|
+
} | {
|
|
221
|
+
op: 'entity-event-upsert';
|
|
222
|
+
event: WorkspaceSyncEntityEventSnapshot;
|
|
205
223
|
} | {
|
|
206
224
|
op: 'task-event-upsert';
|
|
207
225
|
event: WorkspaceSyncTaskEventSnapshot;
|
|
@@ -276,6 +294,8 @@ export interface WorkspaceSyncDocumentSnapshot {
|
|
|
276
294
|
referenceNumber?: number | null;
|
|
277
295
|
version?: number | null;
|
|
278
296
|
taskId?: string | null;
|
|
297
|
+
linkTargetType?: 'task' | 'initiative' | 'workstream' | null;
|
|
298
|
+
linkTargetId?: string | null;
|
|
279
299
|
logicalName?: string | null;
|
|
280
300
|
caption?: string | null;
|
|
281
301
|
originalFilename?: string | null;
|
|
@@ -290,6 +310,8 @@ export interface WorkspaceSyncAssetSnapshot {
|
|
|
290
310
|
mimeType: string;
|
|
291
311
|
referenceNumber?: number | null;
|
|
292
312
|
taskId?: string | null;
|
|
313
|
+
linkTargetType?: 'task' | 'initiative' | 'workstream' | null;
|
|
314
|
+
linkTargetId?: string | null;
|
|
293
315
|
logicalName?: string | null;
|
|
294
316
|
caption?: string | null;
|
|
295
317
|
originalFilename?: string | null;
|
|
@@ -313,7 +335,7 @@ export declare function buildWorkspaceSyncPayloadModel(input: {
|
|
|
313
335
|
documentReviewSessions?: WorkspaceSyncDocumentReviewSessionSnapshot[];
|
|
314
336
|
documentReviewComments?: WorkspaceSyncDocumentReviewCommentSnapshot[];
|
|
315
337
|
annotatedAttachmentSessions?: WorkspaceSyncAnnotatedAttachmentSessionSnapshot[];
|
|
316
|
-
taskEvents?:
|
|
338
|
+
taskEvents?: WorkspaceSyncEntityEventSnapshot[];
|
|
317
339
|
lastPushedInitiativeIds?: Set<string>;
|
|
318
340
|
lastPushedInitiativeWatermarks?: Map<string, string>;
|
|
319
341
|
lastPushedWorkstreamIds?: Set<string>;
|
|
@@ -357,5 +379,5 @@ export declare function buildWorkspaceSyncSignatureModel(input: {
|
|
|
357
379
|
documentReviewSessions?: WorkspaceSyncDocumentReviewSessionSnapshot[];
|
|
358
380
|
documentReviewComments?: WorkspaceSyncDocumentReviewCommentSnapshot[];
|
|
359
381
|
annotatedAttachmentSessions?: WorkspaceSyncAnnotatedAttachmentSessionSnapshot[];
|
|
360
|
-
taskEvents?:
|
|
382
|
+
taskEvents?: WorkspaceSyncEntityEventSnapshot[];
|
|
361
383
|
}): string;
|