@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
@@ -15,6 +15,7 @@ import logoDark from './assets/branding/logos/logo_dark.svg';
15
15
  import taskforceBg from './assets/images/taskforce.png';
16
16
  import { isLightThemeFamily } from './utils/theme';
17
17
  import { Cloud, LaptopMinimal } from 'lucide-react';
18
+ import { getPasswordPolicyGuidance, validatePasswordPolicy } from './shared/passwordPolicy';
18
19
  function isDebugModeEnabled() {
19
20
  const runtimeOverride = globalThis.__DEBUG_MODE__;
20
21
  if (typeof runtimeOverride === 'boolean')
@@ -58,18 +59,21 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
58
59
  const [loginEmail, setLoginEmail] = useState('');
59
60
  const [loginDisplayName, setLoginDisplayName] = useState('');
60
61
  const [loginPassword, setLoginPassword] = useState('');
62
+ const [loginPasswordConfirm, setLoginPasswordConfirm] = useState('');
61
63
  const [authMode, setAuthMode] = useState('login');
62
64
  const [verificationToken, setVerificationToken] = useState('');
63
65
  const [pendingVerificationWorkspaceSetupRequired, setPendingVerificationWorkspaceSetupRequired] = useState(false);
64
66
  const [pendingVerificationCommercialState, setPendingVerificationCommercialState] = useState(null);
65
67
  const [pendingVerificationRedirectPath, setPendingVerificationRedirectPath] = useState(null);
66
68
  const [pendingPostAuthRedirect, setPendingPostAuthRedirect] = useState(null);
69
+ const [commercialOnboardingRedirectActive, setCommercialOnboardingRedirectActive] = useState(false);
67
70
  const [resetToken, setResetToken] = useState('');
68
71
  const [inviteToken, setInviteToken] = useState('');
69
72
  const [inviteEmail, setInviteEmail] = useState(null);
70
73
  const [inviteWorkspaceId, setInviteWorkspaceId] = useState(null);
71
74
  const [inviteResolution, setInviteResolution] = useState('unknown');
72
75
  const [invitePasswordRequired, setInvitePasswordRequired] = useState(false);
76
+ const [inviteOAuthProviders, setInviteOAuthProviders] = useState([]);
73
77
  const [loginNotice, setLoginNotice] = useState(null);
74
78
  const [loginError, setLoginError] = useState(null);
75
79
  const [loginErrorCode, setLoginErrorCode] = useState(null);
@@ -109,7 +113,7 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
109
113
  onTaskCountChange,
110
114
  onClose
111
115
  });
112
- const { runtimeMode, workspaceSwitchingEnabled, currentWorkspaceId, configLoaded, cloudAuthConfigured, authRequiredForApi, authBlocked, isAuthenticated, hasBetaAccess, authSessionResolved, workspaceBootstrapPending, bootstrapPhase, bootstrapError, setupState, runtimeCapabilities, refreshSetupContext, retryBootstrapChecks, createWorkspace, saveWorkspaceProfile, fetchWorkspaces, applyWorkspaceSyncStateSnapshot, workspaceCloudSyncEnabled, workspaceSyncPhase, workspaceSyncSetupIntent, workspaceSyncSummary, workspaceSyncRecommendedAction, workspaceSyncBusy, workspaceLastErrorMessage, retryWorkspaceCloudSync, settingsModel, fetchTasks, loginWithCredentials, registerWithCredentials, requestEmailVerification, confirmEmailVerification, requestPasswordReset, confirmPasswordReset, inspectInviteAcceptance, acceptInviteWithToken, joinInviteWithToken, authUserEmail, currentTheme, logout } = taskforceState;
116
+ const { runtimeMode, workspaceSwitchingEnabled, currentWorkspaceId, cloudAuthConfigured, authRequiredForApi, authBlocked, isAuthenticated, hasBetaAccess, authSessionResolved, setupState, runtimeCapabilities, refreshSetupContext, retryBootstrapChecks, createWorkspace, saveWorkspaceProfile, fetchWorkspaces, applyWorkspaceSyncStateSnapshot, workspaceCloudSyncEnabled, workspaceSyncPhase, workspaceSyncSetupIntent, workspaceSyncSummary, workspaceSyncRecommendedAction, workspaceSyncBusy, workspaceLastErrorMessage, retryWorkspaceCloudSync, settingsModel, fetchTasks, bootstrapState, loginWithCredentials, beginOAuthLogin, availableAuthProviders, registerWithCredentials, requestEmailVerification, confirmEmailVerification, requestPasswordReset, confirmPasswordReset, inspectInviteAcceptance, acceptInviteWithToken, joinInviteWithToken, authUserEmail, currentTheme, logout } = taskforceState;
113
117
  const persistWorkspaceSyncStatePatch = useCallback(async (workspaceId, patch) => {
114
118
  const response = await fetch('/api/taskforce/ui-state', {
115
119
  method: 'POST',
@@ -216,6 +220,9 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
216
220
  && !isPricingRoute
217
221
  && !isPlansRoute
218
222
  && !isPlansScreen;
223
+ const cloudAccountAccessPending = runtimeMode === 'cloud'
224
+ && isAuthenticated
225
+ && (!authSessionResolved || !accountAccessGateResolved);
219
226
  const directRegistrationEnabled = cloudAuthConfigured;
220
227
  const authPageTitle = useMemo(() => {
221
228
  switch (authMode) {
@@ -238,7 +245,7 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
238
245
  const setupIntent = useMemo(() => String(new URLSearchParams(location.search).get('intent') || '').trim().toLowerCase(), [location.search]);
239
246
  const isCreateWorkspaceIntent = isSetupRoute && setupStep === 'workspace' && setupIntent === 'create-workspace';
240
247
  const shouldHoldForAuthBootstrap = mode !== 'widget'
241
- && !authSessionResolved
248
+ && bootstrapState.authPending
242
249
  && !isLoginRoute
243
250
  && !isSetupRoute
244
251
  && !isPricingRoute
@@ -266,23 +273,47 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
266
273
  const needsWorkspaceSetup = workspaceLifecycle.needsWorkspaceSetup;
267
274
  const hasSetupReadError = workspaceLifecycle.hasSetupReadError;
268
275
  const shouldHoldForSetupBootstrap = mode !== 'widget'
269
- && authSessionResolved
276
+ && bootstrapState.auth.resolved
270
277
  && !shouldForceLogin
271
278
  && !shouldForceComingSoon
272
279
  && !isPricingRoute
273
280
  && !isPlansRoute
274
281
  && !isPlansScreen
275
- && (!configLoaded || workspaceBootstrapPending || bootstrapPhase === 'stalled')
282
+ && bootstrapState.appPending
276
283
  && (isSetupRoute || runtimeMode === 'cloud' || isLikelyCloudAppHost);
277
- const bootstrapSubtitle = useMemo(() => {
278
- if (bootstrapPhase === 'auth')
279
- return 'Verifying session...';
280
- if (bootstrapPhase === 'workspace')
281
- return 'Resolving workspace access...';
282
- if (bootstrapPhase === 'config')
283
- return 'Loading configuration...';
284
- return 'Checking account, workspace access, and setup status...';
285
- }, [bootstrapPhase]);
284
+ const shouldHoldForCommercialOnboardingRedirect = runtimeMode === 'cloud'
285
+ && commercialOnboardingRedirectActive
286
+ && !isPlansScreen;
287
+ const bootstrapSubtitle = bootstrapState.subtitle;
288
+ const showGuidedWorkspaceSetup = isCreateWorkspaceIntent
289
+ || (isSetupRoute && Boolean(activeCloudWorkspaceImport))
290
+ || (isSetupRoute && setupGateActive && (hasSetupReadError || needsGlobalSetup || needsWorkspaceSetup));
291
+ const shellRenderState = useMemo(() => {
292
+ if (shouldHoldForAuthBootstrap)
293
+ return 'auth-bootstrap';
294
+ if (shouldHoldForCommercialOnboardingRedirect)
295
+ return 'app-bootstrap';
296
+ if (shouldHoldForSetupBootstrap)
297
+ return 'app-bootstrap';
298
+ if (isLoginRoute)
299
+ return 'login';
300
+ if (shouldForceLogin && !isLoginRoute)
301
+ return 'login-redirect';
302
+ if (isComingSoonRoute && shouldForceComingSoon)
303
+ return 'coming-soon';
304
+ if (showGuidedWorkspaceSetup)
305
+ return 'guided-setup';
306
+ return 'app';
307
+ }, [
308
+ isComingSoonRoute,
309
+ isLoginRoute,
310
+ shouldForceComingSoon,
311
+ shouldForceLogin,
312
+ shouldHoldForCommercialOnboardingRedirect,
313
+ shouldHoldForAuthBootstrap,
314
+ shouldHoldForSetupBootstrap,
315
+ showGuidedWorkspaceSetup
316
+ ]);
286
317
  const isPlaceholderWorkspaceName = useCallback((name, workspaceId, _description) => {
287
318
  const normalizedName = String(name || '').trim().toLowerCase();
288
319
  const normalizedWorkspaceId = String(workspaceId || '').trim().toLowerCase();
@@ -299,7 +330,12 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
299
330
  setSetupModeChoice(modeValue);
300
331
  }, [setupState?.mode]);
301
332
  useEffect(() => {
302
- if (runtimeMode !== 'cloud' || !isAuthenticated || !authSessionResolved) {
333
+ if (runtimeMode !== 'cloud' || !isAuthenticated) {
334
+ setAccountAccessGate(null);
335
+ setAccountAccessGateResolved(false);
336
+ return;
337
+ }
338
+ if (!authSessionResolved) {
303
339
  setAccountAccessGate(null);
304
340
  setAccountAccessGateResolved(false);
305
341
  return;
@@ -637,27 +673,95 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
637
673
  setPendingVerificationRedirectPath(null);
638
674
  }, [authMode, isLoginRoute, loginRouteMode]);
639
675
  useEffect(() => {
640
- if (!isLoginRoute || !pendingPostAuthRedirect || !authSessionResolved || !isAuthenticated)
676
+ if (authMode === 'register')
641
677
  return;
642
- if (runtimeMode === 'cloud' && !pendingPostAuthRedirect.commercialOnboardingGate && !accountAccessGateResolved) {
678
+ setLoginPasswordConfirm('');
679
+ }, [authMode]);
680
+ useEffect(() => {
681
+ if (!pendingPostAuthRedirect || !isAuthenticated)
682
+ return;
683
+ if (!pendingPostAuthRedirect.commercialOnboardingGate && (!authSessionResolved || cloudAccountAccessPending)) {
643
684
  return;
644
685
  }
645
- if (!pendingPostAuthRedirect.commercialOnboardingGate && pendingPostAuthRedirect.workspaceSetupRequired) {
646
- navigate(resolveWorkspaceSetupPath(), { replace: true });
686
+ const destination = !pendingPostAuthRedirect.commercialOnboardingGate && pendingPostAuthRedirect.workspaceSetupRequired
687
+ ? resolveWorkspaceSetupPath()
688
+ : pendingPostAuthRedirect.path;
689
+ const currentRoute = `${location.pathname}${location.search}${location.hash || ''}`;
690
+ if (currentRoute !== destination) {
691
+ navigate(destination, { replace: true });
647
692
  }
648
- else {
649
- navigate(pendingPostAuthRedirect.path, { replace: true });
693
+ }, [
694
+ authSessionResolved,
695
+ cloudAccountAccessPending,
696
+ isAuthenticated,
697
+ location.hash,
698
+ location.pathname,
699
+ location.search,
700
+ navigate,
701
+ pendingPostAuthRedirect,
702
+ resolveWorkspaceSetupPath
703
+ ]);
704
+ useEffect(() => {
705
+ if (!commercialOnboardingRedirectActive)
706
+ return;
707
+ if (!authSessionResolved) {
708
+ return;
650
709
  }
710
+ if (!isAuthenticated) {
711
+ setCommercialOnboardingRedirectActive(false);
712
+ setPendingPostAuthRedirect(null);
713
+ return;
714
+ }
715
+ if (accountAccessGateResolved && accountAccessGate?.canAccessApp === true) {
716
+ setLoginEmail('');
717
+ setLoginDisplayName('');
718
+ setLoginPassword('');
719
+ setLoginPasswordConfirm('');
720
+ setPendingPostAuthRedirect(null);
721
+ setCommercialOnboardingRedirectActive(false);
722
+ return;
723
+ }
724
+ const destination = pendingPostAuthRedirect?.commercialOnboardingGate
725
+ ? pendingPostAuthRedirect.path
726
+ : planSelectionPath;
727
+ const currentRoute = `${location.pathname}${location.search}${location.hash || ''}`;
728
+ if (currentRoute !== destination) {
729
+ navigate(destination, { replace: true });
730
+ }
731
+ }, [
732
+ accountAccessGate?.canAccessApp,
733
+ accountAccessGateResolved,
734
+ authSessionResolved,
735
+ commercialOnboardingRedirectActive,
736
+ isAuthenticated,
737
+ location.hash,
738
+ location.pathname,
739
+ location.search,
740
+ navigate,
741
+ pendingPostAuthRedirect,
742
+ planSelectionPath
743
+ ]);
744
+ useEffect(() => {
745
+ if (!pendingPostAuthRedirect || !isAuthenticated)
746
+ return;
747
+ const destination = !pendingPostAuthRedirect.commercialOnboardingGate && pendingPostAuthRedirect.workspaceSetupRequired
748
+ ? resolveWorkspaceSetupPath()
749
+ : pendingPostAuthRedirect.path;
750
+ const currentRoute = `${location.pathname}${location.search}${location.hash || ''}`;
751
+ if (currentRoute !== destination)
752
+ return;
753
+ if (pendingPostAuthRedirect.commercialOnboardingGate)
754
+ return;
651
755
  setLoginEmail('');
652
756
  setLoginDisplayName('');
653
757
  setLoginPassword('');
758
+ setLoginPasswordConfirm('');
654
759
  setPendingPostAuthRedirect(null);
655
760
  }, [
656
- accountAccessGateResolved,
657
- authSessionResolved,
761
+ location.hash,
762
+ location.pathname,
763
+ location.search,
658
764
  isAuthenticated,
659
- isLoginRoute,
660
- navigate,
661
765
  pendingPostAuthRedirect,
662
766
  resolveWorkspaceSetupPath,
663
767
  runtimeMode
@@ -679,6 +783,9 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
679
783
  setInviteEmail(inspected.email || null);
680
784
  setInviteWorkspaceId(inspected.workspaceId || null);
681
785
  setInvitePasswordRequired(inspected.passwordRequired === true);
786
+ // Capture OAuth providers available for invite-claim (pending_setup only)
787
+ const oauthMethods = (inspected.availableMethods || []).filter(m => m === 'google' || m === 'github' || m === 'apple');
788
+ setInviteOAuthProviders(inspected.inviteeState === 'pending_setup' ? oauthMethods : []);
682
789
  const inviteMatchesAuthenticatedUser = Boolean(isAuthenticated
683
790
  && authUserEmail
684
791
  && inspected.email
@@ -704,6 +811,7 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
704
811
  setInviteWorkspaceId(null);
705
812
  setInviteResolution('invalid');
706
813
  setInvitePasswordRequired(false);
814
+ setInviteOAuthProviders([]);
707
815
  setLoginError(formatAuthError(inspected));
708
816
  setLoginErrorCode(inspected.code || inspected.state || null);
709
817
  }
@@ -730,6 +838,7 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
730
838
  const resetCooldownSeconds = Math.max(0, Math.ceil((resetCooldownUntil - cooldownNow) / 1000));
731
839
  const verifyCooldownActive = verifyCooldownSeconds > 0;
732
840
  const resetCooldownActive = resetCooldownSeconds > 0;
841
+ const registerPasswordGuidance = useMemo(() => getPasswordPolicyGuidance(), []);
733
842
  const formatAuthError = (result) => {
734
843
  const message = result.error || 'Request failed.';
735
844
  const code = result.code || result.state;
@@ -756,7 +865,15 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
756
865
  useEffect(() => {
757
866
  if (mode === 'widget')
758
867
  return;
759
- if (workspaceBootstrapPending)
868
+ if (isLoginRoute && loginBusy) {
869
+ return;
870
+ }
871
+ const shouldBypassWorkspacePendingForAccessGate = runtimeMode === 'cloud'
872
+ && isAuthenticated
873
+ && accountAccessGateResolved
874
+ && accountAccessGate?.canAccessApp === false
875
+ && accountAccessGate?.canAccessPlans !== false;
876
+ if (bootstrapState.workspace.pending && !shouldBypassWorkspacePendingForAccessGate)
760
877
  return;
761
878
  if (shouldForceComingSoon) {
762
879
  if (!isComingSoonRoute)
@@ -775,10 +892,11 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
775
892
  && isAuthenticated
776
893
  && !shouldStayOnInviteRoute
777
894
  && (Boolean(pendingPostAuthRedirect)
778
- || workspaceBootstrapPending
895
+ || bootstrapState.workspace.pending
779
896
  || authMode === 'register'
780
897
  || authMode === 'verify'
781
- || (runtimeMode === 'cloud' && (!configLoaded || !accountAccessGateResolved)));
898
+ || !bootstrapState.config.loaded
899
+ || cloudAccountAccessPending);
782
900
  if (shouldDelayAuthenticatedLoginRedirect) {
783
901
  return;
784
902
  }
@@ -796,6 +914,23 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
796
914
  if (isLoginRoute && !isAuthenticated) {
797
915
  return;
798
916
  }
917
+ if (pendingPostAuthRedirect && isAuthenticated) {
918
+ return;
919
+ }
920
+ const shouldHoldAuthenticatedAuthRoute = isLoginRoute
921
+ && isAuthenticated
922
+ && (authMode === 'register'
923
+ || authMode === 'verify'
924
+ || (authMode === 'invite' && inviteToken.trim().length > 0));
925
+ if (shouldHoldAuthenticatedAuthRoute) {
926
+ return;
927
+ }
928
+ if (commercialOnboardingRedirectActive) {
929
+ return;
930
+ }
931
+ if (isPlansScreen) {
932
+ return;
933
+ }
799
934
  if (shouldForceAccountAccessGate) {
800
935
  if (!isPlansScreen) {
801
936
  const gate = encodeURIComponent(String(accountAccessGate?.gate || 'plan_selection_required'));
@@ -812,6 +947,16 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
812
947
  }
813
948
  return;
814
949
  }
950
+ if (isPlansScreen && cloudAccountAccessPending) {
951
+ return;
952
+ }
953
+ if (isPlansScreen
954
+ && runtimeMode === 'cloud'
955
+ && accountAccessGateResolved
956
+ && accountAccessGate?.canAccessApp === false
957
+ && accountAccessGate?.canAccessPlans !== false) {
958
+ return;
959
+ }
815
960
  if (setupGateActive) {
816
961
  if (hasSetupReadError) {
817
962
  if (!isSetupRoute || setupStep !== 'error') {
@@ -849,9 +994,12 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
849
994
  isComingSoonRoute,
850
995
  isPlansRoute,
851
996
  isPlansScreen,
997
+ accountAccessGate,
852
998
  accountAccessGate?.gate,
853
999
  accountAccessGateResolved,
854
1000
  authMode,
1001
+ commercialOnboardingRedirectActive,
1002
+ cloudAccountAccessPending,
855
1003
  setupGateActive,
856
1004
  setupState,
857
1005
  hasSetupReadError,
@@ -860,9 +1008,11 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
860
1008
  needsGlobalSetup,
861
1009
  needsWorkspaceSetup,
862
1010
  setupStep,
863
- workspaceBootstrapPending,
864
- configLoaded,
1011
+ bootstrapState,
865
1012
  runtimeMode,
1013
+ loginBusy,
1014
+ isAuthenticated,
1015
+ accountAccessGateResolved,
866
1016
  inviteToken,
867
1017
  location.pathname,
868
1018
  location.search,
@@ -877,7 +1027,7 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
877
1027
  return;
878
1028
  if (runtimeMode !== 'local')
879
1029
  return;
880
- if (!configLoaded)
1030
+ if (!bootstrapState.config.loaded)
881
1031
  return;
882
1032
  if (isLoginRoute || isSetupRoute)
883
1033
  return;
@@ -885,7 +1035,7 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
885
1035
  if (!workspaceId || workspaceId === 'default') {
886
1036
  navigate('/setup?step=workspace', { replace: true });
887
1037
  }
888
- }, [mode, runtimeMode, configLoaded, isLoginRoute, isSetupRoute, currentWorkspaceId, navigate]);
1038
+ }, [mode, runtimeMode, bootstrapState.config.loaded, isLoginRoute, isSetupRoute, currentWorkspaceId, navigate]);
889
1039
  const handleRetryBootstrap = useCallback(async () => {
890
1040
  setBootstrapRetryBusy(true);
891
1041
  try {
@@ -913,13 +1063,13 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
913
1063
  params.set('screen', 'plans');
914
1064
  return _jsx(Navigate, { to: `/?${params.toString()}${location.hash || ''}`, replace: true });
915
1065
  }
916
- if (shouldHoldForAuthBootstrap) {
1066
+ if (shellRenderState === 'auth-bootstrap') {
917
1067
  return (_jsx("div", { className: shellStyles.standaloneWrapper, "data-theme": currentTheme, children: _jsx("div", { className: authStyles.loginView, children: _jsxs("div", { className: authStyles.loginCard, children: [_jsxs("div", { className: authStyles.authBrandRow, children: [_jsx("img", { src: authBrandLogo, alt: "Taskforce", className: authStyles.loginLogo }), _jsx("h1", { className: authStyles.loginTitle, children: "Loading Taskforce" })] }), _jsx("p", { className: authStyles.loginSubtitle, children: "Checking your session..." })] }) }) }));
918
1068
  }
919
- if (shouldHoldForSetupBootstrap) {
920
- return (_jsx("div", { className: shellStyles.standaloneWrapper, "data-theme": currentTheme, children: _jsx("div", { className: authStyles.loginView, children: _jsxs("div", { className: authStyles.loginCard, children: [_jsxs("div", { className: authStyles.authBrandRow, children: [_jsx("img", { src: authBrandLogo, alt: "Taskforce", className: authStyles.loginLogo }), _jsx("h1", { className: authStyles.loginTitle, children: "Loading Taskforce" })] }), _jsx("p", { className: authStyles.loginSubtitle, children: bootstrapSubtitle }), bootstrapPhase === 'stalled' && (_jsxs(_Fragment, { children: [_jsx("p", { className: authStyles.loginError, children: bootstrapError || 'Startup checks timed out.' }), _jsx("button", { className: styles.submitBtn, disabled: bootstrapRetryBusy, onClick: handleRetryBootstrap, children: bootstrapRetryBusy ? 'Retrying...' : 'Retry checks' }), isCloudRuntime && (_jsx("button", { className: styles.cancelBtn, disabled: bootstrapRetryBusy, onClick: handleGoToSignIn, children: "Go to sign-in" }))] }))] }) }) }));
1069
+ if (shellRenderState === 'app-bootstrap') {
1070
+ return (_jsx("div", { className: shellStyles.standaloneWrapper, "data-theme": currentTheme, children: _jsx("div", { className: authStyles.loginView, children: _jsxs("div", { className: authStyles.loginCard, children: [_jsxs("div", { className: authStyles.authBrandRow, children: [_jsx("img", { src: authBrandLogo, alt: "Taskforce", className: authStyles.loginLogo }), _jsx("h1", { className: authStyles.loginTitle, children: "Loading Taskforce" })] }), _jsx("p", { className: authStyles.loginSubtitle, children: bootstrapSubtitle }), bootstrapState.stalled && (_jsxs(_Fragment, { children: [_jsx("p", { className: authStyles.loginError, children: bootstrapState.error || 'Startup checks timed out.' }), _jsx("button", { className: styles.submitBtn, disabled: bootstrapRetryBusy, onClick: handleRetryBootstrap, children: bootstrapRetryBusy ? 'Retrying...' : 'Retry checks' }), isCloudRuntime && (_jsx("button", { className: styles.cancelBtn, disabled: bootstrapRetryBusy, onClick: handleGoToSignIn, children: "Go to sign-in" }))] }))] }) }) }));
921
1071
  }
922
- if (isLoginRoute) {
1072
+ if (shellRenderState === 'login') {
923
1073
  return (_jsx("div", { className: shellStyles.standaloneWrapper, "data-theme": currentTheme, children: _jsx("div", { className: authStyles.loginView, style: {
924
1074
  backgroundImage: `linear-gradient(rgba(15, 15, 26, 0.88), rgba(15, 15, 26, 0.9)), url(${taskforceBg})`
925
1075
  }, children: _jsxs("div", { className: authStyles.loginCard, children: [!isCloudRuntime && !shouldForceLogin && (_jsx("button", { className: authStyles.loginCloseBtn, "aria-label": "Close sign in", "data-testid": "auth-close-button", onClick: () => navigate(nextPath, { replace: true }), children: "\u00D7" })), _jsxs("div", { className: authStyles.authBrandRow, children: [_jsx("img", { src: authBrandLogo, alt: "Taskforce", className: authStyles.loginLogo }), _jsxs("h1", { className: authStyles.loginTitle, children: ["TASKFORCE ", _jsx("span", { className: authStyles.loginTitleAccent, children: "HQ" })] })] }), _jsxs("p", { className: authStyles.loginSubtitle, children: [authMode === 'login' && 'Sign in with your account credentials.', authMode === 'register' && 'Create your Taskforce account.', authMode === 'verify' && 'Enter your verification token.', authMode === 'forgot' && 'Request a password reset link.', authMode === 'reset' && 'Set a new password using your reset token.', authMode === 'invite' && (inviteResolution === 'existing_user_ready'
@@ -941,7 +1091,7 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
941
1091
  ? (invitePasswordRequired ? 'Create password' : 'Password')
942
1092
  : 'Password'), autoComplete: authMode === 'register' || authMode === 'reset' || (authMode === 'invite' && invitePasswordRequired)
943
1093
  ? 'new-password'
944
- : 'current-password', "data-testid": "auth-password-input", onChange: (event) => setLoginPassword(event.target.value) })] })), authMode === 'verify' && (_jsxs("label", { className: authStyles.loginField, children: [_jsx("span", { className: authStyles.loginFieldLabel, children: "Verification token" }), _jsx("input", { className: `${styles.input} ${authStyles.loginInput}`, type: "text", value: verificationToken, placeholder: "Verification token", autoComplete: "one-time-code", "data-testid": "auth-verification-token-input", onChange: (event) => setVerificationToken(event.target.value) })] })), authMode === 'reset' && (_jsxs("label", { className: authStyles.loginField, children: [_jsx("span", { className: authStyles.loginFieldLabel, children: "Reset token" }), _jsx("input", { className: `${styles.input} ${authStyles.loginInput}`, type: "text", value: resetToken, placeholder: "Reset token", autoComplete: "one-time-code", "data-testid": "auth-reset-token-input", onChange: (event) => setResetToken(event.target.value) })] })), authMode === 'invite' && (_jsxs(_Fragment, { children: [_jsxs("label", { className: authStyles.loginField, children: [_jsx("span", { className: authStyles.loginFieldLabel, children: "Invite token" }), _jsx("input", { className: `${styles.input} ${authStyles.loginInput}`, type: "text", value: inviteToken, placeholder: "Invite token", "data-testid": "auth-invite-token-input", onChange: (event) => setInviteToken(event.target.value) })] }), inviteEmail && (_jsxs("p", { className: authStyles.loginSubtitle, children: ["Invite for: ", _jsx("strong", { children: inviteEmail }), inviteWorkspaceId ? ` · Workspace: ${inviteWorkspaceId}` : ''] }))] })), loginNotice && _jsx("p", { className: authStyles.loginSubtitle, children: loginNotice }), loginError && _jsx("p", { className: authStyles.loginError, children: loginError }), authMode === 'login' && loginErrorCode === 'EMAIL_NOT_VERIFIED' && loginEmail.trim() && (_jsx("button", { className: authStyles.authModeLink, disabled: loginBusy || verifyCooldownActive, onClick: async () => {
1094
+ : 'current-password', "data-testid": "auth-password-input", onChange: (event) => setLoginPassword(event.target.value) })] })), (authMode === 'register' || (authMode === 'invite' && invitePasswordRequired)) && (_jsx(_Fragment, { children: _jsxs("label", { className: authStyles.loginField, children: [_jsx("span", { className: authStyles.loginFieldLabel, children: "Confirm password" }), _jsx("input", { className: `${styles.input} ${authStyles.loginInput}`, type: "password", value: loginPasswordConfirm, placeholder: "Confirm password", autoComplete: "new-password", "data-testid": "auth-confirm-password-input", onChange: (event) => setLoginPasswordConfirm(event.target.value) })] }) })), (authMode === 'register' || (authMode === 'invite' && invitePasswordRequired)) && (_jsx("p", { className: authStyles.loginSubtitle, children: registerPasswordGuidance.join(' ') })), authMode === 'verify' && (_jsxs("label", { className: authStyles.loginField, children: [_jsx("span", { className: authStyles.loginFieldLabel, children: "Verification token" }), _jsx("input", { className: `${styles.input} ${authStyles.loginInput}`, type: "text", value: verificationToken, placeholder: "Verification token", autoComplete: "one-time-code", "data-testid": "auth-verification-token-input", onChange: (event) => setVerificationToken(event.target.value) })] })), authMode === 'reset' && (_jsxs("label", { className: authStyles.loginField, children: [_jsx("span", { className: authStyles.loginFieldLabel, children: "Reset token" }), _jsx("input", { className: `${styles.input} ${authStyles.loginInput}`, type: "text", value: resetToken, placeholder: "Reset token", autoComplete: "one-time-code", "data-testid": "auth-reset-token-input", onChange: (event) => setResetToken(event.target.value) })] })), authMode === 'invite' && (_jsxs(_Fragment, { children: [_jsxs("label", { className: authStyles.loginField, children: [_jsx("span", { className: authStyles.loginFieldLabel, children: "Invite token" }), _jsx("input", { className: `${styles.input} ${authStyles.loginInput}`, type: "text", value: inviteToken, placeholder: "Invite token", "data-testid": "auth-invite-token-input", onChange: (event) => setInviteToken(event.target.value) })] }), inviteEmail && (_jsxs("p", { className: authStyles.loginSubtitle, children: ["Invite for: ", _jsx("strong", { children: inviteEmail }), inviteWorkspaceId ? ` · Workspace: ${inviteWorkspaceId}` : ''] }))] })), loginNotice && _jsx("p", { className: authStyles.loginSubtitle, children: loginNotice }), loginError && _jsx("p", { className: authStyles.loginError, children: loginError }), authMode === 'login' && loginErrorCode === 'EMAIL_NOT_VERIFIED' && loginEmail.trim() && (_jsx("button", { className: authStyles.authModeLink, disabled: loginBusy || verifyCooldownActive, onClick: async () => {
945
1095
  setLoginBusy(true);
946
1096
  setLoginNotice(null);
947
1097
  const sent = await requestEmailVerification(loginEmail);
@@ -968,6 +1118,24 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
968
1118
  setLoginBusy(false);
969
1119
  return;
970
1120
  }
1121
+ if (authMode === 'register') {
1122
+ const validation = validatePasswordPolicy(loginPassword, {
1123
+ email: loginEmail,
1124
+ displayName: loginDisplayName
1125
+ });
1126
+ if (!validation.ok) {
1127
+ setLoginError(validation.message || 'Password does not meet the password policy.');
1128
+ setLoginErrorCode(validation.code || null);
1129
+ setLoginBusy(false);
1130
+ return;
1131
+ }
1132
+ if (loginPassword !== loginPasswordConfirm) {
1133
+ setLoginError('Passwords do not match.');
1134
+ setLoginErrorCode('PASSWORD_CONFIRMATION_MISMATCH');
1135
+ setLoginBusy(false);
1136
+ return;
1137
+ }
1138
+ }
971
1139
  let result = { success: false };
972
1140
  if (authMode === 'login') {
973
1141
  result = await loginWithCredentials(loginEmail, loginPassword);
@@ -1060,6 +1228,7 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
1060
1228
  : 'Account created. Check your email for verification instructions.');
1061
1229
  }
1062
1230
  else {
1231
+ setCommercialOnboardingRedirectActive(commercialOnboardingGate);
1063
1232
  setPendingPostAuthRedirect({
1064
1233
  path: postRegistrationPath,
1065
1234
  workspaceSetupRequired: Boolean(result.workspaceSetupRequired),
@@ -1071,6 +1240,7 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
1071
1240
  await retryBootstrapChecks();
1072
1241
  const commercialOnboardingGate = pendingVerificationCommercialState === 'pending_plan_selection'
1073
1242
  || pendingVerificationCommercialState === 'checkout_pending';
1243
+ setCommercialOnboardingRedirectActive(commercialOnboardingGate);
1074
1244
  setPendingPostAuthRedirect({
1075
1245
  path: pendingVerificationRedirectPath || nextPath,
1076
1246
  workspaceSetupRequired: pendingVerificationWorkspaceSetupRequired,
@@ -1102,6 +1272,7 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
1102
1272
  setAuthMode('invite');
1103
1273
  setInviteResolution('existing_user_ready');
1104
1274
  setLoginPassword('');
1275
+ setLoginPasswordConfirm('');
1105
1276
  setLoginNotice('Signed in. Review the invite details to continue.');
1106
1277
  setLoginError(null);
1107
1278
  setLoginErrorCode(null);
@@ -1113,6 +1284,7 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
1113
1284
  }
1114
1285
  setInviteResolution('existing_user_signed_out');
1115
1286
  setLoginPassword('');
1287
+ setLoginPasswordConfirm('');
1116
1288
  setLoginNotice(normalizedInviteEmail
1117
1289
  ? `Signed in, but this invite is for ${inviteEmail}. Sign in with that account to continue.`
1118
1290
  : 'Signed in, but this invite requires the invited account. Sign in with that account to continue.');
@@ -1132,6 +1304,7 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
1132
1304
  if (inviteToken.trim()) {
1133
1305
  setAuthMode('invite');
1134
1306
  setLoginPassword('');
1307
+ setLoginPasswordConfirm('');
1135
1308
  setLoginNotice('Signed in. Review the invite details to continue.');
1136
1309
  setLoginBusy(false);
1137
1310
  return;
@@ -1144,12 +1317,14 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
1144
1317
  setLoginEmail('');
1145
1318
  setLoginDisplayName('');
1146
1319
  setLoginPassword('');
1320
+ setLoginPasswordConfirm('');
1147
1321
  navigate(nextPath, { replace: true });
1148
1322
  }
1149
1323
  else {
1150
1324
  setLoginEmail('');
1151
1325
  setLoginDisplayName('');
1152
1326
  setLoginPassword('');
1327
+ setLoginPasswordConfirm('');
1153
1328
  navigate(nextPath, { replace: true });
1154
1329
  }
1155
1330
  setLoginBusy(false);
@@ -1162,7 +1337,7 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
1162
1337
  ? 'Reset Password'
1163
1338
  : (inviteResolution === 'existing_user_signed_out'
1164
1339
  ? 'Sign In to Continue'
1165
- : (invitePasswordRequired ? 'Create Account and Join' : 'Join Workspace'))) }) }), authMode === 'register' && (_jsxs("p", { className: authStyles.registerConsent, children: ["By creating an account, you agree to the", ' ', _jsx("a", { className: authStyles.registerConsentLink, href: "https://taskforcehq.com/legal/terms", target: "_blank", rel: "noopener noreferrer", children: "Terms of Service" }), ' ', "and acknowledge the", ' ', _jsx("a", { className: authStyles.registerConsentLink, href: "https://taskforcehq.com/legal/privacy", target: "_blank", rel: "noopener noreferrer", children: "Privacy Policy" }), "."] })), _jsxs("div", { className: authStyles.authSecondaryActions, role: "group", "aria-label": "Authentication navigation", children: [directRegistrationEnabled && (authMode === 'login' || authMode === 'register') && (_jsxs("p", { className: authStyles.authModeSwitch, children: [authMode === 'login' ? 'Need an account?' : 'Already have an account?', ' ', _jsx("button", { className: authStyles.authModeSwitchLink, disabled: loginBusy, "data-testid": "auth-switch-mode-button", onClick: () => {
1340
+ : (invitePasswordRequired ? 'Create Account and Join' : 'Join Workspace'))) }) }), (authMode === 'login' || authMode === 'register') && availableAuthProviders.length > 0 && (_jsxs("div", { className: authStyles.oauthProviders, children: [_jsx("div", { className: authStyles.oauthDivider, children: _jsx("span", { children: "or continue with" }) }), _jsxs("div", { className: authStyles.oauthButtons, children: [availableAuthProviders.includes('google') && (_jsx("button", { type: "button", className: authStyles.oauthButton, disabled: loginBusy, onClick: () => beginOAuthLogin('google', location.pathname !== '/login' ? location.pathname : '/'), "aria-label": "Continue with Google", children: "Google" })), availableAuthProviders.includes('github') && (_jsx("button", { type: "button", className: authStyles.oauthButton, disabled: loginBusy, onClick: () => beginOAuthLogin('github', location.pathname !== '/login' ? location.pathname : '/'), "aria-label": "Continue with GitHub", children: "GitHub" })), availableAuthProviders.includes('apple') && (_jsx("button", { type: "button", className: authStyles.oauthButton, disabled: loginBusy, onClick: () => beginOAuthLogin('apple', location.pathname !== '/login' ? location.pathname : '/'), "aria-label": "Continue with Apple", children: "Apple" }))] })] })), authMode === 'invite' && inviteResolution === 'new_user' && inviteOAuthProviders.length > 0 && (_jsxs("div", { className: authStyles.oauthProviders, children: [_jsx("div", { className: authStyles.oauthDivider, children: _jsx("span", { children: "or join with" }) }), _jsxs("div", { className: authStyles.oauthButtons, children: [inviteOAuthProviders.includes('google') && (_jsx("button", { type: "button", className: authStyles.oauthButton, disabled: loginBusy, onClick: () => beginOAuthLogin('google', '/', inviteToken), "aria-label": "Join with Google", children: "Google" })), inviteOAuthProviders.includes('github') && (_jsx("button", { type: "button", className: authStyles.oauthButton, disabled: loginBusy, onClick: () => beginOAuthLogin('github', '/', inviteToken), "aria-label": "Join with GitHub", children: "GitHub" })), inviteOAuthProviders.includes('apple') && (_jsx("button", { type: "button", className: authStyles.oauthButton, disabled: loginBusy, onClick: () => beginOAuthLogin('apple', '/', inviteToken), "aria-label": "Join with Apple", children: "Apple" }))] })] })), authMode === 'register' && (_jsxs("p", { className: authStyles.registerConsent, children: ["By creating an account, you agree to the", ' ', _jsx("a", { className: authStyles.registerConsentLink, href: "https://taskforcehq.com/legal/terms", target: "_blank", rel: "noopener noreferrer", children: "Terms of Service" }), ' ', "and acknowledge the", ' ', _jsx("a", { className: authStyles.registerConsentLink, href: "https://taskforcehq.com/legal/privacy", target: "_blank", rel: "noopener noreferrer", children: "Privacy Policy" }), "."] })), _jsxs("div", { className: authStyles.authSecondaryActions, role: "group", "aria-label": "Authentication navigation", children: [directRegistrationEnabled && (authMode === 'login' || authMode === 'register') && (_jsxs("p", { className: authStyles.authModeSwitch, children: [authMode === 'login' ? 'Need an account?' : 'Already have an account?', ' ', _jsx("button", { className: authStyles.authModeSwitchLink, disabled: loginBusy, "data-testid": "auth-switch-mode-button", onClick: () => {
1166
1341
  setLoginError(null);
1167
1342
  setLoginErrorCode(null);
1168
1343
  setLoginNotice(null);
@@ -1185,18 +1360,15 @@ function TaskforceCoreWithRouter({ config = {}, initialTaskId, onTaskCountChange
1185
1360
  setLoginBusy(false);
1186
1361
  }, children: verifyCooldownActive ? `Resend Verification (${verifyCooldownSeconds}s)` : 'Resend Verification' })), _jsx("button", { className: authStyles.authModeLink, disabled: loginBusy, "data-testid": "auth-return-sign-in-button", onClick: () => { setLoginError(null); setLoginErrorCode(null); setLoginNotice(null); setLoginMode('login'); }, children: authMode === 'verify' ? 'Back to Sign In' : 'Sign In' }), directRegistrationEnabled && authMode !== 'verify' && (_jsx("button", { className: authStyles.authModeLink, disabled: loginBusy, "data-testid": "auth-return-register-button", onClick: () => { setLoginError(null); setLoginErrorCode(null); setLoginNotice(null); setLoginMode('register'); }, children: "Register" })), authMode === 'reset' && (_jsx("button", { className: authStyles.authModeLink, disabled: loginBusy || resetCooldownActive, "data-testid": "auth-return-forgot-password-button", onClick: () => { setLoginError(null); setLoginErrorCode(null); setLoginNotice(null); setLoginMode('forgot'); }, children: resetCooldownActive ? `Forgot Password (${resetCooldownSeconds}s)` : 'Forgot Password' }))] }))] })] })] }) }) }));
1187
1362
  }
1188
- if (shouldForceLogin && !isLoginRoute) {
1363
+ if (shellRenderState === 'login-redirect') {
1189
1364
  return (_jsx("div", { className: shellStyles.standaloneWrapper, "data-theme": currentTheme, children: _jsx("div", { className: authStyles.loginView, children: _jsxs("div", { className: authStyles.loginCard, children: [_jsxs("div", { className: authStyles.authBrandRow, children: [_jsx("img", { src: authBrandLogo, alt: "Taskforce", className: authStyles.loginLogo }), _jsx("h1", { className: authStyles.loginTitle, children: "Loading Taskforce" })] }), _jsx("p", { className: authStyles.loginSubtitle, children: "Redirecting to sign in..." })] }) }) }));
1190
1365
  }
1191
- if (isComingSoonRoute && shouldForceComingSoon) {
1366
+ if (shellRenderState === 'coming-soon') {
1192
1367
  return (_jsx("div", { className: shellStyles.standaloneWrapper, "data-theme": currentTheme, children: _jsx("div", { className: authStyles.loginView, style: {
1193
1368
  backgroundImage: `linear-gradient(rgba(15, 15, 26, 0.88), rgba(15, 15, 26, 0.9)), url(${taskforceBg})`
1194
1369
  }, children: _jsxs("div", { className: authStyles.loginCard, children: [_jsxs("div", { className: authStyles.authBrandRow, children: [_jsx("img", { src: authBrandLogo, alt: "Taskforce", className: authStyles.loginLogo }), _jsx("h1", { className: authStyles.loginTitle, children: "Private Beta" })] }), _jsx("p", { className: authStyles.loginSubtitle, children: "You are signed in, but your account is not in the beta allowlist yet." }), _jsx("p", { className: authStyles.loginSubtitle, children: "You will see the full app as soon as beta access is enabled." }), _jsx("button", { className: styles.cancelBtn, onClick: async () => { await taskforceState.logout(); navigate('/login', { replace: true }); }, children: "Sign Out" })] }) }) }));
1195
1370
  }
1196
- const showGuidedWorkspaceSetup = isCreateWorkspaceIntent
1197
- || (isSetupRoute && Boolean(activeCloudWorkspaceImport))
1198
- || (isSetupRoute && setupGateActive && (hasSetupReadError || needsGlobalSetup || needsWorkspaceSetup));
1199
- if (showGuidedWorkspaceSetup) {
1371
+ if (shellRenderState === 'guided-setup') {
1200
1372
  const isError = !isCreateWorkspaceIntent && (hasSetupReadError || setupStep === 'error');
1201
1373
  const isGlobal = !isCreateWorkspaceIntent && !isError && (needsGlobalSetup || setupStep === 'global');
1202
1374
  const heading = isError