@taskforcehq/taskforce 0.3.304 → 0.3.306

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 (383) hide show
  1. package/README.md +140 -247
  2. package/dist/Taskforce.module.css +295 -89
  3. package/dist/TaskforceCore.js +378 -111
  4. package/dist/TaskforceCore.test.js +1221 -107
  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 +52 -2
  14. package/dist/compat/workspaceSyncCompat.test.js +38 -1
  15. package/dist/components/context/ContextAttachmentManager.d.ts +14 -0
  16. package/dist/components/context/ContextAttachmentManager.js +549 -0
  17. package/dist/components/features/AgentsModule.d.ts +10 -1
  18. package/dist/components/features/AgentsModule.js +260 -15
  19. package/dist/components/features/AgentsModule.test.js +255 -5
  20. package/dist/components/features/DocumentIndex.d.ts +1 -1
  21. package/dist/components/features/DocumentIndex.js +1 -1
  22. package/dist/components/features/DocumentViewer.d.ts +6 -2
  23. package/dist/components/features/DocumentViewer.js +90 -10
  24. package/dist/components/features/DocumentWorkspace.d.ts +5 -22
  25. package/dist/components/features/DocumentWorkspace.js +12 -155
  26. package/dist/components/features/DocumentWorkspace.test.js +226 -6
  27. package/dist/components/features/TaskSettings.js +29 -3
  28. package/dist/components/features/TaskSettings.test.js +42 -1
  29. package/dist/components/features/documentWorkspaceModel.d.ts +24 -0
  30. package/dist/components/features/documentWorkspaceModel.js +57 -0
  31. package/dist/components/features/useDocumentWorkspaceController.d.ts +34 -0
  32. package/dist/components/features/useDocumentWorkspaceController.js +113 -0
  33. package/dist/components/task/TaskCard.js +19 -28
  34. package/dist/components/task/TaskCard.test.js +38 -3
  35. package/dist/components/task/TaskContextUpload.js +4 -526
  36. package/dist/components/task/TaskForm.d.ts +8 -8
  37. package/dist/components/task/TaskForm.js +362 -230
  38. package/dist/components/task/TaskForm.test.js +558 -381
  39. package/dist/components/task/TaskKanban.d.ts +2 -1
  40. package/dist/components/task/TaskKanban.js +96 -14
  41. package/dist/components/task/TaskKanban.test.js +36 -0
  42. package/dist/components/ui/EditableAvatarButton.d.ts +18 -0
  43. package/dist/components/ui/EditableAvatarButton.js +18 -0
  44. package/dist/components/views/PlanComparisonPage.d.ts +9 -1
  45. package/dist/components/views/PlanComparisonPage.js +70 -17
  46. package/dist/components/views/PlanComparisonPage.test.js +289 -41
  47. package/dist/components/views/PlansPage.js +239 -106
  48. package/dist/components/views/PlansPage.test.js +593 -42
  49. package/dist/components/views/StandaloneLayout.js +310 -554
  50. package/dist/components/views/panels/FilterToolbar.test.js +6 -4
  51. package/dist/components/views/panels/PlanningDrawer.d.ts +8 -1
  52. package/dist/components/views/panels/PlanningDrawer.js +18 -11
  53. package/dist/components/views/panels/PlanningDrawer.test.d.ts +1 -0
  54. package/dist/components/views/panels/PlanningDrawer.test.js +141 -0
  55. package/dist/components/views/planningScope.d.ts +20 -0
  56. package/dist/components/views/planningScope.js +25 -0
  57. package/dist/components/views/planningScope.test.d.ts +1 -0
  58. package/dist/components/views/planningScope.test.js +60 -0
  59. package/dist/components/views/standalone/modals/AccountHubModal.d.ts +27 -14
  60. package/dist/components/views/standalone/modals/AccountHubModal.js +87 -15
  61. package/dist/components/views/standalone/modals/AccountHubModal.test.js +42 -2
  62. package/dist/components/views/standalone/modals/AvatarImageManagerModal.d.ts +20 -0
  63. package/dist/components/views/standalone/modals/AvatarImageManagerModal.js +127 -0
  64. package/dist/components/views/standalone/modals/EditProfileModal.d.ts +2 -9
  65. package/dist/components/views/standalone/modals/EditProfileModal.js +3 -2
  66. package/dist/components/views/standalone/modals/SyncEnableWarningModal.d.ts +9 -0
  67. package/dist/components/views/standalone/modals/SyncEnableWarningModal.js +6 -0
  68. package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.d.ts +1 -0
  69. package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.js +24 -0
  70. package/dist/components/views/standalone/modals/SyncStatusModal.d.ts +2 -1
  71. package/dist/components/views/standalone/modals/SyncStatusModal.js +2 -2
  72. package/dist/config/envSchema.js +1 -1
  73. package/dist/core/AiProfileService.d.ts +45 -3
  74. package/dist/core/AiProfileService.js +774 -63
  75. package/dist/core/AiProfileService.test.js +22 -2
  76. package/dist/core/AiProfiles.test.js +761 -2
  77. package/dist/core/AttachmentLinkService.js +57 -15
  78. package/dist/core/AuthIdentityService.d.ts +107 -0
  79. package/dist/core/AuthIdentityService.js +284 -0
  80. package/dist/core/AuthTokenService.d.ts +4 -0
  81. package/dist/core/AuthTokenService.js +34 -6
  82. package/dist/core/AuthTokenService.test.d.ts +1 -0
  83. package/dist/core/AuthTokenService.test.js +78 -0
  84. package/dist/core/EntitlementsPolicy.test.js +77 -15
  85. package/dist/core/GlobalSettingsService.js +115 -6
  86. package/dist/core/PlanEntitlementService.d.ts +30 -3
  87. package/dist/core/PlanEntitlementService.js +454 -93
  88. package/dist/core/PlanFeatureCatalog.test.d.ts +1 -0
  89. package/dist/core/PlanFeatureCatalog.test.js +84 -0
  90. package/dist/core/PlanVersionPolicy.test.js +54 -28
  91. package/dist/core/PlanningEntities.test.js +52 -0
  92. package/dist/core/SignupMonetizationSettings.test.js +241 -44
  93. package/dist/core/SyncReconciliationService.js +2 -65
  94. package/dist/core/SystemAdmin.test.js +244 -88
  95. package/dist/core/TaskAttachmentsCanonical.test.js +51 -1
  96. package/dist/core/TaskTaxonomyValidation.test.js +53 -0
  97. package/dist/core/Taskforce.d.ts +228 -14
  98. package/dist/core/Taskforce.js +814 -201
  99. package/dist/core/Taskforce.listTasksSlim.test.d.ts +1 -0
  100. package/dist/core/Taskforce.listTasksSlim.test.js +91 -0
  101. package/dist/core/UserProfileAvatarDrafts.test.js +30 -3
  102. package/dist/core/WorkspaceLifecycleService.js +0 -5
  103. package/dist/core/WorkspacePermissions.test.js +25 -1
  104. package/dist/core/WorkspacePlanMode.test.js +128 -27
  105. package/dist/core/shared.d.ts +3 -1
  106. package/dist/core/shared.js +16 -1
  107. package/dist/core/types.d.ts +68 -2
  108. package/dist/hooks/auth/useTaskforceAuthBootstrap.js +26 -1
  109. package/dist/hooks/sync/auth.js +3 -1
  110. package/dist/hooks/sync/bootstrap.js +2 -0
  111. package/dist/hooks/sync/controlPlane.d.ts +37 -0
  112. package/dist/hooks/sync/controlPlane.js +78 -0
  113. package/dist/hooks/sync/controlPlane.test.d.ts +1 -0
  114. package/dist/hooks/sync/controlPlane.test.js +121 -0
  115. package/dist/hooks/sync/lifecyclePolicy.d.ts +45 -0
  116. package/dist/hooks/sync/lifecyclePolicy.js +93 -0
  117. package/dist/hooks/sync/lifecyclePolicy.test.d.ts +1 -0
  118. package/dist/hooks/sync/lifecyclePolicy.test.js +124 -0
  119. package/dist/hooks/sync/orchestratorShared.d.ts +10 -1
  120. package/dist/hooks/sync/orchestratorShared.js +68 -47
  121. package/dist/hooks/sync/orchestratorShared.test.js +50 -1
  122. package/dist/hooks/sync/pullLifecycle.d.ts +31 -0
  123. package/dist/hooks/sync/pullLifecycle.js +24 -0
  124. package/dist/hooks/sync/pullLifecycle.test.d.ts +1 -0
  125. package/dist/hooks/sync/pullLifecycle.test.js +80 -0
  126. package/dist/hooks/sync/recovery.d.ts +16 -2
  127. package/dist/hooks/sync/recovery.js +171 -53
  128. package/dist/hooks/sync/recovery.test.d.ts +1 -0
  129. package/dist/hooks/sync/recovery.test.js +292 -0
  130. package/dist/hooks/sync/transfers.d.ts +16 -3
  131. package/dist/hooks/sync/transfers.js +186 -65
  132. package/dist/hooks/sync/transfers.test.d.ts +1 -0
  133. package/dist/hooks/sync/transfers.test.js +396 -0
  134. package/dist/hooks/sync/useRecentSyncEvents.d.ts +21 -0
  135. package/dist/hooks/sync/useRecentSyncEvents.js +92 -0
  136. package/dist/hooks/sync/useRecentSyncEvents.test.d.ts +1 -0
  137. package/dist/hooks/sync/useRecentSyncEvents.test.js +124 -0
  138. package/dist/hooks/sync/useSyncStatusActions.d.ts +30 -0
  139. package/dist/hooks/sync/useSyncStatusActions.js +88 -0
  140. package/dist/hooks/sync/useSyncStatusActions.test.d.ts +1 -0
  141. package/dist/hooks/sync/useSyncStatusActions.test.js +133 -0
  142. package/dist/hooks/sync/useSyncStatusControls.d.ts +25 -0
  143. package/dist/hooks/sync/useSyncStatusControls.js +60 -0
  144. package/dist/hooks/sync/useSyncStatusControls.test.d.ts +1 -0
  145. package/dist/hooks/sync/useSyncStatusControls.test.js +88 -0
  146. package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +12 -0
  147. package/dist/hooks/useSyncOrchestrator.d.ts +16 -6
  148. package/dist/hooks/useSyncOrchestrator.js +424 -175
  149. package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +487 -10
  150. package/dist/hooks/useTaskData.js +8 -3
  151. package/dist/hooks/useTaskData.test.js +45 -0
  152. package/dist/hooks/useTaskMutations.d.ts +2 -1
  153. package/dist/hooks/useTaskMutations.js +12 -1
  154. package/dist/hooks/useTaskMutations.test.js +30 -1
  155. package/dist/hooks/useTaskforce.d.ts +65 -4
  156. package/dist/hooks/useTaskforce.js +564 -243
  157. package/dist/hooks/useTaskforce.runtime-routing.test.d.ts +1 -0
  158. package/dist/hooks/useTaskforce.runtime-routing.test.js +152 -0
  159. package/dist/hooks/useTaskforce.sync-behavior.test.js +2454 -208
  160. package/dist/hooks/useWorkspaceSyncController.d.ts +4 -1
  161. package/dist/hooks/useWorkspaceSyncController.js +17 -2
  162. package/dist/hooks/useWorkspaceSyncController.test.js +1 -0
  163. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.d.ts +16 -0
  164. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +316 -35
  165. package/dist/localization/locales/en-US.d.ts +0 -1
  166. package/dist/localization/locales/en-US.js +0 -1
  167. package/dist/localization/locales/es-419.js +0 -1
  168. package/dist/localization/locales/pt-BR.js +0 -1
  169. package/dist/mcp/adminWorkspaceRegistrar.d.ts +2 -0
  170. package/dist/mcp/adminWorkspaceRegistrar.js +154 -0
  171. package/dist/mcp/collaborationRegistrar.d.ts +2 -0
  172. package/dist/mcp/collaborationRegistrar.js +71 -0
  173. package/dist/mcp/documentAssetRegistrar.d.ts +2 -0
  174. package/dist/mcp/documentAssetRegistrar.js +346 -0
  175. package/dist/mcp/runtime.d.ts +2 -0
  176. package/dist/mcp/runtime.js +2433 -3534
  177. package/dist/mcp/runtime.test.js +440 -2
  178. package/dist/mcp/taskPlanningRegistrar.d.ts +2 -0
  179. package/dist/mcp/taskPlanningRegistrar.js +418 -0
  180. package/dist/mcp/toolCatalog.d.ts +35 -0
  181. package/dist/mcp/toolCatalog.js +3 -0
  182. package/dist/migrations/taskSchemaMigrations.d.ts +1 -1
  183. package/dist/migrations/taskSchemaMigrations.js +171 -61
  184. package/dist/migrations/taskSchemaMigrations.test.js +15 -0
  185. package/dist/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
  186. package/dist/resources/templates/workflows/collaborate.yaml +1 -1
  187. package/dist/resources/templates/workflows/evaluate.yaml +2 -2
  188. package/dist/resources/templates/workflows/plan.yaml +1 -1
  189. package/dist/resources/templates/workflows/review.yaml +2 -2
  190. package/dist/server/annotatedAttachmentsRoutes.test.js +3 -3
  191. package/dist/server/auth/providers/apple.d.ts +33 -0
  192. package/dist/server/auth/providers/apple.js +82 -0
  193. package/dist/server/auth/providers/appleClientSecret.d.ts +37 -0
  194. package/dist/server/auth/providers/appleClientSecret.js +65 -0
  195. package/dist/server/auth/providers/github.d.ts +26 -0
  196. package/dist/server/auth/providers/github.js +86 -0
  197. package/dist/server/auth/providers/google.d.ts +21 -0
  198. package/dist/server/auth/providers/google.js +56 -0
  199. package/dist/server/auth/providers/types.d.ts +21 -0
  200. package/dist/server/auth/providers/types.js +1 -0
  201. package/dist/server/auth.d.ts +2 -0
  202. package/dist/server/auth.js +6 -3
  203. package/dist/server/documentReviewRoutes.test.js +36 -3
  204. package/dist/server/index.cookieProxy.test.js +1 -0
  205. package/dist/server/index.d.ts +12 -0
  206. package/dist/server/index.js +120 -9
  207. package/dist/server/index.rateLimit.test.js +3 -0
  208. package/dist/server/index.test.js +106 -3
  209. package/dist/server/routes/admin.d.ts +4 -5
  210. package/dist/server/routes/admin.js +410 -80
  211. package/dist/server/routes/annotatedAttachments.d.ts +1 -1
  212. package/dist/server/routes/annotatedAttachments.js +1 -1
  213. package/dist/server/routes/auth.d.ts +16 -6
  214. package/dist/server/routes/auth.js +1015 -118
  215. package/dist/server/routes/authSupport.d.ts +30 -0
  216. package/dist/server/routes/authSupport.js +81 -0
  217. package/dist/server/routes/billing.d.ts +1 -1
  218. package/dist/server/routes/billing.js +276 -34
  219. package/dist/server/routes/billing.test.js +760 -52
  220. package/dist/server/routes/documentReviews.d.ts +1 -1
  221. package/dist/server/routes/documentReviews.js +1 -1
  222. package/dist/server/routes/documents.d.ts +5 -2
  223. package/dist/server/routes/documents.js +242 -74
  224. package/dist/server/routes/primitives.d.ts +11 -0
  225. package/dist/server/routes/primitives.js +73 -0
  226. package/dist/server/routes/resources.d.ts +1 -1
  227. package/dist/server/routes/resources.js +1 -1
  228. package/dist/server/routes/shared.d.ts +29 -3
  229. package/dist/server/routes/shared.js +69 -4
  230. package/dist/server/routes/sync.d.ts +1 -1
  231. package/dist/server/routes/sync.integration.test.js +437 -39
  232. package/dist/server/routes/sync.js +62 -606
  233. package/dist/server/routes/syncAuxRoutes.d.ts +15 -0
  234. package/dist/server/routes/syncAuxRoutes.js +91 -0
  235. package/dist/server/routes/syncAuxRoutes.test.d.ts +1 -0
  236. package/dist/server/routes/syncAuxRoutes.test.js +158 -0
  237. package/dist/server/routes/syncPullApplyRoutes.d.ts +36 -0
  238. package/dist/server/routes/syncPullApplyRoutes.js +204 -0
  239. package/dist/server/routes/syncPushRoutes.d.ts +24 -0
  240. package/dist/server/routes/syncPushRoutes.js +212 -0
  241. package/dist/server/routes/syncRouteGuards.d.ts +36 -0
  242. package/dist/server/routes/syncRouteGuards.js +67 -0
  243. package/dist/server/routes/syncRouteGuards.test.d.ts +1 -0
  244. package/dist/server/routes/syncRouteGuards.test.js +94 -0
  245. package/dist/server/routes/syncRouteTypes.d.ts +13 -0
  246. package/dist/server/routes/syncRouteTypes.js +1 -0
  247. package/dist/server/routes/syncSnapshotRoutes.d.ts +66 -0
  248. package/dist/server/routes/syncSnapshotRoutes.js +180 -0
  249. package/dist/server/routes/tasks.d.ts +1 -1
  250. package/dist/server/routes/tasks.js +44 -2
  251. package/dist/server/routes/workspaces.d.ts +1 -1
  252. package/dist/server/routes/workspaces.js +37 -6
  253. package/dist/server/routes.d.ts +2 -9
  254. package/dist/server/routes.js +136 -165
  255. package/dist/server/routes.test.js +2457 -162
  256. package/dist/services/workflowExportSnapshots.test.js +2 -0
  257. package/dist/shared/aiProfileSeatScope.d.ts +5 -0
  258. package/dist/shared/aiProfileSeatScope.js +21 -0
  259. package/dist/shared/passwordPolicy.d.ts +13 -0
  260. package/dist/shared/passwordPolicy.js +84 -0
  261. package/dist/shared/passwordPolicy.test.d.ts +1 -0
  262. package/dist/shared/passwordPolicy.test.js +34 -0
  263. package/dist/storage/workspaceAssetStore.d.ts +15 -3
  264. package/dist/storage/workspaceAssetStore.js +132 -44
  265. package/dist/storage/workspaceAssetStore.test.js +93 -6
  266. package/dist/styles/fonts.css +70 -0
  267. package/dist/sync/collaborationSyncPayload.d.ts +6 -1
  268. package/dist/sync/collaborationSyncPayload.js +17 -11
  269. package/dist/sync/collaborationSyncPayload.test.js +13 -1
  270. package/dist/sync/contentSyncState.d.ts +4 -8
  271. package/dist/sync/contentSyncState.js +33 -77
  272. package/dist/sync/syncApplyHandlers.d.ts +7 -0
  273. package/dist/sync/syncApplyHandlers.js +28 -13
  274. package/dist/sync/syncApplyHandlers.test.js +72 -3
  275. package/dist/sync/syncFieldSemantics.d.ts +12 -0
  276. package/dist/sync/syncFieldSemantics.js +55 -0
  277. package/dist/sync/syncResourceAdapters.d.ts +44 -0
  278. package/dist/sync/syncResourceAdapters.js +77 -0
  279. package/dist/sync/syncService.d.ts +6 -0
  280. package/dist/sync/syncService.js +60 -0
  281. package/dist/sync/syncService.test.js +71 -3
  282. package/dist/sync/taskSyncChangeKey.d.ts +2 -0
  283. package/dist/sync/taskSyncChangeKey.js +143 -0
  284. package/dist/sync/taskSyncPayload.js +3 -8
  285. package/dist/sync/workspacePullFeed.js +4 -3
  286. package/dist/sync/workspacePullFeed.test.js +43 -0
  287. package/dist/sync/workspaceRepair.js +5 -2
  288. package/dist/sync/workspaceSyncModel.d.ts +48 -0
  289. package/dist/sync/workspaceSyncModel.js +195 -31
  290. package/dist/sync/workspaceSyncModel.test.js +325 -12
  291. package/dist/sync/workspaceSyncState.d.ts +19 -0
  292. package/dist/sync/workspaceSyncState.js +3 -1
  293. package/dist/sync/workspaceSyncSurface.js +3 -8
  294. package/dist/types.d.ts +17 -0
  295. package/dist/ui/assets/AgentsModule-DrLawwNl.js +1 -0
  296. package/dist/ui/assets/{AnnotatedAttachmentWorkspace-BlS-cqnl.js → AnnotatedAttachmentWorkspace-Z9_whf7F.js} +1 -1
  297. package/dist/ui/assets/CourierPrime-Bold-BuLj_dpw.woff2 +0 -0
  298. package/dist/ui/assets/CourierPrime-BoldItalic-BrK2pUkZ.woff2 +0 -0
  299. package/dist/ui/assets/CourierPrime-Italic-DFUZK5Ey.woff2 +0 -0
  300. package/dist/ui/assets/CourierPrime-Regular-BsKphzVf.woff2 +0 -0
  301. package/dist/ui/assets/DocumentWorkspace-B03MaSkw.js +252 -0
  302. package/dist/ui/assets/DocumentWorkspace-Dhdso07p.css +1 -0
  303. package/dist/ui/assets/{InitiativesModule-BjR6iBf9.js → InitiativesModule-9E6ParrY.js} +1 -1
  304. package/dist/ui/assets/Noir_medium-bxQwKGzB.woff2 +0 -0
  305. package/dist/ui/assets/Noir_regular-ojf2kxlG.woff2 +0 -0
  306. package/dist/ui/assets/PlansPage-CvfnMiWq.css +1 -0
  307. package/dist/ui/assets/PlansPage-DRXscYxH.js +1 -0
  308. package/dist/ui/assets/RussoOne-Regular-Cu_qq_qC.woff2 +0 -0
  309. package/dist/ui/assets/SpecialElite-Regular-Di6gSvAS.woff2 +0 -0
  310. package/dist/ui/assets/TaskSettings-DZX4jk7e.js +9 -0
  311. package/dist/ui/assets/{WorkflowsModule-DnFqdUME.js → WorkflowsModule-BA7jcEpH.js} +1 -1
  312. package/dist/ui/assets/index-9eT8e0Lu.css +1 -0
  313. package/dist/ui/assets/index-C6k75jr8.js +6 -0
  314. package/dist/ui/assets/{vendor-icons-I7ZwG1z_.js → vendor-icons-DuEd_65c.js} +1 -1
  315. package/dist/ui/fonts/CourierPrime-Bold.ttf +0 -0
  316. package/dist/ui/fonts/CourierPrime-Bold.woff2 +0 -0
  317. package/dist/ui/fonts/CourierPrime-BoldItalic.ttf +0 -0
  318. package/dist/ui/fonts/CourierPrime-BoldItalic.woff2 +0 -0
  319. package/dist/ui/fonts/CourierPrime-Italic.ttf +0 -0
  320. package/dist/ui/fonts/CourierPrime-Italic.woff2 +0 -0
  321. package/dist/ui/fonts/CourierPrime-Regular.ttf +0 -0
  322. package/dist/ui/fonts/CourierPrime-Regular.woff2 +0 -0
  323. package/dist/ui/fonts/Noir_medium.otf +0 -0
  324. package/dist/ui/fonts/Noir_medium.woff2 +0 -0
  325. package/dist/ui/fonts/Noir_regular.otf +0 -0
  326. package/dist/ui/fonts/Noir_regular.woff2 +0 -0
  327. package/dist/ui/fonts/RussoOne-Regular.woff2 +0 -0
  328. package/dist/ui/fonts/SpecialElite-Regular.ttf +0 -0
  329. package/dist/ui/fonts/SpecialElite-Regular.woff2 +0 -0
  330. package/dist/ui/index.html +3 -3
  331. package/dist/utils/accountProfileSummaryCache.d.ts +5 -0
  332. package/dist/utils/assignees.d.ts +2 -0
  333. package/dist/utils/assignees.js +2 -0
  334. package/dist/utils/avatarUpload.d.ts +27 -0
  335. package/dist/utils/avatarUpload.js +132 -0
  336. package/dist/utils/avatarUpload.test.d.ts +1 -0
  337. package/dist/utils/avatarUpload.test.js +40 -0
  338. package/dist/utils/bootstrapTrace.d.ts +7 -0
  339. package/dist/utils/bootstrapTrace.js +29 -0
  340. package/dist/utils/commercialLifecyclePresentation.d.ts +19 -0
  341. package/dist/utils/commercialLifecyclePresentation.js +199 -0
  342. package/dist/utils/contextAssetEvents.d.ts +2 -0
  343. package/dist/utils/syncEventDetails.d.ts +3 -0
  344. package/dist/utils/syncEventDetails.js +64 -0
  345. package/dist/utils/syncEventDetails.test.d.ts +1 -0
  346. package/dist/utils/syncEventDetails.test.js +23 -0
  347. package/dist/utils/syncEventPresentation.d.ts +15 -0
  348. package/dist/utils/syncEventPresentation.js +129 -0
  349. package/dist/utils/syncEventPresentation.test.d.ts +1 -0
  350. package/dist/utils/syncEventPresentation.test.js +64 -0
  351. package/dist/utils/syncStatusPresentation.d.ts +72 -0
  352. package/dist/utils/syncStatusPresentation.js +217 -0
  353. package/dist/utils/syncStatusPresentation.test.d.ts +1 -0
  354. package/dist/utils/syncStatusPresentation.test.js +164 -0
  355. package/dist/utils/taskActivity.d.ts +2 -0
  356. package/dist/utils/taskActivity.js +228 -22
  357. package/dist/utils/taskActivity.test.js +119 -8
  358. package/dist/utils/workspaceSyncPresentation.d.ts +4 -0
  359. package/dist/utils/workspaceSyncPresentation.js +68 -2
  360. package/dist/utils/workspaceSyncPresentation.test.js +36 -1
  361. package/package.json +10 -2
  362. package/scripts/check-cloud-mcp.mjs +83 -0
  363. package/scripts/export-sqlite-to-postgres.mjs +7 -9
  364. package/scripts/playwright-auth.sh +5 -1
  365. package/scripts/run-billing-performance-smoke.sh +24 -0
  366. package/scripts/run-e2e-realtime.sh +17 -3
  367. package/scripts/run-smoke.sh +17 -5
  368. package/scripts/run-soak.sh +17 -5
  369. package/src/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
  370. package/src/resources/templates/workflows/collaborate.yaml +1 -1
  371. package/src/resources/templates/workflows/evaluate.yaml +2 -2
  372. package/src/resources/templates/workflows/plan.yaml +1 -1
  373. package/src/resources/templates/workflows/review.yaml +2 -2
  374. package/dist/ui/assets/AgentsModule-BLWVbuKP.js +0 -1
  375. package/dist/ui/assets/DocumentWorkspace-BH_6DF6x.js +0 -250
  376. package/dist/ui/assets/DocumentWorkspace-C_8T8oz-.css +0 -1
  377. package/dist/ui/assets/PlansPage-C2dd2n1X.css +0 -1
  378. package/dist/ui/assets/PlansPage-CSDQ4sLa.js +0 -1
  379. package/dist/ui/assets/RussoOne-Regular-C3BxZIj7.ttf +0 -0
  380. package/dist/ui/assets/TaskSettings-CEDy34Jo.js +0 -9
  381. package/dist/ui/assets/index-DXUdtH1B.js +0 -6
  382. package/dist/ui/assets/index-Ii0B0rTO.css +0 -1
  383. package/scripts/migrate-planning-model.ts +0 -233
@@ -1,6 +1,10 @@
1
1
  import { useCallback, useEffect } from 'react';
2
2
  import { createDefaultAssigneeOptions } from '../../utils/assignees';
3
+ import { logBootstrapDebug } from '../workspace/workspaceLocalState';
3
4
  import { persistLocalMutationActorUserId, readLocalMutationActorUserId } from '../../utils/taskforceApiClient';
5
+ function getBootstrapTimestamp() {
6
+ return typeof performance !== 'undefined' ? performance.now() : Date.now();
7
+ }
4
8
  export function useTaskforceAuthBootstrap({ runtimeConfigReady, shouldProbeCloudAuth, authSessionResolved, resolveCloudAuthUrl, authOnlyCloudMode, authRequiredError, runtimeMode, workspaceSelectionScope, markBootstrapPhase, markBootstrapStalled, setRuntimeMode, setAuthRequiredForApi, setIsAuthenticated, setAuthUserId, setAuthWorkspaceId, setAuthUserEmail, setAuthUserDisplayName, setAuthUserAvatarUrl, setUserGlobalSyncStatus, setUserGlobalSyncError, setHasBetaAccess, setAvailableWorkspaces, setHydratedWorkspaceRole, setAssigneeOptions, setAuthBlocked, setAuthSessionResolved, setError, applyResolvedWorkspaceId, readPersistedWorkspaceId, authSessionRequestRef, authSessionEpochRef, authSessionLastCheckedAtRef, authSessionLastResultRef, isLoopbackHost, setAuthStateReadyRefs }) {
5
9
  const checkAuthSession = useCallback(async (options) => {
6
10
  const force = options?.force === true;
@@ -41,11 +45,20 @@ export function useTaskforceAuthBootstrap({ runtimeConfigReady, shouldProbeCloud
41
45
  const requestEpoch = ++authSessionEpochRef.current;
42
46
  let request = null;
43
47
  request = (async () => {
48
+ const startedAt = getBootstrapTimestamp();
44
49
  const abortController = new AbortController();
45
50
  const timeoutId = typeof window !== 'undefined'
46
51
  ? window.setTimeout(() => abortController.abort(), 8000)
47
52
  : null;
48
53
  const isStaleRequest = () => authSessionEpochRef.current !== requestEpoch;
54
+ const logResult = (event, details) => {
55
+ logBootstrapDebug(event, {
56
+ durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt)),
57
+ force,
58
+ sessionUrl,
59
+ ...details
60
+ });
61
+ };
49
62
  try {
50
63
  const res = await fetch(sessionUrl, {
51
64
  method: 'GET',
@@ -59,6 +72,7 @@ export function useTaskforceAuthBootstrap({ runtimeConfigReady, shouldProbeCloud
59
72
  if (res.status === 429) {
60
73
  setAuthSessionResolved(true);
61
74
  setAuthStateReadyRefs(authSessionLastResultRef.current, true, false);
75
+ logResult('auth_session_rate_limited', { status: res.status });
62
76
  return authSessionLastResultRef.current;
63
77
  }
64
78
  if (!res.ok) {
@@ -70,6 +84,7 @@ export function useTaskforceAuthBootstrap({ runtimeConfigReady, shouldProbeCloud
70
84
  setAuthSessionResolved(true);
71
85
  setAuthStateReadyRefs(false, true, false);
72
86
  authSessionLastResultRef.current = false;
87
+ logResult('auth_session_request_failed', { status: res.status });
73
88
  return false;
74
89
  }
75
90
  const data = await res.json();
@@ -117,9 +132,16 @@ export function useTaskforceAuthBootstrap({ runtimeConfigReady, shouldProbeCloud
117
132
  authSessionLastResultRef.current = authenticated;
118
133
  if (authenticated)
119
134
  markBootstrapPhase('ready');
135
+ logResult('auth_session_resolved', {
136
+ status: res.status,
137
+ authenticated,
138
+ workspaceId: authenticated ? workspaceId : '',
139
+ userId: authenticated ? userId : 'anonymous',
140
+ authRequiredForApi: nextAuthRequiredForApi
141
+ });
120
142
  return authenticated;
121
143
  }
122
- catch {
144
+ catch (error) {
123
145
  if (isStaleRequest()) {
124
146
  return authSessionLastResultRef.current;
125
147
  }
@@ -129,6 +151,9 @@ export function useTaskforceAuthBootstrap({ runtimeConfigReady, shouldProbeCloud
129
151
  setAuthStateReadyRefs(false, true, false);
130
152
  authSessionLastResultRef.current = false;
131
153
  markBootstrapStalled('Unable to verify your session.');
154
+ logResult('auth_session_exception', {
155
+ error: error instanceof Error ? error.message : String(error)
156
+ });
132
157
  return authSessionLastResultRef.current;
133
158
  }
134
159
  finally {
@@ -49,7 +49,9 @@ export function createSyncAuthCoordinator({ currentWorkspaceId, workspaceSyncPha
49
49
  if (ensured.transient || isTransientWorkspaceSyncStatus(ensured.statusCode)) {
50
50
  scheduleWorkspaceSyncRetry(ensured.retryAfterMs);
51
51
  }
52
- else if (workspaceSyncPhase === 'active') {
52
+ else if (workspaceSyncPhase === 'active'
53
+ || workspaceSyncPhase === 'attach-cloud'
54
+ || workspaceSyncPhase === 'provision-local') {
53
55
  persistWorkspaceSyncPatchSafely({ phase: 'error', lastErrorMessage: message });
54
56
  }
55
57
  return false;
@@ -45,6 +45,8 @@ export function resolveRepairPhase(args) {
45
45
  return 'provision-local';
46
46
  if (workspaceSyncPhase === 'attach-cloud')
47
47
  return 'attach-cloud';
48
+ if (workspaceSyncPhase === 'active' || lastBootstrapPhase === 'active')
49
+ return 'active';
48
50
  if (lastBootstrapPhase === 'provision-local' || lastBootstrapPhase === 'attach-cloud') {
49
51
  return lastBootstrapPhase;
50
52
  }
@@ -0,0 +1,37 @@
1
+ import type { WorkspaceSyncPhase } from '../../sync/workspaceSyncState';
2
+ export type WorkspaceSyncBlockedReason = 'cloud-auth-unconfigured' | 'runtime-not-local' | 'sync-disabled' | 'invalid-workspace' | 'repair-active' | 'attach-cloud' | 'provision-local' | 'auth-required' | 'push-in-flight' | 'pull-in-flight' | 'retry-pending' | 'lease-held';
3
+ export type WorkspaceSyncOperation = 'pull' | 'push' | 'repair';
4
+ export type WorkspaceSyncControlPlaneDecision = {
5
+ allowed: true;
6
+ } | {
7
+ allowed: false;
8
+ reason: WorkspaceSyncBlockedReason;
9
+ retainPendingSignature: boolean;
10
+ };
11
+ interface WorkspaceSyncControlPlaneBaseArgs {
12
+ cloudAuthConfigured: boolean;
13
+ runtimeMode: 'local' | 'cloud';
14
+ workspaceCloudSyncEnabled: boolean;
15
+ currentWorkspaceId: string;
16
+ isAuthenticated: boolean;
17
+ }
18
+ interface PushSyncReadinessArgs extends WorkspaceSyncControlPlaneBaseArgs {
19
+ workspaceSyncPhase: WorkspaceSyncPhase;
20
+ repairModeActive: boolean;
21
+ repairModeBypass: boolean;
22
+ pushInFlight: boolean;
23
+ pullInFlight: boolean;
24
+ }
25
+ interface PullSyncReadinessArgs extends WorkspaceSyncControlPlaneBaseArgs {
26
+ workspaceSyncPhase: WorkspaceSyncPhase;
27
+ repairModeActive: boolean;
28
+ repairModeBypass: boolean;
29
+ retryPending: boolean;
30
+ pushInFlight: boolean;
31
+ pullInFlight: boolean;
32
+ }
33
+ export declare function resolvePushSyncReadiness(args: PushSyncReadinessArgs): WorkspaceSyncControlPlaneDecision;
34
+ export declare function resolvePullSyncReadiness(args: PullSyncReadinessArgs): WorkspaceSyncControlPlaneDecision;
35
+ export declare function resolveRetrySyncReadiness(args: WorkspaceSyncControlPlaneBaseArgs): WorkspaceSyncControlPlaneDecision;
36
+ export declare function createWorkspaceSyncLeaseHeldDecision(operation: WorkspaceSyncOperation): WorkspaceSyncControlPlaneDecision;
37
+ export {};
@@ -0,0 +1,78 @@
1
+ import { isValidWorkspaceKey } from './orchestratorShared';
2
+ const ALLOW_SYNC_OPERATION = { allowed: true };
3
+ function blockSyncOperation(reason, options) {
4
+ return {
5
+ allowed: false,
6
+ reason,
7
+ retainPendingSignature: options?.retainPendingSignature === true
8
+ };
9
+ }
10
+ function resolveBaseSyncReadiness(args, options) {
11
+ if (!args.cloudAuthConfigured)
12
+ return blockSyncOperation('cloud-auth-unconfigured');
13
+ if (args.runtimeMode !== 'local')
14
+ return blockSyncOperation('runtime-not-local');
15
+ if (!args.workspaceCloudSyncEnabled)
16
+ return blockSyncOperation('sync-disabled');
17
+ if ((options?.requireValidWorkspace ?? true) && !isValidWorkspaceKey(args.currentWorkspaceId)) {
18
+ return blockSyncOperation('invalid-workspace');
19
+ }
20
+ return null;
21
+ }
22
+ export function resolvePushSyncReadiness(args) {
23
+ const baseReadiness = resolveBaseSyncReadiness(args);
24
+ if (baseReadiness)
25
+ return baseReadiness;
26
+ if (args.repairModeActive && !args.repairModeBypass) {
27
+ return blockSyncOperation('repair-active', { retainPendingSignature: true });
28
+ }
29
+ if (args.workspaceSyncPhase === 'attach-cloud') {
30
+ return blockSyncOperation('attach-cloud', { retainPendingSignature: true });
31
+ }
32
+ if (!args.isAuthenticated) {
33
+ return blockSyncOperation('auth-required');
34
+ }
35
+ if (args.pushInFlight) {
36
+ return blockSyncOperation('push-in-flight', { retainPendingSignature: true });
37
+ }
38
+ if (args.pullInFlight) {
39
+ return blockSyncOperation('pull-in-flight', { retainPendingSignature: true });
40
+ }
41
+ return ALLOW_SYNC_OPERATION;
42
+ }
43
+ export function resolvePullSyncReadiness(args) {
44
+ const baseReadiness = resolveBaseSyncReadiness(args);
45
+ if (baseReadiness)
46
+ return baseReadiness;
47
+ if (args.repairModeActive && !args.repairModeBypass) {
48
+ return blockSyncOperation('repair-active');
49
+ }
50
+ if (args.workspaceSyncPhase === 'provision-local') {
51
+ return blockSyncOperation('provision-local');
52
+ }
53
+ if (args.retryPending) {
54
+ return blockSyncOperation('retry-pending');
55
+ }
56
+ if (!args.isAuthenticated) {
57
+ return blockSyncOperation('auth-required');
58
+ }
59
+ if (args.pullInFlight) {
60
+ return blockSyncOperation('pull-in-flight');
61
+ }
62
+ if (args.pushInFlight) {
63
+ return blockSyncOperation('push-in-flight');
64
+ }
65
+ return ALLOW_SYNC_OPERATION;
66
+ }
67
+ export function resolveRetrySyncReadiness(args) {
68
+ const baseReadiness = resolveBaseSyncReadiness(args, { requireValidWorkspace: false });
69
+ if (baseReadiness)
70
+ return baseReadiness;
71
+ if (!args.isAuthenticated) {
72
+ return blockSyncOperation('auth-required');
73
+ }
74
+ return ALLOW_SYNC_OPERATION;
75
+ }
76
+ export function createWorkspaceSyncLeaseHeldDecision(operation) {
77
+ return blockSyncOperation('lease-held', { retainPendingSignature: operation === 'push' });
78
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,121 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { createWorkspaceSyncLeaseHeldDecision, resolvePullSyncReadiness, resolvePushSyncReadiness, resolveRetrySyncReadiness, } from './controlPlane';
3
+ const makeBaseArgs = () => ({
4
+ cloudAuthConfigured: true,
5
+ runtimeMode: 'local',
6
+ workspaceCloudSyncEnabled: true,
7
+ currentWorkspaceId: 'workspace-123',
8
+ isAuthenticated: true
9
+ });
10
+ describe('sync control plane', () => {
11
+ it('blocks push during repair and retains the pending signature', () => {
12
+ expect(resolvePushSyncReadiness({
13
+ ...makeBaseArgs(),
14
+ workspaceSyncPhase: 'active',
15
+ repairModeActive: true,
16
+ repairModeBypass: false,
17
+ pushInFlight: false,
18
+ pullInFlight: false
19
+ })).toEqual({
20
+ allowed: false,
21
+ reason: 'repair-active',
22
+ retainPendingSignature: true
23
+ });
24
+ });
25
+ it('allows repair push to bypass the repair-active gate', () => {
26
+ expect(resolvePushSyncReadiness({
27
+ ...makeBaseArgs(),
28
+ workspaceSyncPhase: 'active',
29
+ repairModeActive: true,
30
+ repairModeBypass: true,
31
+ pushInFlight: false,
32
+ pullInFlight: false
33
+ })).toEqual({ allowed: true });
34
+ });
35
+ it('blocks push during attach-cloud and retains the pending signature', () => {
36
+ expect(resolvePushSyncReadiness({
37
+ ...makeBaseArgs(),
38
+ workspaceSyncPhase: 'attach-cloud',
39
+ repairModeActive: false,
40
+ repairModeBypass: false,
41
+ pushInFlight: false,
42
+ pullInFlight: false
43
+ })).toEqual({
44
+ allowed: false,
45
+ reason: 'attach-cloud',
46
+ retainPendingSignature: true
47
+ });
48
+ });
49
+ it('blocks pull during provision-local', () => {
50
+ expect(resolvePullSyncReadiness({
51
+ ...makeBaseArgs(),
52
+ workspaceSyncPhase: 'provision-local',
53
+ repairModeActive: false,
54
+ repairModeBypass: false,
55
+ retryPending: false,
56
+ pushInFlight: false,
57
+ pullInFlight: false
58
+ })).toEqual({
59
+ allowed: false,
60
+ reason: 'provision-local',
61
+ retainPendingSignature: false
62
+ });
63
+ });
64
+ it('blocks pull when a retry is already pending', () => {
65
+ expect(resolvePullSyncReadiness({
66
+ ...makeBaseArgs(),
67
+ workspaceSyncPhase: 'active',
68
+ repairModeActive: false,
69
+ repairModeBypass: false,
70
+ retryPending: true,
71
+ pushInFlight: false,
72
+ pullInFlight: false
73
+ })).toEqual({
74
+ allowed: false,
75
+ reason: 'retry-pending',
76
+ retainPendingSignature: false
77
+ });
78
+ });
79
+ it('surfaces auth-required for retry readiness before the session is refreshed', () => {
80
+ expect(resolveRetrySyncReadiness({
81
+ ...makeBaseArgs(),
82
+ isAuthenticated: false
83
+ })).toEqual({
84
+ allowed: false,
85
+ reason: 'auth-required',
86
+ retainPendingSignature: false
87
+ });
88
+ });
89
+ it('rejects invalid workspace ids for transfer operations', () => {
90
+ expect(resolvePushSyncReadiness({
91
+ ...makeBaseArgs(),
92
+ currentWorkspaceId: 'default',
93
+ workspaceSyncPhase: 'active',
94
+ repairModeActive: false,
95
+ repairModeBypass: false,
96
+ pushInFlight: false,
97
+ pullInFlight: false
98
+ })).toEqual({
99
+ allowed: false,
100
+ reason: 'invalid-workspace',
101
+ retainPendingSignature: false
102
+ });
103
+ });
104
+ it('marks lease contention as retaining the pending signature only for push', () => {
105
+ expect(createWorkspaceSyncLeaseHeldDecision('push')).toEqual({
106
+ allowed: false,
107
+ reason: 'lease-held',
108
+ retainPendingSignature: true
109
+ });
110
+ expect(createWorkspaceSyncLeaseHeldDecision('pull')).toEqual({
111
+ allowed: false,
112
+ reason: 'lease-held',
113
+ retainPendingSignature: false
114
+ });
115
+ expect(createWorkspaceSyncLeaseHeldDecision('repair')).toEqual({
116
+ allowed: false,
117
+ reason: 'lease-held',
118
+ retainPendingSignature: false
119
+ });
120
+ });
121
+ });
@@ -0,0 +1,45 @@
1
+ import type { WorkspaceSyncPhase } from '../../sync/workspaceSyncState';
2
+ export type WorkspaceSyncPresentationStatus = 'off' | 'syncing' | 'attention' | 'healthy';
3
+ interface WorkspaceSyncPresentationArgs {
4
+ enabled: boolean;
5
+ phase: WorkspaceSyncPhase;
6
+ busy: boolean;
7
+ retryAt: string | null;
8
+ lastErrorMessage: string | null;
9
+ }
10
+ interface WorkspaceSyncLifecycleBaseArgs {
11
+ cloudAuthConfigured: boolean;
12
+ runtimeMode: 'local' | 'cloud';
13
+ workspaceCloudSyncEnabled: boolean;
14
+ authSessionResolved: boolean;
15
+ }
16
+ interface WorkspaceSyncAutomaticPullArgs extends WorkspaceSyncLifecycleBaseArgs {
17
+ workspaceSyncPhase: WorkspaceSyncPhase;
18
+ lastPullAt: string | null;
19
+ retryPending: boolean;
20
+ }
21
+ interface WorkspaceSyncFullReconcileArgs extends WorkspaceSyncLifecycleBaseArgs {
22
+ workspaceSyncPhase: WorkspaceSyncPhase;
23
+ isAuthenticated: boolean;
24
+ }
25
+ interface WorkspaceSyncStartupRepairArgs extends WorkspaceSyncFullReconcileArgs {
26
+ alreadyRan: boolean;
27
+ }
28
+ interface WorkspaceSyncReactivePushArgs extends WorkspaceSyncLifecycleBaseArgs {
29
+ workspaceSyncPhase: WorkspaceSyncPhase;
30
+ workspaceSyncReferenceSnapshotsReady: boolean;
31
+ }
32
+ export declare function resolveWorkspaceSyncPresentation({ enabled, phase, busy, retryAt, lastErrorMessage }: WorkspaceSyncPresentationArgs): {
33
+ status: WorkspaceSyncPresentationStatus;
34
+ summary: string;
35
+ recommendedAction: string;
36
+ };
37
+ export declare function shouldScheduleWorkspaceReactivePush(args: WorkspaceSyncReactivePushArgs): boolean;
38
+ export declare function shouldStartWorkspacePushWatchdog(args: WorkspaceSyncReactivePushArgs): boolean;
39
+ export declare function resolveWorkspaceAutomaticPullPolicy(args: WorkspaceSyncAutomaticPullArgs): {
40
+ shouldStart: boolean;
41
+ shouldKickOffImmediately: boolean;
42
+ };
43
+ export declare function shouldStartWorkspacePeriodicFullReconcile(args: WorkspaceSyncFullReconcileArgs): boolean;
44
+ export declare function shouldRunWorkspaceStartupRepair(args: WorkspaceSyncStartupRepairArgs): boolean;
45
+ export {};
@@ -0,0 +1,93 @@
1
+ function canRunLocalWorkspaceSyncLifecycle(args) {
2
+ return args.cloudAuthConfigured
3
+ && args.runtimeMode === 'local'
4
+ && args.workspaceCloudSyncEnabled
5
+ && args.authSessionResolved;
6
+ }
7
+ export function resolveWorkspaceSyncPresentation({ enabled, phase, busy, retryAt, lastErrorMessage }) {
8
+ if (!enabled) {
9
+ return {
10
+ status: 'off',
11
+ summary: 'Sync is turned off for this workspace.',
12
+ recommendedAction: 'Turn on sync when you are ready to back up this workspace.'
13
+ };
14
+ }
15
+ if (phase === 'provision-local') {
16
+ return {
17
+ status: 'syncing',
18
+ summary: busy
19
+ ? 'Uploading this workspace to cloud for the first time.'
20
+ : 'Preparing the first upload to cloud.',
21
+ recommendedAction: 'Keep this window open while the first upload finishes. If it seems stalled, press Sync.'
22
+ };
23
+ }
24
+ if (phase === 'attach-cloud') {
25
+ return {
26
+ status: 'syncing',
27
+ summary: busy
28
+ ? 'Pulling the cloud workspace into this device.'
29
+ : 'Waiting for the first cloud pull into this device.',
30
+ recommendedAction: 'Keep this window open for the first cloud pull. If it does not move, press Repair.'
31
+ };
32
+ }
33
+ if (retryAt) {
34
+ return {
35
+ status: 'attention',
36
+ summary: 'Sync hit a temporary problem and will retry automatically.',
37
+ recommendedAction: 'Wait for the automatic retry, or press Sync to retry now.'
38
+ };
39
+ }
40
+ if (lastErrorMessage || phase === 'error') {
41
+ return {
42
+ status: 'attention',
43
+ summary: 'Sync needs attention before it can continue.',
44
+ recommendedAction: 'Press Sync to retry. If the same error keeps returning, press Repair.'
45
+ };
46
+ }
47
+ if (busy) {
48
+ return {
49
+ status: 'syncing',
50
+ summary: 'Sync is currently running.',
51
+ recommendedAction: 'No action needed.'
52
+ };
53
+ }
54
+ return {
55
+ status: 'healthy',
56
+ summary: 'Sync is healthy.',
57
+ recommendedAction: 'No action needed.'
58
+ };
59
+ }
60
+ export function shouldScheduleWorkspaceReactivePush(args) {
61
+ return canRunLocalWorkspaceSyncLifecycle(args)
62
+ && args.workspaceSyncPhase !== 'attach-cloud'
63
+ && args.workspaceSyncReferenceSnapshotsReady;
64
+ }
65
+ export function shouldStartWorkspacePushWatchdog(args) {
66
+ return canRunLocalWorkspaceSyncLifecycle(args)
67
+ && args.workspaceSyncPhase === 'active'
68
+ && args.workspaceSyncReferenceSnapshotsReady;
69
+ }
70
+ export function resolveWorkspaceAutomaticPullPolicy(args) {
71
+ if (!canRunLocalWorkspaceSyncLifecycle(args)) {
72
+ return { shouldStart: false, shouldKickOffImmediately: false };
73
+ }
74
+ if (args.workspaceSyncPhase === 'provision-local' || args.workspaceSyncPhase === 'error' || args.retryPending) {
75
+ return { shouldStart: false, shouldKickOffImmediately: false };
76
+ }
77
+ return {
78
+ shouldStart: true,
79
+ shouldKickOffImmediately: args.workspaceSyncPhase === 'attach-cloud' || !args.lastPullAt
80
+ };
81
+ }
82
+ export function shouldStartWorkspacePeriodicFullReconcile(args) {
83
+ return canRunLocalWorkspaceSyncLifecycle(args)
84
+ && args.isAuthenticated
85
+ && args.workspaceSyncPhase === 'active';
86
+ }
87
+ export function shouldRunWorkspaceStartupRepair(args) {
88
+ return canRunLocalWorkspaceSyncLifecycle(args)
89
+ && args.isAuthenticated
90
+ && args.workspaceSyncPhase !== 'provision-local'
91
+ && args.workspaceSyncPhase !== 'attach-cloud'
92
+ && !args.alreadyRan;
93
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -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,5 +1,6 @@
1
1
  import type { WorkspaceTaxonomyState } from '../../shared/taxonomyState.js';
2
2
  import type { WorkspaceSyncAiProfileSnapshot, WorkspaceSyncDocumentReviewCommentSnapshot, WorkspaceSyncDocumentReviewSessionSnapshot, WorkspaceSyncTaskEventSnapshot } from '../../sync/workspaceSyncModel';
3
+ import type { WorkspaceSyncPushBaselineSnapshot } from '../../sync/workspaceSyncState.js';
3
4
  import type { TaskItem } 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";
@@ -20,9 +21,13 @@ export declare function buildTaxonomyStateFingerprint(taxonomyState?: WorkspaceT
20
21
  export declare function flattenDocumentReviewComments(sessions: WorkspaceSyncDocumentReviewSessionSnapshot[]): WorkspaceSyncDocumentReviewCommentSnapshot[];
21
22
  export declare function flattenTaskEvents(tasks: TaskItem[], archivedTasks: TaskItem[]): WorkspaceSyncTaskEventSnapshot[];
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;