@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.
Files changed (232) hide show
  1. package/README.md +0 -2
  2. package/dist/Taskforce.module.css +317 -27
  3. package/dist/TaskforceCore.js +1 -0
  4. package/dist/TaskforceCore.test.js +178 -0
  5. package/dist/components/activity/EntityActivityTimeline.d.ts +34 -0
  6. package/dist/components/activity/EntityActivityTimeline.js +81 -0
  7. package/dist/components/context/ContextAttachmentManager.js +15 -3
  8. package/dist/components/features/AgentsModule.d.ts +5 -1
  9. package/dist/components/features/AgentsModule.js +142 -39
  10. package/dist/components/features/AgentsModule.test.js +260 -11
  11. package/dist/components/features/AnnotatedAttachmentWorkspace.d.ts +3 -1
  12. package/dist/components/features/AnnotatedAttachmentWorkspace.js +118 -4
  13. package/dist/components/features/AnnotatedAttachmentWorkspace.test.js +52 -0
  14. package/dist/components/features/DocumentIndex.d.ts +2 -2
  15. package/dist/components/features/DocumentIndex.js +3 -4
  16. package/dist/components/features/DocumentViewer.d.ts +3 -1
  17. package/dist/components/features/DocumentViewer.js +6 -5
  18. package/dist/components/features/DocumentWorkspace.d.ts +10 -2
  19. package/dist/components/features/DocumentWorkspace.js +15 -4
  20. package/dist/components/features/DocumentWorkspace.test.js +20 -3
  21. package/dist/components/features/TaskSettings.d.ts +2 -0
  22. package/dist/components/features/TaskSettings.js +83 -78
  23. package/dist/components/features/TaskSettings.test.js +171 -82
  24. package/dist/components/task/TaskActionHeader.js +11 -5
  25. package/dist/components/task/TaskActionHeader.test.js +10 -0
  26. package/dist/components/task/TaskCard.js +6 -2
  27. package/dist/components/task/TaskContextUpload.test.js +3 -3
  28. package/dist/components/task/TaskForm.js +14 -64
  29. package/dist/components/task/TaskKanban.js +0 -8
  30. package/dist/components/task/TaskList.js +5 -1
  31. package/dist/components/task/TaskList.test.js +4 -0
  32. package/dist/components/ui/HierarchyActionBadge.d.ts +10 -0
  33. package/dist/components/ui/HierarchyActionBadge.js +5 -0
  34. package/dist/components/views/AppShellHeader.d.ts +3 -1
  35. package/dist/components/views/AppShellHeader.js +27 -11
  36. package/dist/components/views/AppShellHeader.test.js +18 -1
  37. package/dist/components/views/PlanComparisonPage.d.ts +20 -15
  38. package/dist/components/views/PlanComparisonPage.js +221 -82
  39. package/dist/components/views/PlanComparisonPage.test.js +268 -14
  40. package/dist/components/views/PlansPage.js +16 -10
  41. package/dist/components/views/PlansPage.test.js +4 -2
  42. package/dist/components/views/StandaloneLayout.js +256 -69
  43. package/dist/components/views/WidgetView.js +10 -8
  44. package/dist/components/views/panels/PlanningDrawer.d.ts +19 -6
  45. package/dist/components/views/panels/PlanningDrawer.js +259 -51
  46. package/dist/components/views/panels/PlanningDrawer.test.js +392 -4
  47. package/dist/config/envSchema.js +1 -0
  48. package/dist/core/AiProfileService.d.ts +7 -0
  49. package/dist/core/AiProfileService.js +460 -35
  50. package/dist/core/AiProfiles.test.js +648 -2
  51. package/dist/core/AttachmentLinkService.d.ts +3 -0
  52. package/dist/core/AttachmentLinkService.js +58 -13
  53. package/dist/core/GlobalSettingsService.js +30 -0
  54. package/dist/core/GlobalSettingsService.test.d.ts +1 -0
  55. package/dist/core/GlobalSettingsService.test.js +45 -0
  56. package/dist/core/McpTokenService.d.ts +12 -0
  57. package/dist/core/McpTokenService.js +44 -1
  58. package/dist/core/PlanEntitlementService.d.ts +20 -0
  59. package/dist/core/PlanEntitlementService.js +215 -19
  60. package/dist/core/PlanFeatureCatalog.test.js +55 -0
  61. package/dist/core/PlanningEntities.test.js +366 -4
  62. package/dist/core/TaskActivityService.d.ts +28 -1
  63. package/dist/core/TaskActivityService.js +227 -46
  64. package/dist/core/TaskActivitySync.test.d.ts +1 -0
  65. package/dist/core/TaskActivitySync.test.js +90 -0
  66. package/dist/core/TaskAuditTimeline.test.js +96 -0
  67. package/dist/core/Taskforce.d.ts +204 -26
  68. package/dist/core/Taskforce.ids.test.js +58 -0
  69. package/dist/core/Taskforce.js +781 -71
  70. package/dist/core/Taskforce.mcpAuth.test.js +109 -0
  71. package/dist/core/types.d.ts +10 -0
  72. package/dist/hooks/auth/useTaskforceAuthBootstrap.js +2 -1
  73. package/dist/hooks/bootstrapTimeouts.d.ts +4 -0
  74. package/dist/hooks/bootstrapTimeouts.js +8 -0
  75. package/dist/hooks/bootstrapTimeouts.test.d.ts +1 -0
  76. package/dist/hooks/bootstrapTimeouts.test.js +12 -0
  77. package/dist/hooks/sync/orchestratorShared.d.ts +3 -3
  78. package/dist/hooks/sync/orchestratorShared.js +61 -1
  79. package/dist/hooks/sync/recovery.js +8 -0
  80. package/dist/hooks/sync/recovery.test.js +5 -5
  81. package/dist/hooks/sync/transfers.d.ts +2 -1
  82. package/dist/hooks/sync/transfers.js +36 -9
  83. package/dist/hooks/sync/transfers.test.js +534 -2
  84. package/dist/hooks/useFilterSort.js +13 -13
  85. package/dist/hooks/useFilterSort.test.js +87 -1
  86. package/dist/hooks/useSyncOrchestrator.js +50 -5
  87. package/dist/hooks/useTaskforce.d.ts +85 -50
  88. package/dist/hooks/useTaskforce.js +44 -14
  89. package/dist/hooks/useTaskforce.runtime-routing.test.js +94 -0
  90. package/dist/hooks/useTaskforce.sync-behavior.test.js +99 -0
  91. package/dist/hooks/useWorkspaceSyncController.js +7 -1
  92. package/dist/hooks/useWorkspaceSyncController.test.js +48 -0
  93. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +14 -7
  94. package/dist/mcp/canonicalAssetHelpers.d.ts +16 -4
  95. package/dist/mcp/canonicalAssetHelpers.js +18 -10
  96. package/dist/mcp/canonicalAssetHelpers.test.d.ts +1 -0
  97. package/dist/mcp/canonicalAssetHelpers.test.js +67 -0
  98. package/dist/mcp/clientIntegrations.d.ts +1 -0
  99. package/dist/mcp/clientIntegrations.js +25 -0
  100. package/dist/mcp/clientIntegrations.test.js +14 -3
  101. package/dist/mcp/clientProfileDefaults.js +3 -3
  102. package/dist/mcp/collaborationRegistrar.js +7 -7
  103. package/dist/mcp/documentAssetRegistrar.js +113 -7
  104. package/dist/mcp/runtime.d.ts +1 -0
  105. package/dist/mcp/runtime.js +969 -122
  106. package/dist/mcp/runtime.test.js +1083 -11
  107. package/dist/mcp/taskAttachmentTypes.d.ts +1 -1
  108. package/dist/mcp/taskPlanningRegistrar.js +48 -0
  109. package/dist/mcp/toolRegistry.d.ts +56 -0
  110. package/dist/mcp/toolRegistry.js +8 -0
  111. package/dist/mcp/toolRegistry.test.js +4 -0
  112. package/dist/migrations/taskSchemaMigrations.js +58 -15
  113. package/dist/server/aiProfileAvatarAssets.d.ts +49 -0
  114. package/dist/server/aiProfileAvatarAssets.js +319 -0
  115. package/dist/server/aiProfileAvatarAssets.test.d.ts +1 -0
  116. package/dist/server/aiProfileAvatarAssets.test.js +213 -0
  117. package/dist/server/annotatedAttachmentsRoutes.test.js +66 -7
  118. package/dist/server/index.js +4 -0
  119. package/dist/server/index.test.js +6 -1
  120. package/dist/server/routes/admin.js +328 -9
  121. package/dist/server/routes/annotatedAttachments.js +51 -0
  122. package/dist/server/routes/auth.d.ts +11 -0
  123. package/dist/server/routes/auth.js +189 -27
  124. package/dist/server/routes/authSupport.d.ts +5 -0
  125. package/dist/server/routes/authSupport.js +13 -1
  126. package/dist/server/routes/billing.d.ts +1 -0
  127. package/dist/server/routes/billing.js +116 -63
  128. package/dist/server/routes/billing.test.js +162 -11
  129. package/dist/server/routes/documents.js +10 -0
  130. package/dist/server/routes/shared.js +0 -10
  131. package/dist/server/routes/sync.integration.test.js +221 -0
  132. package/dist/server/routes/sync.js +13 -3
  133. package/dist/server/routes/syncSnapshotRoutes.js +2 -0
  134. package/dist/server/routes/tasks.js +12 -9
  135. package/dist/server/routes.js +87 -8
  136. package/dist/server/routes.test.js +972 -23
  137. package/dist/shared/aiProfileSurfaceType.d.ts +1 -1
  138. package/dist/shared/aiProfileSurfaceType.js +10 -8
  139. package/dist/storage/objectStorage.d.ts +1 -0
  140. package/dist/storage/objectStorage.js +2 -1
  141. package/dist/storage/objectStorageClient.d.ts +1 -0
  142. package/dist/storage/objectStorageClient.js +41 -8
  143. package/dist/storage/objectStorageClient.test.js +26 -1
  144. package/dist/storage/objectStorageConfig.js +3 -1
  145. package/dist/storage/objectStorageConfig.test.js +13 -1
  146. package/dist/sync/collaborationSyncPayload.js +2 -0
  147. package/dist/sync/collaborationSyncPayload.test.js +1 -0
  148. package/dist/sync/collaborationSyncState.d.ts +3 -3
  149. package/dist/sync/collaborationSyncState.js +19 -12
  150. package/dist/sync/contentSyncPayload.d.ts +5 -1
  151. package/dist/sync/contentSyncPayload.js +9 -0
  152. package/dist/sync/contentSyncPayload.test.js +39 -0
  153. package/dist/sync/contentSyncState.d.ts +5 -1
  154. package/dist/sync/contentSyncState.js +231 -37
  155. package/dist/sync/planningSyncPayload.js +5 -0
  156. package/dist/sync/planningSyncPayload.test.js +24 -0
  157. package/dist/sync/syncApplyHandlers.d.ts +4 -4
  158. package/dist/sync/syncApplyHandlers.js +89 -31
  159. package/dist/sync/syncApplyHandlers.test.js +184 -4
  160. package/dist/sync/syncResourceAdapters.d.ts +2 -0
  161. package/dist/sync/syncResourceAdapters.js +2 -0
  162. package/dist/sync/syncService.d.ts +1 -0
  163. package/dist/sync/syncService.js +13 -1
  164. package/dist/sync/syncService.test.js +39 -0
  165. package/dist/sync/workspacePullFeed.d.ts +4 -0
  166. package/dist/sync/workspacePullFeed.js +129 -70
  167. package/dist/sync/workspacePullFeed.test.js +49 -0
  168. package/dist/sync/workspaceSyncModel.d.ts +28 -6
  169. package/dist/sync/workspaceSyncModel.js +159 -45
  170. package/dist/sync/workspaceSyncModel.test.js +269 -3
  171. package/dist/types.d.ts +33 -2
  172. package/dist/ui/agent-logos/ChatGPT.png +0 -0
  173. package/dist/ui/agent-logos/Gemini CLI.jpeg +0 -0
  174. package/dist/ui/agent-logos/antigravity.jpeg +0 -0
  175. package/dist/ui/agent-logos/claude-code.jpeg +0 -0
  176. package/dist/ui/agent-logos/codex.jpeg +0 -0
  177. package/dist/ui/agent-logos/cursor.png +0 -0
  178. package/dist/ui/agent-logos/openclaw.jpeg +0 -0
  179. package/dist/ui/agent-logos/windsurf.png +0 -0
  180. package/dist/ui/assets/AgentsModule-BS4Pi_nC.js +1 -0
  181. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BVKew-mH.css +1 -0
  182. package/dist/ui/assets/AnnotatedAttachmentWorkspace-CCckzWYZ.js +3 -0
  183. package/dist/ui/assets/ContextAttachmentManager-CfG_ER7C.js +3 -0
  184. package/dist/ui/assets/DocumentWorkspace-BVaWPA25.js +252 -0
  185. package/dist/ui/assets/DocumentWorkspace-D4rJKXzd.css +1 -0
  186. package/dist/ui/assets/EntityActivityTimeline-DSj0ThaK.js +1 -0
  187. package/dist/ui/assets/EntityActivityTimeline-DyqvvhuF.css +1 -0
  188. package/dist/ui/assets/{InitiativesModule-9E6ParrY.js → InitiativesModule-AxMkWtxH.js} +1 -1
  189. package/dist/ui/assets/PlansPage-B_z-D6Nh.css +1 -0
  190. package/dist/ui/assets/PlansPage-Ndt7mYfo.js +1 -0
  191. package/dist/ui/assets/TaskContextUpload-Dw4rTF4i.js +1 -0
  192. package/dist/ui/assets/TaskSettings-f2ga42_V.js +9 -0
  193. package/dist/ui/assets/{WorkflowsModule-BA7jcEpH.js → WorkflowsModule-E4UL3mov.js} +4 -4
  194. package/dist/ui/assets/documentReferences-BOUcJm6-.js +1 -0
  195. package/dist/ui/assets/index-BvAbqx5Q.css +1 -0
  196. package/dist/ui/assets/index-MAHKvFqp.js +4 -0
  197. package/dist/ui/assets/{vendor-icons-DuEd_65c.js → vendor-icons-B32hGuF2.js} +1 -1
  198. package/dist/ui/index.html +3 -3
  199. package/dist/ui/og-image.png +0 -0
  200. package/dist/ui/product/agent manager.png +0 -0
  201. package/dist/ui/product/agent_manager_02.png +0 -0
  202. package/dist/utils/aiProfileEvents.d.ts +7 -0
  203. package/dist/utils/aiProfileEvents.js +6 -0
  204. package/dist/utils/assignees.d.ts +6 -0
  205. package/dist/utils/assignees.js +8 -1
  206. package/dist/utils/assignees.test.d.ts +1 -0
  207. package/dist/utils/assignees.test.js +25 -0
  208. package/dist/utils/avatarDisplay.d.ts +1 -0
  209. package/dist/utils/avatarDisplay.js +15 -0
  210. package/dist/utils/contextFiles.d.ts +3 -1
  211. package/dist/utils/contextFiles.js +2 -1
  212. package/dist/utils/taskActivity.d.ts +7 -1
  213. package/dist/utils/taskActivity.js +63 -1
  214. package/dist/utils/taskActivity.test.js +23 -1
  215. package/dist/utils/taskSearch.d.ts +22 -0
  216. package/dist/utils/taskSearch.js +87 -0
  217. package/dist/utils/taskSearch.test.d.ts +1 -0
  218. package/dist/utils/taskSearch.test.js +69 -0
  219. package/dist/utils/taskUtils.js +10 -3
  220. package/dist/utils/taskUtils.test.d.ts +1 -0
  221. package/dist/utils/taskUtils.test.js +19 -0
  222. package/package.json +1 -1
  223. package/dist/ui/assets/AgentsModule-DrLawwNl.js +0 -1
  224. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BaS2VwIr.css +0 -1
  225. package/dist/ui/assets/AnnotatedAttachmentWorkspace-Z9_whf7F.js +0 -3
  226. package/dist/ui/assets/DocumentWorkspace-B03MaSkw.js +0 -252
  227. package/dist/ui/assets/DocumentWorkspace-Dhdso07p.css +0 -1
  228. package/dist/ui/assets/PlansPage-CvfnMiWq.css +0 -1
  229. package/dist/ui/assets/PlansPage-DRXscYxH.js +0 -1
  230. package/dist/ui/assets/TaskSettings-DZX4jk7e.js +0 -9
  231. package/dist/ui/assets/index-9eT8e0Lu.css +0 -1
  232. package/dist/ui/assets/index-C6k75jr8.js +0 -6
@@ -44,10 +44,25 @@ export interface TaskEventDetails {
44
44
  changes?: Record<string, TaskEventChange>;
45
45
  [key: string]: unknown;
46
46
  }
47
+ export type ActivityEntityType = 'task' | 'initiative' | 'workstream';
48
+ interface BaseEntityEvent {
49
+ id: string;
50
+ workspaceId: string;
51
+ entityType: ActivityEntityType;
52
+ entityId: string;
53
+ action: string;
54
+ actor: string;
55
+ actorType: 'human' | 'ai' | 'system';
56
+ createdAt: string;
57
+ details?: TaskEventDetails;
58
+ actorProfile?: TaskActor | null;
59
+ }
47
60
  export interface TaskEvent {
48
61
  id: string;
49
62
  taskId: string;
50
63
  workspaceId: string;
64
+ entityType?: 'task';
65
+ entityId?: string;
51
66
  action: string;
52
67
  actor: string;
53
68
  actorType: 'human' | 'ai' | 'system';
@@ -55,6 +70,11 @@ export interface TaskEvent {
55
70
  details?: TaskEventDetails;
56
71
  actorProfile?: TaskActor | null;
57
72
  }
73
+ export interface PlanningEntityEvent extends BaseEntityEvent {
74
+ entityType: 'initiative' | 'workstream';
75
+ entityId: string;
76
+ }
77
+ export type EntityEvent = TaskEvent | PlanningEntityEvent;
58
78
  export interface CommentActivityItem {
59
79
  id: string;
60
80
  type: 'comment';
@@ -68,6 +88,13 @@ export interface AuditActivityItem {
68
88
  event: TaskEvent;
69
89
  }
70
90
  export type TaskActivityItem = CommentActivityItem | AuditActivityItem;
91
+ export interface EntityAuditActivityItem {
92
+ id: string;
93
+ type: 'event';
94
+ timestamp: string;
95
+ event: EntityEvent;
96
+ }
97
+ export type EntityActivityItem = CommentActivityItem | EntityAuditActivityItem;
71
98
  export type DeletedTaskSource = 'ui' | 'mcp' | 'sync' | 'workspace-delete' | 'system';
72
99
  export interface DeletedTaskDetails {
73
100
  reason?: string | null;
@@ -110,12 +137,7 @@ export interface TaskItem {
110
137
  comments?: Comment[];
111
138
  activity?: TaskActivityItem[];
112
139
  taskEvents?: TaskEvent[];
113
- attachments?: Array<string | {
114
- path: string;
115
- fsPath?: string;
116
- caption?: string;
117
- timestamp?: string;
118
- }>;
140
+ attachments?: AttachmentItem[];
119
141
  /** @deprecated Use status='done'. Safe to remove after v0.4.x migration gate. */
120
142
  completed?: boolean;
121
143
  /** @deprecated Use status='cancelled'. Safe to remove after v0.4.x migration gate. */
@@ -134,6 +156,18 @@ export interface TaskItem {
134
156
  workstreamId?: string | null;
135
157
  checklistItems?: ChecklistItem[];
136
158
  }
159
+ export type AttachmentItem = string | {
160
+ path: string;
161
+ fsPath?: string;
162
+ caption?: string;
163
+ displayName?: string;
164
+ originalFilename?: string;
165
+ timestamp?: string;
166
+ assetId?: string | null;
167
+ referenceNumber?: number | null;
168
+ referenceLabel?: string | null;
169
+ taskId?: string | null;
170
+ };
137
171
  export interface InitiativeItem {
138
172
  id: string;
139
173
  referenceNumber?: number | null;
@@ -142,12 +176,9 @@ export interface InitiativeItem {
142
176
  description: string | null;
143
177
  ownerId?: string | null;
144
178
  comments?: Comment[];
145
- attachments?: Array<string | {
146
- path: string;
147
- fsPath?: string;
148
- caption?: string;
149
- timestamp?: string;
150
- }>;
179
+ activity?: EntityActivityItem[];
180
+ entityEvents?: PlanningEntityEvent[];
181
+ attachments?: AttachmentItem[];
151
182
  createdAt: string;
152
183
  updatedAt?: string;
153
184
  order?: number | null;
@@ -162,12 +193,9 @@ export interface WorkstreamItem {
162
193
  description: string | null;
163
194
  ownerId?: string | null;
164
195
  comments?: Comment[];
165
- attachments?: Array<string | {
166
- path: string;
167
- fsPath?: string;
168
- caption?: string;
169
- timestamp?: string;
170
- }>;
196
+ activity?: EntityActivityItem[];
197
+ entityEvents?: PlanningEntityEvent[];
198
+ attachments?: AttachmentItem[];
171
199
  createdAt: string;
172
200
  updatedAt?: string;
173
201
  order?: number | null;
@@ -388,6 +416,21 @@ interface UserAvatarUploadDraftRecord {
388
416
  createdAt: string;
389
417
  updatedAt: string;
390
418
  }
419
+ interface TaskAttachmentUploadDraftRecord {
420
+ draftId: string;
421
+ workspaceId: string;
422
+ taskId: string;
423
+ actorRef: string;
424
+ storageKey: string;
425
+ mimeType: string;
426
+ originalFilename: string;
427
+ sizeBytes: number;
428
+ storageProvider: 'local' | 'r2' | 'external';
429
+ consumedAt?: string | null;
430
+ discardedAt?: string | null;
431
+ createdAt: string;
432
+ updatedAt: string;
433
+ }
391
434
  interface WorkspaceUserRecord {
392
435
  userId: string;
393
436
  email: string;
@@ -412,6 +455,8 @@ export interface AiProfileRecord {
412
455
  color: string;
413
456
  avatarUrl?: string | null;
414
457
  avatarSourceUrl?: string | null;
458
+ avatarRevision?: number;
459
+ avatarUpdatedAt?: string | null;
415
460
  description?: string | null;
416
461
  role?: string | null;
417
462
  provider?: string | null;
@@ -572,6 +617,8 @@ export interface PlanFeatureCatalogItem {
572
617
  featureKey: string;
573
618
  label: string;
574
619
  description: string;
620
+ isCustom?: boolean;
621
+ publicDescriptionVisible?: boolean | null;
575
622
  allowedAccessModes: PlanFeatureAccess[];
576
623
  configTemplate: Record<string, unknown>;
577
624
  dependsOn?: string[];
@@ -714,6 +761,9 @@ export interface McpOAuthAccessTokenAuthResult {
714
761
  provider: McpOAuthProvider;
715
762
  scopes: McpAccessTokenScope[];
716
763
  status: McpOAuthGrantStatus;
764
+ aiProfileId?: string | null;
765
+ aiProfileToken?: string | null;
766
+ aiProfileName?: string | null;
717
767
  }
718
768
  /**
719
769
  * Subset of TaskforceCore methods required by the sync route.
@@ -780,6 +830,21 @@ export interface TaskforceSyncCapable {
780
830
  listTaskEventsForSync(input: {
781
831
  workspaceId?: string | null;
782
832
  }): TaskEvent[];
833
+ getTaskEventForSync(input: {
834
+ workspaceId?: string | null;
835
+ taskId: string;
836
+ eventId: string;
837
+ }): TaskEvent | null;
838
+ taskExistsForSync(id: string, workspaceId?: string | null): boolean;
839
+ listEntityEventsForSync(input: {
840
+ workspaceId?: string | null;
841
+ }): EntityEvent[];
842
+ getEntityEventForSync(input: {
843
+ workspaceId?: string | null;
844
+ eventId: string;
845
+ }): EntityEvent | null;
846
+ initiativeExistsForSync(id: string, workspaceId?: string | null): boolean;
847
+ workstreamExistsForSync(id: string, workspaceId?: string | null): boolean;
783
848
  upsertAiProfileForSync(profile: AiProfileRecord): AiProfileRecord;
784
849
  replaceWorkspaceUsersForSync(input: {
785
850
  workspaceId: string;
@@ -791,6 +856,7 @@ export interface TaskforceSyncCapable {
791
856
  upsertDocumentReviewCommentForSync(comment: DocumentReviewCommentSyncRecord): DocumentReviewCommentSyncRecord;
792
857
  upsertAnnotatedAttachmentSessionForSync(session: AnnotatedAttachmentSessionRecord): AnnotatedAttachmentSessionRecord;
793
858
  upsertTaskEventForSync(event: TaskEvent): TaskEvent;
859
+ upsertEntityEventForSync(event: EntityEvent): EntityEvent;
794
860
  deleteDocumentReviewSessionForSync(input: {
795
861
  workspaceId?: string | null;
796
862
  sessionId: string;
@@ -823,6 +889,11 @@ export interface TaskforceSyncCapable {
823
889
  avatarUrl?: string | null;
824
890
  avatarSourceUrl?: string | null;
825
891
  }): AiProfileRecord;
892
+ updateAiProfileSurfaceType(input: {
893
+ workspaceId: string;
894
+ profileId: string;
895
+ surfaceType?: AiProfileSurfaceType | null;
896
+ }): AiProfileRecord;
826
897
  resolveWorkspaceActor(workspaceId: string, actorRef: unknown): TaskActor | null;
827
898
  }
828
899
  export declare class TaskforceCore implements TaskforceSyncCapable {
@@ -856,6 +927,7 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
856
927
  private isGenericAiActorReference;
857
928
  private isKnownAiModelName;
858
929
  private isHumanActorReference;
930
+ private isStableActorReference;
859
931
  private normalizeAiProfileName;
860
932
  private normalizeAiProfileUsername;
861
933
  private normalizeAiProfileIcon;
@@ -866,6 +938,9 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
866
938
  private workspaceUserToActor;
867
939
  private aiProfileRowToRecord;
868
940
  private aiProfileToActor;
941
+ private resolveCanonicalAiProfileId;
942
+ private findCanonicalAiProfileIdsByAlias;
943
+ private resolveUniqueAiProfileActorByAlias;
869
944
  private canonicalizeActorReference;
870
945
  private normalizeCreatedBy;
871
946
  private normalizeCommentAuthor;
@@ -874,9 +949,13 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
874
949
  private normalizePlanningAttachments;
875
950
  private replaceTaskComments;
876
951
  private normalizeTaskEventActor;
952
+ private listEntityEventsInternal;
877
953
  private listTaskEventsInternal;
954
+ private buildEntityActivity;
878
955
  private buildTaskActivity;
956
+ private addEntityEvent;
879
957
  private addTaskEvent;
958
+ private replaceEntityEvents;
880
959
  private replaceTaskEvents;
881
960
  private mapDeletedTaskRow;
882
961
  private pruneDeletedTasks;
@@ -917,6 +996,9 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
917
996
  private initiativeExists;
918
997
  private workstreamExists;
919
998
  private valueEqualsForBulkUpdate;
999
+ private buildPlanningEntityEventChanges;
1000
+ private getPlanningEntityEventAction;
1001
+ private addWorkstreamTaskMembershipEvents;
920
1002
  private assertWorkstreamLinkAllowed;
921
1003
  private assertInitiativeLinkAllowed;
922
1004
  constructor(config: TaskforceConfig);
@@ -986,6 +1068,7 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
986
1068
  private migrateUserBetaAccessBackfillIfNeeded;
987
1069
  private migrateDuplicateAiProfilesIfNeeded;
988
1070
  private migrateLegacyActorReferencesIfNeeded;
1071
+ private migrateLegacyCommentActorReferencesIfNeeded;
989
1072
  private getWorkspaceOwnerUserId;
990
1073
  getWorkspacePlanMode(workspaceId: string): 'personal' | 'team';
991
1074
  setWorkspacePlanMode(workspaceId: string, mode: 'personal' | 'team', source?: string): 'personal' | 'team';
@@ -1065,6 +1148,7 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
1065
1148
  getJsonBackupEnabled(workspaceId?: string, userId?: string): boolean;
1066
1149
  private listCanonicalTaskAttachments;
1067
1150
  private syncCanonicalTaskAttachmentLinks;
1151
+ private syncCanonicalPlanningAttachmentLinks;
1068
1152
  private rowToTask;
1069
1153
  private rowToInitiative;
1070
1154
  private rowToWorkstream;
@@ -1076,17 +1160,44 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
1076
1160
  resolveTaskIdentifier(value: string, workspaceId?: string): TaskItem | null;
1077
1161
  getInitiative(id: string, workspaceId?: string): InitiativeItem | null;
1078
1162
  listInitiatives(workspaceId?: string): InitiativeItem[];
1079
- createInitiative(input: Partial<InitiativeItem>, workspaceId?: string): InitiativeItem;
1080
- updateInitiative(id: string, patch: Partial<InitiativeItem>, workspaceId?: string): InitiativeItem;
1081
- archiveInitiative(id: string, workspaceId?: string): InitiativeItem;
1082
- unarchiveInitiative(id: string, workspaceId?: string): InitiativeItem;
1163
+ private isTransientPlanningHydrationError;
1164
+ private getInitiativeForWriteResult;
1165
+ private getWorkstreamForWriteResult;
1166
+ createInitiative(input: Partial<InitiativeItem>, workspaceId?: string, options?: {
1167
+ actorRef?: string;
1168
+ skipEntityEvents?: boolean;
1169
+ }): InitiativeItem;
1170
+ updateInitiative(id: string, patch: Partial<InitiativeItem>, workspaceId?: string, options?: {
1171
+ actorRef?: string;
1172
+ skipEntityEvents?: boolean;
1173
+ }): InitiativeItem;
1174
+ archiveInitiative(id: string, workspaceId?: string, options?: {
1175
+ actorRef?: string;
1176
+ skipEntityEvents?: boolean;
1177
+ }): InitiativeItem;
1178
+ unarchiveInitiative(id: string, workspaceId?: string, options?: {
1179
+ actorRef?: string;
1180
+ skipEntityEvents?: boolean;
1181
+ }): InitiativeItem;
1083
1182
  getWorkstream(id: string, workspaceId?: string): WorkstreamItem | null;
1084
1183
  listWorkstreams(workspaceId?: string): WorkstreamItem[];
1085
1184
  listPlanningBootstrap(workspaceId?: string, diagnostics?: PlanningBootstrapDiagnostics): PlanningBootstrapPayload;
1086
- createWorkstream(input: Partial<WorkstreamItem>, workspaceId?: string): WorkstreamItem;
1087
- updateWorkstream(id: string, patch: Partial<WorkstreamItem>, workspaceId?: string): WorkstreamItem;
1088
- archiveWorkstream(id: string, workspaceId?: string): WorkstreamItem;
1089
- unarchiveWorkstream(id: string, workspaceId?: string): WorkstreamItem;
1185
+ createWorkstream(input: Partial<WorkstreamItem>, workspaceId?: string, options?: {
1186
+ actorRef?: string;
1187
+ skipEntityEvents?: boolean;
1188
+ }): WorkstreamItem;
1189
+ updateWorkstream(id: string, patch: Partial<WorkstreamItem>, workspaceId?: string, options?: {
1190
+ actorRef?: string;
1191
+ skipEntityEvents?: boolean;
1192
+ }): WorkstreamItem;
1193
+ archiveWorkstream(id: string, workspaceId?: string, options?: {
1194
+ actorRef?: string;
1195
+ skipEntityEvents?: boolean;
1196
+ }): WorkstreamItem;
1197
+ unarchiveWorkstream(id: string, workspaceId?: string, options?: {
1198
+ actorRef?: string;
1199
+ skipEntityEvents?: boolean;
1200
+ }): WorkstreamItem;
1090
1201
  upsertInitiativeForSync(initiative: InitiativeItem, workspaceId?: string | null): InitiativeItem;
1091
1202
  upsertWorkstreamForSync(workstream: WorkstreamItem, workspaceId?: string | null): WorkstreamItem;
1092
1203
  listChecklistItems(taskId: string, workspaceId?: string): ChecklistItem[];
@@ -1229,6 +1340,20 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
1229
1340
  markUserAvatarUploadDraftConsumed(userId: string, draftId: string): UserAvatarUploadDraftRecord | null;
1230
1341
  discardUserAvatarUploadDraft(userId: string, draftId: string): UserAvatarUploadDraftRecord | null;
1231
1342
  cleanupStaleUserAvatarUploadDrafts(userId: string, olderThanIso: string): UserAvatarUploadDraftRecord[];
1343
+ createTaskAttachmentUploadDraft(input: {
1344
+ draftId: string;
1345
+ workspaceId: string;
1346
+ taskId: string;
1347
+ actorRef: string;
1348
+ storageKey: string;
1349
+ mimeType: string;
1350
+ originalFilename: string;
1351
+ sizeBytes: number;
1352
+ storageProvider?: 'local' | 'r2' | 'external';
1353
+ }): TaskAttachmentUploadDraftRecord;
1354
+ getTaskAttachmentUploadDraft(draftId: string): TaskAttachmentUploadDraftRecord | null;
1355
+ markTaskAttachmentUploadDraftConsumed(draftId: string): TaskAttachmentUploadDraftRecord | null;
1356
+ discardTaskAttachmentUploadDraft(draftId: string): TaskAttachmentUploadDraftRecord | null;
1232
1357
  getSystemRole(userId: string): SystemRole;
1233
1358
  getUserBetaAccess(userId: string): boolean;
1234
1359
  countSystemAdmins(): number;
@@ -1287,6 +1412,11 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
1287
1412
  avatarUrl?: string | null;
1288
1413
  avatarSourceUrl?: string | null;
1289
1414
  }): AiProfileRecord;
1415
+ updateAiProfileSurfaceType(input: {
1416
+ workspaceId: string;
1417
+ profileId: string;
1418
+ surfaceType?: AiProfileSurfaceType | null;
1419
+ }): AiProfileRecord;
1290
1420
  resolveAiProfile(input: ResolveAiProfileInput, options?: ResolveAiProfileOptions): ResolveAiProfileResult;
1291
1421
  listAnnotatedAttachmentSessions(input: {
1292
1422
  workspaceId?: string | null;
@@ -1362,6 +1492,7 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
1362
1492
  upsertDocumentReviewCommentForSync(comment: DocumentReviewCommentSyncRecord): DocumentReviewCommentSyncRecord;
1363
1493
  upsertAnnotatedAttachmentSessionForSync(session: AnnotatedAttachmentSessionRecord): AnnotatedAttachmentSessionRecord;
1364
1494
  upsertTaskEventForSync(event: TaskEvent): TaskEvent;
1495
+ upsertEntityEventForSync(event: EntityEvent): EntityEvent;
1365
1496
  deleteDocumentReviewSessionForSync(input: {
1366
1497
  workspaceId?: string | null;
1367
1498
  sessionId: string;
@@ -1489,10 +1620,22 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
1489
1620
  };
1490
1621
  listPlanCatalog(): import("./types.js").PlanCatalogSnapshot[];
1491
1622
  listPlanFeatureCatalog(): import("./types.js").PlanFeatureCatalogItem[];
1623
+ createCustomPlanFeatureCatalogEntry(input: {
1624
+ label: string;
1625
+ description?: string | null;
1626
+ publicLabel?: string | null;
1627
+ publicDescription?: string | null;
1628
+ publicDescriptionVisible?: boolean | null;
1629
+ publicDisplayOrder?: number | null;
1630
+ }): import("./types.js").PlanFeatureCatalogItem;
1631
+ deleteCustomPlanFeatureCatalogEntry(featureKey: string): void;
1492
1632
  updatePlanFeatureCatalogMarketingCopy(input: {
1493
1633
  featureKey: string;
1634
+ label?: string | null;
1635
+ description?: string | null;
1494
1636
  publicLabel?: string | null;
1495
1637
  publicDescription?: string | null;
1638
+ publicDescriptionVisible?: boolean | null;
1496
1639
  publicDisplayOrder?: number | null;
1497
1640
  }): import("./types.js").PlanFeatureCatalogItem;
1498
1641
  listPlanVersions(planId: string): import("./types.js").PlanVersionSnapshot[];
@@ -1732,6 +1875,11 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
1732
1875
  workspaceId: string;
1733
1876
  tokenId: string;
1734
1877
  }): McpAccessTokenRecord;
1878
+ deleteMcpAccessToken(input: {
1879
+ actorUserId: string;
1880
+ workspaceId: string;
1881
+ tokenId: string;
1882
+ }): boolean;
1735
1883
  regenerateMcpAccessToken(input: {
1736
1884
  actorUserId: string;
1737
1885
  workspaceId: string;
@@ -1783,6 +1931,13 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
1783
1931
  grantId: string;
1784
1932
  }): McpOAuthConnectorGrantRecord;
1785
1933
  authenticateMcpOAuthAccessToken(token: string, workspaceId?: string): McpOAuthAccessTokenAuthResult | null;
1934
+ bindMcpOAuthConnectorGrantAiProfile(input: {
1935
+ grantId: string;
1936
+ workspaceId: string;
1937
+ profileId: string;
1938
+ profileToken: string;
1939
+ profileName: string;
1940
+ }): boolean;
1786
1941
  recordMcpOAuthConnectorGrantUsage(input: {
1787
1942
  grantId: string;
1788
1943
  workspaceId: string;
@@ -1882,9 +2037,32 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
1882
2037
  updateWorkspaceUserRole(userId: string, workspaceId: string, role: AccessRole): boolean;
1883
2038
  getTask(id: string, workspaceId?: string): TaskItem | null;
1884
2039
  listTaskEvents(taskId: string, workspaceId?: string): TaskEvent[];
2040
+ taskExistsForSync(id: string, workspaceId?: string | null): boolean;
2041
+ initiativeExistsForSync(id: string, workspaceId?: string | null): boolean;
2042
+ workstreamExistsForSync(id: string, workspaceId?: string | null): boolean;
2043
+ recordTaskEvent(input: {
2044
+ taskId: string;
2045
+ workspaceId?: string | null;
2046
+ action: string;
2047
+ actor?: unknown;
2048
+ createdAt?: string;
2049
+ details?: TaskEventDetails;
2050
+ }): void;
1885
2051
  listTaskEventsForSync(input: {
1886
2052
  workspaceId?: string | null;
1887
2053
  }): TaskEvent[];
2054
+ getTaskEventForSync(input: {
2055
+ workspaceId?: string | null;
2056
+ taskId: string;
2057
+ eventId: string;
2058
+ }): TaskEvent | null;
2059
+ listEntityEventsForSync(input: {
2060
+ workspaceId?: string | null;
2061
+ }): EntityEvent[];
2062
+ getEntityEventForSync(input: {
2063
+ workspaceId?: string | null;
2064
+ eventId: string;
2065
+ }): EntityEvent | null;
1888
2066
  getScheduleBoard(weekKey: string, showWeekends?: boolean, workspaceId?: string): ScheduleBoardResult;
1889
2067
  updateTaskSchedule(id: string, input: {
1890
2068
  scheduledDate: string | null;
@@ -426,6 +426,31 @@ describe('TaskforceCore id policy', () => {
426
426
  })
427
427
  })
428
428
  ]);
429
+ const removalSnapshotResult = core.applyWorkspaceSyncSnapshot({
430
+ tasks: [
431
+ {
432
+ id: 'task-sync-comments-update',
433
+ title: 'Comment sync task',
434
+ status: 'task',
435
+ updatedAt: '2026-02-20T12:00:00.000Z',
436
+ comments: [
437
+ {
438
+ id: 'comment-new',
439
+ author: 'ai',
440
+ text: 'Newer synced comment',
441
+ timestamp: '2026-02-20T11:00:00.000Z'
442
+ }
443
+ ]
444
+ }
445
+ ]
446
+ }, 'workspace-test');
447
+ expect(removalSnapshotResult.updated).toBe(1);
448
+ expect(core.getTask('task-sync-comments-update', 'workspace-test')?.comments).toEqual([
449
+ expect.objectContaining({
450
+ id: 'comment-new',
451
+ text: 'Newer synced comment',
452
+ })
453
+ ]);
429
454
  const staleResult = core.applyWorkspaceSyncSnapshot({
430
455
  tasks: [
431
456
  {
@@ -463,6 +488,39 @@ describe('TaskforceCore id policy', () => {
463
488
  cleanup();
464
489
  }
465
490
  });
491
+ it('keeps task sync watermarks monotonic when adding comments', () => {
492
+ const { core, cleanup } = makeCore();
493
+ try {
494
+ const task = core.createTask({
495
+ title: 'Comment watermark task',
496
+ status: 'task'
497
+ }, { workspaceId: 'workspace-test' });
498
+ const futureWatermark = '2099-02-20T10:00:00.000Z';
499
+ const db = core.db;
500
+ db.prepare(`
501
+ UPDATE tasks
502
+ SET updated_at = ?
503
+ WHERE tenant_id = ? AND workspace_id = ? AND id = ?
504
+ `).run(futureWatermark, 'default', 'workspace-test', task.id);
505
+ const updated = core.addComment(task.id, 'Comment should advance sync', 'user', 'workspace-test');
506
+ expect(Date.parse(String(updated?.updatedAt || ''))).toBeGreaterThan(Date.parse(futureWatermark));
507
+ const syncRows = core.listTasksForSync('workspace-test', {
508
+ watermark: futureWatermark,
509
+ id: task.id
510
+ }, 10);
511
+ expect(syncRows).toHaveLength(1);
512
+ expect(syncRows[0]?.task.comments).toEqual([
513
+ expect.objectContaining({
514
+ author: 'user',
515
+ submittedAuthor: 'user',
516
+ text: 'Comment should advance sync'
517
+ })
518
+ ]);
519
+ }
520
+ finally {
521
+ cleanup();
522
+ }
523
+ });
466
524
  it('applies incoming sync update when timestamps are equal (deterministic tie behavior)', () => {
467
525
  const { core, cleanup } = makeCore();
468
526
  try {