@taskforcehq/taskforce 0.3.306 → 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.
Files changed (215) 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.js +9 -1
  38. package/dist/components/views/PlanComparisonPage.test.js +19 -0
  39. package/dist/components/views/PlansPage.js +1 -1
  40. package/dist/components/views/StandaloneLayout.js +256 -69
  41. package/dist/components/views/WidgetView.js +10 -8
  42. package/dist/components/views/panels/PlanningDrawer.d.ts +19 -6
  43. package/dist/components/views/panels/PlanningDrawer.js +259 -51
  44. package/dist/components/views/panels/PlanningDrawer.test.js +392 -4
  45. package/dist/config/envSchema.js +1 -0
  46. package/dist/core/AiProfileService.d.ts +7 -0
  47. package/dist/core/AiProfileService.js +460 -35
  48. package/dist/core/AiProfiles.test.js +648 -2
  49. package/dist/core/AttachmentLinkService.d.ts +3 -0
  50. package/dist/core/AttachmentLinkService.js +58 -13
  51. package/dist/core/GlobalSettingsService.js +12 -0
  52. package/dist/core/McpTokenService.d.ts +12 -0
  53. package/dist/core/McpTokenService.js +44 -1
  54. package/dist/core/PlanningEntities.test.js +366 -4
  55. package/dist/core/TaskActivityService.d.ts +28 -1
  56. package/dist/core/TaskActivityService.js +227 -46
  57. package/dist/core/TaskActivitySync.test.d.ts +1 -0
  58. package/dist/core/TaskActivitySync.test.js +90 -0
  59. package/dist/core/TaskAuditTimeline.test.js +96 -0
  60. package/dist/core/Taskforce.d.ts +190 -26
  61. package/dist/core/Taskforce.ids.test.js +58 -0
  62. package/dist/core/Taskforce.js +775 -71
  63. package/dist/core/Taskforce.mcpAuth.test.js +109 -0
  64. package/dist/core/types.d.ts +7 -0
  65. package/dist/hooks/auth/useTaskforceAuthBootstrap.js +2 -1
  66. package/dist/hooks/bootstrapTimeouts.d.ts +4 -0
  67. package/dist/hooks/bootstrapTimeouts.js +8 -0
  68. package/dist/hooks/bootstrapTimeouts.test.d.ts +1 -0
  69. package/dist/hooks/bootstrapTimeouts.test.js +12 -0
  70. package/dist/hooks/sync/orchestratorShared.d.ts +3 -3
  71. package/dist/hooks/sync/orchestratorShared.js +61 -1
  72. package/dist/hooks/sync/recovery.js +8 -0
  73. package/dist/hooks/sync/recovery.test.js +5 -5
  74. package/dist/hooks/sync/transfers.d.ts +2 -1
  75. package/dist/hooks/sync/transfers.js +36 -9
  76. package/dist/hooks/sync/transfers.test.js +534 -2
  77. package/dist/hooks/useFilterSort.js +13 -13
  78. package/dist/hooks/useFilterSort.test.js +87 -1
  79. package/dist/hooks/useSyncOrchestrator.js +50 -5
  80. package/dist/hooks/useTaskforce.d.ts +85 -50
  81. package/dist/hooks/useTaskforce.js +44 -14
  82. package/dist/hooks/useTaskforce.runtime-routing.test.js +94 -0
  83. package/dist/hooks/useTaskforce.sync-behavior.test.js +99 -0
  84. package/dist/hooks/useWorkspaceSyncController.js +7 -1
  85. package/dist/hooks/useWorkspaceSyncController.test.js +48 -0
  86. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +14 -7
  87. package/dist/mcp/canonicalAssetHelpers.d.ts +16 -4
  88. package/dist/mcp/canonicalAssetHelpers.js +18 -10
  89. package/dist/mcp/canonicalAssetHelpers.test.d.ts +1 -0
  90. package/dist/mcp/canonicalAssetHelpers.test.js +67 -0
  91. package/dist/mcp/clientIntegrations.d.ts +1 -0
  92. package/dist/mcp/clientIntegrations.js +25 -0
  93. package/dist/mcp/clientIntegrations.test.js +14 -3
  94. package/dist/mcp/clientProfileDefaults.js +3 -3
  95. package/dist/mcp/collaborationRegistrar.js +7 -7
  96. package/dist/mcp/documentAssetRegistrar.js +113 -7
  97. package/dist/mcp/runtime.d.ts +1 -0
  98. package/dist/mcp/runtime.js +969 -122
  99. package/dist/mcp/runtime.test.js +1083 -11
  100. package/dist/mcp/taskAttachmentTypes.d.ts +1 -1
  101. package/dist/mcp/taskPlanningRegistrar.js +48 -0
  102. package/dist/mcp/toolRegistry.d.ts +56 -0
  103. package/dist/mcp/toolRegistry.js +8 -0
  104. package/dist/mcp/toolRegistry.test.js +4 -0
  105. package/dist/migrations/taskSchemaMigrations.js +21 -0
  106. package/dist/server/aiProfileAvatarAssets.d.ts +49 -0
  107. package/dist/server/aiProfileAvatarAssets.js +319 -0
  108. package/dist/server/aiProfileAvatarAssets.test.d.ts +1 -0
  109. package/dist/server/aiProfileAvatarAssets.test.js +213 -0
  110. package/dist/server/annotatedAttachmentsRoutes.test.js +66 -7
  111. package/dist/server/index.js +4 -0
  112. package/dist/server/index.test.js +6 -1
  113. package/dist/server/routes/admin.js +187 -9
  114. package/dist/server/routes/annotatedAttachments.js +51 -0
  115. package/dist/server/routes/auth.d.ts +11 -0
  116. package/dist/server/routes/auth.js +189 -27
  117. package/dist/server/routes/authSupport.d.ts +4 -0
  118. package/dist/server/routes/authSupport.js +12 -1
  119. package/dist/server/routes/billing.js +11 -0
  120. package/dist/server/routes/billing.test.js +3 -0
  121. package/dist/server/routes/documents.js +10 -0
  122. package/dist/server/routes/shared.js +0 -10
  123. package/dist/server/routes/sync.integration.test.js +221 -0
  124. package/dist/server/routes/sync.js +13 -3
  125. package/dist/server/routes/syncSnapshotRoutes.js +2 -0
  126. package/dist/server/routes/tasks.js +12 -9
  127. package/dist/server/routes.js +87 -8
  128. package/dist/server/routes.test.js +890 -22
  129. package/dist/shared/aiProfileSurfaceType.d.ts +1 -1
  130. package/dist/shared/aiProfileSurfaceType.js +10 -8
  131. package/dist/storage/objectStorage.d.ts +1 -0
  132. package/dist/storage/objectStorage.js +2 -1
  133. package/dist/storage/objectStorageClient.d.ts +1 -0
  134. package/dist/storage/objectStorageClient.js +41 -8
  135. package/dist/storage/objectStorageClient.test.js +26 -1
  136. package/dist/storage/objectStorageConfig.js +3 -1
  137. package/dist/storage/objectStorageConfig.test.js +13 -1
  138. package/dist/sync/collaborationSyncPayload.js +2 -0
  139. package/dist/sync/collaborationSyncPayload.test.js +1 -0
  140. package/dist/sync/collaborationSyncState.d.ts +3 -3
  141. package/dist/sync/collaborationSyncState.js +19 -12
  142. package/dist/sync/contentSyncPayload.d.ts +5 -1
  143. package/dist/sync/contentSyncPayload.js +9 -0
  144. package/dist/sync/contentSyncPayload.test.js +39 -0
  145. package/dist/sync/contentSyncState.d.ts +5 -1
  146. package/dist/sync/contentSyncState.js +231 -37
  147. package/dist/sync/planningSyncPayload.js +5 -0
  148. package/dist/sync/planningSyncPayload.test.js +24 -0
  149. package/dist/sync/syncApplyHandlers.d.ts +4 -4
  150. package/dist/sync/syncApplyHandlers.js +89 -31
  151. package/dist/sync/syncApplyHandlers.test.js +184 -4
  152. package/dist/sync/syncResourceAdapters.d.ts +2 -0
  153. package/dist/sync/syncResourceAdapters.js +2 -0
  154. package/dist/sync/syncService.d.ts +1 -0
  155. package/dist/sync/syncService.js +13 -1
  156. package/dist/sync/syncService.test.js +39 -0
  157. package/dist/sync/workspacePullFeed.d.ts +4 -0
  158. package/dist/sync/workspacePullFeed.js +129 -70
  159. package/dist/sync/workspacePullFeed.test.js +49 -0
  160. package/dist/sync/workspaceSyncModel.d.ts +28 -6
  161. package/dist/sync/workspaceSyncModel.js +159 -45
  162. package/dist/sync/workspaceSyncModel.test.js +269 -3
  163. package/dist/types.d.ts +33 -2
  164. package/dist/ui/assets/AgentsModule-2y82_3DO.js +1 -0
  165. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BTLZZCiQ.js +3 -0
  166. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BVKew-mH.css +1 -0
  167. package/dist/ui/assets/ContextAttachmentManager-D2epuNnG.js +3 -0
  168. package/dist/ui/assets/DocumentWorkspace-D4rJKXzd.css +1 -0
  169. package/dist/ui/assets/DocumentWorkspace-sVa-3Do6.js +252 -0
  170. package/dist/ui/assets/EntityActivityTimeline-DyqvvhuF.css +1 -0
  171. package/dist/ui/assets/EntityActivityTimeline-Zods27y_.js +1 -0
  172. package/dist/ui/assets/{InitiativesModule-9E6ParrY.js → InitiativesModule-D4XseTwW.js} +1 -1
  173. package/dist/ui/assets/PlansPage-D5AcbO0L.js +1 -0
  174. package/dist/ui/assets/PlansPage-Dvqsz5zc.css +1 -0
  175. package/dist/ui/assets/TaskContextUpload-uC5qx4Bv.js +1 -0
  176. package/dist/ui/assets/TaskSettings-CqvPAsTv.js +9 -0
  177. package/dist/ui/assets/{WorkflowsModule-BA7jcEpH.js → WorkflowsModule-oOA9bcdK.js} +4 -4
  178. package/dist/ui/assets/documentReferences-DPZuTgHh.js +1 -0
  179. package/dist/ui/assets/index-607WPo_X.js +4 -0
  180. package/dist/ui/assets/index-CYyodXsg.css +1 -0
  181. package/dist/ui/assets/{vendor-icons-DuEd_65c.js → vendor-icons-B32hGuF2.js} +1 -1
  182. package/dist/ui/index.html +3 -3
  183. package/dist/ui/product/agent manager.png +0 -0
  184. package/dist/ui/product/agent_manager_02.png +0 -0
  185. package/dist/utils/aiProfileEvents.d.ts +7 -0
  186. package/dist/utils/aiProfileEvents.js +6 -0
  187. package/dist/utils/assignees.d.ts +6 -0
  188. package/dist/utils/assignees.js +8 -1
  189. package/dist/utils/assignees.test.d.ts +1 -0
  190. package/dist/utils/assignees.test.js +25 -0
  191. package/dist/utils/avatarDisplay.d.ts +1 -0
  192. package/dist/utils/avatarDisplay.js +15 -0
  193. package/dist/utils/contextFiles.d.ts +3 -1
  194. package/dist/utils/contextFiles.js +2 -1
  195. package/dist/utils/taskActivity.d.ts +7 -1
  196. package/dist/utils/taskActivity.js +63 -1
  197. package/dist/utils/taskActivity.test.js +23 -1
  198. package/dist/utils/taskSearch.d.ts +22 -0
  199. package/dist/utils/taskSearch.js +87 -0
  200. package/dist/utils/taskSearch.test.d.ts +1 -0
  201. package/dist/utils/taskSearch.test.js +69 -0
  202. package/dist/utils/taskUtils.js +10 -3
  203. package/dist/utils/taskUtils.test.d.ts +1 -0
  204. package/dist/utils/taskUtils.test.js +19 -0
  205. package/package.json +1 -1
  206. package/dist/ui/assets/AgentsModule-DrLawwNl.js +0 -1
  207. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BaS2VwIr.css +0 -1
  208. package/dist/ui/assets/AnnotatedAttachmentWorkspace-Z9_whf7F.js +0 -3
  209. package/dist/ui/assets/DocumentWorkspace-B03MaSkw.js +0 -252
  210. package/dist/ui/assets/DocumentWorkspace-Dhdso07p.css +0 -1
  211. package/dist/ui/assets/PlansPage-CvfnMiWq.css +0 -1
  212. package/dist/ui/assets/PlansPage-DRXscYxH.js +0 -1
  213. package/dist/ui/assets/TaskSettings-DZX4jk7e.js +0 -9
  214. package/dist/ui/assets/index-9eT8e0Lu.css +0 -1
  215. 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;
@@ -714,6 +759,9 @@ export interface McpOAuthAccessTokenAuthResult {
714
759
  provider: McpOAuthProvider;
715
760
  scopes: McpAccessTokenScope[];
716
761
  status: McpOAuthGrantStatus;
762
+ aiProfileId?: string | null;
763
+ aiProfileToken?: string | null;
764
+ aiProfileName?: string | null;
717
765
  }
718
766
  /**
719
767
  * Subset of TaskforceCore methods required by the sync route.
@@ -780,6 +828,21 @@ export interface TaskforceSyncCapable {
780
828
  listTaskEventsForSync(input: {
781
829
  workspaceId?: string | null;
782
830
  }): TaskEvent[];
831
+ getTaskEventForSync(input: {
832
+ workspaceId?: string | null;
833
+ taskId: string;
834
+ eventId: string;
835
+ }): TaskEvent | null;
836
+ taskExistsForSync(id: string, workspaceId?: string | null): boolean;
837
+ listEntityEventsForSync(input: {
838
+ workspaceId?: string | null;
839
+ }): EntityEvent[];
840
+ getEntityEventForSync(input: {
841
+ workspaceId?: string | null;
842
+ eventId: string;
843
+ }): EntityEvent | null;
844
+ initiativeExistsForSync(id: string, workspaceId?: string | null): boolean;
845
+ workstreamExistsForSync(id: string, workspaceId?: string | null): boolean;
783
846
  upsertAiProfileForSync(profile: AiProfileRecord): AiProfileRecord;
784
847
  replaceWorkspaceUsersForSync(input: {
785
848
  workspaceId: string;
@@ -791,6 +854,7 @@ export interface TaskforceSyncCapable {
791
854
  upsertDocumentReviewCommentForSync(comment: DocumentReviewCommentSyncRecord): DocumentReviewCommentSyncRecord;
792
855
  upsertAnnotatedAttachmentSessionForSync(session: AnnotatedAttachmentSessionRecord): AnnotatedAttachmentSessionRecord;
793
856
  upsertTaskEventForSync(event: TaskEvent): TaskEvent;
857
+ upsertEntityEventForSync(event: EntityEvent): EntityEvent;
794
858
  deleteDocumentReviewSessionForSync(input: {
795
859
  workspaceId?: string | null;
796
860
  sessionId: string;
@@ -823,6 +887,11 @@ export interface TaskforceSyncCapable {
823
887
  avatarUrl?: string | null;
824
888
  avatarSourceUrl?: string | null;
825
889
  }): AiProfileRecord;
890
+ updateAiProfileSurfaceType(input: {
891
+ workspaceId: string;
892
+ profileId: string;
893
+ surfaceType?: AiProfileSurfaceType | null;
894
+ }): AiProfileRecord;
826
895
  resolveWorkspaceActor(workspaceId: string, actorRef: unknown): TaskActor | null;
827
896
  }
828
897
  export declare class TaskforceCore implements TaskforceSyncCapable {
@@ -856,6 +925,7 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
856
925
  private isGenericAiActorReference;
857
926
  private isKnownAiModelName;
858
927
  private isHumanActorReference;
928
+ private isStableActorReference;
859
929
  private normalizeAiProfileName;
860
930
  private normalizeAiProfileUsername;
861
931
  private normalizeAiProfileIcon;
@@ -866,6 +936,9 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
866
936
  private workspaceUserToActor;
867
937
  private aiProfileRowToRecord;
868
938
  private aiProfileToActor;
939
+ private resolveCanonicalAiProfileId;
940
+ private findCanonicalAiProfileIdsByAlias;
941
+ private resolveUniqueAiProfileActorByAlias;
869
942
  private canonicalizeActorReference;
870
943
  private normalizeCreatedBy;
871
944
  private normalizeCommentAuthor;
@@ -874,9 +947,13 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
874
947
  private normalizePlanningAttachments;
875
948
  private replaceTaskComments;
876
949
  private normalizeTaskEventActor;
950
+ private listEntityEventsInternal;
877
951
  private listTaskEventsInternal;
952
+ private buildEntityActivity;
878
953
  private buildTaskActivity;
954
+ private addEntityEvent;
879
955
  private addTaskEvent;
956
+ private replaceEntityEvents;
880
957
  private replaceTaskEvents;
881
958
  private mapDeletedTaskRow;
882
959
  private pruneDeletedTasks;
@@ -917,6 +994,9 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
917
994
  private initiativeExists;
918
995
  private workstreamExists;
919
996
  private valueEqualsForBulkUpdate;
997
+ private buildPlanningEntityEventChanges;
998
+ private getPlanningEntityEventAction;
999
+ private addWorkstreamTaskMembershipEvents;
920
1000
  private assertWorkstreamLinkAllowed;
921
1001
  private assertInitiativeLinkAllowed;
922
1002
  constructor(config: TaskforceConfig);
@@ -986,6 +1066,7 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
986
1066
  private migrateUserBetaAccessBackfillIfNeeded;
987
1067
  private migrateDuplicateAiProfilesIfNeeded;
988
1068
  private migrateLegacyActorReferencesIfNeeded;
1069
+ private migrateLegacyCommentActorReferencesIfNeeded;
989
1070
  private getWorkspaceOwnerUserId;
990
1071
  getWorkspacePlanMode(workspaceId: string): 'personal' | 'team';
991
1072
  setWorkspacePlanMode(workspaceId: string, mode: 'personal' | 'team', source?: string): 'personal' | 'team';
@@ -1065,6 +1146,7 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
1065
1146
  getJsonBackupEnabled(workspaceId?: string, userId?: string): boolean;
1066
1147
  private listCanonicalTaskAttachments;
1067
1148
  private syncCanonicalTaskAttachmentLinks;
1149
+ private syncCanonicalPlanningAttachmentLinks;
1068
1150
  private rowToTask;
1069
1151
  private rowToInitiative;
1070
1152
  private rowToWorkstream;
@@ -1076,17 +1158,44 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
1076
1158
  resolveTaskIdentifier(value: string, workspaceId?: string): TaskItem | null;
1077
1159
  getInitiative(id: string, workspaceId?: string): InitiativeItem | null;
1078
1160
  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;
1161
+ private isTransientPlanningHydrationError;
1162
+ private getInitiativeForWriteResult;
1163
+ private getWorkstreamForWriteResult;
1164
+ createInitiative(input: Partial<InitiativeItem>, workspaceId?: string, options?: {
1165
+ actorRef?: string;
1166
+ skipEntityEvents?: boolean;
1167
+ }): InitiativeItem;
1168
+ updateInitiative(id: string, patch: Partial<InitiativeItem>, workspaceId?: string, options?: {
1169
+ actorRef?: string;
1170
+ skipEntityEvents?: boolean;
1171
+ }): InitiativeItem;
1172
+ archiveInitiative(id: string, workspaceId?: string, options?: {
1173
+ actorRef?: string;
1174
+ skipEntityEvents?: boolean;
1175
+ }): InitiativeItem;
1176
+ unarchiveInitiative(id: string, workspaceId?: string, options?: {
1177
+ actorRef?: string;
1178
+ skipEntityEvents?: boolean;
1179
+ }): InitiativeItem;
1083
1180
  getWorkstream(id: string, workspaceId?: string): WorkstreamItem | null;
1084
1181
  listWorkstreams(workspaceId?: string): WorkstreamItem[];
1085
1182
  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;
1183
+ createWorkstream(input: Partial<WorkstreamItem>, workspaceId?: string, options?: {
1184
+ actorRef?: string;
1185
+ skipEntityEvents?: boolean;
1186
+ }): WorkstreamItem;
1187
+ updateWorkstream(id: string, patch: Partial<WorkstreamItem>, workspaceId?: string, options?: {
1188
+ actorRef?: string;
1189
+ skipEntityEvents?: boolean;
1190
+ }): WorkstreamItem;
1191
+ archiveWorkstream(id: string, workspaceId?: string, options?: {
1192
+ actorRef?: string;
1193
+ skipEntityEvents?: boolean;
1194
+ }): WorkstreamItem;
1195
+ unarchiveWorkstream(id: string, workspaceId?: string, options?: {
1196
+ actorRef?: string;
1197
+ skipEntityEvents?: boolean;
1198
+ }): WorkstreamItem;
1090
1199
  upsertInitiativeForSync(initiative: InitiativeItem, workspaceId?: string | null): InitiativeItem;
1091
1200
  upsertWorkstreamForSync(workstream: WorkstreamItem, workspaceId?: string | null): WorkstreamItem;
1092
1201
  listChecklistItems(taskId: string, workspaceId?: string): ChecklistItem[];
@@ -1229,6 +1338,20 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
1229
1338
  markUserAvatarUploadDraftConsumed(userId: string, draftId: string): UserAvatarUploadDraftRecord | null;
1230
1339
  discardUserAvatarUploadDraft(userId: string, draftId: string): UserAvatarUploadDraftRecord | null;
1231
1340
  cleanupStaleUserAvatarUploadDrafts(userId: string, olderThanIso: string): UserAvatarUploadDraftRecord[];
1341
+ createTaskAttachmentUploadDraft(input: {
1342
+ draftId: string;
1343
+ workspaceId: string;
1344
+ taskId: string;
1345
+ actorRef: string;
1346
+ storageKey: string;
1347
+ mimeType: string;
1348
+ originalFilename: string;
1349
+ sizeBytes: number;
1350
+ storageProvider?: 'local' | 'r2' | 'external';
1351
+ }): TaskAttachmentUploadDraftRecord;
1352
+ getTaskAttachmentUploadDraft(draftId: string): TaskAttachmentUploadDraftRecord | null;
1353
+ markTaskAttachmentUploadDraftConsumed(draftId: string): TaskAttachmentUploadDraftRecord | null;
1354
+ discardTaskAttachmentUploadDraft(draftId: string): TaskAttachmentUploadDraftRecord | null;
1232
1355
  getSystemRole(userId: string): SystemRole;
1233
1356
  getUserBetaAccess(userId: string): boolean;
1234
1357
  countSystemAdmins(): number;
@@ -1287,6 +1410,11 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
1287
1410
  avatarUrl?: string | null;
1288
1411
  avatarSourceUrl?: string | null;
1289
1412
  }): AiProfileRecord;
1413
+ updateAiProfileSurfaceType(input: {
1414
+ workspaceId: string;
1415
+ profileId: string;
1416
+ surfaceType?: AiProfileSurfaceType | null;
1417
+ }): AiProfileRecord;
1290
1418
  resolveAiProfile(input: ResolveAiProfileInput, options?: ResolveAiProfileOptions): ResolveAiProfileResult;
1291
1419
  listAnnotatedAttachmentSessions(input: {
1292
1420
  workspaceId?: string | null;
@@ -1362,6 +1490,7 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
1362
1490
  upsertDocumentReviewCommentForSync(comment: DocumentReviewCommentSyncRecord): DocumentReviewCommentSyncRecord;
1363
1491
  upsertAnnotatedAttachmentSessionForSync(session: AnnotatedAttachmentSessionRecord): AnnotatedAttachmentSessionRecord;
1364
1492
  upsertTaskEventForSync(event: TaskEvent): TaskEvent;
1493
+ upsertEntityEventForSync(event: EntityEvent): EntityEvent;
1365
1494
  deleteDocumentReviewSessionForSync(input: {
1366
1495
  workspaceId?: string | null;
1367
1496
  sessionId: string;
@@ -1732,6 +1861,11 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
1732
1861
  workspaceId: string;
1733
1862
  tokenId: string;
1734
1863
  }): McpAccessTokenRecord;
1864
+ deleteMcpAccessToken(input: {
1865
+ actorUserId: string;
1866
+ workspaceId: string;
1867
+ tokenId: string;
1868
+ }): boolean;
1735
1869
  regenerateMcpAccessToken(input: {
1736
1870
  actorUserId: string;
1737
1871
  workspaceId: string;
@@ -1783,6 +1917,13 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
1783
1917
  grantId: string;
1784
1918
  }): McpOAuthConnectorGrantRecord;
1785
1919
  authenticateMcpOAuthAccessToken(token: string, workspaceId?: string): McpOAuthAccessTokenAuthResult | null;
1920
+ bindMcpOAuthConnectorGrantAiProfile(input: {
1921
+ grantId: string;
1922
+ workspaceId: string;
1923
+ profileId: string;
1924
+ profileToken: string;
1925
+ profileName: string;
1926
+ }): boolean;
1786
1927
  recordMcpOAuthConnectorGrantUsage(input: {
1787
1928
  grantId: string;
1788
1929
  workspaceId: string;
@@ -1882,9 +2023,32 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
1882
2023
  updateWorkspaceUserRole(userId: string, workspaceId: string, role: AccessRole): boolean;
1883
2024
  getTask(id: string, workspaceId?: string): TaskItem | null;
1884
2025
  listTaskEvents(taskId: string, workspaceId?: string): TaskEvent[];
2026
+ taskExistsForSync(id: string, workspaceId?: string | null): boolean;
2027
+ initiativeExistsForSync(id: string, workspaceId?: string | null): boolean;
2028
+ workstreamExistsForSync(id: string, workspaceId?: string | null): boolean;
2029
+ recordTaskEvent(input: {
2030
+ taskId: string;
2031
+ workspaceId?: string | null;
2032
+ action: string;
2033
+ actor?: unknown;
2034
+ createdAt?: string;
2035
+ details?: TaskEventDetails;
2036
+ }): void;
1885
2037
  listTaskEventsForSync(input: {
1886
2038
  workspaceId?: string | null;
1887
2039
  }): TaskEvent[];
2040
+ getTaskEventForSync(input: {
2041
+ workspaceId?: string | null;
2042
+ taskId: string;
2043
+ eventId: string;
2044
+ }): TaskEvent | null;
2045
+ listEntityEventsForSync(input: {
2046
+ workspaceId?: string | null;
2047
+ }): EntityEvent[];
2048
+ getEntityEventForSync(input: {
2049
+ workspaceId?: string | null;
2050
+ eventId: string;
2051
+ }): EntityEvent | null;
1888
2052
  getScheduleBoard(weekKey: string, showWeekends?: boolean, workspaceId?: string): ScheduleBoardResult;
1889
2053
  updateTaskSchedule(id: string, input: {
1890
2054
  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 {