@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
@@ -2,29 +2,60 @@ import { useCallback, useEffect } from 'react';
2
2
  import { createDefaultAssigneeOptions, createWorkspaceAssigneeOptions, mergeAssigneeOptions } from '../../utils/assignees';
3
3
  import { hasWorkspaceTaxonomyStatePayload, normalizeWorkspaceTaxonomyStatePayload } from '../../shared/taxonomyState.js';
4
4
  import { logBootstrapDebug, readPersistedWorkspaceId } from './workspaceLocalState';
5
+ function getBootstrapTimestamp() {
6
+ return typeof performance !== 'undefined' ? performance.now() : Date.now();
7
+ }
5
8
  export function useTaskforceWorkspaceBootstrap(args) {
6
- const { shouldDeferProtectedApiCalls, shouldBlockProtectedApiCalls, getWorkspaceRequestState, isWorkspaceRequestStale, isWorkspaceEpochStale, isAbortError, isBootstrapTimeoutError, fetchWithTimeout, handleUnauthorized, applyBootstrapConfig, loadPersistedUiState, fetchBuildInfo, markBootstrapPhase, markBootstrapStalled, fetchWorkflows, fetchInitiativeTemplates, loadAvailableEnvironments, setReferenceDataLoaded, setCustomCategories, setCustomTypes, setPriorities, setTaxonomies, setTaxonomyDisplayLabels, setConfigLoaded, hasLoadedUiStateRef, currentWorkspaceIdRef, referenceDataRequestRef, referenceDataAbortRef, bootstrapConfigAbortRef, workspaceListAbortRef, assigneeOptionsAbortRef, workspaceListHydratedRef, setAvailableWorkspaces, runtimeMode, applyResolvedWorkspaceId, workspaceSwitchingEnabled, authSessionResolved, isAuthenticated, authUserId, setHydratedWorkspaceRole, setAssigneeOptions, setAssigneeOptionsLoaded, commitCurrentWorkspaceId, currentWorkspaceId, workspaceSelectionScope, abortWorkspaceScopedRequests, setWorkspaceBootstrapPending, checkAuthSession, lastConfigRefreshKeyRef, lastAssigneeOptionsLoadKeyRef, lastWorkspaceSyncStateLoadKeyRef, lastTaskSurfaceLoadKeyRef, lastSettingsSurfaceLoadKeyRef, isOpen, activeTab, showArchive, taskScope, settingsSection, fetchTasks, fetchArchive, fetchPlanningEntities, refreshTaskCollections, loadWorkspaceSyncState, archiveBootstrapTimerRef, hasBootstrappedDataRef } = args;
9
+ const { shouldDeferProtectedApiCalls, shouldBlockProtectedApiCalls, getWorkspaceRequestState, isWorkspaceRequestStale, isWorkspaceEpochStale, isAbortError, isBootstrapTimeoutError, fetchWithTimeout, handleUnauthorized, applyBootstrapConfig, loadPersistedUiState, fetchBuildInfo, markBootstrapPhase, markBootstrapStalled, fetchWorkflows, fetchInitiativeTemplates, loadAvailableEnvironments, setReferenceDataLoaded, setCustomCategories, setCustomTypes, setPriorities, setTaxonomies, setTaxonomyDisplayLabels, setConfigLoaded, hasLoadedUiStateRef, currentWorkspaceIdRef, referenceDataRequestRef, referenceDataAbortRef, bootstrapConfigAbortRef, workspaceListAbortRef, assigneeOptionsAbortRef, workspaceListHydratedRef, setAvailableWorkspaces, runtimeMode, applyResolvedWorkspaceId, workspaceSwitchingEnabled, authSessionResolved, isAuthenticated, authUserId, authUserAvatarUrl, setHydratedWorkspaceRole, setAssigneeOptions, setAssigneeOptionsLoaded, commitCurrentWorkspaceId, currentWorkspaceId, workspaceSelectionScope, abortWorkspaceScopedRequests, setWorkspaceBootstrapPending, checkAuthSession, lastConfigRefreshKeyRef, lastAssigneeOptionsLoadKeyRef, lastWorkspaceSyncStateLoadKeyRef, lastTaskSurfaceLoadKeyRef, lastSettingsSurfaceLoadKeyRef, isOpen, activeTab, showArchive, taskScope, settingsSection, workspaceBootstrapPending, fetchTasks, fetchArchive, fetchPlanningEntities, refreshTaskCollections, loadWorkspaceSyncState, archiveBootstrapTimerRef, hasBootstrappedDataRef } = args;
7
10
  const fetchReferenceData = useCallback(async (options) => {
8
11
  const ignoreAuthGuard = options?.ignoreAuthGuard === true;
9
12
  const force = options?.force === true;
10
- if (!ignoreAuthGuard && (shouldDeferProtectedApiCalls || shouldBlockProtectedApiCalls))
13
+ if (!ignoreAuthGuard && (shouldDeferProtectedApiCalls || shouldBlockProtectedApiCalls)) {
14
+ logBootstrapDebug('bootstrap_reference_data_skipped', {
15
+ reason: shouldBlockProtectedApiCalls ? 'auth_blocked' : 'auth_deferred',
16
+ runtimeMode,
17
+ workspaceId: String(getWorkspaceRequestState().workspaceId || '').trim() || 'default',
18
+ force
19
+ });
11
20
  return;
21
+ }
12
22
  const requestState = getWorkspaceRequestState();
23
+ const normalizedWorkspaceId = String(requestState.workspaceId || '').trim() || 'default';
24
+ const cloudWorkspaceResolved = runtimeMode !== 'cloud'
25
+ || !authSessionResolved
26
+ || !isAuthenticated
27
+ || (normalizedWorkspaceId !== '' && normalizedWorkspaceId !== 'default');
28
+ if (!cloudWorkspaceResolved) {
29
+ logBootstrapDebug('bootstrap_reference_data_skipped', {
30
+ reason: 'workspace_unresolved',
31
+ runtimeMode,
32
+ workspaceId: normalizedWorkspaceId,
33
+ force
34
+ });
35
+ return;
36
+ }
13
37
  if (!force && referenceDataRequestRef.current?.workspaceId === requestState.workspaceId) {
38
+ logBootstrapDebug('bootstrap_reference_data_reused', {
39
+ workspaceId: normalizedWorkspaceId,
40
+ force
41
+ });
14
42
  await referenceDataRequestRef.current.promise;
15
43
  return;
16
44
  }
17
45
  setReferenceDataLoaded(false);
46
+ const startedAt = getBootstrapTimestamp();
18
47
  const abortController = new AbortController();
19
48
  referenceDataAbortRef.current = abortController;
20
49
  const request = (async () => {
21
50
  await Promise.allSettled([
22
51
  (async () => {
52
+ let source = 'empty-taxonomy-state';
23
53
  const taxonomyRes = await fetch('/api/taskforce/taxonomy-state', { signal: abortController.signal });
24
54
  if (!taxonomyRes.ok)
25
55
  return;
26
56
  const taxonomyData = await taxonomyRes.json().catch(() => ({}));
27
57
  if (!hasWorkspaceTaxonomyStatePayload(taxonomyData)) {
58
+ source = 'fallback-endpoints';
28
59
  const [catRes, typeRes, priorityRes, taxRes] = await Promise.all([
29
60
  fetch('/api/taskforce/categories', { signal: abortController.signal }),
30
61
  fetch('/api/taskforce/types', { signal: abortController.signal }),
@@ -42,9 +73,17 @@ export function useTaskforceWorkspaceBootstrap(args) {
42
73
  taxonomyData.priorities = priorityData.priorities;
43
74
  taxonomyData.taxonomies = taxData.taxonomies;
44
75
  }
76
+ else {
77
+ source = 'taxonomy-state';
78
+ }
45
79
  const normalized = normalizeWorkspaceTaxonomyStatePayload(taxonomyData);
46
- if (isWorkspaceRequestStale(requestState))
80
+ if (isWorkspaceRequestStale(requestState)) {
81
+ logBootstrapDebug('bootstrap_reference_data_stale_drop', {
82
+ workspaceId: normalizedWorkspaceId,
83
+ source
84
+ });
47
85
  return;
86
+ }
48
87
  if (normalized.categories.length > 0)
49
88
  setCustomCategories(normalized.categories);
50
89
  if (normalized.types.length > 0)
@@ -53,6 +92,14 @@ export function useTaskforceWorkspaceBootstrap(args) {
53
92
  setPriorities(normalized.priorities);
54
93
  setTaxonomies(normalized.taxonomies);
55
94
  setTaxonomyDisplayLabels(normalized.displayLabels || {});
95
+ logBootstrapDebug('bootstrap_reference_data_source', {
96
+ workspaceId: normalizedWorkspaceId,
97
+ source,
98
+ categories: normalized.categories.length,
99
+ types: normalized.types.length,
100
+ priorities: normalized.priorities.length,
101
+ taxonomies: normalized.taxonomies.length
102
+ });
56
103
  })(),
57
104
  fetchWorkflows(),
58
105
  fetchInitiativeTemplates(),
@@ -61,6 +108,11 @@ export function useTaskforceWorkspaceBootstrap(args) {
61
108
  if (isWorkspaceRequestStale(requestState))
62
109
  return;
63
110
  setReferenceDataLoaded(true);
111
+ logBootstrapDebug('bootstrap_reference_data_loaded', {
112
+ durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt)),
113
+ workspaceId: normalizedWorkspaceId,
114
+ force
115
+ });
64
116
  })();
65
117
  referenceDataRequestRef.current = { workspaceId: requestState.workspaceId, promise: request };
66
118
  try {
@@ -72,13 +124,14 @@ export function useTaskforceWorkspaceBootstrap(args) {
72
124
  if (referenceDataAbortRef.current === abortController)
73
125
  referenceDataAbortRef.current = null;
74
126
  }
75
- }, [fetchInitiativeTemplates, fetchWorkflows, getWorkspaceRequestState, isWorkspaceRequestStale, loadAvailableEnvironments, referenceDataAbortRef, referenceDataRequestRef, setCustomCategories, setCustomTypes, setPriorities, setReferenceDataLoaded, setTaxonomies, setTaxonomyDisplayLabels, shouldBlockProtectedApiCalls, shouldDeferProtectedApiCalls]);
127
+ }, [authSessionResolved, fetchInitiativeTemplates, fetchWorkflows, getWorkspaceRequestState, isAuthenticated, isWorkspaceRequestStale, loadAvailableEnvironments, referenceDataAbortRef, referenceDataRequestRef, runtimeMode, setCustomCategories, setCustomTypes, setPriorities, setReferenceDataLoaded, setTaxonomies, setTaxonomyDisplayLabels, shouldBlockProtectedApiCalls, shouldDeferProtectedApiCalls]);
76
128
  const fetchBootstrapConfig = useCallback(async (options) => {
77
129
  const ignoreAuthGuard = options?.ignoreAuthGuard === true;
78
130
  if (!ignoreAuthGuard && (shouldDeferProtectedApiCalls || shouldBlockProtectedApiCalls))
79
131
  return;
80
132
  markBootstrapPhase('config');
81
133
  const requestState = getWorkspaceRequestState();
134
+ const startedAt = getBootstrapTimestamp();
82
135
  const abortController = new AbortController();
83
136
  bootstrapConfigAbortRef.current = abortController;
84
137
  try {
@@ -114,6 +167,11 @@ export function useTaskforceWorkspaceBootstrap(args) {
114
167
  }
115
168
  setConfigLoaded(true);
116
169
  markBootstrapPhase('ready');
170
+ logBootstrapDebug('bootstrap_config_loaded', {
171
+ durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt)),
172
+ status: res.status,
173
+ workspaceId: configResolvedWorkspaceId || requestState.workspaceId
174
+ });
117
175
  void fetchBuildInfo();
118
176
  }
119
177
  catch (error) {
@@ -125,6 +183,11 @@ export function useTaskforceWorkspaceBootstrap(args) {
125
183
  }
126
184
  markBootstrapStalled(isBootstrapTimeoutError(error) ? 'Startup checks timed out.' : 'Unable to finish startup checks.');
127
185
  setConfigLoaded(true);
186
+ logBootstrapDebug('bootstrap_config_failed', {
187
+ durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt)),
188
+ workspaceId: requestState.workspaceId,
189
+ error: error instanceof Error ? error.message : String(error)
190
+ });
128
191
  }
129
192
  finally {
130
193
  if (bootstrapConfigAbortRef.current === abortController)
@@ -135,6 +198,16 @@ export function useTaskforceWorkspaceBootstrap(args) {
135
198
  await fetchBootstrapConfig(options);
136
199
  await fetchReferenceData(options);
137
200
  }, [fetchBootstrapConfig, fetchReferenceData]);
201
+ const scheduleDeferredArchiveBootstrap = useCallback(() => {
202
+ if (typeof window === 'undefined')
203
+ return;
204
+ if (archiveBootstrapTimerRef.current !== null)
205
+ window.clearTimeout(archiveBootstrapTimerRef.current);
206
+ archiveBootstrapTimerRef.current = window.setTimeout(() => {
207
+ archiveBootstrapTimerRef.current = null;
208
+ void fetchArchive(true).then(() => logBootstrapDebug('bootstrap_archive_loaded_deferred', {}));
209
+ }, 1500);
210
+ }, [archiveBootstrapTimerRef, fetchArchive]);
138
211
  const fetchWorkspaces = useCallback(async () => {
139
212
  if (!workspaceSwitchingEnabled) {
140
213
  setAvailableWorkspaces([]);
@@ -142,6 +215,7 @@ export function useTaskforceWorkspaceBootstrap(args) {
142
215
  return { success: true, workspaces: [] };
143
216
  }
144
217
  const requestState = getWorkspaceRequestState();
218
+ const startedAt = getBootstrapTimestamp();
145
219
  const abortController = new AbortController();
146
220
  workspaceListAbortRef.current = abortController;
147
221
  try {
@@ -177,6 +251,12 @@ export function useTaskforceWorkspaceBootstrap(args) {
177
251
  if (runtimeMode !== 'local' && typeof data?.currentWorkspaceId === 'string' && data.currentWorkspaceId.trim().length > 0) {
178
252
  applyResolvedWorkspaceId(data.currentWorkspaceId.trim(), { preserveNonDefaultDefault: true });
179
253
  }
254
+ logBootstrapDebug('bootstrap_workspaces_loaded', {
255
+ durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt)),
256
+ workspaceId: requestState.workspaceId,
257
+ count: workspaces.length,
258
+ status: res.status
259
+ });
180
260
  return { success: true, workspaces };
181
261
  }
182
262
  catch (error) {
@@ -184,6 +264,11 @@ export function useTaskforceWorkspaceBootstrap(args) {
184
264
  markBootstrapStalled('Startup checks timed out.');
185
265
  setAvailableWorkspaces([]);
186
266
  workspaceListHydratedRef.current = false;
267
+ logBootstrapDebug('bootstrap_workspaces_failed', {
268
+ durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt)),
269
+ workspaceId: requestState.workspaceId,
270
+ error: error instanceof Error ? error.message : String(error)
271
+ });
187
272
  return { success: false, error: isAbortError(error) ? 'Workspace list request aborted.' : 'Failed to load workspaces.' };
188
273
  }
189
274
  finally {
@@ -193,6 +278,7 @@ export function useTaskforceWorkspaceBootstrap(args) {
193
278
  }, [applyResolvedWorkspaceId, fetchWithTimeout, getWorkspaceRequestState, isAbortError, isBootstrapTimeoutError, isWorkspaceEpochStale, markBootstrapStalled, runtimeMode, setAvailableWorkspaces, workspaceListAbortRef, workspaceListHydratedRef, workspaceSwitchingEnabled]);
194
279
  const fetchAssigneeOptions = useCallback(async () => {
195
280
  const requestState = getWorkspaceRequestState();
281
+ const startedAt = getBootstrapTimestamp();
196
282
  const abortController = new AbortController();
197
283
  assigneeOptionsAbortRef.current = abortController;
198
284
  setAssigneeOptionsLoaded(false);
@@ -218,6 +304,19 @@ export function useTaskforceWorkspaceBootstrap(args) {
218
304
  setAssigneeOptionsLoaded(true);
219
305
  return { success: false, error: data?.error || `Failed to load assignee options (${assigneeResult.status})` };
220
306
  }
307
+ const normalizedAuthUserId = String(authUserId || '').trim();
308
+ const currentUserAvatarUrl = String(authUserAvatarUrl || '').trim();
309
+ const resolveMemberAvatarUrl = (candidate, fallbackValue) => {
310
+ const candidateAvatarUrl = typeof candidate?.avatarUrl === 'string' && candidate.avatarUrl.trim().length > 0
311
+ ? candidate.avatarUrl.trim()
312
+ : '';
313
+ if (candidateAvatarUrl)
314
+ return candidateAvatarUrl;
315
+ const candidateUserId = String(candidate?.userId || fallbackValue || '').trim();
316
+ return normalizedAuthUserId && candidateUserId === normalizedAuthUserId && currentUserAvatarUrl
317
+ ? currentUserAvatarUrl
318
+ : null;
319
+ };
221
320
  const assignees = Array.isArray(data?.assignees) ? data.assignees : [];
222
321
  const directOptions = assignees.map((entry) => {
223
322
  const value = String(entry?.value || '').trim();
@@ -225,21 +324,35 @@ export function useTaskforceWorkspaceBootstrap(args) {
225
324
  if (!value)
226
325
  return null;
227
326
  if (kindRaw === 'agent' || kindRaw === 'ai')
228
- return { value, label: String(entry?.label || value).trim() || value, icon: String(entry?.icon || 'Bot'), color: String(entry?.color || '#8b5cf6'), kind: 'agent' };
327
+ return {
328
+ value,
329
+ label: String(entry?.label || value).trim() || value,
330
+ icon: String(entry?.icon || 'Bot'),
331
+ color: String(entry?.color || '#8b5cf6'),
332
+ kind: 'agent',
333
+ avatarUrl: typeof entry?.avatarUrl === 'string' && entry.avatarUrl.trim().length > 0 ? entry.avatarUrl.trim() : null
334
+ };
229
335
  if (kindRaw === 'member' || kindRaw === 'human')
230
- return { value, label: String(entry?.label || value).trim() || value, icon: String(entry?.icon || 'User'), color: String(entry?.color || '#22c55e'), kind: 'member' };
336
+ return {
337
+ value,
338
+ label: String(entry?.label || value).trim() || value,
339
+ icon: String(entry?.icon || 'User'),
340
+ color: String(entry?.color || '#22c55e'),
341
+ kind: 'member',
342
+ avatarUrl: resolveMemberAvatarUrl(entry, value)
343
+ };
231
344
  return null;
232
345
  }).filter(Boolean);
233
346
  const fallbackCandidates = assignees.map((candidate) => ({
234
347
  userId: String(candidate?.userId || '').trim(),
235
348
  email: String(candidate?.email || '').trim().toLowerCase(),
236
- displayName: typeof candidate?.displayName === 'string' ? candidate.displayName : null
349
+ displayName: typeof candidate?.displayName === 'string' ? candidate.displayName : null,
350
+ avatarUrl: resolveMemberAvatarUrl(candidate)
237
351
  })).filter((candidate) => candidate.userId);
238
352
  let memberCandidates = fallbackCandidates;
239
353
  if (workspaceMembersResult?.ok) {
240
354
  const workspaceMembersData = await workspaceMembersResult.json().catch(() => ({}));
241
355
  const users = Array.isArray(workspaceMembersData?.users) ? workspaceMembersData.users : [];
242
- const normalizedAuthUserId = String(authUserId || '').trim();
243
356
  const currentMember = users.find((candidate) => String(candidate?.userId || '').trim() === normalizedAuthUserId);
244
357
  const currentMemberRole = String(currentMember?.role || '').trim().toLowerCase();
245
358
  if (currentMemberRole === 'owner' || currentMemberRole === 'admin' || currentMemberRole === 'member' || currentMemberRole === 'read-only') {
@@ -251,7 +364,8 @@ export function useTaskforceWorkspaceBootstrap(args) {
251
364
  const workspaceMemberCandidates = users.map((candidate) => ({
252
365
  userId: String(candidate?.userId || '').trim(),
253
366
  email: String(candidate?.email || '').trim().toLowerCase(),
254
- displayName: typeof candidate?.displayName === 'string' ? candidate.displayName : null
367
+ displayName: typeof candidate?.displayName === 'string' ? candidate.displayName : null,
368
+ avatarUrl: resolveMemberAvatarUrl(candidate)
255
369
  })).filter((candidate) => candidate.userId);
256
370
  memberCandidates = Array.from(new Map([...fallbackCandidates, ...workspaceMemberCandidates].map((candidate) => [candidate.userId, candidate])).values());
257
371
  }
@@ -263,6 +377,11 @@ export function useTaskforceWorkspaceBootstrap(args) {
263
377
  return { success: false, error: 'Workspace changed while loading assignee options.' };
264
378
  setAssigneeOptions(merged);
265
379
  setAssigneeOptionsLoaded(true);
380
+ logBootstrapDebug('bootstrap_assignee_options_loaded', {
381
+ durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt)),
382
+ workspaceId: requestState.workspaceId,
383
+ count: merged.length
384
+ });
266
385
  return { success: true };
267
386
  }
268
387
  catch (error) {
@@ -270,20 +389,32 @@ export function useTaskforceWorkspaceBootstrap(args) {
270
389
  setAssigneeOptions(createDefaultAssigneeOptions());
271
390
  setAssigneeOptionsLoaded(true);
272
391
  }
392
+ logBootstrapDebug('bootstrap_assignee_options_failed', {
393
+ durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt)),
394
+ workspaceId: requestState.workspaceId,
395
+ error: error instanceof Error ? error.message : String(error)
396
+ });
273
397
  return { success: false, error: isAbortError(error) ? 'Assignee options request aborted.' : 'Failed to load assignee options.' };
274
398
  }
275
399
  finally {
276
400
  if (assigneeOptionsAbortRef.current === abortController)
277
401
  assigneeOptionsAbortRef.current = null;
278
402
  }
279
- }, [assigneeOptionsAbortRef, authSessionResolved, authUserId, fetchWithTimeout, getWorkspaceRequestState, isAbortError, isAuthenticated, isWorkspaceRequestStale, setAssigneeOptions, setAssigneeOptionsLoaded, setHydratedWorkspaceRole, workspaceSwitchingEnabled]);
403
+ }, [assigneeOptionsAbortRef, authSessionResolved, authUserAvatarUrl, authUserId, fetchWithTimeout, getWorkspaceRequestState, isAbortError, isAuthenticated, isWorkspaceRequestStale, setAssigneeOptions, setAssigneeOptionsLoaded, setHydratedWorkspaceRole, workspaceSwitchingEnabled]);
280
404
  const switchWorkspace = useCallback(async (workspaceId, options) => {
281
405
  if (!workspaceSwitchingEnabled)
282
406
  return { success: false, error: 'Workspace switching is unavailable in local mode.', code: 'WORKSPACE_SWITCHING_DISABLED' };
283
407
  const normalizedWorkspaceId = String(workspaceId || '').trim();
284
408
  if (!normalizedWorkspaceId)
285
409
  return { success: false, error: 'workspaceId is required.' };
410
+ const previousWorkspaceId = String(currentWorkspaceIdRef.current || '').trim() || 'default';
411
+ const startedAt = getBootstrapTimestamp();
286
412
  try {
413
+ logBootstrapDebug('bootstrap_workspace_switch_started', {
414
+ fromWorkspaceId: previousWorkspaceId,
415
+ toWorkspaceId: normalizedWorkspaceId,
416
+ hydrate: options?.hydrate !== false
417
+ });
287
418
  const res = await fetch('/api/taskforce/session/workspace', {
288
419
  method: 'POST',
289
420
  headers: { 'Content-Type': 'application/json' },
@@ -309,17 +440,36 @@ export function useTaskforceWorkspaceBootstrap(args) {
309
440
  lastTaskSurfaceLoadKeyRef.current = `${normalizedWorkspaceId}:${activeTab}:${showArchive ? 'archive' : 'active'}:${taskScope}`;
310
441
  if (isOpen && activeTab === 'settings')
311
442
  lastSettingsSurfaceLoadKeyRef.current = `${normalizedWorkspaceId}:${activeTab}:${settingsSection}`;
312
- await Promise.all([fetchConfig(), fetchWorkspaces(), refreshTaskCollections({ isSilent: false }), fetchAssigneeOptions(), loadWorkspaceSyncState()]);
443
+ await Promise.all([
444
+ fetchConfig(),
445
+ fetchWorkspaces(),
446
+ refreshTaskCollections({ isSilent: false }),
447
+ loadWorkspaceSyncState()
448
+ ]);
449
+ void fetchPlanningEntities({ ignoreAuthGuard: true });
313
450
  }
451
+ logBootstrapDebug('bootstrap_workspace_switch_completed', {
452
+ fromWorkspaceId: previousWorkspaceId,
453
+ toWorkspaceId: normalizedWorkspaceId,
454
+ hydrate: options?.hydrate !== false,
455
+ durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt))
456
+ });
314
457
  return { success: true };
315
458
  }
316
- catch {
459
+ catch (error) {
460
+ logBootstrapDebug('bootstrap_workspace_switch_failed', {
461
+ fromWorkspaceId: previousWorkspaceId,
462
+ toWorkspaceId: normalizedWorkspaceId,
463
+ hydrate: options?.hydrate !== false,
464
+ durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt)),
465
+ error: error instanceof Error ? error.message : String(error)
466
+ });
317
467
  return { success: false, error: 'Failed to switch workspace.' };
318
468
  }
319
469
  finally {
320
470
  setWorkspaceBootstrapPending(false);
321
471
  }
322
- }, [abortWorkspaceScopedRequests, activeTab, checkAuthSession, commitCurrentWorkspaceId, fetchAssigneeOptions, fetchConfig, fetchWorkspaces, isOpen, lastAssigneeOptionsLoadKeyRef, lastConfigRefreshKeyRef, lastSettingsSurfaceLoadKeyRef, lastTaskSurfaceLoadKeyRef, lastWorkspaceSyncStateLoadKeyRef, loadWorkspaceSyncState, markBootstrapPhase, refreshTaskCollections, runtimeMode, settingsSection, setWorkspaceBootstrapPending, showArchive, taskScope, workspaceSelectionScope, workspaceSwitchingEnabled]);
472
+ }, [abortWorkspaceScopedRequests, activeTab, checkAuthSession, commitCurrentWorkspaceId, currentWorkspaceIdRef, fetchConfig, fetchPlanningEntities, fetchWorkspaces, isOpen, lastAssigneeOptionsLoadKeyRef, lastConfigRefreshKeyRef, lastSettingsSurfaceLoadKeyRef, lastTaskSurfaceLoadKeyRef, lastWorkspaceSyncStateLoadKeyRef, loadWorkspaceSyncState, markBootstrapPhase, refreshTaskCollections, runtimeMode, settingsSection, setWorkspaceBootstrapPending, showArchive, taskScope, workspaceSelectionScope, workspaceSwitchingEnabled]);
323
473
  const resolveWorkspaceAfterAuth = useCallback(async (options) => {
324
474
  markBootstrapPhase('workspace');
325
475
  setWorkspaceBootstrapPending(true);
@@ -366,59 +516,188 @@ export function useTaskforceWorkspaceBootstrap(args) {
366
516
  }, [commitCurrentWorkspaceId, currentWorkspaceId, currentWorkspaceIdRef, fetchWorkspaces, markBootstrapPhase, markBootstrapStalled, setWorkspaceBootstrapPending, switchWorkspace, workspaceSelectionScope, workspaceSwitchingEnabled]);
367
517
  const retryBootstrapChecks = useCallback(async () => {
368
518
  markBootstrapPhase('auth');
519
+ const startedAt = getBootstrapTimestamp();
520
+ logBootstrapDebug('bootstrap_retry_started', {
521
+ workspaceId: String(currentWorkspaceIdRef.current || 'default').trim() || 'default'
522
+ });
369
523
  const authenticated = await checkAuthSession({ force: true });
524
+ let workspaceSetupRequired = false;
370
525
  if (workspaceSwitchingEnabled && authenticated) {
371
526
  const workspaceResolution = await resolveWorkspaceAfterAuth();
372
527
  if (!workspaceResolution.success || workspaceResolution.workspaceSetupRequired) {
373
528
  await fetchConfig({ ignoreAuthGuard: true });
529
+ logBootstrapDebug('bootstrap_retry_completed', {
530
+ workspaceId: String(currentWorkspaceIdRef.current || 'default').trim() || 'default',
531
+ authenticated,
532
+ workspaceSetupRequired: workspaceResolution.workspaceSetupRequired === true,
533
+ success: workspaceResolution.success,
534
+ durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt))
535
+ });
374
536
  return;
375
537
  }
376
538
  }
377
- await fetchConfig({ ignoreAuthGuard: true });
378
- }, [checkAuthSession, fetchConfig, markBootstrapPhase, resolveWorkspaceAfterAuth, workspaceSwitchingEnabled]);
539
+ setWorkspaceBootstrapPending(true);
540
+ try {
541
+ await fetchConfig({ ignoreAuthGuard: true });
542
+ if (authenticated && !workspaceSetupRequired) {
543
+ await Promise.all([
544
+ fetchTasks(true, { ignoreAuthGuard: true }),
545
+ fetchReferenceData({ ignoreAuthGuard: true, force: true })
546
+ ]);
547
+ void fetchPlanningEntities({ ignoreAuthGuard: true });
548
+ }
549
+ logBootstrapDebug('bootstrap_retry_completed', {
550
+ workspaceId: String(currentWorkspaceIdRef.current || 'default').trim() || 'default',
551
+ authenticated,
552
+ workspaceSetupRequired,
553
+ success: true,
554
+ durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt))
555
+ });
556
+ }
557
+ finally {
558
+ setWorkspaceBootstrapPending(false);
559
+ }
560
+ }, [checkAuthSession, currentWorkspaceIdRef, fetchConfig, fetchPlanningEntities, fetchReferenceData, fetchTasks, markBootstrapPhase, resolveWorkspaceAfterAuth, setWorkspaceBootstrapPending, workspaceSwitchingEnabled]);
561
+ const runCloudBootstrap = useCallback(async (options) => {
562
+ const reason = options?.reason || 'initial-load';
563
+ const ignoreAuthGuard = options?.ignoreAuthGuard === true;
564
+ const tasksSilent = options?.tasksSilent !== false;
565
+ const includeDeferredArchive = options?.includeDeferredArchive !== false;
566
+ const startedAt = getBootstrapTimestamp();
567
+ markBootstrapPhase('auth');
568
+ const authenticated = await checkAuthSession({ force: true });
569
+ if (!authenticated) {
570
+ await fetchConfig({ ignoreAuthGuard: true });
571
+ logBootstrapDebug('cloud_bootstrap_completed', {
572
+ reason,
573
+ durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt)),
574
+ authenticated: false,
575
+ workspaceSetupRequired: false,
576
+ success: false
577
+ });
578
+ return { success: false, authenticated: false, workspaceSetupRequired: false, error: 'Sign in required.', code: 'AUTH_REQUIRED' };
579
+ }
580
+ if (workspaceSwitchingEnabled) {
581
+ const workspaceResolution = await resolveWorkspaceAfterAuth();
582
+ if (!workspaceResolution.success) {
583
+ await fetchConfig({ ignoreAuthGuard: true });
584
+ logBootstrapDebug('cloud_bootstrap_completed', {
585
+ reason,
586
+ durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt)),
587
+ authenticated: true,
588
+ workspaceSetupRequired: false,
589
+ success: false,
590
+ error: workspaceResolution.error || 'Workspace resolution failed.'
591
+ });
592
+ return {
593
+ success: false,
594
+ authenticated: true,
595
+ workspaceSetupRequired: false,
596
+ error: workspaceResolution.error || 'Unable to resolve workspace access.',
597
+ code: workspaceResolution.code
598
+ };
599
+ }
600
+ if (workspaceResolution.workspaceSetupRequired) {
601
+ await fetchConfig({ ignoreAuthGuard: true });
602
+ logBootstrapDebug('cloud_bootstrap_completed', {
603
+ reason,
604
+ durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt)),
605
+ authenticated: true,
606
+ workspaceSetupRequired: true,
607
+ success: true
608
+ });
609
+ return { success: true, authenticated: true, workspaceSetupRequired: true };
610
+ }
611
+ }
612
+ setWorkspaceBootstrapPending(true);
613
+ try {
614
+ await fetchBootstrapConfig({ ignoreAuthGuard });
615
+ await Promise.all([
616
+ fetchTasks(tasksSilent, { ignoreAuthGuard }),
617
+ fetchReferenceData({ ignoreAuthGuard })
618
+ ]);
619
+ void fetchPlanningEntities({ ignoreAuthGuard });
620
+ if (includeDeferredArchive) {
621
+ scheduleDeferredArchiveBootstrap();
622
+ }
623
+ logBootstrapDebug('cloud_bootstrap_completed', {
624
+ reason,
625
+ durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt)),
626
+ authenticated: true,
627
+ workspaceSetupRequired: false,
628
+ success: true,
629
+ workspaceId: String(currentWorkspaceIdRef.current || 'default').trim() || 'default'
630
+ });
631
+ return { success: true, authenticated: true, workspaceSetupRequired: false };
632
+ }
633
+ finally {
634
+ setWorkspaceBootstrapPending(false);
635
+ }
636
+ }, [
637
+ checkAuthSession,
638
+ currentWorkspaceIdRef,
639
+ fetchBootstrapConfig,
640
+ fetchPlanningEntities,
641
+ fetchReferenceData,
642
+ fetchTasks,
643
+ markBootstrapPhase,
644
+ resolveWorkspaceAfterAuth,
645
+ scheduleDeferredArchiveBootstrap,
646
+ setWorkspaceBootstrapPending,
647
+ workspaceSwitchingEnabled
648
+ ]);
379
649
  useEffect(() => {
380
650
  if (!shouldDeferProtectedApiCalls && !shouldBlockProtectedApiCalls && !hasBootstrappedDataRef.current) {
381
651
  hasBootstrappedDataRef.current = true;
382
652
  void (async () => {
653
+ const startedAt = getBootstrapTimestamp();
383
654
  if (runtimeMode === 'cloud' && authSessionResolved && isAuthenticated) {
384
- const workspaceResolution = await resolveWorkspaceAfterAuth();
385
- if (!workspaceResolution.success || workspaceResolution.workspaceSetupRequired) {
386
- await fetchBootstrapConfig();
387
- void fetchReferenceData();
655
+ const result = await runCloudBootstrap({
656
+ reason: 'initial-load',
657
+ tasksSilent: false,
658
+ includeDeferredArchive: true
659
+ });
660
+ if (!result.success || result.workspaceSetupRequired) {
388
661
  return;
389
662
  }
390
663
  }
391
- await fetchBootstrapConfig();
392
- await Promise.all([fetchTasks(false), fetchReferenceData(), fetchPlanningEntities()]);
393
- if (typeof window !== 'undefined') {
394
- if (archiveBootstrapTimerRef.current !== null)
395
- window.clearTimeout(archiveBootstrapTimerRef.current);
396
- archiveBootstrapTimerRef.current = window.setTimeout(() => {
397
- archiveBootstrapTimerRef.current = null;
398
- void fetchArchive(true).then(() => logBootstrapDebug('bootstrap_archive_loaded_deferred', {}));
399
- }, 1500);
664
+ else {
665
+ await Promise.all([
666
+ fetchBootstrapConfig(),
667
+ fetchTasks(false),
668
+ fetchReferenceData()
669
+ ]);
670
+ void fetchPlanningEntities();
671
+ }
672
+ if (runtimeMode !== 'cloud') {
673
+ scheduleDeferredArchiveBootstrap();
400
674
  }
675
+ logBootstrapDebug('bootstrap_initial_load_completed', {
676
+ durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt)),
677
+ runtimeMode,
678
+ workspaceId: String(currentWorkspaceIdRef.current || 'default').trim() || 'default'
679
+ });
401
680
  })();
402
681
  }
403
- }, [archiveBootstrapTimerRef, authSessionResolved, fetchArchive, fetchBootstrapConfig, fetchPlanningEntities, fetchReferenceData, fetchTasks, hasBootstrappedDataRef, isAuthenticated, resolveWorkspaceAfterAuth, runtimeMode, shouldBlockProtectedApiCalls, shouldDeferProtectedApiCalls]);
682
+ }, [authSessionResolved, currentWorkspaceIdRef, fetchBootstrapConfig, fetchPlanningEntities, fetchReferenceData, fetchTasks, hasBootstrappedDataRef, isAuthenticated, runCloudBootstrap, runtimeMode, scheduleDeferredArchiveBootstrap, shouldBlockProtectedApiCalls, shouldDeferProtectedApiCalls]);
404
683
  useEffect(() => {
405
- if (shouldDeferProtectedApiCalls || shouldBlockProtectedApiCalls || workspaceSelectionScope === 'bootstrap' || !hasBootstrappedDataRef.current)
684
+ if (shouldDeferProtectedApiCalls || shouldBlockProtectedApiCalls || workspaceBootstrapPending || workspaceSelectionScope === 'bootstrap' || !hasBootstrappedDataRef.current)
406
685
  return;
407
686
  const loadKey = `${runtimeMode}:${currentWorkspaceId}:${workspaceSelectionScope}`;
408
687
  if (lastConfigRefreshKeyRef.current === loadKey)
409
688
  return;
410
689
  lastConfigRefreshKeyRef.current = loadKey;
411
690
  void fetchConfig();
412
- }, [currentWorkspaceId, fetchConfig, hasBootstrappedDataRef, lastConfigRefreshKeyRef, runtimeMode, shouldBlockProtectedApiCalls, shouldDeferProtectedApiCalls, workspaceSelectionScope]);
691
+ }, [currentWorkspaceId, fetchConfig, hasBootstrappedDataRef, lastConfigRefreshKeyRef, runtimeMode, shouldBlockProtectedApiCalls, shouldDeferProtectedApiCalls, workspaceBootstrapPending, workspaceSelectionScope]);
413
692
  useEffect(() => {
414
- if (shouldDeferProtectedApiCalls || shouldBlockProtectedApiCalls)
693
+ if (shouldDeferProtectedApiCalls || shouldBlockProtectedApiCalls || workspaceBootstrapPending)
415
694
  return;
416
695
  const loadKey = currentWorkspaceId;
417
696
  if (lastWorkspaceSyncStateLoadKeyRef.current === loadKey)
418
697
  return;
419
698
  lastWorkspaceSyncStateLoadKeyRef.current = loadKey;
420
699
  void loadWorkspaceSyncState();
421
- }, [currentWorkspaceId, lastWorkspaceSyncStateLoadKeyRef, loadWorkspaceSyncState, shouldBlockProtectedApiCalls, shouldDeferProtectedApiCalls]);
700
+ }, [currentWorkspaceId, lastWorkspaceSyncStateLoadKeyRef, loadWorkspaceSyncState, shouldBlockProtectedApiCalls, shouldDeferProtectedApiCalls, workspaceBootstrapPending]);
422
701
  useEffect(() => {
423
702
  if (runtimeMode !== 'cloud' || !authSessionResolved || !isAuthenticated) {
424
703
  if (runtimeMode !== 'cloud')
@@ -426,9 +705,11 @@ export function useTaskforceWorkspaceBootstrap(args) {
426
705
  workspaceListHydratedRef.current = false;
427
706
  return;
428
707
  }
708
+ if (workspaceBootstrapPending)
709
+ return;
429
710
  if (!hasBootstrappedDataRef.current || workspaceListHydratedRef.current)
430
711
  return;
431
712
  void fetchWorkspaces();
432
- }, [authSessionResolved, fetchWorkspaces, hasBootstrappedDataRef, isAuthenticated, runtimeMode, setAvailableWorkspaces, workspaceListHydratedRef]);
433
- return { fetchReferenceData, fetchBootstrapConfig, fetchConfig, fetchWorkspaces, fetchAssigneeOptions, switchWorkspace, resolveWorkspaceAfterAuth, retryBootstrapChecks };
713
+ }, [authSessionResolved, fetchWorkspaces, hasBootstrappedDataRef, isAuthenticated, runtimeMode, setAvailableWorkspaces, workspaceBootstrapPending, workspaceListHydratedRef]);
714
+ return { fetchReferenceData, fetchBootstrapConfig, fetchConfig, fetchWorkspaces, fetchAssigneeOptions, switchWorkspace, resolveWorkspaceAfterAuth, retryBootstrapChecks, runCloudBootstrap };
434
715
  }
@@ -12,7 +12,6 @@ export interface MessageCatalog {
12
12
  updatedLabel: string;
13
13
  completedLabel: string;
14
14
  emptyValue: string;
15
- parentCannotSchedule: string;
16
15
  dueBeforeScheduled: string;
17
16
  overdue: string;
18
17
  };
@@ -12,7 +12,6 @@ export const enUS = {
12
12
  updatedLabel: 'Updated:',
13
13
  completedLabel: 'Completed:',
14
14
  emptyValue: '—',
15
- parentCannotSchedule: 'Parent tasks cannot be scheduled. Schedule leaf tasks instead.',
16
15
  dueBeforeScheduled: 'Due date is before scheduled date.',
17
16
  overdue: 'This task is overdue.'
18
17
  },
@@ -12,7 +12,6 @@ export const es419 = {
12
12
  updatedLabel: 'Actualizado:',
13
13
  completedLabel: 'Completado:',
14
14
  emptyValue: '—',
15
- parentCannotSchedule: 'Las tareas padre no se pueden programar. Programa tareas hoja en su lugar.',
16
15
  dueBeforeScheduled: 'La fecha de vencimiento es anterior a la fecha programada.',
17
16
  overdue: 'Esta tarea esta vencida.'
18
17
  },
@@ -12,7 +12,6 @@ export const ptBR = {
12
12
  updatedLabel: 'Atualizado:',
13
13
  completedLabel: 'Concluido:',
14
14
  emptyValue: '—',
15
- parentCannotSchedule: 'Tarefas pai nao podem ser agendadas. Agende as tarefas folha.',
16
15
  dueBeforeScheduled: 'A data de vencimento e anterior a data agendada.',
17
16
  overdue: 'Esta tarefa esta atrasada.'
18
17
  },
@@ -0,0 +1,2 @@
1
+ import type { DomainToolExecutor, RegisterMcpTool } from './toolCatalog.js';
2
+ export declare function registerAdminWorkspaceTools(registerTool: RegisterMcpTool, executeTool: DomainToolExecutor): void;