@taskforcehq/taskforce 0.3.305 → 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 (337) hide show
  1. package/dist/Taskforce.module.css +295 -89
  2. package/dist/TaskforceCore.js +215 -43
  3. package/dist/TaskforceCore.test.js +433 -28
  4. package/dist/assets/fonts/CourierPrime-Bold.woff2 +0 -0
  5. package/dist/assets/fonts/CourierPrime-BoldItalic.woff2 +0 -0
  6. package/dist/assets/fonts/CourierPrime-Italic.woff2 +0 -0
  7. package/dist/assets/fonts/CourierPrime-Regular.woff2 +0 -0
  8. package/dist/assets/fonts/Noir_medium.woff2 +0 -0
  9. package/dist/assets/fonts/Noir_regular.woff2 +0 -0
  10. package/dist/assets/fonts/RussoOne-Regular.woff2 +0 -0
  11. package/dist/assets/fonts/SpecialElite-Regular.woff2 +0 -0
  12. package/dist/compat/workspaceSyncCompat.js +46 -2
  13. package/dist/compat/workspaceSyncCompat.test.js +38 -1
  14. package/dist/components/context/ContextAttachmentManager.d.ts +14 -0
  15. package/dist/components/context/ContextAttachmentManager.js +549 -0
  16. package/dist/components/features/AgentsModule.d.ts +10 -1
  17. package/dist/components/features/AgentsModule.js +260 -15
  18. package/dist/components/features/AgentsModule.test.js +255 -5
  19. package/dist/components/features/DocumentViewer.d.ts +5 -1
  20. package/dist/components/features/DocumentViewer.js +60 -3
  21. package/dist/components/features/DocumentWorkspace.js +1 -1
  22. package/dist/components/features/DocumentWorkspace.test.js +33 -0
  23. package/dist/components/features/documentWorkspaceModel.d.ts +1 -1
  24. package/dist/components/task/TaskCard.js +19 -28
  25. package/dist/components/task/TaskCard.test.js +38 -3
  26. package/dist/components/task/TaskContextUpload.js +4 -526
  27. package/dist/components/task/TaskForm.js +85 -90
  28. package/dist/components/task/TaskForm.test.js +110 -8
  29. package/dist/components/task/TaskKanban.d.ts +2 -1
  30. package/dist/components/task/TaskKanban.js +94 -13
  31. package/dist/components/task/TaskKanban.test.js +36 -0
  32. package/dist/components/ui/EditableAvatarButton.d.ts +18 -0
  33. package/dist/components/ui/EditableAvatarButton.js +18 -0
  34. package/dist/components/views/PlanComparisonPage.d.ts +9 -1
  35. package/dist/components/views/PlanComparisonPage.js +70 -14
  36. package/dist/components/views/PlanComparisonPage.test.js +238 -0
  37. package/dist/components/views/PlansPage.js +127 -36
  38. package/dist/components/views/PlansPage.test.js +294 -12
  39. package/dist/components/views/StandaloneLayout.js +283 -533
  40. package/dist/components/views/panels/PlanningDrawer.d.ts +8 -1
  41. package/dist/components/views/panels/PlanningDrawer.js +18 -11
  42. package/dist/components/views/panels/PlanningDrawer.test.d.ts +1 -0
  43. package/dist/components/views/panels/PlanningDrawer.test.js +141 -0
  44. package/dist/components/views/planningScope.d.ts +20 -0
  45. package/dist/components/views/planningScope.js +25 -0
  46. package/dist/components/views/planningScope.test.d.ts +1 -0
  47. package/dist/components/views/planningScope.test.js +60 -0
  48. package/dist/components/views/standalone/modals/AccountHubModal.d.ts +26 -1
  49. package/dist/components/views/standalone/modals/AccountHubModal.js +76 -2
  50. package/dist/components/views/standalone/modals/AccountHubModal.test.js +20 -3
  51. package/dist/components/views/standalone/modals/AvatarImageManagerModal.d.ts +20 -0
  52. package/dist/components/views/standalone/modals/AvatarImageManagerModal.js +127 -0
  53. package/dist/components/views/standalone/modals/EditProfileModal.d.ts +2 -9
  54. package/dist/components/views/standalone/modals/EditProfileModal.js +3 -2
  55. package/dist/components/views/standalone/modals/SyncEnableWarningModal.d.ts +9 -0
  56. package/dist/components/views/standalone/modals/SyncEnableWarningModal.js +6 -0
  57. package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.d.ts +1 -0
  58. package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.js +24 -0
  59. package/dist/components/views/standalone/modals/SyncStatusModal.d.ts +2 -1
  60. package/dist/components/views/standalone/modals/SyncStatusModal.js +2 -2
  61. package/dist/core/AiProfileService.d.ts +39 -2
  62. package/dist/core/AiProfileService.js +639 -73
  63. package/dist/core/AiProfileService.test.js +19 -1
  64. package/dist/core/AiProfiles.test.js +566 -7
  65. package/dist/core/AttachmentLinkService.js +57 -15
  66. package/dist/core/AuthIdentityService.d.ts +107 -0
  67. package/dist/core/AuthIdentityService.js +284 -0
  68. package/dist/core/AuthTokenService.d.ts +4 -0
  69. package/dist/core/AuthTokenService.js +34 -6
  70. package/dist/core/AuthTokenService.test.js +3 -3
  71. package/dist/core/EntitlementsPolicy.test.js +2 -2
  72. package/dist/core/GlobalSettingsService.js +115 -6
  73. package/dist/core/PlanEntitlementService.d.ts +23 -2
  74. package/dist/core/PlanEntitlementService.js +343 -57
  75. package/dist/core/PlanFeatureCatalog.test.d.ts +1 -0
  76. package/dist/core/PlanFeatureCatalog.test.js +84 -0
  77. package/dist/core/PlanVersionPolicy.test.js +35 -2
  78. package/dist/core/PlanningEntities.test.js +52 -0
  79. package/dist/core/SignupMonetizationSettings.test.js +199 -27
  80. package/dist/core/SyncReconciliationService.js +2 -65
  81. package/dist/core/SystemAdmin.test.js +42 -42
  82. package/dist/core/TaskAttachmentsCanonical.test.js +51 -1
  83. package/dist/core/Taskforce.d.ts +225 -14
  84. package/dist/core/Taskforce.js +765 -192
  85. package/dist/core/Taskforce.listTasksSlim.test.d.ts +1 -0
  86. package/dist/core/Taskforce.listTasksSlim.test.js +91 -0
  87. package/dist/core/UserProfileAvatarDrafts.test.js +30 -3
  88. package/dist/core/WorkspaceLifecycleService.js +0 -5
  89. package/dist/core/WorkspacePermissions.test.js +25 -1
  90. package/dist/core/WorkspacePlanMode.test.js +117 -16
  91. package/dist/core/shared.d.ts +1 -1
  92. package/dist/core/shared.js +5 -1
  93. package/dist/core/types.d.ts +68 -2
  94. package/dist/hooks/auth/useTaskforceAuthBootstrap.js +26 -1
  95. package/dist/hooks/sync/bootstrap.js +2 -0
  96. package/dist/hooks/sync/controlPlane.d.ts +37 -0
  97. package/dist/hooks/sync/controlPlane.js +78 -0
  98. package/dist/hooks/sync/controlPlane.test.d.ts +1 -0
  99. package/dist/hooks/sync/controlPlane.test.js +121 -0
  100. package/dist/hooks/sync/lifecyclePolicy.d.ts +45 -0
  101. package/dist/hooks/sync/lifecyclePolicy.js +93 -0
  102. package/dist/hooks/sync/lifecyclePolicy.test.d.ts +1 -0
  103. package/dist/hooks/sync/lifecyclePolicy.test.js +124 -0
  104. package/dist/hooks/sync/orchestratorShared.d.ts +10 -1
  105. package/dist/hooks/sync/orchestratorShared.js +68 -47
  106. package/dist/hooks/sync/orchestratorShared.test.js +50 -1
  107. package/dist/hooks/sync/pullLifecycle.d.ts +31 -0
  108. package/dist/hooks/sync/pullLifecycle.js +24 -0
  109. package/dist/hooks/sync/pullLifecycle.test.d.ts +1 -0
  110. package/dist/hooks/sync/pullLifecycle.test.js +80 -0
  111. package/dist/hooks/sync/recovery.d.ts +16 -2
  112. package/dist/hooks/sync/recovery.js +171 -53
  113. package/dist/hooks/sync/recovery.test.d.ts +1 -0
  114. package/dist/hooks/sync/recovery.test.js +292 -0
  115. package/dist/hooks/sync/transfers.d.ts +15 -3
  116. package/dist/hooks/sync/transfers.js +179 -62
  117. package/dist/hooks/sync/transfers.test.d.ts +1 -0
  118. package/dist/hooks/sync/transfers.test.js +396 -0
  119. package/dist/hooks/sync/useRecentSyncEvents.d.ts +21 -0
  120. package/dist/hooks/sync/useRecentSyncEvents.js +92 -0
  121. package/dist/hooks/sync/useRecentSyncEvents.test.d.ts +1 -0
  122. package/dist/hooks/sync/useRecentSyncEvents.test.js +124 -0
  123. package/dist/hooks/sync/useSyncStatusActions.d.ts +30 -0
  124. package/dist/hooks/sync/useSyncStatusActions.js +88 -0
  125. package/dist/hooks/sync/useSyncStatusActions.test.d.ts +1 -0
  126. package/dist/hooks/sync/useSyncStatusActions.test.js +133 -0
  127. package/dist/hooks/sync/useSyncStatusControls.d.ts +25 -0
  128. package/dist/hooks/sync/useSyncStatusControls.js +60 -0
  129. package/dist/hooks/sync/useSyncStatusControls.test.d.ts +1 -0
  130. package/dist/hooks/sync/useSyncStatusControls.test.js +88 -0
  131. package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +12 -0
  132. package/dist/hooks/useSyncOrchestrator.d.ts +9 -2
  133. package/dist/hooks/useSyncOrchestrator.js +359 -178
  134. package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +407 -0
  135. package/dist/hooks/useTaskData.js +8 -3
  136. package/dist/hooks/useTaskData.test.js +45 -0
  137. package/dist/hooks/useTaskforce.d.ts +60 -2
  138. package/dist/hooks/useTaskforce.js +549 -240
  139. package/dist/hooks/useTaskforce.runtime-routing.test.d.ts +1 -0
  140. package/dist/hooks/useTaskforce.runtime-routing.test.js +152 -0
  141. package/dist/hooks/useTaskforce.sync-behavior.test.js +2380 -212
  142. package/dist/hooks/useWorkspaceSyncController.d.ts +1 -0
  143. package/dist/hooks/useWorkspaceSyncController.js +6 -1
  144. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.d.ts +16 -0
  145. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +316 -35
  146. package/dist/localization/locales/en-US.d.ts +0 -1
  147. package/dist/localization/locales/en-US.js +0 -1
  148. package/dist/localization/locales/es-419.js +0 -1
  149. package/dist/localization/locales/pt-BR.js +0 -1
  150. package/dist/mcp/documentAssetRegistrar.js +3 -3
  151. package/dist/mcp/runtime.d.ts +2 -0
  152. package/dist/mcp/runtime.js +131 -64
  153. package/dist/mcp/runtime.test.js +291 -12
  154. package/dist/migrations/taskSchemaMigrations.d.ts +1 -1
  155. package/dist/migrations/taskSchemaMigrations.js +171 -61
  156. package/dist/migrations/taskSchemaMigrations.test.js +15 -0
  157. package/dist/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
  158. package/dist/resources/templates/workflows/collaborate.yaml +1 -1
  159. package/dist/resources/templates/workflows/evaluate.yaml +2 -2
  160. package/dist/resources/templates/workflows/plan.yaml +1 -1
  161. package/dist/resources/templates/workflows/review.yaml +2 -2
  162. package/dist/server/annotatedAttachmentsRoutes.test.js +3 -3
  163. package/dist/server/auth/providers/apple.d.ts +33 -0
  164. package/dist/server/auth/providers/apple.js +82 -0
  165. package/dist/server/auth/providers/appleClientSecret.d.ts +37 -0
  166. package/dist/server/auth/providers/appleClientSecret.js +65 -0
  167. package/dist/server/auth/providers/github.d.ts +26 -0
  168. package/dist/server/auth/providers/github.js +86 -0
  169. package/dist/server/auth/providers/google.d.ts +21 -0
  170. package/dist/server/auth/providers/google.js +56 -0
  171. package/dist/server/auth/providers/types.d.ts +21 -0
  172. package/dist/server/auth/providers/types.js +1 -0
  173. package/dist/server/auth.d.ts +2 -0
  174. package/dist/server/auth.js +6 -3
  175. package/dist/server/documentReviewRoutes.test.js +36 -3
  176. package/dist/server/index.cookieProxy.test.js +1 -0
  177. package/dist/server/index.d.ts +12 -0
  178. package/dist/server/index.js +120 -9
  179. package/dist/server/index.rateLimit.test.js +3 -0
  180. package/dist/server/index.test.js +106 -3
  181. package/dist/server/routes/admin.d.ts +3 -0
  182. package/dist/server/routes/admin.js +272 -19
  183. package/dist/server/routes/auth.d.ts +15 -2
  184. package/dist/server/routes/auth.js +994 -57
  185. package/dist/server/routes/authSupport.d.ts +1 -1
  186. package/dist/server/routes/authSupport.js +1 -1
  187. package/dist/server/routes/billing.js +361 -35
  188. package/dist/server/routes/billing.test.js +592 -12
  189. package/dist/server/routes/documents.d.ts +1 -0
  190. package/dist/server/routes/documents.js +172 -70
  191. package/dist/server/routes/shared.d.ts +28 -2
  192. package/dist/server/routes/shared.js +69 -4
  193. package/dist/server/routes/sync.integration.test.js +437 -39
  194. package/dist/server/routes/sync.js +61 -605
  195. package/dist/server/routes/syncAuxRoutes.d.ts +15 -0
  196. package/dist/server/routes/syncAuxRoutes.js +91 -0
  197. package/dist/server/routes/syncAuxRoutes.test.d.ts +1 -0
  198. package/dist/server/routes/syncAuxRoutes.test.js +158 -0
  199. package/dist/server/routes/syncPullApplyRoutes.d.ts +36 -0
  200. package/dist/server/routes/syncPullApplyRoutes.js +204 -0
  201. package/dist/server/routes/syncPushRoutes.d.ts +24 -0
  202. package/dist/server/routes/syncPushRoutes.js +212 -0
  203. package/dist/server/routes/syncRouteGuards.d.ts +36 -0
  204. package/dist/server/routes/syncRouteGuards.js +67 -0
  205. package/dist/server/routes/syncRouteGuards.test.d.ts +1 -0
  206. package/dist/server/routes/syncRouteGuards.test.js +94 -0
  207. package/dist/server/routes/syncRouteTypes.d.ts +13 -0
  208. package/dist/server/routes/syncRouteTypes.js +1 -0
  209. package/dist/server/routes/syncSnapshotRoutes.d.ts +66 -0
  210. package/dist/server/routes/syncSnapshotRoutes.js +180 -0
  211. package/dist/server/routes/tasks.js +43 -1
  212. package/dist/server/routes/workspaces.js +36 -5
  213. package/dist/server/routes.js +60 -3
  214. package/dist/server/routes.test.js +1824 -171
  215. package/dist/services/workflowExportSnapshots.test.js +2 -0
  216. package/dist/shared/aiProfileSeatScope.d.ts +5 -0
  217. package/dist/shared/aiProfileSeatScope.js +21 -0
  218. package/dist/shared/passwordPolicy.d.ts +13 -0
  219. package/dist/shared/passwordPolicy.js +84 -0
  220. package/dist/shared/passwordPolicy.test.d.ts +1 -0
  221. package/dist/shared/passwordPolicy.test.js +34 -0
  222. package/dist/storage/workspaceAssetStore.d.ts +15 -3
  223. package/dist/storage/workspaceAssetStore.js +132 -44
  224. package/dist/storage/workspaceAssetStore.test.js +93 -6
  225. package/dist/styles/fonts.css +70 -0
  226. package/dist/sync/collaborationSyncPayload.d.ts +6 -1
  227. package/dist/sync/collaborationSyncPayload.js +17 -11
  228. package/dist/sync/collaborationSyncPayload.test.js +13 -1
  229. package/dist/sync/contentSyncState.d.ts +4 -8
  230. package/dist/sync/contentSyncState.js +17 -70
  231. package/dist/sync/syncApplyHandlers.d.ts +7 -0
  232. package/dist/sync/syncApplyHandlers.js +28 -13
  233. package/dist/sync/syncApplyHandlers.test.js +70 -3
  234. package/dist/sync/syncFieldSemantics.d.ts +12 -0
  235. package/dist/sync/syncFieldSemantics.js +55 -0
  236. package/dist/sync/syncResourceAdapters.d.ts +44 -0
  237. package/dist/sync/syncResourceAdapters.js +77 -0
  238. package/dist/sync/syncService.d.ts +5 -0
  239. package/dist/sync/syncService.js +52 -0
  240. package/dist/sync/syncService.test.js +57 -3
  241. package/dist/sync/taskSyncChangeKey.d.ts +2 -0
  242. package/dist/sync/taskSyncChangeKey.js +143 -0
  243. package/dist/sync/taskSyncPayload.js +3 -8
  244. package/dist/sync/workspacePullFeed.js +4 -3
  245. package/dist/sync/workspacePullFeed.test.js +43 -0
  246. package/dist/sync/workspaceRepair.js +5 -2
  247. package/dist/sync/workspaceSyncModel.d.ts +45 -0
  248. package/dist/sync/workspaceSyncModel.js +183 -28
  249. package/dist/sync/workspaceSyncModel.test.js +291 -12
  250. package/dist/sync/workspaceSyncState.d.ts +17 -0
  251. package/dist/sync/workspaceSyncState.js +2 -1
  252. package/dist/sync/workspaceSyncSurface.js +3 -8
  253. package/dist/types.d.ts +17 -0
  254. package/dist/ui/assets/AgentsModule-DrLawwNl.js +1 -0
  255. package/dist/ui/assets/{AnnotatedAttachmentWorkspace-BG6P_GVW.js → AnnotatedAttachmentWorkspace-Z9_whf7F.js} +1 -1
  256. package/dist/ui/assets/CourierPrime-Bold-BuLj_dpw.woff2 +0 -0
  257. package/dist/ui/assets/CourierPrime-BoldItalic-BrK2pUkZ.woff2 +0 -0
  258. package/dist/ui/assets/CourierPrime-Italic-DFUZK5Ey.woff2 +0 -0
  259. package/dist/ui/assets/CourierPrime-Regular-BsKphzVf.woff2 +0 -0
  260. package/dist/ui/assets/DocumentWorkspace-B03MaSkw.js +252 -0
  261. package/dist/ui/assets/DocumentWorkspace-Dhdso07p.css +1 -0
  262. package/dist/ui/assets/{InitiativesModule-Dhm7M8e7.js → InitiativesModule-9E6ParrY.js} +1 -1
  263. package/dist/ui/assets/Noir_medium-bxQwKGzB.woff2 +0 -0
  264. package/dist/ui/assets/Noir_regular-ojf2kxlG.woff2 +0 -0
  265. package/dist/ui/assets/PlansPage-CvfnMiWq.css +1 -0
  266. package/dist/ui/assets/PlansPage-DRXscYxH.js +1 -0
  267. package/dist/ui/assets/RussoOne-Regular-Cu_qq_qC.woff2 +0 -0
  268. package/dist/ui/assets/SpecialElite-Regular-Di6gSvAS.woff2 +0 -0
  269. package/dist/ui/assets/{TaskSettings-ln0aF7xc.js → TaskSettings-DZX4jk7e.js} +1 -1
  270. package/dist/ui/assets/{WorkflowsModule-BcS4afRn.js → WorkflowsModule-BA7jcEpH.js} +1 -1
  271. package/dist/ui/assets/index-9eT8e0Lu.css +1 -0
  272. package/dist/ui/assets/index-C6k75jr8.js +6 -0
  273. package/dist/ui/assets/{vendor-icons-BSUaRwF8.js → vendor-icons-DuEd_65c.js} +1 -1
  274. package/dist/ui/fonts/CourierPrime-Bold.ttf +0 -0
  275. package/dist/ui/fonts/CourierPrime-Bold.woff2 +0 -0
  276. package/dist/ui/fonts/CourierPrime-BoldItalic.ttf +0 -0
  277. package/dist/ui/fonts/CourierPrime-BoldItalic.woff2 +0 -0
  278. package/dist/ui/fonts/CourierPrime-Italic.ttf +0 -0
  279. package/dist/ui/fonts/CourierPrime-Italic.woff2 +0 -0
  280. package/dist/ui/fonts/CourierPrime-Regular.ttf +0 -0
  281. package/dist/ui/fonts/CourierPrime-Regular.woff2 +0 -0
  282. package/dist/ui/fonts/Noir_medium.otf +0 -0
  283. package/dist/ui/fonts/Noir_medium.woff2 +0 -0
  284. package/dist/ui/fonts/Noir_regular.otf +0 -0
  285. package/dist/ui/fonts/Noir_regular.woff2 +0 -0
  286. package/dist/ui/fonts/RussoOne-Regular.woff2 +0 -0
  287. package/dist/ui/fonts/SpecialElite-Regular.ttf +0 -0
  288. package/dist/ui/fonts/SpecialElite-Regular.woff2 +0 -0
  289. package/dist/ui/index.html +3 -3
  290. package/dist/utils/accountProfileSummaryCache.d.ts +5 -0
  291. package/dist/utils/assignees.d.ts +2 -0
  292. package/dist/utils/assignees.js +2 -0
  293. package/dist/utils/avatarUpload.d.ts +27 -0
  294. package/dist/utils/avatarUpload.js +132 -0
  295. package/dist/utils/avatarUpload.test.d.ts +1 -0
  296. package/dist/utils/avatarUpload.test.js +40 -0
  297. package/dist/utils/bootstrapTrace.d.ts +7 -0
  298. package/dist/utils/bootstrapTrace.js +29 -0
  299. package/dist/utils/commercialLifecyclePresentation.js +3 -0
  300. package/dist/utils/contextAssetEvents.d.ts +2 -0
  301. package/dist/utils/syncEventDetails.d.ts +3 -0
  302. package/dist/utils/syncEventDetails.js +64 -0
  303. package/dist/utils/syncEventDetails.test.d.ts +1 -0
  304. package/dist/utils/syncEventDetails.test.js +23 -0
  305. package/dist/utils/syncEventPresentation.d.ts +15 -0
  306. package/dist/utils/syncEventPresentation.js +129 -0
  307. package/dist/utils/syncEventPresentation.test.d.ts +1 -0
  308. package/dist/utils/syncEventPresentation.test.js +64 -0
  309. package/dist/utils/syncStatusPresentation.d.ts +72 -0
  310. package/dist/utils/syncStatusPresentation.js +217 -0
  311. package/dist/utils/syncStatusPresentation.test.d.ts +1 -0
  312. package/dist/utils/syncStatusPresentation.test.js +164 -0
  313. package/dist/utils/taskActivity.d.ts +2 -0
  314. package/dist/utils/taskActivity.js +228 -22
  315. package/dist/utils/taskActivity.test.js +119 -8
  316. package/dist/utils/workspaceSyncPresentation.d.ts +4 -0
  317. package/dist/utils/workspaceSyncPresentation.js +68 -2
  318. package/dist/utils/workspaceSyncPresentation.test.js +36 -1
  319. package/package.json +3 -2
  320. package/scripts/export-sqlite-to-postgres.mjs +7 -9
  321. package/scripts/run-e2e-realtime.sh +17 -3
  322. package/scripts/run-smoke.sh +17 -5
  323. package/scripts/run-soak.sh +17 -5
  324. package/src/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
  325. package/src/resources/templates/workflows/collaborate.yaml +1 -1
  326. package/src/resources/templates/workflows/evaluate.yaml +2 -2
  327. package/src/resources/templates/workflows/plan.yaml +1 -1
  328. package/src/resources/templates/workflows/review.yaml +2 -2
  329. package/dist/ui/assets/AgentsModule-N2MnQBZk.js +0 -1
  330. package/dist/ui/assets/DocumentWorkspace-B3nV_Gc5.css +0 -1
  331. package/dist/ui/assets/DocumentWorkspace-DRbDMwh8.js +0 -252
  332. package/dist/ui/assets/PlansPage-C2dd2n1X.css +0 -1
  333. package/dist/ui/assets/PlansPage-Cq0zXj3I.js +0 -1
  334. package/dist/ui/assets/RussoOne-Regular-C3BxZIj7.ttf +0 -0
  335. package/dist/ui/assets/index-C2-OXZV7.css +0 -1
  336. package/dist/ui/assets/index-DcSI5F86.js +0 -6
  337. package/scripts/migrate-planning-model.ts +0 -233
@@ -896,6 +896,114 @@ describe('useSyncOrchestrator', () => {
896
896
  ]));
897
897
  unmount();
898
898
  });
899
+ it('schedules a delete push when authoritative deleted task state changes', async () => {
900
+ vi.useFakeTimers();
901
+ const baseTask = {
902
+ id: 'task-local-delete-1',
903
+ title: 'Local delete task',
904
+ status: 'task',
905
+ createdAt: '2026-03-14T12:00:00.000Z',
906
+ updatedAt: '2026-03-14T12:00:00.000Z'
907
+ };
908
+ runWorkspacePushSyncServiceMock.mockResolvedValue({
909
+ success: true,
910
+ syncedAt: '2026-03-15T15:05:00.000Z',
911
+ requestMs: 1,
912
+ changeCount: 1,
913
+ deleteCount: 0,
914
+ currentTaskIds: new Set(['task-local-delete-1']),
915
+ deleteTaskIds: new Set(),
916
+ currentDocumentPaths: new Set(),
917
+ deleteDocumentPaths: new Set(),
918
+ currentDocumentWatermarks: new Map(),
919
+ currentAssetPaths: new Set(),
920
+ deleteAssetPaths: new Set(),
921
+ currentAssetWatermarks: new Map(),
922
+ currentDocumentReviewSessionIds: new Set(),
923
+ deleteDocumentReviewSessionIds: new Set(),
924
+ currentDocumentReviewSessionWatermarks: new Map(),
925
+ currentAnnotatedAttachmentSessionIds: new Set(),
926
+ deleteAnnotatedAttachmentSessionIds: new Set(),
927
+ currentAnnotatedAttachmentSessionWatermarks: new Map(),
928
+ pushedWatermarks: new Map([['task-local-delete-1', '2026-03-14T12:00:00.000Z']]),
929
+ emittedEventIds: []
930
+ });
931
+ let input = buildInput({
932
+ tasks: [baseTask]
933
+ });
934
+ const { result, rerender, unmount } = renderHook((props) => useSyncOrchestrator(props), {
935
+ initialProps: input
936
+ });
937
+ act(() => {
938
+ result.current.applyWorkspaceSyncStateSnapshot({
939
+ enabled: true,
940
+ phase: 'provision-local',
941
+ pullCursor: null
942
+ });
943
+ });
944
+ await act(async () => {
945
+ await vi.runOnlyPendingTimersAsync();
946
+ await Promise.resolve();
947
+ await Promise.resolve();
948
+ });
949
+ runWorkspacePushSyncServiceMock.mockClear();
950
+ runWorkspacePushSyncServiceMock.mockResolvedValue({
951
+ success: true,
952
+ syncedAt: '2026-03-15T15:06:00.000Z',
953
+ requestMs: 1,
954
+ changeCount: 0,
955
+ deleteCount: 1,
956
+ currentTaskIds: new Set(),
957
+ deleteTaskIds: new Set(['task-local-delete-1']),
958
+ currentDocumentPaths: new Set(),
959
+ deleteDocumentPaths: new Set(),
960
+ currentDocumentWatermarks: new Map(),
961
+ currentAssetPaths: new Set(),
962
+ deleteAssetPaths: new Set(),
963
+ currentAssetWatermarks: new Map(),
964
+ currentDocumentReviewSessionIds: new Set(),
965
+ deleteDocumentReviewSessionIds: new Set(),
966
+ currentDocumentReviewSessionWatermarks: new Map(),
967
+ currentAnnotatedAttachmentSessionIds: new Set(),
968
+ deleteAnnotatedAttachmentSessionIds: new Set(),
969
+ currentAnnotatedAttachmentSessionWatermarks: new Map(),
970
+ pushedWatermarks: new Map(),
971
+ emittedEventIds: []
972
+ });
973
+ input = buildInput({
974
+ tasks: [],
975
+ deletedTasks: [{
976
+ id: 'deleted-task-local-delete-1',
977
+ taskId: 'task-local-delete-1',
978
+ workspaceId: 'workspace-local-active',
979
+ deletedAt: '2026-03-15T15:06:00.000Z',
980
+ actor: 'user-1',
981
+ actorType: 'human',
982
+ source: 'ui',
983
+ taskSnapshot: baseTask
984
+ }]
985
+ });
986
+ rerender(input);
987
+ await act(async () => {
988
+ await vi.advanceTimersByTimeAsync(1600);
989
+ await Promise.resolve();
990
+ await Promise.resolve();
991
+ });
992
+ expect(runWorkspacePushSyncServiceMock.mock.calls.length).toBeGreaterThanOrEqual(1);
993
+ const pushedChanges = runWorkspacePushSyncServiceMock.mock.calls
994
+ .map((call) => call?.[0]?.payload?.changes)
995
+ .filter(Array.isArray);
996
+ expect(pushedChanges).toEqual(expect.arrayContaining([
997
+ expect.arrayContaining([
998
+ expect.objectContaining({
999
+ op: 'delete',
1000
+ taskId: 'task-local-delete-1',
1001
+ deletedAt: '2026-03-15T15:06:00.000Z'
1002
+ })
1003
+ ])
1004
+ ]));
1005
+ unmount();
1006
+ });
899
1007
  it('runs a startup full reconcile after the first successful pull when a saved cursor exists', async () => {
900
1008
  vi.useFakeTimers();
901
1009
  runWorkspacePullSyncServiceMock.mockResolvedValue({
@@ -931,6 +1039,66 @@ describe('useSyncOrchestrator', () => {
931
1039
  expect(runWorkspacePullSyncServiceMock.mock.calls.some((call) => call?.[0]?.cursor === null)).toBe(true);
932
1040
  unmount();
933
1041
  });
1042
+ it('clears an invalid saved pull cursor and retries from the beginning', async () => {
1043
+ vi.useFakeTimers();
1044
+ runWorkspacePullSyncServiceMock
1045
+ .mockResolvedValueOnce({
1046
+ success: false,
1047
+ kind: 'pull_http',
1048
+ status: 400,
1049
+ errorCode: 'INVALID_SYNC_CURSOR',
1050
+ error: 'Invalid sync cursor.',
1051
+ cursor: 'stale-cursor',
1052
+ pages: 0,
1053
+ appliedChanges: 0,
1054
+ pullRequestMs: 1,
1055
+ applyMs: 0,
1056
+ pulledDeleteTaskIds: new Set(),
1057
+ pulledActiveUpserts: false,
1058
+ pulledArchivedUpserts: false,
1059
+ documentDecryptFailures: []
1060
+ })
1061
+ .mockResolvedValueOnce({
1062
+ success: true,
1063
+ syncedAt: '2026-03-15T19:31:00.000Z',
1064
+ cursor: 'fresh-cursor-1',
1065
+ pages: 1,
1066
+ appliedChanges: 0,
1067
+ pullRequestMs: 1,
1068
+ applyMs: 0,
1069
+ pulledDeleteTaskIds: new Set(),
1070
+ pulledActiveUpserts: false,
1071
+ pulledArchivedUpserts: false,
1072
+ documentDecryptFailures: []
1073
+ });
1074
+ const { result, unmount } = renderHook((props) => useSyncOrchestrator(props), {
1075
+ initialProps: buildInput()
1076
+ });
1077
+ act(() => {
1078
+ result.current.applyWorkspaceSyncStateSnapshot({
1079
+ enabled: true,
1080
+ phase: 'active',
1081
+ pullCursor: 'stale-cursor'
1082
+ });
1083
+ });
1084
+ await act(async () => {
1085
+ await vi.advanceTimersByTimeAsync(500);
1086
+ await Promise.resolve();
1087
+ await Promise.resolve();
1088
+ });
1089
+ await act(async () => {
1090
+ await vi.runOnlyPendingTimersAsync();
1091
+ await Promise.resolve();
1092
+ await Promise.resolve();
1093
+ });
1094
+ expect(runWorkspacePullSyncServiceMock.mock.calls.length).toBeGreaterThanOrEqual(2);
1095
+ expect(runWorkspacePullSyncServiceMock.mock.calls[0]?.[0]?.cursor).toBe('stale-cursor');
1096
+ expect(runWorkspacePullSyncServiceMock.mock.calls.some((call) => call?.[0]?.cursor === null)).toBe(true);
1097
+ expect(result.current.workspaceRetryAt).toBeNull();
1098
+ expect(result.current.workspaceLastErrorMessage).toBeNull();
1099
+ expect(result.current.workspaceSyncPhase).toBe('active');
1100
+ unmount();
1101
+ });
934
1102
  it('finishes provision-local bootstrap by moving to active after the first push', async () => {
935
1103
  runWorkspacePushSyncServiceMock.mockResolvedValue({
936
1104
  success: true,
@@ -1000,6 +1168,243 @@ describe('useSyncOrchestrator', () => {
1000
1168
  expect(result.current.workspaceSyncPhase).toBe('active');
1001
1169
  expect(result.current.workspaceLastPullAt).toBe('2026-03-15T19:00:00.000Z');
1002
1170
  });
1171
+ const persisted = localStorage.getItem('taskforce.syncWatermarks.v3.workspace-local-active');
1172
+ expect(persisted).toBeTruthy();
1173
+ expect(JSON.parse(String(persisted))).toEqual(expect.objectContaining({
1174
+ v: 11,
1175
+ taskIds: [],
1176
+ taxonomyStateFingerprint: expect.any(String),
1177
+ documentWatermarks: [],
1178
+ assetWatermarks: [],
1179
+ taskEventWatermarks: []
1180
+ }));
1181
+ unmount();
1182
+ });
1183
+ it('persists task and planning baselines when attach-cloud bootstrap completes', async () => {
1184
+ runWorkspacePullSyncServiceMock.mockResolvedValue({
1185
+ success: true,
1186
+ syncedAt: '2026-03-15T19:00:00.000Z',
1187
+ cursor: null,
1188
+ pages: 1,
1189
+ appliedChanges: 0,
1190
+ pullRequestMs: 1,
1191
+ applyMs: 0,
1192
+ pulledDeleteTaskIds: new Set(),
1193
+ pulledActiveUpserts: false,
1194
+ pulledArchivedUpserts: false,
1195
+ documentDecryptFailures: []
1196
+ });
1197
+ const { result, unmount } = renderHook((props) => useSyncOrchestrator(props), {
1198
+ initialProps: buildInput({
1199
+ tasks: [{
1200
+ id: 'task-1',
1201
+ title: 'Seeded task',
1202
+ status: 'task',
1203
+ createdAt: '2026-03-15T18:00:00.000Z',
1204
+ updatedAt: '2026-03-15T18:05:00.000Z'
1205
+ }],
1206
+ initiatives: [{
1207
+ id: 'initiative-1',
1208
+ title: 'Seeded initiative',
1209
+ createdAt: '2026-03-15T17:00:00.000Z',
1210
+ updatedAt: '2026-03-15T17:05:00.000Z',
1211
+ isArchived: false
1212
+ }],
1213
+ workstreams: [{
1214
+ id: 'workstream-1',
1215
+ title: 'Seeded workstream',
1216
+ initiativeId: 'initiative-1',
1217
+ createdAt: '2026-03-15T17:10:00.000Z',
1218
+ updatedAt: '2026-03-15T17:15:00.000Z',
1219
+ isArchived: false
1220
+ }]
1221
+ })
1222
+ });
1223
+ act(() => {
1224
+ result.current.applyWorkspaceSyncStateSnapshot({
1225
+ enabled: true,
1226
+ phase: 'attach-cloud',
1227
+ pullCursor: null
1228
+ });
1229
+ });
1230
+ await waitFor(() => {
1231
+ expect(result.current.workspaceSyncPhase).toBe('active');
1232
+ });
1233
+ const persisted = JSON.parse(String(localStorage.getItem('taskforce.syncWatermarks.v3.workspace-local-active')));
1234
+ expect(persisted.taskIds).toEqual(['task-1']);
1235
+ expect(persisted.taskWatermarks).toEqual([['task-1', '2026-03-15T18:05:00.000Z']]);
1236
+ expect(persisted.initiativeWatermarks).toEqual([['initiative-1', '2026-03-15T17:05:00.000Z']]);
1237
+ expect(persisted.workstreamWatermarks).toEqual([['workstream-1', '2026-03-15T17:15:00.000Z']]);
1238
+ unmount();
1239
+ });
1240
+ it('rehydrates push baselines from workspace sync state when local storage is empty', async () => {
1241
+ vi.stubGlobal('fetch', vi.fn((url, init) => {
1242
+ if (url.includes('/api/taskforce/ui-state?key=workspace-sync')) {
1243
+ return Promise.resolve({
1244
+ ok: true,
1245
+ json: () => Promise.resolve({
1246
+ success: true,
1247
+ state: {
1248
+ version: 2,
1249
+ enabled: true,
1250
+ phase: 'active',
1251
+ pullCursor: null,
1252
+ pushBaseline: {
1253
+ taskIds: ['task-1'],
1254
+ taskWatermarks: [['task-1', '2026-03-15T18:05:00.000Z']],
1255
+ initiativeWatermarks: [['initiative-1', '2026-03-15T17:05:00.000Z']],
1256
+ workstreamWatermarks: [['workstream-1', '2026-03-15T17:15:00.000Z']],
1257
+ aiProfileWatermarks: [['ai-profile-codex', '2026-03-15T18:00:00.000Z']],
1258
+ documentWatermarks: [],
1259
+ assetWatermarks: [],
1260
+ documentReviewSessionWatermarks: [],
1261
+ documentReviewCommentWatermarks: [],
1262
+ annotatedAttachmentSessionWatermarks: [],
1263
+ taskEventWatermarks: [],
1264
+ taxonomyStateFingerprint: 'null'
1265
+ }
1266
+ }
1267
+ })
1268
+ });
1269
+ }
1270
+ if (url.includes('/api/taskforce/ui-state') && String(init?.method || '').toUpperCase() === 'POST') {
1271
+ return Promise.resolve({ ok: true, json: () => Promise.resolve({ success: true }) });
1272
+ }
1273
+ return Promise.resolve({ ok: true, json: () => Promise.resolve({ success: true }) });
1274
+ }));
1275
+ const { result, unmount } = renderHook((props) => useSyncOrchestrator(props), {
1276
+ initialProps: buildInput({
1277
+ tasks: [{
1278
+ id: 'task-1',
1279
+ title: 'Seeded task',
1280
+ status: 'task',
1281
+ createdAt: '2026-03-15T18:00:00.000Z',
1282
+ updatedAt: '2026-03-15T18:05:00.000Z'
1283
+ }]
1284
+ })
1285
+ });
1286
+ expect(localStorage.getItem('taskforce.syncWatermarks.v3.workspace-local-active')).toBeNull();
1287
+ await act(async () => {
1288
+ await result.current.loadWorkspaceSyncState();
1289
+ });
1290
+ await waitFor(() => {
1291
+ const persisted = JSON.parse(String(localStorage.getItem('taskforce.syncWatermarks.v3.workspace-local-active')));
1292
+ expect(persisted.taskIds).toEqual(['task-1']);
1293
+ expect(persisted.taskWatermarks).toEqual([['task-1', '2026-03-15T18:05:00.000Z']]);
1294
+ expect(persisted.initiativeWatermarks).toEqual([['initiative-1', '2026-03-15T17:05:00.000Z']]);
1295
+ expect(persisted.workstreamWatermarks).toEqual([['workstream-1', '2026-03-15T17:15:00.000Z']]);
1296
+ expect(persisted.aiProfileWatermarks).toEqual([['ai-profile-codex', '2026-03-15T18:00:00.000Z']]);
1297
+ });
1298
+ unmount();
1299
+ });
1300
+ it('rehydrates task delete baselines from persisted taskIds even when task watermarks are empty', async () => {
1301
+ vi.useFakeTimers();
1302
+ vi.stubGlobal('fetch', vi.fn((url, init) => {
1303
+ if (url.includes('/api/taskforce/ui-state?key=workspace-sync')) {
1304
+ return Promise.resolve({
1305
+ ok: true,
1306
+ json: () => Promise.resolve({
1307
+ success: true,
1308
+ state: {
1309
+ version: 2,
1310
+ enabled: true,
1311
+ phase: 'active',
1312
+ pullCursor: null,
1313
+ pushBaseline: {
1314
+ taskIds: ['task-delete-hydrated-1'],
1315
+ taskWatermarks: [],
1316
+ initiativeWatermarks: [],
1317
+ workstreamWatermarks: [],
1318
+ aiProfileWatermarks: [],
1319
+ documentWatermarks: [],
1320
+ assetWatermarks: [],
1321
+ documentReviewSessionWatermarks: [],
1322
+ documentReviewCommentWatermarks: [],
1323
+ annotatedAttachmentSessionWatermarks: [],
1324
+ taskEventWatermarks: [],
1325
+ taxonomyStateFingerprint: 'fingerprint-a'
1326
+ }
1327
+ }
1328
+ })
1329
+ });
1330
+ }
1331
+ if (url.includes('/api/taskforce/ui-state') && String(init?.method || '').toUpperCase() === 'POST') {
1332
+ return Promise.resolve({ ok: true, json: () => Promise.resolve({ success: true }) });
1333
+ }
1334
+ return Promise.resolve({ ok: true, json: () => Promise.resolve({ success: true }) });
1335
+ }));
1336
+ runWorkspacePushSyncServiceMock.mockResolvedValue({
1337
+ success: true,
1338
+ syncedAt: '2026-03-16T12:00:00.000Z',
1339
+ requestMs: 1,
1340
+ changeCount: 0,
1341
+ deleteCount: 1,
1342
+ currentTaskIds: new Set(),
1343
+ deleteTaskIds: new Set(['task-delete-hydrated-1']),
1344
+ currentDocumentPaths: new Set(),
1345
+ deleteDocumentPaths: new Set(),
1346
+ currentDocumentWatermarks: new Map(),
1347
+ currentAssetPaths: new Set(),
1348
+ deleteAssetPaths: new Set(),
1349
+ currentAssetWatermarks: new Map(),
1350
+ currentDocumentReviewSessionIds: new Set(),
1351
+ deleteDocumentReviewSessionIds: new Set(),
1352
+ currentDocumentReviewSessionWatermarks: new Map(),
1353
+ currentAnnotatedAttachmentSessionIds: new Set(),
1354
+ deleteAnnotatedAttachmentSessionIds: new Set(),
1355
+ currentAnnotatedAttachmentSessionWatermarks: new Map(),
1356
+ pushedWatermarks: new Map(),
1357
+ emittedEventIds: []
1358
+ });
1359
+ const { result, unmount } = renderHook((props) => useSyncOrchestrator(props), {
1360
+ initialProps: buildInput({
1361
+ tasks: [],
1362
+ deletedTasks: [{
1363
+ id: 'deleted-task-delete-hydrated-1',
1364
+ taskId: 'task-delete-hydrated-1',
1365
+ workspaceId: 'workspace-local-active',
1366
+ deletedAt: '2026-03-16T11:59:00.000Z',
1367
+ actor: 'user-1',
1368
+ actorType: 'human',
1369
+ source: 'ui',
1370
+ taskSnapshot: {
1371
+ id: 'task-delete-hydrated-1',
1372
+ title: 'Deleted before reload',
1373
+ status: 'task',
1374
+ createdAt: '2026-03-15T10:00:00.000Z',
1375
+ updatedAt: '2026-03-15T10:00:00.000Z'
1376
+ }
1377
+ }]
1378
+ })
1379
+ });
1380
+ await act(async () => {
1381
+ await result.current.loadWorkspaceSyncState();
1382
+ });
1383
+ act(() => {
1384
+ result.current.applyWorkspaceSyncStateSnapshot({
1385
+ enabled: true,
1386
+ phase: 'active',
1387
+ pullCursor: null
1388
+ });
1389
+ });
1390
+ await act(async () => {
1391
+ await vi.advanceTimersByTimeAsync(1600);
1392
+ await Promise.resolve();
1393
+ await Promise.resolve();
1394
+ });
1395
+ expect(runWorkspacePushSyncServiceMock.mock.calls.length).toBeGreaterThanOrEqual(1);
1396
+ const pushedChanges = runWorkspacePushSyncServiceMock.mock.calls
1397
+ .map((call) => call?.[0]?.payload?.changes)
1398
+ .filter(Array.isArray);
1399
+ expect(pushedChanges).toEqual(expect.arrayContaining([
1400
+ expect.arrayContaining([
1401
+ expect.objectContaining({
1402
+ op: 'delete',
1403
+ taskId: 'task-delete-hydrated-1',
1404
+ deletedAt: '2026-03-16T11:59:00.000Z'
1405
+ })
1406
+ ])
1407
+ ]));
1003
1408
  unmount();
1004
1409
  });
1005
1410
  it('finishes attach-cloud bootstrap locally even if persisting the active phase fails', async () => {
@@ -1614,6 +2019,8 @@ describe('useSyncOrchestrator', () => {
1614
2019
  ])
1615
2020
  })
1616
2021
  ]));
2022
+ const persisted = JSON.parse(String(localStorage.getItem('taskforce.syncWatermarks.v3.workspace-local-active')));
2023
+ expect(persisted.aiProfileWatermarks).toEqual([['ai-profile-codex', '2026-03-15T18:00:00.000Z']]);
1617
2024
  expect(result.current.workspaceSyncPendingChanges).toBe(0);
1618
2025
  unmount();
1619
2026
  });
@@ -102,8 +102,14 @@ export function useTaskData({ tasks, archivedTasks, setTasks, setArchivedTasks,
102
102
  const ignoreAuthGuard = options?.ignoreAuthGuard === true;
103
103
  if (!ignoreAuthGuard && (shouldDeferProtectedApiCalls || shouldBlockProtectedApiCalls))
104
104
  return;
105
- if (!isSilent)
105
+ if (!isSilent) {
106
106
  setLoadingTasks(true);
107
+ }
108
+ else {
109
+ // Silent refreshes should not leave the board-level loading indicator active
110
+ // if they supersede a visible fetch that already turned it on.
111
+ setLoadingTasks(false);
112
+ }
107
113
  const requestWorkspaceId = String(getCurrentWorkspaceId() || '').trim();
108
114
  tasksAbortRef.current?.abort('superseded');
109
115
  const abortController = new AbortController();
@@ -155,9 +161,8 @@ export function useTaskData({ tasks, archivedTasks, setTasks, setArchivedTasks,
155
161
  const isCurrentRequest = tasksAbortRef.current === abortController;
156
162
  if (isCurrentRequest) {
157
163
  tasksAbortRef.current = null;
158
- }
159
- if (!isSilent && isCurrentRequest)
160
164
  setLoadingTasks(false);
165
+ }
161
166
  }
162
167
  }, [
163
168
  getTaskRevisionKey,
@@ -243,4 +243,49 @@ describe('useTaskData', () => {
243
243
  expect(setLoadingTasks).toHaveBeenLastCalledWith(false);
244
244
  expect(setLoadingTasks).toHaveBeenCalledTimes(3);
245
245
  });
246
+ it('clears loading when a silent tasks refresh replaces a visible fetch', async () => {
247
+ const firstRequest = makeControlledAbortableRequest({ tasks: [] });
248
+ const secondRequest = makeControlledAbortableRequest({ tasks: [] });
249
+ const fetchMock = vi.mocked(fetch);
250
+ const setLoadingTasks = vi.fn();
251
+ let requestCount = 0;
252
+ fetchMock.mockImplementation((_input, init) => {
253
+ const signal = init?.signal;
254
+ requestCount += 1;
255
+ if (requestCount === 1) {
256
+ firstRequest.attach(signal);
257
+ return firstRequest.promise;
258
+ }
259
+ secondRequest.attach(signal);
260
+ return secondRequest.promise;
261
+ });
262
+ const { result } = renderHook(() => useTaskData({
263
+ tasks: [],
264
+ archivedTasks: [],
265
+ setTasks: vi.fn(),
266
+ setArchivedTasks: vi.fn(),
267
+ setLoadingTasks,
268
+ getCurrentWorkspaceId: () => 'workspace-1',
269
+ workspaceResetKey: 'workspace-1',
270
+ shouldDeferProtectedApiCalls: false,
271
+ shouldBlockProtectedApiCalls: false,
272
+ handleUnauthorized: vi.fn(),
273
+ authRequiredForApi: false
274
+ }));
275
+ let firstPromise;
276
+ let secondPromise;
277
+ await act(async () => {
278
+ firstPromise = result.current.fetchTasks(false);
279
+ secondPromise = result.current.fetchTasks(true);
280
+ await Promise.resolve();
281
+ });
282
+ expect(setLoadingTasks).toHaveBeenNthCalledWith(1, true);
283
+ expect(setLoadingTasks).toHaveBeenNthCalledWith(2, false);
284
+ await act(async () => {
285
+ secondRequest.resolve();
286
+ await secondPromise;
287
+ await firstPromise;
288
+ });
289
+ expect(setLoadingTasks).toHaveBeenLastCalledWith(false);
290
+ });
246
291
  });
@@ -1,4 +1,4 @@
1
- import type { TaskforceConfig, TaskforceTheme, Comment, AttachmentItem, CategoryConfig, TaskItem, TaxonomyDefinition, Environment, TaskAssignee, TaskStatus, DeletedTaskRecord, InitiativeItem, WorkstreamItem, ChecklistItem } from '../types';
1
+ import type { TaskforceConfig, TaskforceTheme, Comment, AttachmentItem, CategoryConfig, TaskItem, TaxonomyDefinition, Environment, TaskAssignee, TaskStatus, DeletedTaskRecord, InitiativeItem, WorkstreamItem, ChecklistItem, PlanningBootstrapWorkstreamTaskSummary } from '../types';
2
2
  import { type FirstClassTaxonomyDisplayLabels } from '../shared/taxonomyState.js';
3
3
  import type { UiNotice } from '../utils/uiNotice';
4
4
  import type { TaskAssigneeOption } from '../utils/assignees';
@@ -37,6 +37,27 @@ interface RuntimeCapabilities {
37
37
  supportsAdminManagedSetupOverrides: boolean;
38
38
  supportsPackageScriptSetupOverrides: boolean;
39
39
  }
40
+ interface BootstrapStateSnapshot {
41
+ phase: BootstrapPhase;
42
+ auth: {
43
+ resolved: boolean;
44
+ pending: boolean;
45
+ };
46
+ config: {
47
+ loaded: boolean;
48
+ };
49
+ workspace: {
50
+ pending: boolean;
51
+ };
52
+ pending: boolean;
53
+ authPending: boolean;
54
+ appPending: boolean;
55
+ ready: boolean;
56
+ stalled: boolean;
57
+ subtitle: string;
58
+ error: string | null;
59
+ startedAt: number | null;
60
+ }
40
61
  interface WorkspaceSummary {
41
62
  id: string;
42
63
  slug?: string | null;
@@ -122,7 +143,7 @@ export declare function useTaskforce({ config, initialTaskId, onTaskCountChange,
122
143
  authUserDisplayName: string;
123
144
  authUserAvatarUrl: string;
124
145
  authWorkspaceId: string;
125
- userGlobalSyncStatus: "error" | "idle" | "disconnected" | "syncing";
146
+ userGlobalSyncStatus: "error" | "idle" | "syncing" | "disconnected";
126
147
  workspaceLastPullAt: string | null;
127
148
  workspaceLastPushAt: string | null;
128
149
  workspaceLastErrorAt: string | null;
@@ -152,6 +173,13 @@ export declare function useTaskforce({ config, initialTaskId, onTaskCountChange,
152
173
  pendingChanges: number;
153
174
  lastErrorMessage: string | null;
154
175
  recommendedAction: string;
176
+ pushBlockedReason: import("./sync/controlPlane").WorkspaceSyncBlockedReason | null;
177
+ pullBlockedReason: import("./sync/controlPlane").WorkspaceSyncBlockedReason | null;
178
+ retryBlockedReason: import("./sync/controlPlane").WorkspaceSyncBlockedReason | null;
179
+ repairActive: boolean;
180
+ pushInFlight: boolean;
181
+ pullInFlight: boolean;
182
+ retryPending: boolean;
155
183
  documentSnapshotCount: number;
156
184
  aiProfileSnapshotCount: number;
157
185
  aiProfileSnapshotRawCount: number;
@@ -185,6 +213,7 @@ export declare function useTaskforce({ config, initialTaskId, onTaskCountChange,
185
213
  enabled: boolean;
186
214
  phase?: import("../sync/workspaceSyncState").WorkspaceSyncPhase | null;
187
215
  }) => void>[0]) => void;
216
+ bootstrapState: BootstrapStateSnapshot;
188
217
  authSessionResolved: boolean;
189
218
  workspaceBootstrapPending: boolean;
190
219
  bootstrapPhase: BootstrapPhase;
@@ -242,6 +271,31 @@ export declare function useTaskforce({ config, initialTaskId, onTaskCountChange,
242
271
  code?: string;
243
272
  workspaceSetupRequired?: boolean;
244
273
  }>;
274
+ beginOAuthLogin: (provider: string, returnTo?: string, inviteToken?: string) => void;
275
+ availableAuthProviders: string[];
276
+ fetchLoginMethods: () => Promise<{
277
+ success: boolean;
278
+ error?: string;
279
+ methods?: Array<{
280
+ provider: string;
281
+ providerEmail: string | null;
282
+ displayNameSnapshot: string | null;
283
+ avatarUrlSnapshot: string | null;
284
+ linkedAt: string | null;
285
+ lastLoginAt: string | null;
286
+ }>;
287
+ }>;
288
+ unlinkLoginMethod: (provider: string) => Promise<{
289
+ success: boolean;
290
+ error?: string;
291
+ code?: string;
292
+ }>;
293
+ addPasswordToAccount: (password: string) => Promise<{
294
+ success: boolean;
295
+ error?: string;
296
+ code?: string;
297
+ }>;
298
+ beginOAuthLink: (provider: string, returnTo?: string) => void;
245
299
  registerWithCredentials: (email: string, password: string, options?: {
246
300
  displayName?: string | null;
247
301
  planId?: string | null;
@@ -312,6 +366,8 @@ export declare function useTaskforce({ config, initialTaskId, onTaskCountChange,
312
366
  workspaceId?: string;
313
367
  inviteeKind?: "existing_user" | "new_user";
314
368
  passwordRequired?: boolean;
369
+ inviteeState?: "pending_setup" | "existing_account";
370
+ availableMethods?: string[];
315
371
  }>;
316
372
  acceptInviteWithToken: (token: string, password: string) => Promise<{
317
373
  success: boolean;
@@ -356,6 +412,7 @@ export declare function useTaskforce({ config, initialTaskId, onTaskCountChange,
356
412
  archivedTasks: TaskItem[];
357
413
  initiatives: InitiativeItem[];
358
414
  workstreams: WorkstreamItem[];
415
+ planningBootstrapTaskSummaries: PlanningBootstrapWorkstreamTaskSummary[];
359
416
  deletedTasks: DeletedTaskRecord[];
360
417
  activeCategories: CategoryConfig[];
361
418
  activeTypes: {
@@ -394,6 +451,7 @@ export declare function useTaskforce({ config, initialTaskId, onTaskCountChange,
394
451
  setFilterAssignees: (nextValues: TaskAssignee[] | ((prev: TaskAssignee[]) => TaskAssignee[])) => void;
395
452
  filterTaxonomies: Record<string, (string | number)[]>;
396
453
  setFilterTaxonomies: import("react").Dispatch<import("react").SetStateAction<Record<string, (string | number)[]>>>;
454
+ hasInitedFilters: boolean;
397
455
  sortBy: import("../utils/taxonomySorting").TaskSortKey;
398
456
  setSortBy: import("react").Dispatch<import("react").SetStateAction<import("../utils/taxonomySorting").TaskSortKey>>;
399
457
  sortOrder: "asc" | "desc";