@taskforcehq/taskforce 0.3.305 → 0.3.307

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (440) hide show
  1. package/README.md +0 -2
  2. package/dist/Taskforce.module.css +603 -107
  3. package/dist/TaskforceCore.js +216 -43
  4. package/dist/TaskforceCore.test.js +611 -28
  5. package/dist/assets/fonts/CourierPrime-Bold.woff2 +0 -0
  6. package/dist/assets/fonts/CourierPrime-BoldItalic.woff2 +0 -0
  7. package/dist/assets/fonts/CourierPrime-Italic.woff2 +0 -0
  8. package/dist/assets/fonts/CourierPrime-Regular.woff2 +0 -0
  9. package/dist/assets/fonts/Noir_medium.woff2 +0 -0
  10. package/dist/assets/fonts/Noir_regular.woff2 +0 -0
  11. package/dist/assets/fonts/RussoOne-Regular.woff2 +0 -0
  12. package/dist/assets/fonts/SpecialElite-Regular.woff2 +0 -0
  13. package/dist/compat/workspaceSyncCompat.js +46 -2
  14. package/dist/compat/workspaceSyncCompat.test.js +38 -1
  15. package/dist/components/activity/EntityActivityTimeline.d.ts +34 -0
  16. package/dist/components/activity/EntityActivityTimeline.js +81 -0
  17. package/dist/components/context/ContextAttachmentManager.d.ts +14 -0
  18. package/dist/components/context/ContextAttachmentManager.js +561 -0
  19. package/dist/components/features/AgentsModule.d.ts +14 -1
  20. package/dist/components/features/AgentsModule.js +366 -18
  21. package/dist/components/features/AgentsModule.test.js +507 -8
  22. package/dist/components/features/AnnotatedAttachmentWorkspace.d.ts +3 -1
  23. package/dist/components/features/AnnotatedAttachmentWorkspace.js +118 -4
  24. package/dist/components/features/AnnotatedAttachmentWorkspace.test.js +52 -0
  25. package/dist/components/features/DocumentIndex.d.ts +2 -2
  26. package/dist/components/features/DocumentIndex.js +3 -4
  27. package/dist/components/features/DocumentViewer.d.ts +7 -1
  28. package/dist/components/features/DocumentViewer.js +62 -4
  29. package/dist/components/features/DocumentWorkspace.d.ts +10 -2
  30. package/dist/components/features/DocumentWorkspace.js +15 -4
  31. package/dist/components/features/DocumentWorkspace.test.js +51 -1
  32. package/dist/components/features/TaskSettings.d.ts +2 -0
  33. package/dist/components/features/TaskSettings.js +83 -78
  34. package/dist/components/features/TaskSettings.test.js +171 -82
  35. package/dist/components/features/documentWorkspaceModel.d.ts +1 -1
  36. package/dist/components/task/TaskActionHeader.js +11 -5
  37. package/dist/components/task/TaskActionHeader.test.js +10 -0
  38. package/dist/components/task/TaskCard.js +24 -29
  39. package/dist/components/task/TaskCard.test.js +38 -3
  40. package/dist/components/task/TaskContextUpload.js +4 -526
  41. package/dist/components/task/TaskContextUpload.test.js +3 -3
  42. package/dist/components/task/TaskForm.js +61 -116
  43. package/dist/components/task/TaskForm.test.js +110 -8
  44. package/dist/components/task/TaskKanban.d.ts +2 -1
  45. package/dist/components/task/TaskKanban.js +94 -21
  46. package/dist/components/task/TaskKanban.test.js +36 -0
  47. package/dist/components/task/TaskList.js +5 -1
  48. package/dist/components/task/TaskList.test.js +4 -0
  49. package/dist/components/ui/EditableAvatarButton.d.ts +18 -0
  50. package/dist/components/ui/EditableAvatarButton.js +18 -0
  51. package/dist/components/ui/HierarchyActionBadge.d.ts +10 -0
  52. package/dist/components/ui/HierarchyActionBadge.js +5 -0
  53. package/dist/components/views/AppShellHeader.d.ts +3 -1
  54. package/dist/components/views/AppShellHeader.js +27 -11
  55. package/dist/components/views/AppShellHeader.test.js +18 -1
  56. package/dist/components/views/PlanComparisonPage.d.ts +9 -1
  57. package/dist/components/views/PlanComparisonPage.js +78 -14
  58. package/dist/components/views/PlanComparisonPage.test.js +257 -0
  59. package/dist/components/views/PlansPage.js +127 -36
  60. package/dist/components/views/PlansPage.test.js +294 -12
  61. package/dist/components/views/StandaloneLayout.js +529 -592
  62. package/dist/components/views/WidgetView.js +10 -8
  63. package/dist/components/views/panels/PlanningDrawer.d.ts +25 -5
  64. package/dist/components/views/panels/PlanningDrawer.js +270 -55
  65. package/dist/components/views/panels/PlanningDrawer.test.d.ts +1 -0
  66. package/dist/components/views/panels/PlanningDrawer.test.js +529 -0
  67. package/dist/components/views/planningScope.d.ts +20 -0
  68. package/dist/components/views/planningScope.js +25 -0
  69. package/dist/components/views/planningScope.test.d.ts +1 -0
  70. package/dist/components/views/planningScope.test.js +60 -0
  71. package/dist/components/views/standalone/modals/AccountHubModal.d.ts +26 -1
  72. package/dist/components/views/standalone/modals/AccountHubModal.js +76 -2
  73. package/dist/components/views/standalone/modals/AccountHubModal.test.js +20 -3
  74. package/dist/components/views/standalone/modals/AvatarImageManagerModal.d.ts +20 -0
  75. package/dist/components/views/standalone/modals/AvatarImageManagerModal.js +127 -0
  76. package/dist/components/views/standalone/modals/EditProfileModal.d.ts +2 -9
  77. package/dist/components/views/standalone/modals/EditProfileModal.js +3 -2
  78. package/dist/components/views/standalone/modals/SyncEnableWarningModal.d.ts +9 -0
  79. package/dist/components/views/standalone/modals/SyncEnableWarningModal.js +6 -0
  80. package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.d.ts +1 -0
  81. package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.js +24 -0
  82. package/dist/components/views/standalone/modals/SyncStatusModal.d.ts +2 -1
  83. package/dist/components/views/standalone/modals/SyncStatusModal.js +2 -2
  84. package/dist/config/envSchema.js +1 -0
  85. package/dist/core/AiProfileService.d.ts +46 -2
  86. package/dist/core/AiProfileService.js +1073 -82
  87. package/dist/core/AiProfileService.test.js +19 -1
  88. package/dist/core/AiProfiles.test.js +1249 -44
  89. package/dist/core/AttachmentLinkService.d.ts +3 -0
  90. package/dist/core/AttachmentLinkService.js +110 -23
  91. package/dist/core/AuthIdentityService.d.ts +107 -0
  92. package/dist/core/AuthIdentityService.js +284 -0
  93. package/dist/core/AuthTokenService.d.ts +4 -0
  94. package/dist/core/AuthTokenService.js +34 -6
  95. package/dist/core/AuthTokenService.test.js +3 -3
  96. package/dist/core/EntitlementsPolicy.test.js +2 -2
  97. package/dist/core/GlobalSettingsService.js +127 -6
  98. package/dist/core/McpTokenService.d.ts +12 -0
  99. package/dist/core/McpTokenService.js +44 -1
  100. package/dist/core/PlanEntitlementService.d.ts +23 -2
  101. package/dist/core/PlanEntitlementService.js +343 -57
  102. package/dist/core/PlanFeatureCatalog.test.d.ts +1 -0
  103. package/dist/core/PlanFeatureCatalog.test.js +84 -0
  104. package/dist/core/PlanVersionPolicy.test.js +35 -2
  105. package/dist/core/PlanningEntities.test.js +418 -4
  106. package/dist/core/SignupMonetizationSettings.test.js +199 -27
  107. package/dist/core/SyncReconciliationService.js +2 -65
  108. package/dist/core/SystemAdmin.test.js +42 -42
  109. package/dist/core/TaskActivityService.d.ts +28 -1
  110. package/dist/core/TaskActivityService.js +227 -46
  111. package/dist/core/TaskActivitySync.test.d.ts +1 -0
  112. package/dist/core/TaskActivitySync.test.js +90 -0
  113. package/dist/core/TaskAttachmentsCanonical.test.js +51 -1
  114. package/dist/core/TaskAuditTimeline.test.js +96 -0
  115. package/dist/core/Taskforce.d.ts +415 -40
  116. package/dist/core/Taskforce.ids.test.js +58 -0
  117. package/dist/core/Taskforce.js +1543 -266
  118. package/dist/core/Taskforce.listTasksSlim.test.d.ts +1 -0
  119. package/dist/core/Taskforce.listTasksSlim.test.js +91 -0
  120. package/dist/core/Taskforce.mcpAuth.test.js +109 -0
  121. package/dist/core/UserProfileAvatarDrafts.test.js +30 -3
  122. package/dist/core/WorkspaceLifecycleService.js +0 -5
  123. package/dist/core/WorkspacePermissions.test.js +25 -1
  124. package/dist/core/WorkspacePlanMode.test.js +117 -16
  125. package/dist/core/shared.d.ts +1 -1
  126. package/dist/core/shared.js +5 -1
  127. package/dist/core/types.d.ts +75 -2
  128. package/dist/hooks/auth/useTaskforceAuthBootstrap.js +28 -2
  129. package/dist/hooks/bootstrapTimeouts.d.ts +4 -0
  130. package/dist/hooks/bootstrapTimeouts.js +8 -0
  131. package/dist/hooks/bootstrapTimeouts.test.d.ts +1 -0
  132. package/dist/hooks/bootstrapTimeouts.test.js +12 -0
  133. package/dist/hooks/sync/bootstrap.js +2 -0
  134. package/dist/hooks/sync/controlPlane.d.ts +37 -0
  135. package/dist/hooks/sync/controlPlane.js +78 -0
  136. package/dist/hooks/sync/controlPlane.test.d.ts +1 -0
  137. package/dist/hooks/sync/controlPlane.test.js +121 -0
  138. package/dist/hooks/sync/lifecyclePolicy.d.ts +45 -0
  139. package/dist/hooks/sync/lifecyclePolicy.js +93 -0
  140. package/dist/hooks/sync/lifecyclePolicy.test.d.ts +1 -0
  141. package/dist/hooks/sync/lifecyclePolicy.test.js +124 -0
  142. package/dist/hooks/sync/orchestratorShared.d.ts +13 -4
  143. package/dist/hooks/sync/orchestratorShared.js +129 -48
  144. package/dist/hooks/sync/orchestratorShared.test.js +50 -1
  145. package/dist/hooks/sync/pullLifecycle.d.ts +31 -0
  146. package/dist/hooks/sync/pullLifecycle.js +24 -0
  147. package/dist/hooks/sync/pullLifecycle.test.d.ts +1 -0
  148. package/dist/hooks/sync/pullLifecycle.test.js +80 -0
  149. package/dist/hooks/sync/recovery.d.ts +16 -2
  150. package/dist/hooks/sync/recovery.js +179 -53
  151. package/dist/hooks/sync/recovery.test.d.ts +1 -0
  152. package/dist/hooks/sync/recovery.test.js +292 -0
  153. package/dist/hooks/sync/transfers.d.ts +16 -3
  154. package/dist/hooks/sync/transfers.js +210 -66
  155. package/dist/hooks/sync/transfers.test.d.ts +1 -0
  156. package/dist/hooks/sync/transfers.test.js +928 -0
  157. package/dist/hooks/sync/useRecentSyncEvents.d.ts +21 -0
  158. package/dist/hooks/sync/useRecentSyncEvents.js +92 -0
  159. package/dist/hooks/sync/useRecentSyncEvents.test.d.ts +1 -0
  160. package/dist/hooks/sync/useRecentSyncEvents.test.js +124 -0
  161. package/dist/hooks/sync/useSyncStatusActions.d.ts +30 -0
  162. package/dist/hooks/sync/useSyncStatusActions.js +88 -0
  163. package/dist/hooks/sync/useSyncStatusActions.test.d.ts +1 -0
  164. package/dist/hooks/sync/useSyncStatusActions.test.js +133 -0
  165. package/dist/hooks/sync/useSyncStatusControls.d.ts +25 -0
  166. package/dist/hooks/sync/useSyncStatusControls.js +60 -0
  167. package/dist/hooks/sync/useSyncStatusControls.test.d.ts +1 -0
  168. package/dist/hooks/sync/useSyncStatusControls.test.js +88 -0
  169. package/dist/hooks/useFilterSort.js +13 -13
  170. package/dist/hooks/useFilterSort.test.js +87 -1
  171. package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +12 -0
  172. package/dist/hooks/useSyncOrchestrator.d.ts +9 -2
  173. package/dist/hooks/useSyncOrchestrator.js +409 -183
  174. package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +407 -0
  175. package/dist/hooks/useTaskData.js +8 -3
  176. package/dist/hooks/useTaskData.test.js +45 -0
  177. package/dist/hooks/useTaskforce.d.ts +145 -52
  178. package/dist/hooks/useTaskforce.js +592 -253
  179. package/dist/hooks/useTaskforce.runtime-routing.test.d.ts +1 -0
  180. package/dist/hooks/useTaskforce.runtime-routing.test.js +246 -0
  181. package/dist/hooks/useTaskforce.sync-behavior.test.js +2468 -201
  182. package/dist/hooks/useWorkspaceSyncController.d.ts +1 -0
  183. package/dist/hooks/useWorkspaceSyncController.js +13 -2
  184. package/dist/hooks/useWorkspaceSyncController.test.js +48 -0
  185. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.d.ts +16 -0
  186. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +328 -40
  187. package/dist/localization/locales/en-US.d.ts +0 -1
  188. package/dist/localization/locales/en-US.js +0 -1
  189. package/dist/localization/locales/es-419.js +0 -1
  190. package/dist/localization/locales/pt-BR.js +0 -1
  191. package/dist/mcp/canonicalAssetHelpers.d.ts +16 -4
  192. package/dist/mcp/canonicalAssetHelpers.js +18 -10
  193. package/dist/mcp/canonicalAssetHelpers.test.d.ts +1 -0
  194. package/dist/mcp/canonicalAssetHelpers.test.js +67 -0
  195. package/dist/mcp/clientIntegrations.d.ts +1 -0
  196. package/dist/mcp/clientIntegrations.js +25 -0
  197. package/dist/mcp/clientIntegrations.test.js +14 -3
  198. package/dist/mcp/clientProfileDefaults.js +3 -3
  199. package/dist/mcp/collaborationRegistrar.js +7 -7
  200. package/dist/mcp/documentAssetRegistrar.js +116 -10
  201. package/dist/mcp/runtime.d.ts +3 -0
  202. package/dist/mcp/runtime.js +1099 -185
  203. package/dist/mcp/runtime.test.js +1491 -140
  204. package/dist/mcp/taskAttachmentTypes.d.ts +1 -1
  205. package/dist/mcp/taskPlanningRegistrar.js +48 -0
  206. package/dist/mcp/toolRegistry.d.ts +56 -0
  207. package/dist/mcp/toolRegistry.js +8 -0
  208. package/dist/mcp/toolRegistry.test.js +4 -0
  209. package/dist/migrations/taskSchemaMigrations.d.ts +1 -1
  210. package/dist/migrations/taskSchemaMigrations.js +192 -61
  211. package/dist/migrations/taskSchemaMigrations.test.js +15 -0
  212. package/dist/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
  213. package/dist/resources/templates/workflows/collaborate.yaml +1 -1
  214. package/dist/resources/templates/workflows/evaluate.yaml +2 -2
  215. package/dist/resources/templates/workflows/plan.yaml +1 -1
  216. package/dist/resources/templates/workflows/review.yaml +2 -2
  217. package/dist/server/aiProfileAvatarAssets.d.ts +49 -0
  218. package/dist/server/aiProfileAvatarAssets.js +319 -0
  219. package/dist/server/aiProfileAvatarAssets.test.d.ts +1 -0
  220. package/dist/server/aiProfileAvatarAssets.test.js +213 -0
  221. package/dist/server/annotatedAttachmentsRoutes.test.js +69 -10
  222. package/dist/server/auth/providers/apple.d.ts +33 -0
  223. package/dist/server/auth/providers/apple.js +82 -0
  224. package/dist/server/auth/providers/appleClientSecret.d.ts +37 -0
  225. package/dist/server/auth/providers/appleClientSecret.js +65 -0
  226. package/dist/server/auth/providers/github.d.ts +26 -0
  227. package/dist/server/auth/providers/github.js +86 -0
  228. package/dist/server/auth/providers/google.d.ts +21 -0
  229. package/dist/server/auth/providers/google.js +56 -0
  230. package/dist/server/auth/providers/types.d.ts +21 -0
  231. package/dist/server/auth/providers/types.js +1 -0
  232. package/dist/server/auth.d.ts +2 -0
  233. package/dist/server/auth.js +6 -3
  234. package/dist/server/documentReviewRoutes.test.js +36 -3
  235. package/dist/server/index.cookieProxy.test.js +1 -0
  236. package/dist/server/index.d.ts +12 -0
  237. package/dist/server/index.js +124 -9
  238. package/dist/server/index.rateLimit.test.js +3 -0
  239. package/dist/server/index.test.js +111 -3
  240. package/dist/server/routes/admin.d.ts +3 -0
  241. package/dist/server/routes/admin.js +459 -28
  242. package/dist/server/routes/annotatedAttachments.js +51 -0
  243. package/dist/server/routes/auth.d.ts +26 -2
  244. package/dist/server/routes/auth.js +1170 -71
  245. package/dist/server/routes/authSupport.d.ts +5 -1
  246. package/dist/server/routes/authSupport.js +13 -2
  247. package/dist/server/routes/billing.js +372 -35
  248. package/dist/server/routes/billing.test.js +595 -12
  249. package/dist/server/routes/documents.d.ts +1 -0
  250. package/dist/server/routes/documents.js +182 -70
  251. package/dist/server/routes/shared.d.ts +28 -2
  252. package/dist/server/routes/shared.js +69 -14
  253. package/dist/server/routes/sync.integration.test.js +658 -39
  254. package/dist/server/routes/sync.js +74 -608
  255. package/dist/server/routes/syncAuxRoutes.d.ts +15 -0
  256. package/dist/server/routes/syncAuxRoutes.js +91 -0
  257. package/dist/server/routes/syncAuxRoutes.test.d.ts +1 -0
  258. package/dist/server/routes/syncAuxRoutes.test.js +158 -0
  259. package/dist/server/routes/syncPullApplyRoutes.d.ts +36 -0
  260. package/dist/server/routes/syncPullApplyRoutes.js +204 -0
  261. package/dist/server/routes/syncPushRoutes.d.ts +24 -0
  262. package/dist/server/routes/syncPushRoutes.js +212 -0
  263. package/dist/server/routes/syncRouteGuards.d.ts +36 -0
  264. package/dist/server/routes/syncRouteGuards.js +67 -0
  265. package/dist/server/routes/syncRouteGuards.test.d.ts +1 -0
  266. package/dist/server/routes/syncRouteGuards.test.js +94 -0
  267. package/dist/server/routes/syncRouteTypes.d.ts +13 -0
  268. package/dist/server/routes/syncRouteTypes.js +1 -0
  269. package/dist/server/routes/syncSnapshotRoutes.d.ts +66 -0
  270. package/dist/server/routes/syncSnapshotRoutes.js +182 -0
  271. package/dist/server/routes/tasks.js +55 -10
  272. package/dist/server/routes/workspaces.js +36 -5
  273. package/dist/server/routes.js +147 -11
  274. package/dist/server/routes.test.js +2704 -183
  275. package/dist/services/workflowExportSnapshots.test.js +2 -0
  276. package/dist/shared/aiProfileSeatScope.d.ts +5 -0
  277. package/dist/shared/aiProfileSeatScope.js +21 -0
  278. package/dist/shared/aiProfileSurfaceType.d.ts +1 -1
  279. package/dist/shared/aiProfileSurfaceType.js +10 -8
  280. package/dist/shared/passwordPolicy.d.ts +13 -0
  281. package/dist/shared/passwordPolicy.js +84 -0
  282. package/dist/shared/passwordPolicy.test.d.ts +1 -0
  283. package/dist/shared/passwordPolicy.test.js +34 -0
  284. package/dist/storage/objectStorage.d.ts +1 -0
  285. package/dist/storage/objectStorage.js +2 -1
  286. package/dist/storage/objectStorageClient.d.ts +1 -0
  287. package/dist/storage/objectStorageClient.js +41 -8
  288. package/dist/storage/objectStorageClient.test.js +26 -1
  289. package/dist/storage/objectStorageConfig.js +3 -1
  290. package/dist/storage/objectStorageConfig.test.js +13 -1
  291. package/dist/storage/workspaceAssetStore.d.ts +15 -3
  292. package/dist/storage/workspaceAssetStore.js +132 -44
  293. package/dist/storage/workspaceAssetStore.test.js +93 -6
  294. package/dist/styles/fonts.css +70 -0
  295. package/dist/sync/collaborationSyncPayload.d.ts +6 -1
  296. package/dist/sync/collaborationSyncPayload.js +19 -11
  297. package/dist/sync/collaborationSyncPayload.test.js +14 -1
  298. package/dist/sync/collaborationSyncState.d.ts +3 -3
  299. package/dist/sync/collaborationSyncState.js +19 -12
  300. package/dist/sync/contentSyncPayload.d.ts +5 -1
  301. package/dist/sync/contentSyncPayload.js +9 -0
  302. package/dist/sync/contentSyncPayload.test.js +39 -0
  303. package/dist/sync/contentSyncState.d.ts +9 -9
  304. package/dist/sync/contentSyncState.js +248 -107
  305. package/dist/sync/planningSyncPayload.js +5 -0
  306. package/dist/sync/planningSyncPayload.test.js +24 -0
  307. package/dist/sync/syncApplyHandlers.d.ts +11 -4
  308. package/dist/sync/syncApplyHandlers.js +115 -42
  309. package/dist/sync/syncApplyHandlers.test.js +251 -4
  310. package/dist/sync/syncFieldSemantics.d.ts +12 -0
  311. package/dist/sync/syncFieldSemantics.js +55 -0
  312. package/dist/sync/syncResourceAdapters.d.ts +46 -0
  313. package/dist/sync/syncResourceAdapters.js +79 -0
  314. package/dist/sync/syncService.d.ts +6 -0
  315. package/dist/sync/syncService.js +65 -1
  316. package/dist/sync/syncService.test.js +96 -3
  317. package/dist/sync/taskSyncChangeKey.d.ts +2 -0
  318. package/dist/sync/taskSyncChangeKey.js +143 -0
  319. package/dist/sync/taskSyncPayload.js +3 -8
  320. package/dist/sync/workspacePullFeed.d.ts +4 -0
  321. package/dist/sync/workspacePullFeed.js +132 -72
  322. package/dist/sync/workspacePullFeed.test.js +92 -0
  323. package/dist/sync/workspaceRepair.js +5 -2
  324. package/dist/sync/workspaceSyncModel.d.ts +73 -6
  325. package/dist/sync/workspaceSyncModel.js +342 -73
  326. package/dist/sync/workspaceSyncModel.test.js +559 -14
  327. package/dist/sync/workspaceSyncState.d.ts +17 -0
  328. package/dist/sync/workspaceSyncState.js +2 -1
  329. package/dist/sync/workspaceSyncSurface.js +3 -8
  330. package/dist/types.d.ts +50 -2
  331. package/dist/ui/assets/AgentsModule-2y82_3DO.js +1 -0
  332. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BTLZZCiQ.js +3 -0
  333. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BVKew-mH.css +1 -0
  334. package/dist/ui/assets/ContextAttachmentManager-D2epuNnG.js +3 -0
  335. package/dist/ui/assets/CourierPrime-Bold-BuLj_dpw.woff2 +0 -0
  336. package/dist/ui/assets/CourierPrime-BoldItalic-BrK2pUkZ.woff2 +0 -0
  337. package/dist/ui/assets/CourierPrime-Italic-DFUZK5Ey.woff2 +0 -0
  338. package/dist/ui/assets/CourierPrime-Regular-BsKphzVf.woff2 +0 -0
  339. package/dist/ui/assets/DocumentWorkspace-D4rJKXzd.css +1 -0
  340. package/dist/ui/assets/DocumentWorkspace-sVa-3Do6.js +252 -0
  341. package/dist/ui/assets/EntityActivityTimeline-DyqvvhuF.css +1 -0
  342. package/dist/ui/assets/EntityActivityTimeline-Zods27y_.js +1 -0
  343. package/dist/ui/assets/{InitiativesModule-Dhm7M8e7.js → InitiativesModule-D4XseTwW.js} +1 -1
  344. package/dist/ui/assets/Noir_medium-bxQwKGzB.woff2 +0 -0
  345. package/dist/ui/assets/Noir_regular-ojf2kxlG.woff2 +0 -0
  346. package/dist/ui/assets/PlansPage-D5AcbO0L.js +1 -0
  347. package/dist/ui/assets/PlansPage-Dvqsz5zc.css +1 -0
  348. package/dist/ui/assets/RussoOne-Regular-Cu_qq_qC.woff2 +0 -0
  349. package/dist/ui/assets/SpecialElite-Regular-Di6gSvAS.woff2 +0 -0
  350. package/dist/ui/assets/TaskContextUpload-uC5qx4Bv.js +1 -0
  351. package/dist/ui/assets/TaskSettings-CqvPAsTv.js +9 -0
  352. package/dist/ui/assets/{WorkflowsModule-BcS4afRn.js → WorkflowsModule-oOA9bcdK.js} +4 -4
  353. package/dist/ui/assets/documentReferences-DPZuTgHh.js +1 -0
  354. package/dist/ui/assets/index-607WPo_X.js +4 -0
  355. package/dist/ui/assets/index-CYyodXsg.css +1 -0
  356. package/dist/ui/assets/{vendor-icons-BSUaRwF8.js → vendor-icons-B32hGuF2.js} +1 -1
  357. package/dist/ui/fonts/CourierPrime-Bold.ttf +0 -0
  358. package/dist/ui/fonts/CourierPrime-Bold.woff2 +0 -0
  359. package/dist/ui/fonts/CourierPrime-BoldItalic.ttf +0 -0
  360. package/dist/ui/fonts/CourierPrime-BoldItalic.woff2 +0 -0
  361. package/dist/ui/fonts/CourierPrime-Italic.ttf +0 -0
  362. package/dist/ui/fonts/CourierPrime-Italic.woff2 +0 -0
  363. package/dist/ui/fonts/CourierPrime-Regular.ttf +0 -0
  364. package/dist/ui/fonts/CourierPrime-Regular.woff2 +0 -0
  365. package/dist/ui/fonts/Noir_medium.otf +0 -0
  366. package/dist/ui/fonts/Noir_medium.woff2 +0 -0
  367. package/dist/ui/fonts/Noir_regular.otf +0 -0
  368. package/dist/ui/fonts/Noir_regular.woff2 +0 -0
  369. package/dist/ui/fonts/RussoOne-Regular.woff2 +0 -0
  370. package/dist/ui/fonts/SpecialElite-Regular.ttf +0 -0
  371. package/dist/ui/fonts/SpecialElite-Regular.woff2 +0 -0
  372. package/dist/ui/index.html +3 -3
  373. package/dist/ui/product/agent manager.png +0 -0
  374. package/dist/ui/product/agent_manager_02.png +0 -0
  375. package/dist/utils/accountProfileSummaryCache.d.ts +5 -0
  376. package/dist/utils/aiProfileEvents.d.ts +7 -0
  377. package/dist/utils/aiProfileEvents.js +6 -0
  378. package/dist/utils/assignees.d.ts +8 -0
  379. package/dist/utils/assignees.js +10 -1
  380. package/dist/utils/assignees.test.d.ts +1 -0
  381. package/dist/utils/assignees.test.js +25 -0
  382. package/dist/utils/avatarDisplay.d.ts +1 -0
  383. package/dist/utils/avatarDisplay.js +15 -0
  384. package/dist/utils/avatarUpload.d.ts +27 -0
  385. package/dist/utils/avatarUpload.js +132 -0
  386. package/dist/utils/avatarUpload.test.d.ts +1 -0
  387. package/dist/utils/avatarUpload.test.js +40 -0
  388. package/dist/utils/bootstrapTrace.d.ts +7 -0
  389. package/dist/utils/bootstrapTrace.js +29 -0
  390. package/dist/utils/commercialLifecyclePresentation.js +3 -0
  391. package/dist/utils/contextAssetEvents.d.ts +2 -0
  392. package/dist/utils/contextFiles.d.ts +3 -1
  393. package/dist/utils/contextFiles.js +2 -1
  394. package/dist/utils/syncEventDetails.d.ts +3 -0
  395. package/dist/utils/syncEventDetails.js +64 -0
  396. package/dist/utils/syncEventDetails.test.d.ts +1 -0
  397. package/dist/utils/syncEventDetails.test.js +23 -0
  398. package/dist/utils/syncEventPresentation.d.ts +15 -0
  399. package/dist/utils/syncEventPresentation.js +129 -0
  400. package/dist/utils/syncEventPresentation.test.d.ts +1 -0
  401. package/dist/utils/syncEventPresentation.test.js +64 -0
  402. package/dist/utils/syncStatusPresentation.d.ts +72 -0
  403. package/dist/utils/syncStatusPresentation.js +217 -0
  404. package/dist/utils/syncStatusPresentation.test.d.ts +1 -0
  405. package/dist/utils/syncStatusPresentation.test.js +164 -0
  406. package/dist/utils/taskActivity.d.ts +9 -1
  407. package/dist/utils/taskActivity.js +290 -22
  408. package/dist/utils/taskActivity.test.js +141 -8
  409. package/dist/utils/taskSearch.d.ts +22 -0
  410. package/dist/utils/taskSearch.js +87 -0
  411. package/dist/utils/taskSearch.test.d.ts +1 -0
  412. package/dist/utils/taskSearch.test.js +69 -0
  413. package/dist/utils/taskUtils.js +10 -3
  414. package/dist/utils/taskUtils.test.d.ts +1 -0
  415. package/dist/utils/taskUtils.test.js +19 -0
  416. package/dist/utils/workspaceSyncPresentation.d.ts +4 -0
  417. package/dist/utils/workspaceSyncPresentation.js +68 -2
  418. package/dist/utils/workspaceSyncPresentation.test.js +36 -1
  419. package/package.json +3 -2
  420. package/scripts/export-sqlite-to-postgres.mjs +7 -9
  421. package/scripts/run-e2e-realtime.sh +17 -3
  422. package/scripts/run-smoke.sh +17 -5
  423. package/scripts/run-soak.sh +17 -5
  424. package/src/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
  425. package/src/resources/templates/workflows/collaborate.yaml +1 -1
  426. package/src/resources/templates/workflows/evaluate.yaml +2 -2
  427. package/src/resources/templates/workflows/plan.yaml +1 -1
  428. package/src/resources/templates/workflows/review.yaml +2 -2
  429. package/dist/ui/assets/AgentsModule-N2MnQBZk.js +0 -1
  430. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BG6P_GVW.js +0 -3
  431. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BaS2VwIr.css +0 -1
  432. package/dist/ui/assets/DocumentWorkspace-B3nV_Gc5.css +0 -1
  433. package/dist/ui/assets/DocumentWorkspace-DRbDMwh8.js +0 -252
  434. package/dist/ui/assets/PlansPage-C2dd2n1X.css +0 -1
  435. package/dist/ui/assets/PlansPage-Cq0zXj3I.js +0 -1
  436. package/dist/ui/assets/RussoOne-Regular-C3BxZIj7.ttf +0 -0
  437. package/dist/ui/assets/TaskSettings-ln0aF7xc.js +0 -9
  438. package/dist/ui/assets/index-C2-OXZV7.css +0 -1
  439. package/dist/ui/assets/index-DcSI5F86.js +0 -6
  440. package/scripts/migrate-planning-model.ts +0 -233
@@ -0,0 +1,124 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { resolveWorkspaceAutomaticPullPolicy, resolveWorkspaceSyncPresentation, shouldRunWorkspaceStartupRepair, shouldScheduleWorkspaceReactivePush, shouldStartWorkspacePeriodicFullReconcile, shouldStartWorkspacePushWatchdog, } from './lifecyclePolicy';
3
+ const makeLifecycleBaseArgs = () => ({
4
+ cloudAuthConfigured: true,
5
+ runtimeMode: 'local',
6
+ workspaceCloudSyncEnabled: true,
7
+ authSessionResolved: true
8
+ });
9
+ describe('sync lifecycle policy', () => {
10
+ it('reports bootstrap phases as syncing with phase-specific guidance', () => {
11
+ expect(resolveWorkspaceSyncPresentation({
12
+ enabled: true,
13
+ phase: 'attach-cloud',
14
+ busy: false,
15
+ retryAt: null,
16
+ lastErrorMessage: null
17
+ })).toEqual({
18
+ status: 'syncing',
19
+ summary: 'Waiting for the first cloud pull into this device.',
20
+ recommendedAction: 'Keep this window open for the first cloud pull. If it does not move, press Repair.'
21
+ });
22
+ });
23
+ it('reports retry state as attention even when sync is otherwise idle', () => {
24
+ expect(resolveWorkspaceSyncPresentation({
25
+ enabled: true,
26
+ phase: 'active',
27
+ busy: false,
28
+ retryAt: '2026-04-18T16:00:00.000Z',
29
+ lastErrorMessage: null
30
+ })).toEqual({
31
+ status: 'attention',
32
+ summary: 'Sync hit a temporary problem and will retry automatically.',
33
+ recommendedAction: 'Wait for the automatic retry, or press Sync to retry now.'
34
+ });
35
+ });
36
+ it('allows reactive push only after bootstrap and reference snapshots are ready', () => {
37
+ expect(shouldScheduleWorkspaceReactivePush({
38
+ ...makeLifecycleBaseArgs(),
39
+ workspaceSyncPhase: 'active',
40
+ workspaceSyncReferenceSnapshotsReady: true
41
+ })).toBe(true);
42
+ expect(shouldScheduleWorkspaceReactivePush({
43
+ ...makeLifecycleBaseArgs(),
44
+ workspaceSyncPhase: 'attach-cloud',
45
+ workspaceSyncReferenceSnapshotsReady: true
46
+ })).toBe(false);
47
+ expect(shouldScheduleWorkspaceReactivePush({
48
+ ...makeLifecycleBaseArgs(),
49
+ workspaceSyncPhase: 'active',
50
+ workspaceSyncReferenceSnapshotsReady: false
51
+ })).toBe(false);
52
+ });
53
+ it('starts the push watchdog only for active sync', () => {
54
+ expect(shouldStartWorkspacePushWatchdog({
55
+ ...makeLifecycleBaseArgs(),
56
+ workspaceSyncPhase: 'active',
57
+ workspaceSyncReferenceSnapshotsReady: true
58
+ })).toBe(true);
59
+ expect(shouldStartWorkspacePushWatchdog({
60
+ ...makeLifecycleBaseArgs(),
61
+ workspaceSyncPhase: 'error',
62
+ workspaceSyncReferenceSnapshotsReady: true
63
+ })).toBe(false);
64
+ });
65
+ it('starts automatic pull for attach-cloud and kickstarts first active pull when no pull has succeeded yet', () => {
66
+ expect(resolveWorkspaceAutomaticPullPolicy({
67
+ ...makeLifecycleBaseArgs(),
68
+ workspaceSyncPhase: 'attach-cloud',
69
+ lastPullAt: null,
70
+ retryPending: false
71
+ })).toEqual({
72
+ shouldStart: true,
73
+ shouldKickOffImmediately: true
74
+ });
75
+ expect(resolveWorkspaceAutomaticPullPolicy({
76
+ ...makeLifecycleBaseArgs(),
77
+ workspaceSyncPhase: 'active',
78
+ lastPullAt: null,
79
+ retryPending: false
80
+ })).toEqual({
81
+ shouldStart: true,
82
+ shouldKickOffImmediately: true
83
+ });
84
+ expect(resolveWorkspaceAutomaticPullPolicy({
85
+ ...makeLifecycleBaseArgs(),
86
+ workspaceSyncPhase: 'active',
87
+ lastPullAt: '2026-04-18T15:00:00.000Z',
88
+ retryPending: true
89
+ })).toEqual({
90
+ shouldStart: false,
91
+ shouldKickOffImmediately: false
92
+ });
93
+ });
94
+ it('runs periodic full reconcile and startup repair only in authenticated active sync', () => {
95
+ expect(shouldStartWorkspacePeriodicFullReconcile({
96
+ ...makeLifecycleBaseArgs(),
97
+ workspaceSyncPhase: 'active',
98
+ isAuthenticated: true
99
+ })).toBe(true);
100
+ expect(shouldStartWorkspacePeriodicFullReconcile({
101
+ ...makeLifecycleBaseArgs(),
102
+ workspaceSyncPhase: 'attach-cloud',
103
+ isAuthenticated: true
104
+ })).toBe(false);
105
+ expect(shouldRunWorkspaceStartupRepair({
106
+ ...makeLifecycleBaseArgs(),
107
+ workspaceSyncPhase: 'active',
108
+ isAuthenticated: true,
109
+ alreadyRan: false
110
+ })).toBe(true);
111
+ expect(shouldRunWorkspaceStartupRepair({
112
+ ...makeLifecycleBaseArgs(),
113
+ workspaceSyncPhase: 'error',
114
+ isAuthenticated: true,
115
+ alreadyRan: false
116
+ })).toBe(true);
117
+ expect(shouldRunWorkspaceStartupRepair({
118
+ ...makeLifecycleBaseArgs(),
119
+ workspaceSyncPhase: 'active',
120
+ isAuthenticated: true,
121
+ alreadyRan: true
122
+ })).toBe(false);
123
+ });
124
+ });
@@ -1,6 +1,7 @@
1
1
  import type { WorkspaceTaxonomyState } from '../../shared/taxonomyState.js';
2
- import type { WorkspaceSyncAiProfileSnapshot, WorkspaceSyncDocumentReviewCommentSnapshot, WorkspaceSyncDocumentReviewSessionSnapshot, WorkspaceSyncTaskEventSnapshot } from '../../sync/workspaceSyncModel';
3
- import type { TaskItem } from '../../types';
2
+ import type { WorkspaceSyncAiProfileSnapshot, WorkspaceSyncDocumentReviewCommentSnapshot, WorkspaceSyncDocumentReviewSessionSnapshot, WorkspaceSyncEntityEventSnapshot } from '../../sync/workspaceSyncModel';
3
+ import type { WorkspaceSyncPushBaselineSnapshot } from '../../sync/workspaceSyncState.js';
4
+ import type { InitiativeItem, TaskItem, WorkstreamItem } from '../../types';
4
5
  export declare const USER_GLOBAL_SYNC_META_KEY = "taskforce.userGlobalSyncMeta.v1";
5
6
  export declare const SYNC_DEBUG_LOG_KEY = "taskforce.syncDebug.v1";
6
7
  export declare const WORKSPACE_BOOTSTRAP_TIMEOUT_MS = 120000;
@@ -18,11 +19,15 @@ export declare function writeUserGlobalSyncMeta(next: Record<string, {
18
19
  }>): void;
19
20
  export declare function buildTaxonomyStateFingerprint(taxonomyState?: WorkspaceTaxonomyState): string;
20
21
  export declare function flattenDocumentReviewComments(sessions: WorkspaceSyncDocumentReviewSessionSnapshot[]): WorkspaceSyncDocumentReviewCommentSnapshot[];
21
- export declare function flattenTaskEvents(tasks: TaskItem[], archivedTasks: TaskItem[]): WorkspaceSyncTaskEventSnapshot[];
22
+ export declare function flattenTaskEvents(tasks: TaskItem[], archivedTasks: TaskItem[], initiatives?: InitiativeItem[], workstreams?: WorkstreamItem[]): WorkspaceSyncEntityEventSnapshot[];
22
23
  export interface PersistedSyncWatermarks {
24
+ taskIds: Set<string>;
23
25
  taskWatermarks: Map<string, string>;
26
+ taskChangeKeys?: Map<string, string>;
24
27
  initiativeWatermarks: Map<string, string>;
25
28
  workstreamWatermarks: Map<string, string>;
29
+ aiProfileWatermarks: Map<string, string>;
30
+ aiProfileChangeKeys?: Map<string, string>;
26
31
  documentWatermarks: Map<string, string>;
27
32
  assetWatermarks: Map<string, string>;
28
33
  documentReviewSessionWatermarks: Map<string, string>;
@@ -30,7 +35,11 @@ export interface PersistedSyncWatermarks {
30
35
  annotatedAttachmentSessionWatermarks: Map<string, string>;
31
36
  taskEventWatermarks: Map<string, string>;
32
37
  }
38
+ export declare function buildPersistedSyncWatermarksSnapshot(data: PersistedSyncWatermarks & {
39
+ taxonomyStateFingerprint?: string;
40
+ }): WorkspaceSyncPushBaselineSnapshot;
41
+ export declare function parsePersistedSyncWatermarksSnapshot(snapshot: WorkspaceSyncPushBaselineSnapshot | null | undefined, taxonomyStateFingerprint?: string): PersistedSyncWatermarks | null;
33
42
  export declare function readPersistedSyncWatermarks(workspaceId: string, taxonomyStateFingerprint?: string): PersistedSyncWatermarks | null;
34
43
  export declare function savePersistedSyncWatermarks(workspaceId: string, data: PersistedSyncWatermarks & {
35
44
  taxonomyStateFingerprint?: string;
36
- }): void;
45
+ }): boolean;
@@ -1,4 +1,6 @@
1
1
  import { parseAiProfileSurfaceType } from '../../shared/aiProfileSurfaceType.js';
2
+ import { parseAiProfileSeatScope } from '../../shared/aiProfileSeatScope.js';
3
+ import { normalizeSyncNullableId, normalizeSyncNullableIsoString, normalizeSyncNullableString, normalizeSyncSameOriginAssetUrl, } from '../../sync/syncFieldSemantics.js';
2
4
  export const USER_GLOBAL_SYNC_META_KEY = 'taskforce.userGlobalSyncMeta.v1';
3
5
  export const SYNC_DEBUG_LOG_KEY = 'taskforce.syncDebug.v1';
4
6
  export const WORKSPACE_BOOTSTRAP_TIMEOUT_MS = 120_000;
@@ -36,29 +38,27 @@ export function normalizeWorkspaceSyncAiProfileSnapshotEntry(entry) {
36
38
  username: String(entry?.username || '').trim(),
37
39
  icon: String(entry?.icon || 'Bot').trim() || 'Bot',
38
40
  color: String(entry?.color || '#8b5cf6').trim() || '#8b5cf6',
39
- description: typeof entry?.description === 'string' && entry.description.trim().length > 0
40
- ? entry.description.trim()
41
- : null,
42
- role: typeof entry?.role === 'string' && entry.role.trim().length > 0
43
- ? entry.role.trim()
44
- : null,
45
- provider: typeof entry?.provider === 'string' && entry.provider.trim().length > 0
46
- ? entry.provider.trim()
47
- : null,
48
- model: typeof entry?.model === 'string' && entry.model.trim().length > 0
49
- ? entry.model.trim()
50
- : null,
41
+ avatarUrl: normalizeSyncSameOriginAssetUrl(entry?.avatarUrl ?? entry?.avatar_url),
42
+ avatarSourceUrl: normalizeSyncSameOriginAssetUrl(entry?.avatarSourceUrl ?? entry?.avatar_source_url),
43
+ avatarRevision: Number.isFinite(Number(entry?.avatarRevision ?? entry?.avatar_revision)) ? Math.max(0, Math.floor(Number(entry?.avatarRevision ?? entry?.avatar_revision))) : 0,
44
+ avatarUpdatedAt: normalizeSyncNullableIsoString(entry?.avatarUpdatedAt ?? entry?.avatar_updated_at),
45
+ description: normalizeSyncNullableString(entry?.description),
46
+ role: normalizeSyncNullableString(entry?.role),
47
+ provider: normalizeSyncNullableString(entry?.provider),
48
+ model: normalizeSyncNullableString(entry?.model),
51
49
  surfaceType: parseAiProfileSurfaceType(entry?.surfaceType ?? entry?.surface_type),
50
+ seatScope: parseAiProfileSeatScope(entry?.seatScope ?? entry?.seat_scope),
52
51
  providerMetadata: metadata && typeof metadata === 'object' && !Array.isArray(metadata)
53
52
  ? metadata
54
53
  : null,
54
+ archivedAt: normalizeSyncNullableIsoString(entry?.archivedAt ?? entry?.archived_at),
55
+ archivedBy: normalizeSyncNullableId(entry?.archivedBy ?? entry?.archived_by),
56
+ archivedReason: normalizeSyncNullableString(entry?.archivedReason ?? entry?.archived_reason),
57
+ mergedIntoProfileId: normalizeSyncNullableId(entry?.mergedIntoProfileId ?? entry?.merged_into_profile_id),
58
+ rosterStateUpdatedAt: normalizeSyncNullableIsoString(entry?.rosterStateUpdatedAt ?? entry?.roster_state_updated_at),
55
59
  createdAt: String(entry?.createdAt || entry?.created_at || '').trim(),
56
60
  updatedAt: String(entry?.updatedAt || entry?.updated_at || entry?.createdAt || entry?.created_at || '').trim(),
57
- lastActiveAt: typeof entry?.lastActiveAt === 'string' && entry.lastActiveAt.trim().length > 0
58
- ? entry.lastActiveAt.trim()
59
- : typeof entry?.last_active_at === 'string' && entry.last_active_at.trim().length > 0
60
- ? entry.last_active_at.trim()
61
- : null
61
+ lastActiveAt: normalizeSyncNullableIsoString(entry?.lastActiveAt ?? entry?.last_active_at)
62
62
  };
63
63
  }
64
64
  export function readUserGlobalSyncMeta() {
@@ -115,7 +115,7 @@ export function flattenDocumentReviewComments(sessions) {
115
115
  .filter((comment) => comment.id.length > 0 && comment.sessionId.length > 0);
116
116
  });
117
117
  }
118
- export function flattenTaskEvents(tasks, archivedTasks) {
118
+ export function flattenTaskEvents(tasks, archivedTasks, initiatives = [], workstreams = []) {
119
119
  const deduped = new Map();
120
120
  for (const task of [...(tasks || []), ...(archivedTasks || [])]) {
121
121
  const taskEvents = Array.isArray(task?.taskEvents) ? task.taskEvents : [];
@@ -128,8 +128,66 @@ export function flattenTaskEvents(tasks, archivedTasks) {
128
128
  continue;
129
129
  const nextEvent = {
130
130
  id,
131
+ workspaceId,
132
+ entityType: 'task',
133
+ entityId: taskId,
131
134
  taskId,
135
+ action: String(event?.action || '').trim(),
136
+ actor: String(event?.actor || 'system').trim() || 'system',
137
+ actorType: event?.actorType === 'ai' || event?.actorType === 'human' || event?.actorType === 'system'
138
+ ? event.actorType
139
+ : 'system',
140
+ details: event?.details,
141
+ createdAt,
142
+ };
143
+ const existing = deduped.get(id);
144
+ if (!existing || nextEvent.createdAt > existing.createdAt) {
145
+ deduped.set(id, nextEvent);
146
+ }
147
+ }
148
+ }
149
+ for (const initiative of initiatives || []) {
150
+ const entityEvents = Array.isArray(initiative?.entityEvents) ? initiative.entityEvents : [];
151
+ for (const event of entityEvents) {
152
+ const id = String(event?.id || '').trim();
153
+ const entityId = String(event?.entityId || initiative?.id || '').trim();
154
+ const workspaceId = String(event?.workspaceId || '').trim();
155
+ const createdAt = String(event?.createdAt || '').trim();
156
+ if (!id || !entityId || !workspaceId || !createdAt)
157
+ continue;
158
+ const nextEvent = {
159
+ id,
160
+ workspaceId,
161
+ entityType: 'initiative',
162
+ entityId,
163
+ action: String(event?.action || '').trim(),
164
+ actor: String(event?.actor || 'system').trim() || 'system',
165
+ actorType: event?.actorType === 'ai' || event?.actorType === 'human' || event?.actorType === 'system'
166
+ ? event.actorType
167
+ : 'system',
168
+ details: event?.details,
169
+ createdAt,
170
+ };
171
+ const existing = deduped.get(id);
172
+ if (!existing || nextEvent.createdAt > existing.createdAt) {
173
+ deduped.set(id, nextEvent);
174
+ }
175
+ }
176
+ }
177
+ for (const workstream of workstreams || []) {
178
+ const entityEvents = Array.isArray(workstream?.entityEvents) ? workstream.entityEvents : [];
179
+ for (const event of entityEvents) {
180
+ const id = String(event?.id || '').trim();
181
+ const entityId = String(event?.entityId || workstream?.id || '').trim();
182
+ const workspaceId = String(event?.workspaceId || '').trim();
183
+ const createdAt = String(event?.createdAt || '').trim();
184
+ if (!id || !entityId || !workspaceId || !createdAt)
185
+ continue;
186
+ const nextEvent = {
187
+ id,
132
188
  workspaceId,
189
+ entityType: 'workstream',
190
+ entityId,
133
191
  action: String(event?.action || '').trim(),
134
192
  actor: String(event?.actor || 'system').trim() || 'system',
135
193
  actorType: event?.actorType === 'ai' || event?.actorType === 'human' || event?.actorType === 'system'
@@ -150,6 +208,52 @@ export function flattenTaskEvents(tasks, archivedTasks) {
150
208
  return left.id.localeCompare(right.id);
151
209
  });
152
210
  }
211
+ export function buildPersistedSyncWatermarksSnapshot(data) {
212
+ return {
213
+ taskIds: Array.from(data.taskIds.values()),
214
+ taskWatermarks: Array.from(data.taskWatermarks.entries()),
215
+ taskChangeKeys: Array.from((data.taskChangeKeys || new Map()).entries()),
216
+ initiativeWatermarks: Array.from(data.initiativeWatermarks.entries()),
217
+ workstreamWatermarks: Array.from(data.workstreamWatermarks.entries()),
218
+ aiProfileWatermarks: Array.from(data.aiProfileWatermarks.entries()),
219
+ aiProfileChangeKeys: Array.from((data.aiProfileChangeKeys || new Map()).entries()),
220
+ documentWatermarks: Array.from(data.documentWatermarks.entries()),
221
+ assetWatermarks: Array.from(data.assetWatermarks.entries()),
222
+ documentReviewSessionWatermarks: Array.from(data.documentReviewSessionWatermarks.entries()),
223
+ documentReviewCommentWatermarks: Array.from(data.documentReviewCommentWatermarks.entries()),
224
+ annotatedAttachmentSessionWatermarks: Array.from(data.annotatedAttachmentSessionWatermarks.entries()),
225
+ taskEventWatermarks: Array.from(data.taskEventWatermarks.entries()),
226
+ taxonomyStateFingerprint: typeof data.taxonomyStateFingerprint === 'string' ? data.taxonomyStateFingerprint : ''
227
+ };
228
+ }
229
+ export function parsePersistedSyncWatermarksSnapshot(snapshot, taxonomyStateFingerprint) {
230
+ if (!snapshot || typeof snapshot !== 'object')
231
+ return null;
232
+ const savedTaxonomyStateFingerprint = typeof snapshot.taxonomyStateFingerprint === 'string'
233
+ ? snapshot.taxonomyStateFingerprint
234
+ : '';
235
+ const taskWatermarks = (!taxonomyStateFingerprint || !savedTaxonomyStateFingerprint || savedTaxonomyStateFingerprint === taxonomyStateFingerprint)
236
+ ? new Map(Array.isArray(snapshot.taskWatermarks) ? snapshot.taskWatermarks : [])
237
+ : new Map();
238
+ const taskIds = new Set(Array.isArray(snapshot.taskIds)
239
+ ? snapshot.taskIds.map((entry) => String(entry || '').trim()).filter((entry) => entry.length > 0)
240
+ : Array.from(taskWatermarks.keys()));
241
+ return {
242
+ taskIds,
243
+ taskWatermarks,
244
+ taskChangeKeys: new Map(Array.isArray(snapshot.taskChangeKeys) ? snapshot.taskChangeKeys : []),
245
+ initiativeWatermarks: new Map(Array.isArray(snapshot.initiativeWatermarks) ? snapshot.initiativeWatermarks : []),
246
+ workstreamWatermarks: new Map(Array.isArray(snapshot.workstreamWatermarks) ? snapshot.workstreamWatermarks : []),
247
+ aiProfileWatermarks: new Map(Array.isArray(snapshot.aiProfileWatermarks) ? snapshot.aiProfileWatermarks : []),
248
+ aiProfileChangeKeys: new Map(Array.isArray(snapshot.aiProfileChangeKeys) ? snapshot.aiProfileChangeKeys : []),
249
+ documentWatermarks: new Map(Array.isArray(snapshot.documentWatermarks) ? snapshot.documentWatermarks : []),
250
+ assetWatermarks: new Map(Array.isArray(snapshot.assetWatermarks) ? snapshot.assetWatermarks : []),
251
+ documentReviewSessionWatermarks: new Map(Array.isArray(snapshot.documentReviewSessionWatermarks) ? snapshot.documentReviewSessionWatermarks : []),
252
+ documentReviewCommentWatermarks: new Map(Array.isArray(snapshot.documentReviewCommentWatermarks) ? snapshot.documentReviewCommentWatermarks : []),
253
+ annotatedAttachmentSessionWatermarks: new Map(Array.isArray(snapshot.annotatedAttachmentSessionWatermarks) ? snapshot.annotatedAttachmentSessionWatermarks : []),
254
+ taskEventWatermarks: new Map(Array.isArray(snapshot.taskEventWatermarks) ? snapshot.taskEventWatermarks : []),
255
+ };
256
+ }
153
257
  export function readPersistedSyncWatermarks(workspaceId, taxonomyStateFingerprint) {
154
258
  if (typeof window === 'undefined')
155
259
  return null;
@@ -159,25 +263,9 @@ export function readPersistedSyncWatermarks(workspaceId, taxonomyStateFingerprin
159
263
  if (!raw)
160
264
  return null;
161
265
  const parsed = JSON.parse(raw);
162
- if (!parsed || (parsed.v !== 2 && parsed.v !== 3 && parsed.v !== 4 && parsed.v !== 5 && parsed.v !== 6 && parsed.v !== 7 && parsed.v !== 8))
266
+ if (!parsed || (parsed.v !== 2 && parsed.v !== 3 && parsed.v !== 4 && parsed.v !== 5 && parsed.v !== 6 && parsed.v !== 7 && parsed.v !== 8 && parsed.v !== 9 && parsed.v !== 10 && parsed.v !== 11))
163
267
  return null;
164
- const savedTaxonomyStateFingerprint = typeof parsed.taxonomyStateFingerprint === 'string'
165
- ? parsed.taxonomyStateFingerprint
166
- : '';
167
- const taskWatermarks = (!taxonomyStateFingerprint || !savedTaxonomyStateFingerprint || savedTaxonomyStateFingerprint === taxonomyStateFingerprint)
168
- ? new Map(Array.isArray(parsed.taskWatermarks) ? parsed.taskWatermarks : [])
169
- : new Map();
170
- return {
171
- taskWatermarks,
172
- initiativeWatermarks: new Map(Array.isArray(parsed.initiativeWatermarks) ? parsed.initiativeWatermarks : []),
173
- workstreamWatermarks: new Map(Array.isArray(parsed.workstreamWatermarks) ? parsed.workstreamWatermarks : []),
174
- documentWatermarks: new Map(Array.isArray(parsed.documentWatermarks) ? parsed.documentWatermarks : []),
175
- assetWatermarks: new Map(Array.isArray(parsed.assetWatermarks) ? parsed.assetWatermarks : []),
176
- documentReviewSessionWatermarks: new Map(Array.isArray(parsed.documentReviewSessionWatermarks) ? parsed.documentReviewSessionWatermarks : []),
177
- documentReviewCommentWatermarks: new Map(Array.isArray(parsed.documentReviewCommentWatermarks) ? parsed.documentReviewCommentWatermarks : []),
178
- annotatedAttachmentSessionWatermarks: new Map(Array.isArray(parsed.annotatedAttachmentSessionWatermarks) ? parsed.annotatedAttachmentSessionWatermarks : []),
179
- taskEventWatermarks: new Map(Array.isArray(parsed.taskEventWatermarks) ? parsed.taskEventWatermarks : []),
180
- };
268
+ return parsePersistedSyncWatermarksSnapshot(parsed, taxonomyStateFingerprint);
181
269
  }
182
270
  catch {
183
271
  return null;
@@ -185,25 +273,18 @@ export function readPersistedSyncWatermarks(workspaceId, taxonomyStateFingerprin
185
273
  }
186
274
  export function savePersistedSyncWatermarks(workspaceId, data) {
187
275
  if (typeof window === 'undefined')
188
- return;
276
+ return false;
189
277
  try {
190
278
  const key = `${WORKSPACE_SYNC_WATERMARKS_KEY_PREFIX}.${workspaceId}`;
191
279
  window.localStorage.setItem(key, JSON.stringify({
192
- v: 8,
280
+ v: 11,
193
281
  savedAt: new Date().toISOString(),
194
- taskWatermarks: Array.from(data.taskWatermarks.entries()),
195
- initiativeWatermarks: Array.from(data.initiativeWatermarks.entries()),
196
- workstreamWatermarks: Array.from(data.workstreamWatermarks.entries()),
197
- documentWatermarks: Array.from(data.documentWatermarks.entries()),
198
- assetWatermarks: Array.from(data.assetWatermarks.entries()),
199
- documentReviewSessionWatermarks: Array.from(data.documentReviewSessionWatermarks.entries()),
200
- documentReviewCommentWatermarks: Array.from(data.documentReviewCommentWatermarks.entries()),
201
- annotatedAttachmentSessionWatermarks: Array.from(data.annotatedAttachmentSessionWatermarks.entries()),
202
- taskEventWatermarks: Array.from(data.taskEventWatermarks.entries()),
203
- taxonomyStateFingerprint: typeof data.taxonomyStateFingerprint === 'string' ? data.taxonomyStateFingerprint : ''
282
+ ...buildPersistedSyncWatermarksSnapshot(data)
204
283
  }));
284
+ return true;
205
285
  }
206
286
  catch {
207
287
  // localStorage may be full or unavailable; non-fatal
288
+ return false;
208
289
  }
209
290
  }
@@ -8,11 +8,13 @@ describe('orchestratorShared sync watermarks', () => {
8
8
  it('keeps persisted sync watermarks available across long idle periods', () => {
9
9
  const key = `${WORKSPACE_SYNC_WATERMARKS_KEY_PREFIX}.${workspaceId}`;
10
10
  localStorage.setItem(key, JSON.stringify({
11
- v: 8,
11
+ v: 9,
12
12
  savedAt: '2026-04-14T10:00:00.000Z',
13
+ taskIds: ['task-1'],
13
14
  taskWatermarks: [['task-1', '2026-04-14T09:00:00.000Z']],
14
15
  initiativeWatermarks: [['initiative-1', '2026-04-14T09:00:00.000Z']],
15
16
  workstreamWatermarks: [],
17
+ aiProfileWatermarks: [['ai-profile-1', '2026-04-14T09:15:00.000Z']],
16
18
  documentWatermarks: [],
17
19
  assetWatermarks: [],
18
20
  documentReviewSessionWatermarks: [],
@@ -23,15 +25,40 @@ describe('orchestratorShared sync watermarks', () => {
23
25
  }));
24
26
  const persisted = readPersistedSyncWatermarks(workspaceId, '');
25
27
  expect(persisted).not.toBeNull();
28
+ expect(Array.from(persisted?.taskIds || [])).toEqual(['task-1']);
26
29
  expect(persisted?.taskWatermarks.get('task-1')).toBe('2026-04-14T09:00:00.000Z');
27
30
  expect(persisted?.initiativeWatermarks.get('initiative-1')).toBe('2026-04-14T09:00:00.000Z');
31
+ expect(persisted?.aiProfileWatermarks.get('ai-profile-1')).toBe('2026-04-14T09:15:00.000Z');
28
32
  expect(persisted?.taskEventWatermarks.get('event-1')).toBe('2026-04-14T09:30:00.000Z');
29
33
  });
34
+ it('persists task and ai-profile change keys alongside legacy watermarks', () => {
35
+ savePersistedSyncWatermarks(workspaceId, {
36
+ taskIds: new Set(['task-1']),
37
+ taskWatermarks: new Map([['task-1', '2026-04-14T09:00:00.000Z']]),
38
+ taskChangeKeys: new Map([['task-1', 'task-change-key-1']]),
39
+ initiativeWatermarks: new Map(),
40
+ workstreamWatermarks: new Map(),
41
+ aiProfileWatermarks: new Map([['ai-profile-1', '2026-04-14T09:15:00.000Z']]),
42
+ aiProfileChangeKeys: new Map([['ai-profile-1', 'ai-change-key-1']]),
43
+ documentWatermarks: new Map(),
44
+ assetWatermarks: new Map(),
45
+ documentReviewSessionWatermarks: new Map(),
46
+ documentReviewCommentWatermarks: new Map(),
47
+ annotatedAttachmentSessionWatermarks: new Map(),
48
+ taskEventWatermarks: new Map(),
49
+ taxonomyStateFingerprint: 'fingerprint-a'
50
+ });
51
+ const persisted = readPersistedSyncWatermarks(workspaceId, 'fingerprint-a');
52
+ expect(persisted?.taskChangeKeys?.get('task-1')).toBe('task-change-key-1');
53
+ expect(persisted?.aiProfileChangeKeys?.get('ai-profile-1')).toBe('ai-change-key-1');
54
+ });
30
55
  it('still clears task watermarks when the taxonomy fingerprint changes', () => {
31
56
  savePersistedSyncWatermarks(workspaceId, {
57
+ taskIds: new Set(['task-1']),
32
58
  taskWatermarks: new Map([['task-1', '2026-04-14T09:00:00.000Z']]),
33
59
  initiativeWatermarks: new Map([['initiative-1', '2026-04-14T09:00:00.000Z']]),
34
60
  workstreamWatermarks: new Map(),
61
+ aiProfileWatermarks: new Map([['ai-profile-1', '2026-04-14T09:15:00.000Z']]),
35
62
  documentWatermarks: new Map(),
36
63
  assetWatermarks: new Map(),
37
64
  documentReviewSessionWatermarks: new Map(),
@@ -42,8 +69,30 @@ describe('orchestratorShared sync watermarks', () => {
42
69
  });
43
70
  const persisted = readPersistedSyncWatermarks(workspaceId, 'fingerprint-b');
44
71
  expect(persisted).not.toBeNull();
72
+ expect(Array.from(persisted?.taskIds || [])).toEqual(['task-1']);
45
73
  expect(persisted?.taskWatermarks.size).toBe(0);
46
74
  expect(persisted?.initiativeWatermarks.get('initiative-1')).toBe('2026-04-14T09:00:00.000Z');
75
+ expect(persisted?.aiProfileWatermarks.get('ai-profile-1')).toBe('2026-04-14T09:15:00.000Z');
47
76
  expect(persisted?.taskEventWatermarks.get('event-1')).toBe('2026-04-14T09:30:00.000Z');
48
77
  });
78
+ it('falls back to task watermark keys when older persisted snapshots do not have taskIds', () => {
79
+ const key = `${WORKSPACE_SYNC_WATERMARKS_KEY_PREFIX}.${workspaceId}`;
80
+ localStorage.setItem(key, JSON.stringify({
81
+ v: 9,
82
+ savedAt: '2026-04-14T10:00:00.000Z',
83
+ taskWatermarks: [['task-legacy-1', '2026-04-14T09:00:00.000Z']],
84
+ initiativeWatermarks: [],
85
+ workstreamWatermarks: [],
86
+ aiProfileWatermarks: [],
87
+ documentWatermarks: [],
88
+ assetWatermarks: [],
89
+ documentReviewSessionWatermarks: [],
90
+ documentReviewCommentWatermarks: [],
91
+ annotatedAttachmentSessionWatermarks: [],
92
+ taskEventWatermarks: [],
93
+ taxonomyStateFingerprint: ''
94
+ }));
95
+ const persisted = readPersistedSyncWatermarks(workspaceId, '');
96
+ expect(Array.from(persisted?.taskIds || [])).toEqual(['task-legacy-1']);
97
+ });
49
98
  });
@@ -0,0 +1,31 @@
1
+ import type { WorkspaceSyncPhase } from '../../sync/workspaceSyncState';
2
+ export interface WorkspacePullRequestPlan {
3
+ bootstrap: boolean;
4
+ cursor: string | null;
5
+ successEventType: 'bootstrap' | 'pull';
6
+ }
7
+ interface ResolveWorkspacePullRequestPlanArgs {
8
+ workspaceSyncPhase: WorkspaceSyncPhase;
9
+ forceCursorNull?: boolean;
10
+ currentCursor: string | null;
11
+ }
12
+ interface ResolveWorkspacePullSuccessPlanArgs {
13
+ workspaceSyncPhase: WorkspaceSyncPhase;
14
+ forceCursorNull?: boolean;
15
+ startupFullReconcileRan: boolean;
16
+ pendingSignature: string;
17
+ fallbackSignature: string;
18
+ lastPushedSignature: string;
19
+ }
20
+ export interface WorkspacePullSuccessPlan {
21
+ successEventType: 'bootstrap' | 'pull';
22
+ shouldCaptureAttachBootstrapBaseline: boolean;
23
+ shouldClearPendingSignature: boolean;
24
+ shouldRefreshReferenceSnapshots: boolean;
25
+ shouldSeedWorkspaceSnapshotPushBaseline: boolean;
26
+ shouldScheduleStartupFullReconcile: boolean;
27
+ deferredPushSignature: string | null;
28
+ }
29
+ export declare function resolveWorkspacePullRequestPlan({ workspaceSyncPhase, forceCursorNull, currentCursor }: ResolveWorkspacePullRequestPlanArgs): WorkspacePullRequestPlan;
30
+ export declare function resolveWorkspacePullSuccessPlan({ workspaceSyncPhase, forceCursorNull, startupFullReconcileRan, pendingSignature, fallbackSignature, lastPushedSignature }: ResolveWorkspacePullSuccessPlanArgs): WorkspacePullSuccessPlan;
31
+ export {};
@@ -0,0 +1,24 @@
1
+ export function resolveWorkspacePullRequestPlan({ workspaceSyncPhase, forceCursorNull, currentCursor }) {
2
+ const bootstrap = workspaceSyncPhase === 'attach-cloud';
3
+ return {
4
+ bootstrap,
5
+ cursor: bootstrap || forceCursorNull === true ? null : currentCursor,
6
+ successEventType: bootstrap ? 'bootstrap' : 'pull'
7
+ };
8
+ }
9
+ export function resolveWorkspacePullSuccessPlan({ workspaceSyncPhase, forceCursorNull, startupFullReconcileRan, pendingSignature, fallbackSignature, lastPushedSignature }) {
10
+ const bootstrap = workspaceSyncPhase === 'attach-cloud';
11
+ const nextSignature = pendingSignature || fallbackSignature;
12
+ const deferredPushSignature = (!bootstrap
13
+ && nextSignature
14
+ && nextSignature !== lastPushedSignature) ? nextSignature : null;
15
+ return {
16
+ successEventType: bootstrap ? 'bootstrap' : 'pull',
17
+ shouldCaptureAttachBootstrapBaseline: bootstrap,
18
+ shouldClearPendingSignature: bootstrap || deferredPushSignature !== null,
19
+ shouldRefreshReferenceSnapshots: bootstrap,
20
+ shouldSeedWorkspaceSnapshotPushBaseline: bootstrap,
21
+ shouldScheduleStartupFullReconcile: !forceCursorNull && !bootstrap && !startupFullReconcileRan,
22
+ deferredPushSignature
23
+ };
24
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,80 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { resolveWorkspacePullRequestPlan, resolveWorkspacePullSuccessPlan, } from './pullLifecycle';
3
+ describe('pull lifecycle', () => {
4
+ it('treats attach-cloud pulls as bootstrap pulls with a null cursor', () => {
5
+ expect(resolveWorkspacePullRequestPlan({
6
+ workspaceSyncPhase: 'attach-cloud',
7
+ forceCursorNull: false,
8
+ currentCursor: 'cursor-1'
9
+ })).toEqual({
10
+ bootstrap: true,
11
+ cursor: null,
12
+ successEventType: 'bootstrap'
13
+ });
14
+ });
15
+ it('keeps the saved cursor for normal incremental pulls', () => {
16
+ expect(resolveWorkspacePullRequestPlan({
17
+ workspaceSyncPhase: 'active',
18
+ forceCursorNull: false,
19
+ currentCursor: 'cursor-1'
20
+ })).toEqual({
21
+ bootstrap: false,
22
+ cursor: 'cursor-1',
23
+ successEventType: 'pull'
24
+ });
25
+ });
26
+ it('marks attach-cloud success for reference refresh and baseline seeding without a follow-up push', () => {
27
+ expect(resolveWorkspacePullSuccessPlan({
28
+ workspaceSyncPhase: 'attach-cloud',
29
+ forceCursorNull: false,
30
+ startupFullReconcileRan: false,
31
+ pendingSignature: 'sig-pending',
32
+ fallbackSignature: 'sig-fallback',
33
+ lastPushedSignature: ''
34
+ })).toEqual({
35
+ successEventType: 'bootstrap',
36
+ shouldCaptureAttachBootstrapBaseline: true,
37
+ shouldClearPendingSignature: true,
38
+ shouldRefreshReferenceSnapshots: true,
39
+ shouldSeedWorkspaceSnapshotPushBaseline: true,
40
+ shouldScheduleStartupFullReconcile: false,
41
+ deferredPushSignature: null
42
+ });
43
+ });
44
+ it('schedules a one-time startup full reconcile and deferred push after the first normal pull', () => {
45
+ expect(resolveWorkspacePullSuccessPlan({
46
+ workspaceSyncPhase: 'active',
47
+ forceCursorNull: false,
48
+ startupFullReconcileRan: false,
49
+ pendingSignature: 'sig-pending',
50
+ fallbackSignature: 'sig-fallback',
51
+ lastPushedSignature: 'sig-old'
52
+ })).toEqual({
53
+ successEventType: 'pull',
54
+ shouldCaptureAttachBootstrapBaseline: false,
55
+ shouldClearPendingSignature: true,
56
+ shouldRefreshReferenceSnapshots: false,
57
+ shouldSeedWorkspaceSnapshotPushBaseline: false,
58
+ shouldScheduleStartupFullReconcile: true,
59
+ deferredPushSignature: 'sig-pending'
60
+ });
61
+ });
62
+ it('does not schedule a second startup full reconcile or redundant deferred push', () => {
63
+ expect(resolveWorkspacePullSuccessPlan({
64
+ workspaceSyncPhase: 'active',
65
+ forceCursorNull: true,
66
+ startupFullReconcileRan: true,
67
+ pendingSignature: '',
68
+ fallbackSignature: 'sig-current',
69
+ lastPushedSignature: 'sig-current'
70
+ })).toEqual({
71
+ successEventType: 'pull',
72
+ shouldCaptureAttachBootstrapBaseline: false,
73
+ shouldClearPendingSignature: false,
74
+ shouldRefreshReferenceSnapshots: false,
75
+ shouldSeedWorkspaceSnapshotPushBaseline: false,
76
+ shouldScheduleStartupFullReconcile: false,
77
+ deferredPushSignature: null
78
+ });
79
+ });
80
+ });