@taskforcehq/taskforce 0.3.305 → 0.3.307

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (440) hide show
  1. package/README.md +0 -2
  2. package/dist/Taskforce.module.css +603 -107
  3. package/dist/TaskforceCore.js +216 -43
  4. package/dist/TaskforceCore.test.js +611 -28
  5. package/dist/assets/fonts/CourierPrime-Bold.woff2 +0 -0
  6. package/dist/assets/fonts/CourierPrime-BoldItalic.woff2 +0 -0
  7. package/dist/assets/fonts/CourierPrime-Italic.woff2 +0 -0
  8. package/dist/assets/fonts/CourierPrime-Regular.woff2 +0 -0
  9. package/dist/assets/fonts/Noir_medium.woff2 +0 -0
  10. package/dist/assets/fonts/Noir_regular.woff2 +0 -0
  11. package/dist/assets/fonts/RussoOne-Regular.woff2 +0 -0
  12. package/dist/assets/fonts/SpecialElite-Regular.woff2 +0 -0
  13. package/dist/compat/workspaceSyncCompat.js +46 -2
  14. package/dist/compat/workspaceSyncCompat.test.js +38 -1
  15. package/dist/components/activity/EntityActivityTimeline.d.ts +34 -0
  16. package/dist/components/activity/EntityActivityTimeline.js +81 -0
  17. package/dist/components/context/ContextAttachmentManager.d.ts +14 -0
  18. package/dist/components/context/ContextAttachmentManager.js +561 -0
  19. package/dist/components/features/AgentsModule.d.ts +14 -1
  20. package/dist/components/features/AgentsModule.js +366 -18
  21. package/dist/components/features/AgentsModule.test.js +507 -8
  22. package/dist/components/features/AnnotatedAttachmentWorkspace.d.ts +3 -1
  23. package/dist/components/features/AnnotatedAttachmentWorkspace.js +118 -4
  24. package/dist/components/features/AnnotatedAttachmentWorkspace.test.js +52 -0
  25. package/dist/components/features/DocumentIndex.d.ts +2 -2
  26. package/dist/components/features/DocumentIndex.js +3 -4
  27. package/dist/components/features/DocumentViewer.d.ts +7 -1
  28. package/dist/components/features/DocumentViewer.js +62 -4
  29. package/dist/components/features/DocumentWorkspace.d.ts +10 -2
  30. package/dist/components/features/DocumentWorkspace.js +15 -4
  31. package/dist/components/features/DocumentWorkspace.test.js +51 -1
  32. package/dist/components/features/TaskSettings.d.ts +2 -0
  33. package/dist/components/features/TaskSettings.js +83 -78
  34. package/dist/components/features/TaskSettings.test.js +171 -82
  35. package/dist/components/features/documentWorkspaceModel.d.ts +1 -1
  36. package/dist/components/task/TaskActionHeader.js +11 -5
  37. package/dist/components/task/TaskActionHeader.test.js +10 -0
  38. package/dist/components/task/TaskCard.js +24 -29
  39. package/dist/components/task/TaskCard.test.js +38 -3
  40. package/dist/components/task/TaskContextUpload.js +4 -526
  41. package/dist/components/task/TaskContextUpload.test.js +3 -3
  42. package/dist/components/task/TaskForm.js +61 -116
  43. package/dist/components/task/TaskForm.test.js +110 -8
  44. package/dist/components/task/TaskKanban.d.ts +2 -1
  45. package/dist/components/task/TaskKanban.js +94 -21
  46. package/dist/components/task/TaskKanban.test.js +36 -0
  47. package/dist/components/task/TaskList.js +5 -1
  48. package/dist/components/task/TaskList.test.js +4 -0
  49. package/dist/components/ui/EditableAvatarButton.d.ts +18 -0
  50. package/dist/components/ui/EditableAvatarButton.js +18 -0
  51. package/dist/components/ui/HierarchyActionBadge.d.ts +10 -0
  52. package/dist/components/ui/HierarchyActionBadge.js +5 -0
  53. package/dist/components/views/AppShellHeader.d.ts +3 -1
  54. package/dist/components/views/AppShellHeader.js +27 -11
  55. package/dist/components/views/AppShellHeader.test.js +18 -1
  56. package/dist/components/views/PlanComparisonPage.d.ts +9 -1
  57. package/dist/components/views/PlanComparisonPage.js +78 -14
  58. package/dist/components/views/PlanComparisonPage.test.js +257 -0
  59. package/dist/components/views/PlansPage.js +127 -36
  60. package/dist/components/views/PlansPage.test.js +294 -12
  61. package/dist/components/views/StandaloneLayout.js +529 -592
  62. package/dist/components/views/WidgetView.js +10 -8
  63. package/dist/components/views/panels/PlanningDrawer.d.ts +25 -5
  64. package/dist/components/views/panels/PlanningDrawer.js +270 -55
  65. package/dist/components/views/panels/PlanningDrawer.test.d.ts +1 -0
  66. package/dist/components/views/panels/PlanningDrawer.test.js +529 -0
  67. package/dist/components/views/planningScope.d.ts +20 -0
  68. package/dist/components/views/planningScope.js +25 -0
  69. package/dist/components/views/planningScope.test.d.ts +1 -0
  70. package/dist/components/views/planningScope.test.js +60 -0
  71. package/dist/components/views/standalone/modals/AccountHubModal.d.ts +26 -1
  72. package/dist/components/views/standalone/modals/AccountHubModal.js +76 -2
  73. package/dist/components/views/standalone/modals/AccountHubModal.test.js +20 -3
  74. package/dist/components/views/standalone/modals/AvatarImageManagerModal.d.ts +20 -0
  75. package/dist/components/views/standalone/modals/AvatarImageManagerModal.js +127 -0
  76. package/dist/components/views/standalone/modals/EditProfileModal.d.ts +2 -9
  77. package/dist/components/views/standalone/modals/EditProfileModal.js +3 -2
  78. package/dist/components/views/standalone/modals/SyncEnableWarningModal.d.ts +9 -0
  79. package/dist/components/views/standalone/modals/SyncEnableWarningModal.js +6 -0
  80. package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.d.ts +1 -0
  81. package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.js +24 -0
  82. package/dist/components/views/standalone/modals/SyncStatusModal.d.ts +2 -1
  83. package/dist/components/views/standalone/modals/SyncStatusModal.js +2 -2
  84. package/dist/config/envSchema.js +1 -0
  85. package/dist/core/AiProfileService.d.ts +46 -2
  86. package/dist/core/AiProfileService.js +1073 -82
  87. package/dist/core/AiProfileService.test.js +19 -1
  88. package/dist/core/AiProfiles.test.js +1249 -44
  89. package/dist/core/AttachmentLinkService.d.ts +3 -0
  90. package/dist/core/AttachmentLinkService.js +110 -23
  91. package/dist/core/AuthIdentityService.d.ts +107 -0
  92. package/dist/core/AuthIdentityService.js +284 -0
  93. package/dist/core/AuthTokenService.d.ts +4 -0
  94. package/dist/core/AuthTokenService.js +34 -6
  95. package/dist/core/AuthTokenService.test.js +3 -3
  96. package/dist/core/EntitlementsPolicy.test.js +2 -2
  97. package/dist/core/GlobalSettingsService.js +127 -6
  98. package/dist/core/McpTokenService.d.ts +12 -0
  99. package/dist/core/McpTokenService.js +44 -1
  100. package/dist/core/PlanEntitlementService.d.ts +23 -2
  101. package/dist/core/PlanEntitlementService.js +343 -57
  102. package/dist/core/PlanFeatureCatalog.test.d.ts +1 -0
  103. package/dist/core/PlanFeatureCatalog.test.js +84 -0
  104. package/dist/core/PlanVersionPolicy.test.js +35 -2
  105. package/dist/core/PlanningEntities.test.js +418 -4
  106. package/dist/core/SignupMonetizationSettings.test.js +199 -27
  107. package/dist/core/SyncReconciliationService.js +2 -65
  108. package/dist/core/SystemAdmin.test.js +42 -42
  109. package/dist/core/TaskActivityService.d.ts +28 -1
  110. package/dist/core/TaskActivityService.js +227 -46
  111. package/dist/core/TaskActivitySync.test.d.ts +1 -0
  112. package/dist/core/TaskActivitySync.test.js +90 -0
  113. package/dist/core/TaskAttachmentsCanonical.test.js +51 -1
  114. package/dist/core/TaskAuditTimeline.test.js +96 -0
  115. package/dist/core/Taskforce.d.ts +415 -40
  116. package/dist/core/Taskforce.ids.test.js +58 -0
  117. package/dist/core/Taskforce.js +1543 -266
  118. package/dist/core/Taskforce.listTasksSlim.test.d.ts +1 -0
  119. package/dist/core/Taskforce.listTasksSlim.test.js +91 -0
  120. package/dist/core/Taskforce.mcpAuth.test.js +109 -0
  121. package/dist/core/UserProfileAvatarDrafts.test.js +30 -3
  122. package/dist/core/WorkspaceLifecycleService.js +0 -5
  123. package/dist/core/WorkspacePermissions.test.js +25 -1
  124. package/dist/core/WorkspacePlanMode.test.js +117 -16
  125. package/dist/core/shared.d.ts +1 -1
  126. package/dist/core/shared.js +5 -1
  127. package/dist/core/types.d.ts +75 -2
  128. package/dist/hooks/auth/useTaskforceAuthBootstrap.js +28 -2
  129. package/dist/hooks/bootstrapTimeouts.d.ts +4 -0
  130. package/dist/hooks/bootstrapTimeouts.js +8 -0
  131. package/dist/hooks/bootstrapTimeouts.test.d.ts +1 -0
  132. package/dist/hooks/bootstrapTimeouts.test.js +12 -0
  133. package/dist/hooks/sync/bootstrap.js +2 -0
  134. package/dist/hooks/sync/controlPlane.d.ts +37 -0
  135. package/dist/hooks/sync/controlPlane.js +78 -0
  136. package/dist/hooks/sync/controlPlane.test.d.ts +1 -0
  137. package/dist/hooks/sync/controlPlane.test.js +121 -0
  138. package/dist/hooks/sync/lifecyclePolicy.d.ts +45 -0
  139. package/dist/hooks/sync/lifecyclePolicy.js +93 -0
  140. package/dist/hooks/sync/lifecyclePolicy.test.d.ts +1 -0
  141. package/dist/hooks/sync/lifecyclePolicy.test.js +124 -0
  142. package/dist/hooks/sync/orchestratorShared.d.ts +13 -4
  143. package/dist/hooks/sync/orchestratorShared.js +129 -48
  144. package/dist/hooks/sync/orchestratorShared.test.js +50 -1
  145. package/dist/hooks/sync/pullLifecycle.d.ts +31 -0
  146. package/dist/hooks/sync/pullLifecycle.js +24 -0
  147. package/dist/hooks/sync/pullLifecycle.test.d.ts +1 -0
  148. package/dist/hooks/sync/pullLifecycle.test.js +80 -0
  149. package/dist/hooks/sync/recovery.d.ts +16 -2
  150. package/dist/hooks/sync/recovery.js +179 -53
  151. package/dist/hooks/sync/recovery.test.d.ts +1 -0
  152. package/dist/hooks/sync/recovery.test.js +292 -0
  153. package/dist/hooks/sync/transfers.d.ts +16 -3
  154. package/dist/hooks/sync/transfers.js +210 -66
  155. package/dist/hooks/sync/transfers.test.d.ts +1 -0
  156. package/dist/hooks/sync/transfers.test.js +928 -0
  157. package/dist/hooks/sync/useRecentSyncEvents.d.ts +21 -0
  158. package/dist/hooks/sync/useRecentSyncEvents.js +92 -0
  159. package/dist/hooks/sync/useRecentSyncEvents.test.d.ts +1 -0
  160. package/dist/hooks/sync/useRecentSyncEvents.test.js +124 -0
  161. package/dist/hooks/sync/useSyncStatusActions.d.ts +30 -0
  162. package/dist/hooks/sync/useSyncStatusActions.js +88 -0
  163. package/dist/hooks/sync/useSyncStatusActions.test.d.ts +1 -0
  164. package/dist/hooks/sync/useSyncStatusActions.test.js +133 -0
  165. package/dist/hooks/sync/useSyncStatusControls.d.ts +25 -0
  166. package/dist/hooks/sync/useSyncStatusControls.js +60 -0
  167. package/dist/hooks/sync/useSyncStatusControls.test.d.ts +1 -0
  168. package/dist/hooks/sync/useSyncStatusControls.test.js +88 -0
  169. package/dist/hooks/useFilterSort.js +13 -13
  170. package/dist/hooks/useFilterSort.test.js +87 -1
  171. package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +12 -0
  172. package/dist/hooks/useSyncOrchestrator.d.ts +9 -2
  173. package/dist/hooks/useSyncOrchestrator.js +409 -183
  174. package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +407 -0
  175. package/dist/hooks/useTaskData.js +8 -3
  176. package/dist/hooks/useTaskData.test.js +45 -0
  177. package/dist/hooks/useTaskforce.d.ts +145 -52
  178. package/dist/hooks/useTaskforce.js +592 -253
  179. package/dist/hooks/useTaskforce.runtime-routing.test.d.ts +1 -0
  180. package/dist/hooks/useTaskforce.runtime-routing.test.js +246 -0
  181. package/dist/hooks/useTaskforce.sync-behavior.test.js +2468 -201
  182. package/dist/hooks/useWorkspaceSyncController.d.ts +1 -0
  183. package/dist/hooks/useWorkspaceSyncController.js +13 -2
  184. package/dist/hooks/useWorkspaceSyncController.test.js +48 -0
  185. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.d.ts +16 -0
  186. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +328 -40
  187. package/dist/localization/locales/en-US.d.ts +0 -1
  188. package/dist/localization/locales/en-US.js +0 -1
  189. package/dist/localization/locales/es-419.js +0 -1
  190. package/dist/localization/locales/pt-BR.js +0 -1
  191. package/dist/mcp/canonicalAssetHelpers.d.ts +16 -4
  192. package/dist/mcp/canonicalAssetHelpers.js +18 -10
  193. package/dist/mcp/canonicalAssetHelpers.test.d.ts +1 -0
  194. package/dist/mcp/canonicalAssetHelpers.test.js +67 -0
  195. package/dist/mcp/clientIntegrations.d.ts +1 -0
  196. package/dist/mcp/clientIntegrations.js +25 -0
  197. package/dist/mcp/clientIntegrations.test.js +14 -3
  198. package/dist/mcp/clientProfileDefaults.js +3 -3
  199. package/dist/mcp/collaborationRegistrar.js +7 -7
  200. package/dist/mcp/documentAssetRegistrar.js +116 -10
  201. package/dist/mcp/runtime.d.ts +3 -0
  202. package/dist/mcp/runtime.js +1099 -185
  203. package/dist/mcp/runtime.test.js +1491 -140
  204. package/dist/mcp/taskAttachmentTypes.d.ts +1 -1
  205. package/dist/mcp/taskPlanningRegistrar.js +48 -0
  206. package/dist/mcp/toolRegistry.d.ts +56 -0
  207. package/dist/mcp/toolRegistry.js +8 -0
  208. package/dist/mcp/toolRegistry.test.js +4 -0
  209. package/dist/migrations/taskSchemaMigrations.d.ts +1 -1
  210. package/dist/migrations/taskSchemaMigrations.js +192 -61
  211. package/dist/migrations/taskSchemaMigrations.test.js +15 -0
  212. package/dist/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
  213. package/dist/resources/templates/workflows/collaborate.yaml +1 -1
  214. package/dist/resources/templates/workflows/evaluate.yaml +2 -2
  215. package/dist/resources/templates/workflows/plan.yaml +1 -1
  216. package/dist/resources/templates/workflows/review.yaml +2 -2
  217. package/dist/server/aiProfileAvatarAssets.d.ts +49 -0
  218. package/dist/server/aiProfileAvatarAssets.js +319 -0
  219. package/dist/server/aiProfileAvatarAssets.test.d.ts +1 -0
  220. package/dist/server/aiProfileAvatarAssets.test.js +213 -0
  221. package/dist/server/annotatedAttachmentsRoutes.test.js +69 -10
  222. package/dist/server/auth/providers/apple.d.ts +33 -0
  223. package/dist/server/auth/providers/apple.js +82 -0
  224. package/dist/server/auth/providers/appleClientSecret.d.ts +37 -0
  225. package/dist/server/auth/providers/appleClientSecret.js +65 -0
  226. package/dist/server/auth/providers/github.d.ts +26 -0
  227. package/dist/server/auth/providers/github.js +86 -0
  228. package/dist/server/auth/providers/google.d.ts +21 -0
  229. package/dist/server/auth/providers/google.js +56 -0
  230. package/dist/server/auth/providers/types.d.ts +21 -0
  231. package/dist/server/auth/providers/types.js +1 -0
  232. package/dist/server/auth.d.ts +2 -0
  233. package/dist/server/auth.js +6 -3
  234. package/dist/server/documentReviewRoutes.test.js +36 -3
  235. package/dist/server/index.cookieProxy.test.js +1 -0
  236. package/dist/server/index.d.ts +12 -0
  237. package/dist/server/index.js +124 -9
  238. package/dist/server/index.rateLimit.test.js +3 -0
  239. package/dist/server/index.test.js +111 -3
  240. package/dist/server/routes/admin.d.ts +3 -0
  241. package/dist/server/routes/admin.js +459 -28
  242. package/dist/server/routes/annotatedAttachments.js +51 -0
  243. package/dist/server/routes/auth.d.ts +26 -2
  244. package/dist/server/routes/auth.js +1170 -71
  245. package/dist/server/routes/authSupport.d.ts +5 -1
  246. package/dist/server/routes/authSupport.js +13 -2
  247. package/dist/server/routes/billing.js +372 -35
  248. package/dist/server/routes/billing.test.js +595 -12
  249. package/dist/server/routes/documents.d.ts +1 -0
  250. package/dist/server/routes/documents.js +182 -70
  251. package/dist/server/routes/shared.d.ts +28 -2
  252. package/dist/server/routes/shared.js +69 -14
  253. package/dist/server/routes/sync.integration.test.js +658 -39
  254. package/dist/server/routes/sync.js +74 -608
  255. package/dist/server/routes/syncAuxRoutes.d.ts +15 -0
  256. package/dist/server/routes/syncAuxRoutes.js +91 -0
  257. package/dist/server/routes/syncAuxRoutes.test.d.ts +1 -0
  258. package/dist/server/routes/syncAuxRoutes.test.js +158 -0
  259. package/dist/server/routes/syncPullApplyRoutes.d.ts +36 -0
  260. package/dist/server/routes/syncPullApplyRoutes.js +204 -0
  261. package/dist/server/routes/syncPushRoutes.d.ts +24 -0
  262. package/dist/server/routes/syncPushRoutes.js +212 -0
  263. package/dist/server/routes/syncRouteGuards.d.ts +36 -0
  264. package/dist/server/routes/syncRouteGuards.js +67 -0
  265. package/dist/server/routes/syncRouteGuards.test.d.ts +1 -0
  266. package/dist/server/routes/syncRouteGuards.test.js +94 -0
  267. package/dist/server/routes/syncRouteTypes.d.ts +13 -0
  268. package/dist/server/routes/syncRouteTypes.js +1 -0
  269. package/dist/server/routes/syncSnapshotRoutes.d.ts +66 -0
  270. package/dist/server/routes/syncSnapshotRoutes.js +182 -0
  271. package/dist/server/routes/tasks.js +55 -10
  272. package/dist/server/routes/workspaces.js +36 -5
  273. package/dist/server/routes.js +147 -11
  274. package/dist/server/routes.test.js +2704 -183
  275. package/dist/services/workflowExportSnapshots.test.js +2 -0
  276. package/dist/shared/aiProfileSeatScope.d.ts +5 -0
  277. package/dist/shared/aiProfileSeatScope.js +21 -0
  278. package/dist/shared/aiProfileSurfaceType.d.ts +1 -1
  279. package/dist/shared/aiProfileSurfaceType.js +10 -8
  280. package/dist/shared/passwordPolicy.d.ts +13 -0
  281. package/dist/shared/passwordPolicy.js +84 -0
  282. package/dist/shared/passwordPolicy.test.d.ts +1 -0
  283. package/dist/shared/passwordPolicy.test.js +34 -0
  284. package/dist/storage/objectStorage.d.ts +1 -0
  285. package/dist/storage/objectStorage.js +2 -1
  286. package/dist/storage/objectStorageClient.d.ts +1 -0
  287. package/dist/storage/objectStorageClient.js +41 -8
  288. package/dist/storage/objectStorageClient.test.js +26 -1
  289. package/dist/storage/objectStorageConfig.js +3 -1
  290. package/dist/storage/objectStorageConfig.test.js +13 -1
  291. package/dist/storage/workspaceAssetStore.d.ts +15 -3
  292. package/dist/storage/workspaceAssetStore.js +132 -44
  293. package/dist/storage/workspaceAssetStore.test.js +93 -6
  294. package/dist/styles/fonts.css +70 -0
  295. package/dist/sync/collaborationSyncPayload.d.ts +6 -1
  296. package/dist/sync/collaborationSyncPayload.js +19 -11
  297. package/dist/sync/collaborationSyncPayload.test.js +14 -1
  298. package/dist/sync/collaborationSyncState.d.ts +3 -3
  299. package/dist/sync/collaborationSyncState.js +19 -12
  300. package/dist/sync/contentSyncPayload.d.ts +5 -1
  301. package/dist/sync/contentSyncPayload.js +9 -0
  302. package/dist/sync/contentSyncPayload.test.js +39 -0
  303. package/dist/sync/contentSyncState.d.ts +9 -9
  304. package/dist/sync/contentSyncState.js +248 -107
  305. package/dist/sync/planningSyncPayload.js +5 -0
  306. package/dist/sync/planningSyncPayload.test.js +24 -0
  307. package/dist/sync/syncApplyHandlers.d.ts +11 -4
  308. package/dist/sync/syncApplyHandlers.js +115 -42
  309. package/dist/sync/syncApplyHandlers.test.js +251 -4
  310. package/dist/sync/syncFieldSemantics.d.ts +12 -0
  311. package/dist/sync/syncFieldSemantics.js +55 -0
  312. package/dist/sync/syncResourceAdapters.d.ts +46 -0
  313. package/dist/sync/syncResourceAdapters.js +79 -0
  314. package/dist/sync/syncService.d.ts +6 -0
  315. package/dist/sync/syncService.js +65 -1
  316. package/dist/sync/syncService.test.js +96 -3
  317. package/dist/sync/taskSyncChangeKey.d.ts +2 -0
  318. package/dist/sync/taskSyncChangeKey.js +143 -0
  319. package/dist/sync/taskSyncPayload.js +3 -8
  320. package/dist/sync/workspacePullFeed.d.ts +4 -0
  321. package/dist/sync/workspacePullFeed.js +132 -72
  322. package/dist/sync/workspacePullFeed.test.js +92 -0
  323. package/dist/sync/workspaceRepair.js +5 -2
  324. package/dist/sync/workspaceSyncModel.d.ts +73 -6
  325. package/dist/sync/workspaceSyncModel.js +342 -73
  326. package/dist/sync/workspaceSyncModel.test.js +559 -14
  327. package/dist/sync/workspaceSyncState.d.ts +17 -0
  328. package/dist/sync/workspaceSyncState.js +2 -1
  329. package/dist/sync/workspaceSyncSurface.js +3 -8
  330. package/dist/types.d.ts +50 -2
  331. package/dist/ui/assets/AgentsModule-2y82_3DO.js +1 -0
  332. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BTLZZCiQ.js +3 -0
  333. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BVKew-mH.css +1 -0
  334. package/dist/ui/assets/ContextAttachmentManager-D2epuNnG.js +3 -0
  335. package/dist/ui/assets/CourierPrime-Bold-BuLj_dpw.woff2 +0 -0
  336. package/dist/ui/assets/CourierPrime-BoldItalic-BrK2pUkZ.woff2 +0 -0
  337. package/dist/ui/assets/CourierPrime-Italic-DFUZK5Ey.woff2 +0 -0
  338. package/dist/ui/assets/CourierPrime-Regular-BsKphzVf.woff2 +0 -0
  339. package/dist/ui/assets/DocumentWorkspace-D4rJKXzd.css +1 -0
  340. package/dist/ui/assets/DocumentWorkspace-sVa-3Do6.js +252 -0
  341. package/dist/ui/assets/EntityActivityTimeline-DyqvvhuF.css +1 -0
  342. package/dist/ui/assets/EntityActivityTimeline-Zods27y_.js +1 -0
  343. package/dist/ui/assets/{InitiativesModule-Dhm7M8e7.js → InitiativesModule-D4XseTwW.js} +1 -1
  344. package/dist/ui/assets/Noir_medium-bxQwKGzB.woff2 +0 -0
  345. package/dist/ui/assets/Noir_regular-ojf2kxlG.woff2 +0 -0
  346. package/dist/ui/assets/PlansPage-D5AcbO0L.js +1 -0
  347. package/dist/ui/assets/PlansPage-Dvqsz5zc.css +1 -0
  348. package/dist/ui/assets/RussoOne-Regular-Cu_qq_qC.woff2 +0 -0
  349. package/dist/ui/assets/SpecialElite-Regular-Di6gSvAS.woff2 +0 -0
  350. package/dist/ui/assets/TaskContextUpload-uC5qx4Bv.js +1 -0
  351. package/dist/ui/assets/TaskSettings-CqvPAsTv.js +9 -0
  352. package/dist/ui/assets/{WorkflowsModule-BcS4afRn.js → WorkflowsModule-oOA9bcdK.js} +4 -4
  353. package/dist/ui/assets/documentReferences-DPZuTgHh.js +1 -0
  354. package/dist/ui/assets/index-607WPo_X.js +4 -0
  355. package/dist/ui/assets/index-CYyodXsg.css +1 -0
  356. package/dist/ui/assets/{vendor-icons-BSUaRwF8.js → vendor-icons-B32hGuF2.js} +1 -1
  357. package/dist/ui/fonts/CourierPrime-Bold.ttf +0 -0
  358. package/dist/ui/fonts/CourierPrime-Bold.woff2 +0 -0
  359. package/dist/ui/fonts/CourierPrime-BoldItalic.ttf +0 -0
  360. package/dist/ui/fonts/CourierPrime-BoldItalic.woff2 +0 -0
  361. package/dist/ui/fonts/CourierPrime-Italic.ttf +0 -0
  362. package/dist/ui/fonts/CourierPrime-Italic.woff2 +0 -0
  363. package/dist/ui/fonts/CourierPrime-Regular.ttf +0 -0
  364. package/dist/ui/fonts/CourierPrime-Regular.woff2 +0 -0
  365. package/dist/ui/fonts/Noir_medium.otf +0 -0
  366. package/dist/ui/fonts/Noir_medium.woff2 +0 -0
  367. package/dist/ui/fonts/Noir_regular.otf +0 -0
  368. package/dist/ui/fonts/Noir_regular.woff2 +0 -0
  369. package/dist/ui/fonts/RussoOne-Regular.woff2 +0 -0
  370. package/dist/ui/fonts/SpecialElite-Regular.ttf +0 -0
  371. package/dist/ui/fonts/SpecialElite-Regular.woff2 +0 -0
  372. package/dist/ui/index.html +3 -3
  373. package/dist/ui/product/agent manager.png +0 -0
  374. package/dist/ui/product/agent_manager_02.png +0 -0
  375. package/dist/utils/accountProfileSummaryCache.d.ts +5 -0
  376. package/dist/utils/aiProfileEvents.d.ts +7 -0
  377. package/dist/utils/aiProfileEvents.js +6 -0
  378. package/dist/utils/assignees.d.ts +8 -0
  379. package/dist/utils/assignees.js +10 -1
  380. package/dist/utils/assignees.test.d.ts +1 -0
  381. package/dist/utils/assignees.test.js +25 -0
  382. package/dist/utils/avatarDisplay.d.ts +1 -0
  383. package/dist/utils/avatarDisplay.js +15 -0
  384. package/dist/utils/avatarUpload.d.ts +27 -0
  385. package/dist/utils/avatarUpload.js +132 -0
  386. package/dist/utils/avatarUpload.test.d.ts +1 -0
  387. package/dist/utils/avatarUpload.test.js +40 -0
  388. package/dist/utils/bootstrapTrace.d.ts +7 -0
  389. package/dist/utils/bootstrapTrace.js +29 -0
  390. package/dist/utils/commercialLifecyclePresentation.js +3 -0
  391. package/dist/utils/contextAssetEvents.d.ts +2 -0
  392. package/dist/utils/contextFiles.d.ts +3 -1
  393. package/dist/utils/contextFiles.js +2 -1
  394. package/dist/utils/syncEventDetails.d.ts +3 -0
  395. package/dist/utils/syncEventDetails.js +64 -0
  396. package/dist/utils/syncEventDetails.test.d.ts +1 -0
  397. package/dist/utils/syncEventDetails.test.js +23 -0
  398. package/dist/utils/syncEventPresentation.d.ts +15 -0
  399. package/dist/utils/syncEventPresentation.js +129 -0
  400. package/dist/utils/syncEventPresentation.test.d.ts +1 -0
  401. package/dist/utils/syncEventPresentation.test.js +64 -0
  402. package/dist/utils/syncStatusPresentation.d.ts +72 -0
  403. package/dist/utils/syncStatusPresentation.js +217 -0
  404. package/dist/utils/syncStatusPresentation.test.d.ts +1 -0
  405. package/dist/utils/syncStatusPresentation.test.js +164 -0
  406. package/dist/utils/taskActivity.d.ts +9 -1
  407. package/dist/utils/taskActivity.js +290 -22
  408. package/dist/utils/taskActivity.test.js +141 -8
  409. package/dist/utils/taskSearch.d.ts +22 -0
  410. package/dist/utils/taskSearch.js +87 -0
  411. package/dist/utils/taskSearch.test.d.ts +1 -0
  412. package/dist/utils/taskSearch.test.js +69 -0
  413. package/dist/utils/taskUtils.js +10 -3
  414. package/dist/utils/taskUtils.test.d.ts +1 -0
  415. package/dist/utils/taskUtils.test.js +19 -0
  416. package/dist/utils/workspaceSyncPresentation.d.ts +4 -0
  417. package/dist/utils/workspaceSyncPresentation.js +68 -2
  418. package/dist/utils/workspaceSyncPresentation.test.js +36 -1
  419. package/package.json +3 -2
  420. package/scripts/export-sqlite-to-postgres.mjs +7 -9
  421. package/scripts/run-e2e-realtime.sh +17 -3
  422. package/scripts/run-smoke.sh +17 -5
  423. package/scripts/run-soak.sh +17 -5
  424. package/src/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
  425. package/src/resources/templates/workflows/collaborate.yaml +1 -1
  426. package/src/resources/templates/workflows/evaluate.yaml +2 -2
  427. package/src/resources/templates/workflows/plan.yaml +1 -1
  428. package/src/resources/templates/workflows/review.yaml +2 -2
  429. package/dist/ui/assets/AgentsModule-N2MnQBZk.js +0 -1
  430. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BG6P_GVW.js +0 -3
  431. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BaS2VwIr.css +0 -1
  432. package/dist/ui/assets/DocumentWorkspace-B3nV_Gc5.css +0 -1
  433. package/dist/ui/assets/DocumentWorkspace-DRbDMwh8.js +0 -252
  434. package/dist/ui/assets/PlansPage-C2dd2n1X.css +0 -1
  435. package/dist/ui/assets/PlansPage-Cq0zXj3I.js +0 -1
  436. package/dist/ui/assets/RussoOne-Regular-C3BxZIj7.ttf +0 -0
  437. package/dist/ui/assets/TaskSettings-ln0aF7xc.js +0 -9
  438. package/dist/ui/assets/index-C2-OXZV7.css +0 -1
  439. package/dist/ui/assets/index-DcSI5F86.js +0 -6
  440. package/scripts/migrate-planning-model.ts +0 -233
@@ -9,6 +9,8 @@ describe('PlanComparisonPage', () => {
9
9
  vi.stubGlobal('fetch', vi.fn(async () => ({
10
10
  ok: true,
11
11
  json: async () => ({
12
+ pageTitle: 'Subscription Plans',
13
+ pageDescription: 'Manage your subscription and explore available features. Your current plan is highlighted below.',
12
14
  pricingSource: {
13
15
  environment: 'production',
14
16
  runtimeMode: 'cloud'
@@ -17,6 +19,7 @@ describe('PlanComparisonPage', () => {
17
19
  {
18
20
  planId: 'free',
19
21
  displayName: 'Free',
22
+ description: 'Start using Taskforce at no cost.',
20
23
  status: 'active',
21
24
  defaultVersion: {
22
25
  planVersionId: 'free-v1',
@@ -33,6 +36,7 @@ describe('PlanComparisonPage', () => {
33
36
  {
34
37
  planId: 'team-5',
35
38
  displayName: 'Team 5',
39
+ description: 'For small collaborative teams.',
36
40
  status: 'active',
37
41
  defaultVersion: {
38
42
  planVersionId: 'team-5-v2',
@@ -59,6 +63,28 @@ describe('PlanComparisonPage', () => {
59
63
  render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: false, onBack: () => { }, backLabel: "Back", onSelectPlan: () => { } }));
60
64
  expect(await screen.findByText('Pricing source: production (cloud)')).toBeInTheDocument();
61
65
  });
66
+ it('renders plan descriptions when provided by the pricing payload', async () => {
67
+ render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: false, onBack: () => { }, backLabel: "Back", onSelectPlan: () => { } }));
68
+ expect(await screen.findByText('Start using Taskforce at no cost.')).toBeInTheDocument();
69
+ expect(screen.getByText('For small collaborative teams.')).toBeInTheDocument();
70
+ });
71
+ it('prefers pricing payload header copy when provided', async () => {
72
+ vi.stubGlobal('fetch', vi.fn(async () => ({
73
+ ok: true,
74
+ json: async () => ({
75
+ pageTitle: 'Choose Your Taskforce Plan',
76
+ pageDescription: 'Compare plans and pick the right fit for your team.',
77
+ pricingSource: {
78
+ environment: 'production',
79
+ runtimeMode: 'cloud'
80
+ },
81
+ plans: []
82
+ })
83
+ })));
84
+ render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", subtitle: "Fallback subtitle", isAuthenticated: false, onBack: () => { }, backLabel: "Back", onSelectPlan: () => { } }));
85
+ expect(await screen.findByRole('heading', { name: 'Choose Your Taskforce Plan' })).toBeInTheDocument();
86
+ expect(screen.getByText('Compare plans and pick the right fit for your team.')).toBeInTheDocument();
87
+ });
62
88
  it('falls back to provided pricing source details when the pricing response omits them', async () => {
63
89
  globalThis.__DEBUG_MODE__ = true;
64
90
  vi.stubGlobal('fetch', vi.fn(async () => ({
@@ -92,6 +118,188 @@ describe('PlanComparisonPage', () => {
92
118
  await screen.findByRole('heading', { name: 'Subscription Plans' });
93
119
  expect(screen.queryByText('Pricing source: production (cloud)')).not.toBeInTheDocument();
94
120
  });
121
+ it('renders public feature copy when provided by the pricing payload', async () => {
122
+ vi.stubGlobal('fetch', vi.fn(async () => ({
123
+ ok: true,
124
+ json: async () => ({
125
+ pricingSource: {
126
+ environment: 'production',
127
+ runtimeMode: 'cloud'
128
+ },
129
+ plans: [
130
+ {
131
+ planId: 'team-5',
132
+ displayName: 'Team 5',
133
+ status: 'active',
134
+ defaultVersion: {
135
+ planVersionId: 'team-5-v2',
136
+ versionNumber: 2,
137
+ seatLimit: 5,
138
+ metadata: {}
139
+ },
140
+ features: [
141
+ {
142
+ featureKey: 'collaboration.ai_profiles',
143
+ access: 'enabled',
144
+ label: 'AI Profiles',
145
+ publicLabel: 'AI teammates',
146
+ publicDescription: 'Add reusable AI teammates to your workspace.'
147
+ }
148
+ ],
149
+ pricing: {
150
+ month: { pricingType: 'stripe', stripePriceId: 'price_team_5_month', unitAmount: 2000, currency: 'usd', interval: 'month' },
151
+ year: null
152
+ }
153
+ }
154
+ ]
155
+ })
156
+ })));
157
+ render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: false, onBack: () => { }, backLabel: "Back", onSelectPlan: () => { } }));
158
+ expect(await screen.findByText('AI teammates')).toBeInTheDocument();
159
+ expect(screen.getByText('Add reusable AI teammates to your workspace.')).toBeInTheDocument();
160
+ expect(screen.queryByText('Collaboration Ai Profiles')).not.toBeInTheDocument();
161
+ });
162
+ it('renders inline numeric feature limits next to each feature label', async () => {
163
+ vi.stubGlobal('fetch', vi.fn(async () => ({
164
+ ok: true,
165
+ json: async () => ({
166
+ pricingSource: {
167
+ environment: 'production',
168
+ runtimeMode: 'cloud'
169
+ },
170
+ plans: [
171
+ {
172
+ planId: 'free',
173
+ displayName: 'Free',
174
+ status: 'active',
175
+ defaultVersion: {
176
+ planVersionId: 'free-v1',
177
+ versionNumber: 1,
178
+ seatLimit: 12,
179
+ metadata: {}
180
+ },
181
+ features: [
182
+ {
183
+ featureKey: 'workspace.workspaces',
184
+ access: 'enabled',
185
+ label: 'Workspaces',
186
+ config: { maxWorkspaces: 1 }
187
+ },
188
+ {
189
+ featureKey: 'collaboration.ai_profiles',
190
+ access: 'limited',
191
+ label: 'AI Profiles',
192
+ publicLabel: 'AI Agents',
193
+ config: { maxAiProfiles: 4 }
194
+ },
195
+ {
196
+ featureKey: 'context.uploads',
197
+ access: 'enabled',
198
+ label: 'Cloud Storage',
199
+ config: { storageLimitMb: 24 }
200
+ },
201
+ {
202
+ featureKey: 'collaboration.team_management',
203
+ access: 'enabled',
204
+ label: 'Team Management'
205
+ }
206
+ ],
207
+ pricing: {
208
+ month: { pricingType: 'free', stripePriceId: null, unitAmount: null, currency: null, interval: 'month' },
209
+ year: null
210
+ }
211
+ }
212
+ ]
213
+ })
214
+ })));
215
+ const { container } = render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: false, onBack: () => { }, backLabel: "Back", onSelectPlan: () => { } }));
216
+ const freeCard = await screen.findByTestId('plan-card-free');
217
+ const featureTextNodes = Array.from(freeCard.querySelectorAll('span')).map((node) => node.textContent);
218
+ expect(featureTextNodes).toContain('1x Workspaces');
219
+ expect(featureTextNodes).toContain('4x AI Agents');
220
+ expect(featureTextNodes).toContain('24MB Cloud Storage');
221
+ expect(featureTextNodes).toContain('12x Team Management');
222
+ expect(container.querySelector('[class*="featureLimitUnit"]')?.textContent).toBe('MB');
223
+ });
224
+ it('renders the storage unit suffix in a smaller accent span', async () => {
225
+ vi.stubGlobal('fetch', vi.fn(async () => ({
226
+ ok: true,
227
+ json: async () => ({
228
+ pricingSource: {
229
+ environment: 'production',
230
+ runtimeMode: 'cloud'
231
+ },
232
+ plans: [
233
+ {
234
+ planId: 'free',
235
+ displayName: 'Free',
236
+ status: 'active',
237
+ defaultVersion: {
238
+ planVersionId: 'free-v1',
239
+ versionNumber: 1,
240
+ seatLimit: null,
241
+ metadata: {}
242
+ },
243
+ features: [
244
+ {
245
+ featureKey: 'context.uploads',
246
+ access: 'enabled',
247
+ label: 'Cloud Storage',
248
+ config: { storageLimitMb: 64 }
249
+ }
250
+ ],
251
+ pricing: {
252
+ month: { pricingType: 'free', stripePriceId: null, unitAmount: null, currency: null, interval: 'month' },
253
+ year: null
254
+ }
255
+ }
256
+ ]
257
+ })
258
+ })));
259
+ const { container } = render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: false, onBack: () => { }, backLabel: "Back", onSelectPlan: () => { } }));
260
+ await screen.findByText('Cloud Storage');
261
+ const accent = container.querySelector('[class*="featureLimitAccent"]');
262
+ const unit = container.querySelector('[class*="featureLimitUnit"]');
263
+ expect(accent?.textContent).toBe('64MB');
264
+ expect(unit?.textContent).toBe('MB');
265
+ });
266
+ it('hides missing yearly pricing rows and buttons instead of rendering unavailable state', async () => {
267
+ vi.stubGlobal('fetch', vi.fn(async () => ({
268
+ ok: true,
269
+ json: async () => ({
270
+ pricingSource: {
271
+ environment: 'production',
272
+ runtimeMode: 'cloud'
273
+ },
274
+ plans: [
275
+ {
276
+ planId: 'operator',
277
+ displayName: 'Operator',
278
+ status: 'active',
279
+ defaultVersion: {
280
+ planVersionId: 'operator-v1',
281
+ versionNumber: 1,
282
+ seatLimit: null,
283
+ metadata: {}
284
+ },
285
+ features: [],
286
+ pricing: {
287
+ month: { pricingType: 'stripe', stripePriceId: 'price_operator_month', unitAmount: 999, currency: 'usd', interval: 'month' },
288
+ year: null
289
+ }
290
+ }
291
+ ]
292
+ })
293
+ })));
294
+ render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: true, onBack: () => { }, backLabel: "Back", onSelectPlan: () => { } }));
295
+ const operatorCard = await screen.findByTestId('plan-card-operator');
296
+ expect(within(operatorCard).getByText('$9.99')).toBeInTheDocument();
297
+ expect(within(operatorCard).getByText('/ month')).toBeInTheDocument();
298
+ expect(within(operatorCard).queryByText('/ year')).not.toBeInTheDocument();
299
+ expect(within(operatorCard).queryByText('Unavailable')).not.toBeInTheDocument();
300
+ expect(within(operatorCard).getByRole('button', { name: 'Choose Monthly' })).toBeInTheDocument();
301
+ expect(within(operatorCard).queryByRole('button', { name: 'Choose Yearly' })).not.toBeInTheDocument();
302
+ });
95
303
  it('does not mark a plan current when only the plan id matches but the version does not', async () => {
96
304
  render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: true, currentPlanId: "team-5", currentPlanVersionId: "team-5-v1", currentEntitlementState: "active", onBack: () => { }, backLabel: "Back", onSelectPlan: () => { } }));
97
305
  expect(await screen.findByRole('heading', { name: 'Subscription Plans' })).toBeInTheDocument();
@@ -102,15 +310,64 @@ describe('PlanComparisonPage', () => {
102
310
  expect(await screen.findByRole('heading', { name: 'Subscription Plans' })).toBeInTheDocument();
103
311
  expect(screen.getByText('Current Plan')).toBeInTheDocument();
104
312
  });
313
+ it('can show the current plan as a non-interactive indicator when billing is managed from page chrome', async () => {
314
+ const onSelectPlan = vi.fn();
315
+ render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: true, currentPlanId: "team-5", currentPlanVersionId: "team-5-v2", currentEntitlementState: "active", canManageCurrentPlan: true, currentPlanCardActionMode: "indicator", onBack: () => { }, backLabel: "Back", onSelectPlan: onSelectPlan }));
316
+ expect(await screen.findByRole('heading', { name: 'Subscription Plans' })).toBeInTheDocument();
317
+ const currentCard = screen.getByTestId('plan-card-team-5');
318
+ expect(currentCard).not.toHaveAttribute('role', 'button');
319
+ expect(screen.queryByTestId('plan-manage-team-5')).not.toBeInTheDocument();
320
+ expect(screen.queryByRole('button', { name: 'Manage Plan' })).not.toBeInTheDocument();
321
+ expect(screen.getByTestId('plan-current-team-5')).toBeDisabled();
322
+ fireEvent.click(currentCard);
323
+ expect(onSelectPlan).not.toHaveBeenCalled();
324
+ });
325
+ it('can render the page header bar even when shell chrome is present', async () => {
326
+ render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: true, chrome: _jsx("div", { children: "Shell chrome" }), showHeaderBarWithChrome: true, topActions: _jsx("button", { type: "button", children: "Manage billing" }), onBack: () => { }, backLabel: "Back to App", onSelectPlan: () => { } }));
327
+ expect(await screen.findByRole('heading', { name: 'Subscription Plans' })).toBeInTheDocument();
328
+ expect(screen.getByRole('button', { name: 'Back to App' })).toBeInTheDocument();
329
+ expect(screen.getByRole('button', { name: 'Manage billing' })).toBeInTheDocument();
330
+ });
105
331
  it('does not mark a canceled entitlement as current through the plan-id fallback path', async () => {
106
332
  render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: true, currentPlanId: "team-5", currentPlanVersionId: null, currentEntitlementState: "canceled", onBack: () => { }, backLabel: "Back", onSelectPlan: () => { } }));
107
333
  expect(await screen.findByRole('heading', { name: 'Subscription Plans' })).toBeInTheDocument();
108
334
  expect(screen.queryByText('Current Plan')).not.toBeInTheDocument();
109
335
  });
336
+ it('does not mark a linked pending-plan-selection entitlement as the current plan', async () => {
337
+ render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: true, currentPlanId: "team-5", currentPlanVersionId: "team-5-v2", currentEntitlementState: "pending_plan_selection", canManageCurrentPlan: true, onBack: () => { }, backLabel: "Back", onSelectPlan: () => { } }));
338
+ expect(await screen.findByRole('heading', { name: 'Subscription Plans' })).toBeInTheDocument();
339
+ expect(screen.queryByRole('button', { name: 'Manage Plan' })).not.toBeInTheDocument();
340
+ expect(screen.queryByText('Current Plan')).not.toBeInTheDocument();
341
+ expect(screen.getByRole('button', { name: 'Choose Monthly' })).toBeInTheDocument();
342
+ });
110
343
  it('can disable the page back button while onboarding remains blocked', async () => {
111
344
  render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: true, onBack: () => { }, backLabel: "Back to App", backDisabled: true, onSelectPlan: () => { } }));
112
345
  expect(await screen.findByRole('button', { name: 'Back to App' })).toBeDisabled();
113
346
  });
347
+ it('shows pricing before auth resolves but keeps plan selection disabled until bootstrap finishes', async () => {
348
+ const onSelectPlan = vi.fn();
349
+ const view = render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: false, authSessionResolved: false, onBack: () => { }, backLabel: "Back", onSelectPlan: onSelectPlan }));
350
+ expect(await screen.findByRole('heading', { name: 'Subscription Plans' })).toBeInTheDocument();
351
+ const freeCard = screen.getByTestId('plan-card-free');
352
+ expect(screen.getByRole('button', { name: 'Get Started Free' })).toBeDisabled();
353
+ expect(screen.getByRole('button', { name: 'Get Started Monthly' })).toBeDisabled();
354
+ expect(freeCard).not.toHaveAttribute('role', 'button');
355
+ view.rerender(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: false, authSessionResolved: true, onBack: () => { }, backLabel: "Back", onSelectPlan: onSelectPlan }));
356
+ const enabledFreeCard = screen.getByTestId('plan-card-free');
357
+ expect(screen.getByRole('button', { name: 'Get Started Free' })).toBeEnabled();
358
+ expect(screen.getByRole('button', { name: 'Get Started Monthly' })).toBeEnabled();
359
+ expect(enabledFreeCard).toHaveAttribute('role', 'button');
360
+ fireEvent.click(screen.getByRole('button', { name: 'Get Started Free' }));
361
+ await waitFor(() => {
362
+ expect(onSelectPlan).toHaveBeenCalledWith({
363
+ planId: 'free',
364
+ planVersionId: 'free-v1',
365
+ interval: 'month',
366
+ pricingType: 'free',
367
+ isCurrentPlan: false
368
+ });
369
+ });
370
+ });
114
371
  it('selects the whole plan card using the default available interval', async () => {
115
372
  const onSelectPlan = vi.fn();
116
373
  render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: false, onBack: () => { }, backLabel: "Back", onSelectPlan: onSelectPlan }));
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
3
  import { useLocation, useNavigate } from 'react-router-dom';
4
4
  import { User } from 'lucide-react';
@@ -9,16 +9,29 @@ import { resolveTaskforceCloudEnvironmentFromBaseUrl } from '../../config/cloudE
9
9
  import { ACCOUNT_PROFILE_SUMMARY_PATH, invalidateAccountProfileSummaryCache, loadAccountProfileSummaryCached } from '../../utils/accountProfileSummaryCache';
10
10
  import { isCommercialEntitlementActive, resolveCommercialLifecyclePresentation } from '../../utils/commercialLifecyclePresentation';
11
11
  const TRANSIENT_CHECKOUT_QUERY_CLEAR_DELAY_MS = 1600;
12
- const CHECKOUT_CONFIRM_RETRY_DELAYS_MS = [0, 500, 1000, 2000];
12
+ const CHECKOUT_CONFIRM_INITIAL_RETRY_DELAYS_MS = [0, 500, 1000, 2000];
13
+ const CHECKOUT_CONFIRM_RETRY_INTERVAL_MS = 5000;
14
+ const CHECKOUT_CONFIRM_MAX_AUTO_RETRY_MS = 45000;
15
+ const HIDDEN_GATE_MESSAGE = 'Choose a plan to continue.';
13
16
  function shouldRetryCheckoutConfirmation(statusCode, errorCode) {
14
17
  if (statusCode === 401) {
15
18
  return true;
16
19
  }
17
- return String(errorCode || '').trim().toUpperCase() === 'CHECKOUT_SESSION_INCOMPLETE';
20
+ const normalizedErrorCode = String(errorCode || '').trim().toUpperCase();
21
+ return normalizedErrorCode === 'CHECKOUT_SESSION_INCOMPLETE'
22
+ || normalizedErrorCode === 'CHECKOUT_PLAN_VERSION_UNRESOLVED';
18
23
  }
19
24
  function parseInterval(raw) {
20
25
  return raw === 'year' ? 'year' : 'month';
21
26
  }
27
+ function normalizeIntervalValue(raw) {
28
+ const normalized = String(raw || '').trim().toLowerCase();
29
+ if (normalized === 'year')
30
+ return 'year';
31
+ if (normalized === 'month')
32
+ return 'month';
33
+ return null;
34
+ }
22
35
  function normalizeApiBaseUrl(raw) {
23
36
  const trimmed = String(raw || '').trim();
24
37
  if (!trimmed)
@@ -40,16 +53,19 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
40
53
  const location = useLocation();
41
54
  const [accountProfileSummary, setAccountProfileSummary] = useState(null);
42
55
  const [actionBusy, setActionBusy] = useState(false);
56
+ const [continueActionBusy, setContinueActionBusy] = useState(false);
43
57
  const [feedback, setFeedback] = useState(null);
44
58
  const checkoutStartRan = useRef(false);
45
- const checkoutSuccessHandledRef = useRef(null);
59
+ const checkoutSuccessSettledRef = useRef(null);
46
60
  const transientQueryClearTimeoutRef = useRef(null);
61
+ const onContinueToTaskforceRef = useRef(onContinueToTaskforce);
47
62
  const query = useMemo(() => new URLSearchParams(location.search), [location.search]);
48
63
  const checkoutState = String(query.get('checkout') || '').trim().toLowerCase();
49
64
  const gateState = String(query.get('gate') || '').trim().toLowerCase();
50
65
  const queryPlanId = String(query.get('planId') || '').trim();
51
66
  const queryPlanVersionId = String(query.get('planVersionId') || '').trim();
52
67
  const queryInterval = parseInterval(query.get('interval'));
68
+ const queryIntervalValue = normalizeIntervalValue(query.get('interval'));
53
69
  const querySessionId = String(query.get('session_id') || '').trim();
54
70
  const normalizedApiBaseUrl = useMemo(() => normalizeApiBaseUrl(apiBaseUrl), [apiBaseUrl]);
55
71
  const normalizedConnectedEnvironmentSource = useMemo(() => normalizeApiBaseUrl(connectedEnvironmentSource), [connectedEnvironmentSource]);
@@ -80,16 +96,15 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
80
96
  const nextQuery = params.toString();
81
97
  navigate(`/${nextQuery ? `?${nextQuery}` : ''}${location.hash || ''}`);
82
98
  }, [location.hash, location.search, navigate]);
83
- const pricingEndpoints = useMemo(() => {
84
- const endpoints = [
85
- normalizedApiBaseUrl ? `${normalizedApiBaseUrl}/api/taskforce/public/pricing` : '',
86
- '/api/taskforce/public/pricing'
87
- ].map((value) => String(value || '').trim()).filter((value, index, all) => value && all.indexOf(value) === index);
88
- return endpoints;
89
- }, [normalizedApiBaseUrl]);
99
+ const pricingEndpoint = useMemo(() => buildCloudBillingUrl('/api/taskforce/public/pricing'), [buildCloudBillingUrl]);
90
100
  const lifecyclePresentation = useMemo(() => resolveCommercialLifecyclePresentation(accountProfileSummary, gateState), [accountProfileSummary, gateState]);
91
101
  const hasResolvedActiveEntitlement = useMemo(() => lifecyclePresentation.allowReturnToApp, [lifecyclePresentation.allowReturnToApp]);
92
- const gateMessage = useMemo(() => lifecyclePresentation.message, [lifecyclePresentation.message]);
102
+ const gateMessage = useMemo(() => {
103
+ const message = String(lifecyclePresentation.message || '').trim();
104
+ if (!message || message === HIDDEN_GATE_MESSAGE)
105
+ return null;
106
+ return message;
107
+ }, [lifecyclePresentation.message]);
93
108
  const clearTransientQueryState = useCallback(() => {
94
109
  const next = new URLSearchParams(location.search);
95
110
  next.delete('checkout');
@@ -110,6 +125,9 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
110
125
  transientQueryClearTimeoutRef.current = null;
111
126
  }, TRANSIENT_CHECKOUT_QUERY_CLEAR_DELAY_MS);
112
127
  }, [clearTransientQueryState]);
128
+ useEffect(() => {
129
+ onContinueToTaskforceRef.current = onContinueToTaskforce;
130
+ }, [onContinueToTaskforce]);
113
131
  const loadAccountProfileSummary = useCallback(async (options) => {
114
132
  const accountProfileSummaryUrl = buildCloudBillingUrl(ACCOUNT_PROFILE_SUMMARY_PATH);
115
133
  if (!isAuthenticated) {
@@ -131,11 +149,14 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
131
149
  return null;
132
150
  }
133
151
  }, [authUserId, buildCloudBillingUrl, isAuthenticated, onAccountProfileSummaryChange]);
134
- const resolveRecoveryMessage = useCallback((summary, fallback) => {
152
+ const resolveRecoveryMessage = useCallback((summary, fallback, options) => {
153
+ const normalizedFallback = String(fallback || '').trim();
154
+ if (options?.preferFallback && normalizedFallback)
155
+ return normalizedFallback;
135
156
  const message = resolveCommercialLifecyclePresentation(summary, gateState).message;
136
157
  if (message)
137
158
  return message;
138
- return String(fallback || 'Unable to confirm checkout completion.').trim() || 'Unable to confirm checkout completion.';
159
+ return normalizedFallback || 'Unable to confirm checkout completion.';
139
160
  }, [gateState]);
140
161
  const shouldAutoContinueAfterActivation = useCallback((summary, fallbackGate) => {
141
162
  return !resolveCommercialLifecyclePresentation(summary, fallbackGate).allowReturnToApp;
@@ -226,6 +247,47 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
226
247
  retryable: false
227
248
  };
228
249
  }
250
+ const confirmViaSummary = async () => {
251
+ invalidateAccountProfileSummaryCache(buildCloudBillingUrl(ACCOUNT_PROFILE_SUMMARY_PATH), { identityKey: authUserId });
252
+ const summary = await loadAccountProfileSummary({ force: true });
253
+ const summaryState = String(summary?.entitlementState || '').trim().toLowerCase();
254
+ if (!isCommercialEntitlementActive(summaryState)) {
255
+ return false;
256
+ }
257
+ const expectedPlanId = queryPlanId;
258
+ const expectedPlanVersionId = queryPlanVersionId;
259
+ const expectedInterval = queryIntervalValue;
260
+ const currentPlanId = String(summary?.planId || '').trim();
261
+ const currentPlanVersionId = String(summary?.planVersionId || '').trim();
262
+ const currentInterval = normalizeIntervalValue(summary?.billingInterval ?? null);
263
+ const preSummary = options?.preConfirmationSummary ?? null;
264
+ const preState = String(preSummary?.entitlementState || '').trim().toLowerCase();
265
+ const preWasActive = isCommercialEntitlementActive(preState);
266
+ const prePlanId = String(preSummary?.planId || '').trim();
267
+ const prePlanVersionId = String(preSummary?.planVersionId || '').trim();
268
+ const preInterval = normalizeIntervalValue(preSummary?.billingInterval ?? null);
269
+ if (expectedPlanId && currentPlanId && currentPlanId !== expectedPlanId) {
270
+ return false;
271
+ }
272
+ if (expectedPlanVersionId && currentPlanVersionId && currentPlanVersionId !== expectedPlanVersionId) {
273
+ return false;
274
+ }
275
+ if (expectedInterval && currentInterval && currentInterval !== expectedInterval) {
276
+ return false;
277
+ }
278
+ if (preWasActive) {
279
+ const requestedPlanChanged = Boolean(expectedPlanId) && currentPlanId === expectedPlanId && prePlanId !== currentPlanId;
280
+ const requestedPlanVersionChanged = Boolean(expectedPlanVersionId) && currentPlanVersionId === expectedPlanVersionId && prePlanVersionId !== currentPlanVersionId;
281
+ const requestedIntervalChanged = Boolean(expectedInterval) && currentInterval === expectedInterval && preInterval !== currentInterval;
282
+ if (!requestedPlanChanged && !requestedPlanVersionChanged && !requestedIntervalChanged) {
283
+ return false;
284
+ }
285
+ }
286
+ if (options?.autoContinueOnActivation === true) {
287
+ await onContinueToTaskforceRef.current?.();
288
+ }
289
+ return true;
290
+ };
229
291
  try {
230
292
  const res = await fetch(buildCloudBillingUrl('/api/taskforce/billing/checkout-session/confirm'), {
231
293
  method: 'POST',
@@ -236,17 +298,18 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
236
298
  const payload = await res.json().catch(() => ({}));
237
299
  if (!res.ok) {
238
300
  const errorCode = String(payload?.code || '').trim();
301
+ const retryable = shouldRetryCheckoutConfirmation(res.status, errorCode);
302
+ if (retryable && await confirmViaSummary()) {
303
+ return { confirmed: true };
304
+ }
239
305
  return {
240
306
  confirmed: false,
241
307
  errorMessage: String(payload?.error || 'Unable to confirm checkout completion.'),
242
- retryable: shouldRetryCheckoutConfirmation(res.status, errorCode)
308
+ retryable
243
309
  };
244
310
  }
245
- invalidateAccountProfileSummaryCache(buildCloudBillingUrl(ACCOUNT_PROFILE_SUMMARY_PATH), { identityKey: authUserId });
246
- const summary = await loadAccountProfileSummary({ force: true });
247
- const summaryState = String(summary?.entitlementState || '').trim().toLowerCase();
248
- if (options?.autoContinueOnActivation === true && isCommercialEntitlementActive(summaryState)) {
249
- await onContinueToTaskforce?.();
311
+ if (await confirmViaSummary()) {
312
+ return { confirmed: true };
250
313
  }
251
314
  return { confirmed: true };
252
315
  }
@@ -257,14 +320,14 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
257
320
  retryable: true
258
321
  };
259
322
  }
260
- }, [authUserId, buildCloudBillingUrl, loadAccountProfileSummary, onContinueToTaskforce]);
323
+ }, [authUserId, buildCloudBillingUrl, loadAccountProfileSummary, queryIntervalValue, queryPlanId, queryPlanVersionId]);
261
324
  const openBillingPortal = useCallback(async () => {
262
325
  if (!isAuthenticated) {
263
326
  navigate(`/login?mode=login&next=${encodeURIComponent(buildEmbeddedPlansPath())}`);
264
327
  return;
265
328
  }
266
329
  setActionBusy(true);
267
- setFeedback(null);
330
+ setFeedback({ type: 'info', message: 'Opening billing portal...' });
268
331
  try {
269
332
  const res = await fetch(buildCloudBillingUrl('/api/taskforce/billing/portal-session'), {
270
333
  method: 'POST',
@@ -289,6 +352,17 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
289
352
  setActionBusy(false);
290
353
  }
291
354
  }, [buildCloudBillingUrl, isAuthenticated, navigate]);
355
+ const handleContinueToTaskforce = useCallback(async () => {
356
+ if (!onContinueToTaskforce || continueActionBusy || continueBusy)
357
+ return;
358
+ setContinueActionBusy(true);
359
+ try {
360
+ await onContinueToTaskforce();
361
+ }
362
+ finally {
363
+ setContinueActionBusy(false);
364
+ }
365
+ }, [continueActionBusy, continueBusy, onContinueToTaskforce]);
292
366
  useEffect(() => {
293
367
  void loadAccountProfileSummary();
294
368
  }, [loadAccountProfileSummary]);
@@ -306,7 +380,7 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
306
380
  }, []);
307
381
  useEffect(() => {
308
382
  if (checkoutState !== 'success') {
309
- checkoutSuccessHandledRef.current = null;
383
+ checkoutSuccessSettledRef.current = null;
310
384
  }
311
385
  }, [checkoutState]);
312
386
  useEffect(() => {
@@ -326,7 +400,8 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
326
400
  if (checkoutState === 'success') {
327
401
  checkoutStartRan.current = true;
328
402
  setFeedback({ type: 'success', message: 'Checkout completed successfully. Finalizing your plan...' });
329
- if (!authSessionResolved) {
403
+ const shouldWaitForAuthBootstrap = !isAuthenticated && !authSessionResolved;
404
+ if (shouldWaitForAuthBootstrap) {
330
405
  return () => {
331
406
  cancelled = true;
332
407
  pendingRetryTimeouts.forEach((timeoutId) => window.clearTimeout(timeoutId));
@@ -342,33 +417,40 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
342
417
  };
343
418
  }
344
419
  const successFlowKey = querySessionId || '__missing_session__';
345
- if (checkoutSuccessHandledRef.current === successFlowKey) {
420
+ if (checkoutSuccessSettledRef.current === successFlowKey) {
346
421
  return () => {
347
422
  cancelled = true;
348
423
  pendingRetryTimeouts.forEach((timeoutId) => window.clearTimeout(timeoutId));
349
424
  pendingRetryTimeouts.clear();
350
425
  };
351
426
  }
352
- checkoutSuccessHandledRef.current = successFlowKey;
353
427
  void (async () => {
428
+ const autoConfirmStartedAt = Date.now();
354
429
  const preConfirmationSummary = await loadAccountProfileSummary({ force: true });
355
430
  if (cancelled)
356
431
  return;
357
432
  let confirmation = querySessionId
358
433
  ? { confirmed: false, errorMessage: 'Unable to confirm checkout completion.', retryable: true }
359
434
  : { confirmed: false, errorMessage: 'Checkout session is missing.', retryable: false };
360
- for (const delayMs of CHECKOUT_CONFIRM_RETRY_DELAYS_MS) {
435
+ let attemptIndex = 0;
436
+ while (true) {
437
+ const delayMs = attemptIndex < CHECKOUT_CONFIRM_INITIAL_RETRY_DELAYS_MS.length
438
+ ? CHECKOUT_CONFIRM_INITIAL_RETRY_DELAYS_MS[attemptIndex]
439
+ : CHECKOUT_CONFIRM_RETRY_INTERVAL_MS;
440
+ attemptIndex += 1;
361
441
  await waitForRetry(delayMs);
362
442
  if (cancelled)
363
443
  return;
364
444
  confirmation = querySessionId
365
445
  ? await confirmCheckoutSession(querySessionId, {
366
- autoContinueOnActivation: shouldAutoContinueAfterActivation(preConfirmationSummary, gateState)
446
+ autoContinueOnActivation: shouldAutoContinueAfterActivation(preConfirmationSummary, gateState),
447
+ preConfirmationSummary
367
448
  })
368
449
  : { confirmed: false, errorMessage: 'Checkout session is missing.', retryable: false };
369
450
  if (cancelled)
370
451
  return;
371
452
  if (confirmation.confirmed) {
453
+ checkoutSuccessSettledRef.current = successFlowKey;
372
454
  setFeedback({ type: 'success', message: 'Checkout completed successfully.' });
373
455
  scheduleTransientQueryClear();
374
456
  return;
@@ -376,6 +458,9 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
376
458
  if (!confirmation.retryable) {
377
459
  break;
378
460
  }
461
+ if ((Date.now() - autoConfirmStartedAt) >= CHECKOUT_CONFIRM_MAX_AUTO_RETRY_MS) {
462
+ break;
463
+ }
379
464
  }
380
465
  if (cancelled)
381
466
  return;
@@ -383,11 +468,18 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
383
468
  const summary = await loadAccountProfileSummary({ force: true });
384
469
  if (cancelled)
385
470
  return;
471
+ if (!confirmation.retryable) {
472
+ checkoutSuccessSettledRef.current = successFlowKey;
473
+ }
386
474
  setFeedback({
387
475
  type: 'error',
388
- message: resolveRecoveryMessage(summary, confirmation.errorMessage)
476
+ message: resolveRecoveryMessage(summary, confirmation.errorMessage, {
477
+ preferFallback: !confirmation.retryable
478
+ })
389
479
  });
390
- scheduleTransientQueryClear();
480
+ if (!confirmation.retryable) {
481
+ scheduleTransientQueryClear();
482
+ }
391
483
  return;
392
484
  }
393
485
  })();
@@ -464,7 +556,7 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
464
556
  }, [accountProfileSummary, gateState, isAuthenticated, navigate, openBillingPortal, shouldAutoContinueAfterActivation, startCheckout]);
465
557
  const handleBack = useCallback(() => {
466
558
  if (hasResolvedActiveEntitlement && onContinueToTaskforce) {
467
- void onContinueToTaskforce();
559
+ void handleContinueToTaskforce();
468
560
  return;
469
561
  }
470
562
  if (embedded) {
@@ -476,9 +568,8 @@ export function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessio
476
568
  return;
477
569
  }
478
570
  navigate('/');
479
- }, [closeEmbeddedPlansScreen, embedded, hasResolvedActiveEntitlement, navigate, onContinueToTaskforce]);
480
- const continueAction = hasResolvedActiveEntitlement && onContinueToTaskforce ? (_jsx("button", { className: styles.navAction, onClick: () => { void onContinueToTaskforce(); }, disabled: continueBusy || actionBusy, children: "Take Me to Taskforce" })) : null;
481
- const topActions = embedded ? (_jsxs(_Fragment, { children: [continueAction, isAuthenticated && accountProfileSummary?.stripeCustomerId && (_jsx("button", { className: styles.navAction, onClick: () => { void openBillingPortal(); }, disabled: actionBusy, children: "Manage billing" }))] })) : (_jsxs(_Fragment, { children: [_jsx("button", { className: styles.navAction, onClick: handleBack, disabled: continueBusy || (isAuthenticated && !hasResolvedActiveEntitlement), children: hasResolvedActiveEntitlement ? 'Take Me to Taskforce' : 'Back' }), isAuthenticated && accountProfileSummary?.stripeCustomerId && (_jsx("button", { className: styles.navAction, onClick: () => { void openBillingPortal(); }, disabled: actionBusy, children: "Manage billing" })), !isAuthenticated && (_jsxs("button", { className: styles.navAction, onClick: () => navigate(`/login?mode=login&next=${encodeURIComponent(buildEmbeddedPlansPath())}`), children: [_jsx(User, { size: 16, style: { marginRight: '8px', verticalAlign: 'text-bottom' } }), "Sign In"] }))] }));
482
- const chrome = embedded ? null : (_jsx(AppShellHeader, { projectName: projectName, currentWorkspaceId: currentWorkspaceId, runtimeMode: runtimeMode === 'cloud' ? 'cloud' : 'local', theme: currentTheme, actions: topActions }));
483
- return (_jsx(PlanComparisonPage, { chrome: chrome, heading: "Subscription Plans", subtitle: "Manage your subscription and explore available features. Your current plan is highlighted below.", isAuthenticated: isAuthenticated, authSessionResolved: authSessionResolved, currentPlanId: String(accountProfileSummary?.planId || queryPlanId || '').trim() || null, currentPlanVersionId: String(accountProfileSummary?.planVersionId || queryPlanVersionId || '').trim() || null, currentEntitlementState: String(accountProfileSummary?.entitlementState || '').trim() || null, canManageCurrentPlan: Boolean(accountProfileSummary?.stripeCustomerId), pricingEndpoint: pricingEndpoints[0], statusBanner: feedback, onBack: handleBack, backLabel: hasResolvedActiveEntitlement ? 'Take Me to Taskforce' : (embedded ? 'Back to Board' : 'Back to App'), backDisabled: continueBusy || (isAuthenticated && !hasResolvedActiveEntitlement), topActions: embedded ? topActions : null, shellOwnsScroll: shellOwnsScroll, showPageBackButton: !embedded, fallbackPricingSource: fallbackPricingSource, onSelectPlan: handleSelectPlan }));
571
+ }, [closeEmbeddedPlansScreen, embedded, handleContinueToTaskforce, hasResolvedActiveEntitlement, navigate, onContinueToTaskforce]);
572
+ const headerActions = embedded ? null : (_jsxs(_Fragment, { children: [_jsx("button", { className: styles.navAction, onClick: handleBack, disabled: continueBusy || continueActionBusy || (isAuthenticated && !hasResolvedActiveEntitlement), children: hasResolvedActiveEntitlement ? 'Take Me to Taskforce' : 'Back' }), isAuthenticated && accountProfileSummary?.stripeCustomerId && (_jsx("button", { className: styles.navAction, onClick: () => { void openBillingPortal(); }, disabled: actionBusy, children: "Manage billing" })), !isAuthenticated && (_jsxs("button", { className: styles.navAction, onClick: () => navigate(`/login?mode=login&next=${encodeURIComponent(buildEmbeddedPlansPath())}`), children: [_jsx(User, { size: 16, style: { marginRight: '8px', verticalAlign: 'text-bottom' } }), "Sign In"] }))] }));
573
+ const chrome = embedded ? null : (_jsx(AppShellHeader, { projectName: projectName, currentWorkspaceId: currentWorkspaceId, runtimeMode: runtimeMode === 'cloud' ? 'cloud' : 'local', theme: currentTheme, onBrandClick: handleBack, actions: headerActions }));
574
+ return (_jsx(PlanComparisonPage, { chrome: chrome, heading: "Subscription Plans", subtitle: "Manage your subscription and explore available features. Your current plan is highlighted below.", isAuthenticated: isAuthenticated, authSessionResolved: authSessionResolved, currentPlanId: String(accountProfileSummary?.planId || queryPlanId || '').trim() || null, currentPlanVersionId: String(accountProfileSummary?.planVersionId || queryPlanVersionId || '').trim() || null, currentEntitlementState: String(accountProfileSummary?.entitlementState || '').trim() || null, markCurrentPlan: lifecyclePresentation.markCurrentPlan, canManageCurrentPlan: Boolean(accountProfileSummary?.stripeCustomerId), pricingEndpoint: pricingEndpoint, statusBanner: feedback, onBack: handleBack, backLabel: hasResolvedActiveEntitlement ? 'Take Me to Taskforce' : (embedded ? 'Back to Board' : 'Back to App'), backDisabled: continueBusy || continueActionBusy || (isAuthenticated && !hasResolvedActiveEntitlement), topActions: null, shellOwnsScroll: shellOwnsScroll, showPageBackButton: false, showHeaderBarWithChrome: false, currentPlanCardActionMode: "manage", fallbackPricingSource: fallbackPricingSource, onSelectPlan: handleSelectPlan }));
484
575
  }