@taskforcehq/taskforce 0.3.303 → 0.3.305

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 (237) hide show
  1. package/README.md +140 -247
  2. package/dist/Taskforce.module.css +102 -5
  3. package/dist/TaskforceCore.js +635 -238
  4. package/dist/TaskforceCore.test.js +2243 -495
  5. package/dist/annotatedAttachments/service.d.ts +1 -1
  6. package/dist/annotatedAttachments/types.d.ts +1 -1
  7. package/dist/compat/workspaceSyncCompat.js +6 -0
  8. package/dist/components/features/AgentsModule.js +1 -1
  9. package/dist/components/features/AgentsModule.test.js +1 -1
  10. package/dist/components/features/DocumentIndex.d.ts +1 -1
  11. package/dist/components/features/DocumentIndex.js +1 -1
  12. package/dist/components/features/DocumentViewer.d.ts +1 -1
  13. package/dist/components/features/DocumentViewer.js +32 -9
  14. package/dist/components/features/DocumentWorkspace.d.ts +5 -22
  15. package/dist/components/features/DocumentWorkspace.js +12 -155
  16. package/dist/components/features/DocumentWorkspace.test.js +193 -6
  17. package/dist/components/features/TaskSettings.js +87 -41
  18. package/dist/components/features/TaskSettings.test.js +180 -40
  19. package/dist/components/features/documentWorkspaceModel.d.ts +24 -0
  20. package/dist/components/features/documentWorkspaceModel.js +57 -0
  21. package/dist/components/features/useDocumentWorkspaceController.d.ts +34 -0
  22. package/dist/components/features/useDocumentWorkspaceController.js +113 -0
  23. package/dist/components/task/TaskActionHeader.d.ts +2 -1
  24. package/dist/components/task/TaskActionHeader.js +3 -3
  25. package/dist/components/task/TaskActionHeader.test.js +8 -0
  26. package/dist/components/task/TaskCard.js +16 -1
  27. package/dist/components/task/TaskCard.test.js +31 -0
  28. package/dist/components/task/TaskForm.d.ts +9 -8
  29. package/dist/components/task/TaskForm.js +374 -219
  30. package/dist/components/task/TaskForm.test.js +482 -361
  31. package/dist/components/task/TaskKanban.d.ts +1 -1
  32. package/dist/components/task/TaskKanban.js +33 -161
  33. package/dist/components/task/TaskStatusActions.d.ts +6 -1
  34. package/dist/components/task/TaskStatusActions.js +8 -3
  35. package/dist/components/task/TaskStatusActions.test.js +9 -0
  36. package/dist/components/task/taskKanbanDropRules.d.ts +58 -0
  37. package/dist/components/task/taskKanbanDropRules.js +187 -0
  38. package/dist/components/task/taskKanbanDropRules.test.d.ts +1 -0
  39. package/dist/components/task/taskKanbanDropRules.test.js +114 -0
  40. package/dist/components/ui/Modal.d.ts +1 -1
  41. package/dist/components/ui/Modal.js +1 -0
  42. package/dist/components/views/AppShellHeader.js +5 -1
  43. package/dist/components/views/AppShellHeader.test.js +4 -0
  44. package/dist/components/views/PlanComparisonPage.d.ts +3 -2
  45. package/dist/components/views/PlanComparisonPage.js +9 -10
  46. package/dist/components/views/PlanComparisonPage.test.js +55 -41
  47. package/dist/components/views/PlansPage.d.ts +5 -1
  48. package/dist/components/views/PlansPage.js +150 -81
  49. package/dist/components/views/PlansPage.test.js +367 -41
  50. package/dist/components/views/StandaloneLayout.js +135 -54
  51. package/dist/components/views/WidgetView.js +11 -2
  52. package/dist/components/views/panels/FilterToolbar.test.js +6 -4
  53. package/dist/components/views/standalone/modals/AccountHubModal.d.ts +2 -14
  54. package/dist/components/views/standalone/modals/AccountHubModal.js +12 -14
  55. package/dist/components/views/standalone/modals/AccountHubModal.test.js +24 -1
  56. package/dist/components/views/standalone/modals/SyncStatusModal.js +1 -1
  57. package/dist/config/envSchema.js +1 -1
  58. package/dist/core/AiProfileService.d.ts +6 -1
  59. package/dist/core/AiProfileService.js +161 -16
  60. package/dist/core/AiProfileService.test.js +3 -1
  61. package/dist/core/AiProfiles.test.js +200 -0
  62. package/dist/core/AuthTokenService.test.d.ts +1 -0
  63. package/dist/core/AuthTokenService.test.js +78 -0
  64. package/dist/core/DeletedTaskLifecycleService.d.ts +2 -1
  65. package/dist/core/EntitlementsPolicy.test.js +75 -13
  66. package/dist/core/PlanEntitlementService.d.ts +9 -1
  67. package/dist/core/PlanEntitlementService.js +144 -19
  68. package/dist/core/PlanVersionPolicy.test.js +19 -26
  69. package/dist/core/SignupMonetizationSettings.test.js +75 -15
  70. package/dist/core/SystemAdmin.test.js +212 -56
  71. package/dist/core/TaskActivityService.d.ts +4 -1
  72. package/dist/core/TaskActivityService.js +45 -0
  73. package/dist/core/TaskAuditTimeline.test.js +52 -1
  74. package/dist/core/TaskTaxonomyValidation.test.js +53 -0
  75. package/dist/core/Taskforce.d.ts +18 -11
  76. package/dist/core/Taskforce.js +93 -12
  77. package/dist/core/WorkspacePlanMode.test.js +73 -8
  78. package/dist/core/shared.d.ts +2 -0
  79. package/dist/core/shared.js +11 -0
  80. package/dist/documentReviews/service.d.ts +1 -1
  81. package/dist/documentReviews/types.d.ts +1 -1
  82. package/dist/hooks/auth/useTaskforceAuthBootstrap.d.ts +48 -0
  83. package/dist/hooks/auth/useTaskforceAuthBootstrap.js +219 -0
  84. package/dist/hooks/sync/auth.d.ts +37 -0
  85. package/dist/hooks/sync/auth.js +63 -0
  86. package/dist/hooks/sync/bootstrap.d.ts +34 -0
  87. package/dist/hooks/sync/bootstrap.js +52 -0
  88. package/dist/hooks/sync/orchestratorShared.d.ts +36 -0
  89. package/dist/hooks/sync/orchestratorShared.js +209 -0
  90. package/dist/hooks/sync/orchestratorShared.test.d.ts +1 -0
  91. package/dist/hooks/sync/orchestratorShared.test.js +49 -0
  92. package/dist/hooks/sync/realtime.d.ts +25 -0
  93. package/dist/hooks/sync/realtime.js +60 -0
  94. package/dist/hooks/sync/recovery.d.ts +69 -0
  95. package/dist/hooks/sync/recovery.js +118 -0
  96. package/dist/hooks/sync/transfers.d.ts +123 -0
  97. package/dist/hooks/sync/transfers.js +435 -0
  98. package/dist/hooks/sync/useDataVersionRefresh.d.ts +16 -0
  99. package/dist/hooks/sync/useDataVersionRefresh.js +73 -0
  100. package/dist/hooks/ui/useResourceExport.d.ts +3 -1
  101. package/dist/hooks/ui/useResourceExport.js +5 -2
  102. package/dist/hooks/ui/useWorkflowTemplates.js +11 -6
  103. package/dist/hooks/useRealtimeSync.js +2 -1
  104. package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +8 -0
  105. package/dist/hooks/useSyncOrchestrator.context-assets.test.d.ts +1 -0
  106. package/dist/hooks/useSyncOrchestrator.context-assets.test.js +228 -0
  107. package/dist/hooks/useSyncOrchestrator.d.ts +12 -8
  108. package/dist/hooks/useSyncOrchestrator.js +388 -879
  109. package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +641 -6
  110. package/dist/hooks/useTaskMutations.d.ts +2 -1
  111. package/dist/hooks/useTaskMutations.js +57 -7
  112. package/dist/hooks/useTaskMutations.test.js +176 -0
  113. package/dist/hooks/useTaskforce.d.ts +13 -4
  114. package/dist/hooks/useTaskforce.js +302 -817
  115. package/dist/hooks/useTaskforce.sync-behavior.test.js +78 -0
  116. package/dist/hooks/useWorkspaceSyncController.d.ts +4 -1
  117. package/dist/hooks/useWorkspaceSyncController.js +33 -11
  118. package/dist/hooks/useWorkspaceSyncController.test.js +1 -0
  119. package/dist/hooks/workspace/useTaskforceApiRouting.test.js +17 -0
  120. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.d.ts +166 -0
  121. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +434 -0
  122. package/dist/hooks/workspace/workspaceLocalState.d.ts +19 -0
  123. package/dist/hooks/workspace/workspaceLocalState.js +100 -0
  124. package/dist/hooks/workspace/workspaceLocalState.test.d.ts +1 -0
  125. package/dist/hooks/workspace/workspaceLocalState.test.js +59 -0
  126. package/dist/localization/locales/en-US.js +2 -2
  127. package/dist/mcp/adminWorkspaceRegistrar.d.ts +2 -0
  128. package/dist/mcp/adminWorkspaceRegistrar.js +154 -0
  129. package/dist/mcp/canonicalAssetHelpers.d.ts +70 -0
  130. package/dist/mcp/canonicalAssetHelpers.js +259 -0
  131. package/dist/mcp/clientIntegrations.d.ts +12 -1
  132. package/dist/mcp/clientIntegrations.js +161 -6
  133. package/dist/mcp/clientIntegrations.test.js +76 -4
  134. package/dist/mcp/collaborationRegistrar.d.ts +2 -0
  135. package/dist/mcp/collaborationRegistrar.js +71 -0
  136. package/dist/mcp/documentAssetRegistrar.d.ts +2 -0
  137. package/dist/mcp/documentAssetRegistrar.js +346 -0
  138. package/dist/mcp/documentHelpers.d.ts +100 -0
  139. package/dist/mcp/documentHelpers.js +161 -0
  140. package/dist/mcp/runtime.js +2455 -3925
  141. package/dist/mcp/runtime.test.js +240 -8
  142. package/dist/mcp/taskAttachmentHelpers.d.ts +41 -0
  143. package/dist/mcp/taskAttachmentHelpers.js +60 -0
  144. package/dist/mcp/taskAttachmentTypes.d.ts +37 -0
  145. package/dist/mcp/taskAttachmentTypes.js +1 -0
  146. package/dist/mcp/taskPlanningRegistrar.d.ts +2 -0
  147. package/dist/mcp/taskPlanningRegistrar.js +418 -0
  148. package/dist/mcp/toolCatalog.d.ts +35 -0
  149. package/dist/mcp/toolCatalog.js +3 -0
  150. package/dist/plugins/vite.js +1 -1
  151. package/dist/runtime/appGateDefinitions.d.ts +1 -1
  152. package/dist/runtime/appGateDefinitions.js +1 -1
  153. package/dist/server/index.d.ts +1 -0
  154. package/dist/server/index.js +46 -3
  155. package/dist/server/index.test.js +12 -1
  156. package/dist/server/routes/admin.d.ts +1 -5
  157. package/dist/server/routes/admin.js +151 -80
  158. package/dist/server/routes/annotatedAttachments.d.ts +1 -1
  159. package/dist/server/routes/annotatedAttachments.js +1 -1
  160. package/dist/server/routes/auth.d.ts +1 -4
  161. package/dist/server/routes/auth.js +59 -64
  162. package/dist/server/routes/authSupport.d.ts +30 -0
  163. package/dist/server/routes/authSupport.js +81 -0
  164. package/dist/server/routes/billing.d.ts +1 -1
  165. package/dist/server/routes/billing.js +122 -255
  166. package/dist/server/routes/billing.test.js +257 -86
  167. package/dist/server/routes/documentReviews.d.ts +1 -1
  168. package/dist/server/routes/documentReviews.js +1 -1
  169. package/dist/server/routes/documents.d.ts +4 -2
  170. package/dist/server/routes/documents.js +73 -7
  171. package/dist/server/routes/primitives.d.ts +11 -0
  172. package/dist/server/routes/primitives.js +73 -0
  173. package/dist/server/routes/resources.d.ts +1 -1
  174. package/dist/server/routes/resources.js +1 -1
  175. package/dist/server/routes/shared.d.ts +31 -1
  176. package/dist/server/routes/shared.js +26 -0
  177. package/dist/server/routes/sync.d.ts +1 -1
  178. package/dist/server/routes/sync.integration.test.js +20 -0
  179. package/dist/server/routes/sync.js +111 -238
  180. package/dist/server/routes/tasks.d.ts +1 -1
  181. package/dist/server/routes/tasks.js +50 -8
  182. package/dist/server/routes/workspaces.d.ts +1 -1
  183. package/dist/server/routes/workspaces.js +1 -1
  184. package/dist/server/routes.d.ts +2 -9
  185. package/dist/server/routes.js +84 -181
  186. package/dist/server/routes.test.js +912 -32
  187. package/dist/shared/taskActor.d.ts +10 -0
  188. package/dist/shared/taskActor.js +1 -0
  189. package/dist/sync/collaborationSyncPayload.js +4 -0
  190. package/dist/sync/collaborationSyncPayload.test.js +8 -0
  191. package/dist/sync/collaborationSyncState.d.ts +3 -1
  192. package/dist/sync/collaborationSyncState.js +19 -0
  193. package/dist/sync/contentSyncState.js +28 -17
  194. package/dist/sync/syncApplyHandlers.d.ts +87 -1
  195. package/dist/sync/syncApplyHandlers.js +370 -8
  196. package/dist/sync/syncApplyHandlers.test.d.ts +1 -0
  197. package/dist/sync/syncApplyHandlers.test.js +379 -0
  198. package/dist/sync/syncService.d.ts +9 -1
  199. package/dist/sync/syncService.js +44 -2
  200. package/dist/sync/syncService.test.js +62 -0
  201. package/dist/sync/workspacePullFeed.d.ts +1 -0
  202. package/dist/sync/workspacePullFeed.js +66 -59
  203. package/dist/sync/workspacePullFeed.test.js +72 -4
  204. package/dist/sync/workspaceSyncModel.d.ts +25 -1
  205. package/dist/sync/workspaceSyncModel.js +77 -3
  206. package/dist/sync/workspaceSyncModel.test.js +153 -0
  207. package/dist/sync/workspaceSyncState.d.ts +2 -0
  208. package/dist/sync/workspaceSyncState.js +1 -0
  209. package/dist/types.d.ts +2 -10
  210. package/dist/ui/assets/AgentsModule-N2MnQBZk.js +1 -0
  211. package/dist/ui/assets/{AnnotatedAttachmentWorkspace-C_TmXZwA.js → AnnotatedAttachmentWorkspace-BG6P_GVW.js} +1 -1
  212. package/dist/ui/assets/DocumentWorkspace-B3nV_Gc5.css +1 -0
  213. package/dist/ui/assets/DocumentWorkspace-DRbDMwh8.js +252 -0
  214. package/dist/ui/assets/{InitiativesModule-4-Rh2K2n.js → InitiativesModule-Dhm7M8e7.js} +1 -1
  215. package/dist/ui/assets/{PlansPage-BlVC_lRq.css → PlansPage-C2dd2n1X.css} +1 -1
  216. package/dist/ui/assets/PlansPage-Cq0zXj3I.js +1 -0
  217. package/dist/ui/assets/TaskSettings-ln0aF7xc.js +9 -0
  218. package/dist/ui/assets/{WorkflowsModule-CGk9s3NJ.js → WorkflowsModule-BcS4afRn.js} +1 -1
  219. package/dist/ui/assets/index-C2-OXZV7.css +1 -0
  220. package/dist/ui/assets/index-DcSI5F86.js +6 -0
  221. package/dist/ui/assets/{vendor-icons-pWocEipT.js → vendor-icons-BSUaRwF8.js} +1 -1
  222. package/dist/ui/index.html +4 -4
  223. package/dist/utils/commercialLifecyclePresentation.d.ts +19 -0
  224. package/dist/utils/commercialLifecyclePresentation.js +196 -0
  225. package/dist/utils/taskActivity.js +4 -0
  226. package/dist/utils/taskActivity.test.js +25 -1
  227. package/package.json +10 -1
  228. package/scripts/check-cloud-mcp.mjs +83 -0
  229. package/scripts/playwright-auth.sh +9 -1
  230. package/scripts/run-billing-performance-smoke.sh +24 -0
  231. package/dist/ui/assets/AgentsModule-CpsTmrIW.js +0 -1
  232. package/dist/ui/assets/DocumentWorkspace-C3GyzrWm.js +0 -250
  233. package/dist/ui/assets/DocumentWorkspace-C_8T8oz-.css +0 -1
  234. package/dist/ui/assets/PlansPage-BP7AYOqr.js +0 -1
  235. package/dist/ui/assets/TaskSettings-BOC5F6Ag.js +0 -8
  236. package/dist/ui/assets/index-CLIMgR6g.js +0 -6
  237. package/dist/ui/assets/index-DneETxcu.css +0 -1
@@ -0,0 +1,114 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { buildBacklogDropUpdates, buildScheduleDropResult, buildScheduledDayDropUpdates, buildStatusTransitionUpdates, } from './taskKanbanDropRules';
3
+ const makeTask = (overrides = {}) => ({
4
+ id: 'task-1',
5
+ title: 'Task',
6
+ description: null,
7
+ category: 'default',
8
+ type: 'feature',
9
+ priority: 2,
10
+ status: 'task',
11
+ createdAt: '2026-01-01T00:00:00.000Z',
12
+ ...overrides,
13
+ });
14
+ const toMap = (pairs) => new Map(pairs.map((pair) => [pair.taskId, pair.updates]));
15
+ describe('taskKanbanDropRules', () => {
16
+ it('reorders backlog tasks and recalculates orderInDay', () => {
17
+ const activeTask = makeTask({ id: 'task-2' });
18
+ const result = toMap(buildBacklogDropUpdates({
19
+ activeTask,
20
+ sourceColumnId: 'backlog',
21
+ targetTasks: [makeTask({ id: 'task-1' }), makeTask({ id: 'task-3' })],
22
+ sourceTasks: [makeTask({ id: 'task-1' }), makeTask({ id: 'task-3' })],
23
+ insertAt: 1,
24
+ }));
25
+ expect(result.get('task-1')).toEqual({ orderInDay: 0 });
26
+ expect(result.get('task-2')).toEqual({ orderInDay: 1 });
27
+ expect(result.get('task-3')).toEqual({ orderInDay: 2 });
28
+ });
29
+ it('moving scheduled task to backlog clears scheduled fields', () => {
30
+ const activeTask = makeTask({ id: 'task-2', scheduledDate: '2026-04-14', scheduledWeekKey: '2026-W16' });
31
+ const result = toMap(buildBacklogDropUpdates({
32
+ activeTask,
33
+ sourceColumnId: 'mon',
34
+ targetTasks: [makeTask({ id: 'task-1' })],
35
+ sourceTasks: [],
36
+ insertAt: 1,
37
+ }));
38
+ expect(result.get('task-2')).toEqual({
39
+ scheduledDate: null,
40
+ scheduledWeekKey: null,
41
+ orderInDay: 1,
42
+ });
43
+ });
44
+ it('moving task into a scheduled day sets scheduled fields and reindexes source column', () => {
45
+ const activeTask = makeTask({ id: 'task-3' });
46
+ const result = toMap(buildScheduledDayDropUpdates({
47
+ activeTask,
48
+ sourceColumnId: 'backlog',
49
+ targetColumnId: 'mon',
50
+ targetTasks: [makeTask({ id: 'task-1' })],
51
+ sourceTasks: [makeTask({ id: 'task-2' })],
52
+ insertAt: 1,
53
+ scheduledDate: '2026-04-14',
54
+ scheduledWeekKey: '2026-W16',
55
+ }));
56
+ expect(result.get('task-3')).toEqual({
57
+ scheduledDate: '2026-04-14',
58
+ scheduledWeekKey: '2026-W16',
59
+ orderInDay: 1,
60
+ });
61
+ expect(result.get('task-2')).toEqual({ orderInDay: 0 });
62
+ });
63
+ it('blocks non-terminal tasks from being scheduled into the past', () => {
64
+ const result = buildScheduleDropResult({
65
+ activeTask: makeTask({ id: 'task-3', status: 'task' }),
66
+ sourceColumnId: 'backlog',
67
+ targetColumnId: 'mon',
68
+ targetTasks: [],
69
+ sourceTasks: [],
70
+ overTaskId: null,
71
+ isBelowOverItem: false,
72
+ scheduleDates: {
73
+ mon: '2026-04-13',
74
+ tue: '2026-04-14',
75
+ wed: '2026-04-15',
76
+ thu: '2026-04-16',
77
+ fri: '2026-04-17',
78
+ sat: '2026-04-18',
79
+ sun: '2026-04-19',
80
+ },
81
+ parseToIsoWeekKey: () => '2026-W16',
82
+ todayDate: '2026-04-14',
83
+ });
84
+ expect(result).toEqual({ kind: 'blocked', reason: 'Only completed work can be scheduled in the past.' });
85
+ });
86
+ it('preserves cancelled grouping as a no-op for completed column drops', () => {
87
+ const task = makeTask({ id: 'task-cancelled', status: 'cancelled', completedAt: '2026-04-01T00:00:00.000Z' });
88
+ expect(buildStatusTransitionUpdates(task, 'completed', '2026-04-14T07:00:00.000Z')).toBeNull();
89
+ });
90
+ it('stamps completedAt when moving into completed', () => {
91
+ const nowIso = '2026-04-14T07:00:00.000Z';
92
+ const result = buildStatusTransitionUpdates(makeTask({ id: 'task-done' }), 'completed', nowIso);
93
+ expect(result).toEqual({
94
+ status: 'done',
95
+ inProgress: false,
96
+ readyForReview: false,
97
+ completed: true,
98
+ cancelled: false,
99
+ completedAt: nowIso,
100
+ });
101
+ });
102
+ it('resets review and progress flags when moving back to reviewable workflow states', () => {
103
+ const nowIso = '2026-04-14T07:00:00.000Z';
104
+ const result = buildStatusTransitionUpdates(makeTask({ id: 'task-review', status: 'done', inProgress: true, readyForReview: true, completed: true }), 'review', nowIso);
105
+ expect(result).toEqual({
106
+ status: 'review',
107
+ inProgress: false,
108
+ readyForReview: true,
109
+ completed: false,
110
+ cancelled: false,
111
+ completedAt: null,
112
+ });
113
+ });
114
+ });
@@ -5,7 +5,7 @@ interface ModalProps {
5
5
  title: React.ReactNode;
6
6
  children: React.ReactNode;
7
7
  footer?: React.ReactNode;
8
- size?: 'sm' | 'md' | 'lg' | 'xl' | 'full';
8
+ size?: 'sm' | 'md' | 'mdWide' | 'lg' | 'xl' | 'full';
9
9
  theme?: 'light' | 'dawn' | 'dark' | 'midnight';
10
10
  className?: string;
11
11
  headerActions?: React.ReactNode;
@@ -36,6 +36,7 @@ export function Modal({ isOpen, onClose, title, children, footer, size = 'md', t
36
36
  const sizeClassMap = {
37
37
  sm: styles.modalSizeSm,
38
38
  md: styles.modalSizeMd,
39
+ mdWide: styles.modalSizeMdWide,
39
40
  lg: styles.modalSizeLg,
40
41
  xl: styles.modalSizeXl,
41
42
  full: styles.modalSizeFull
@@ -7,6 +7,10 @@ import favicon from '../../assets/favicon/favicon.svg';
7
7
  import { DEFAULT_TASKFORCE_THEME, isLightThemeFamily } from '../../utils/theme';
8
8
  export function AppShellHeader({ projectName, currentWorkspaceId, brandLabel = 'TaskForce', runtimeMode = 'local', theme = DEFAULT_TASKFORCE_THEME, meta, actions }) {
9
9
  const logo = isLightThemeFamily(theme) ? logoDark : logoLight;
10
+ const normalizedProjectName = String(projectName || '').trim();
11
+ const normalizedWorkspaceId = String(currentWorkspaceId || '').trim().toLowerCase();
12
+ const showProjectName = Boolean(normalizedProjectName
13
+ && (runtimeMode !== 'cloud' || (normalizedWorkspaceId && normalizedWorkspaceId !== 'default')));
10
14
  return (_jsxs("div", { className: `${styles.header} ${shellStyles.standaloneHeader}`, children: [_jsxs("div", { className: `${styles.headerTitle} ${shellStyles.standaloneTitle}`, children: [_jsx("img", { src: logo, alt: "Taskforce Logo", className: styles.brandIcon, onError: (event) => {
11
15
  const target = event.currentTarget;
12
16
  if (target.src !== favicon) {
@@ -15,5 +19,5 @@ export function AppShellHeader({ projectName, currentWorkspaceId, brandLabel = '
15
19
  else {
16
20
  target.style.display = 'none';
17
21
  }
18
- } }), _jsx("span", { children: brandLabel }), runtimeMode === 'cloud' && (_jsx("span", { className: styles.brandCloudSuffix, children: "HQ" })), projectName && (_jsxs(_Fragment, { children: [_jsx("span", { className: styles.projectSlash, children: "/" }), _jsx("span", { className: styles.projectName, title: currentWorkspaceId ? `Workspace ID: ${currentWorkspaceId}` : undefined, children: projectName })] })), meta] }), _jsx("div", { className: styles.headerActions, style: { gap: '16px' }, children: actions })] }));
22
+ } }), _jsx("span", { children: brandLabel }), runtimeMode === 'cloud' && (_jsx("span", { className: styles.brandCloudSuffix, children: "HQ" })), showProjectName && (_jsxs(_Fragment, { children: [_jsx("span", { className: styles.projectSlash, children: "/" }), _jsx("span", { className: styles.projectName, title: currentWorkspaceId ? `Workspace ID: ${currentWorkspaceId}` : undefined, children: normalizedProjectName })] })), meta] }), _jsx("div", { className: styles.headerActions, style: { gap: '16px' }, children: actions })] }));
19
23
  }
@@ -18,4 +18,8 @@ describe('AppShellHeader', () => {
18
18
  render(_jsx(AppShellHeader, { runtimeMode: "local", theme: "dawn" }));
19
19
  expect(screen.getByAltText('Taskforce Logo')).toHaveAttribute('src', logoDark);
20
20
  });
21
+ it('hides a stale project label while cloud runtime is still on the default workspace', () => {
22
+ render(_jsx(AppShellHeader, { runtimeMode: "cloud", projectName: "Old Workspace", currentWorkspaceId: "default" }));
23
+ expect(screen.queryByText('Old Workspace')).not.toBeInTheDocument();
24
+ });
21
25
  });
@@ -58,16 +58,17 @@ interface PlanComparisonPageProps {
58
58
  canManageCurrentPlan?: boolean;
59
59
  pricingEndpoint?: string;
60
60
  statusBanner?: {
61
- type: 'success' | 'error';
61
+ type: 'success' | 'error' | 'info';
62
62
  message: string;
63
63
  } | null;
64
64
  onBack: () => void;
65
65
  backLabel: string;
66
+ backDisabled?: boolean;
66
67
  topActions?: React.ReactNode;
67
68
  shellOwnsScroll?: boolean;
68
69
  showPageBackButton?: boolean;
69
70
  fallbackPricingSource?: PricingSourceDetails | null;
70
71
  onSelectPlan: (intent: PlanSelectionIntent) => void | Promise<void>;
71
72
  }
72
- export declare function PlanComparisonPage({ heading, subtitle, variant, chrome, footer, isAuthenticated, authSessionResolved, currentPlanId, currentPlanVersionId, currentEntitlementState, canManageCurrentPlan, pricingEndpoint, statusBanner, onBack, backLabel, topActions, shellOwnsScroll, showPageBackButton, fallbackPricingSource, onSelectPlan }: PlanComparisonPageProps): import("react/jsx-runtime").JSX.Element;
73
+ export declare function PlanComparisonPage({ heading, subtitle, variant, chrome, footer, isAuthenticated, authSessionResolved, currentPlanId, currentPlanVersionId, currentEntitlementState, canManageCurrentPlan, pricingEndpoint, statusBanner, onBack, backLabel, backDisabled, topActions, shellOwnsScroll, showPageBackButton, fallbackPricingSource, onSelectPlan }: PlanComparisonPageProps): import("react/jsx-runtime").JSX.Element;
73
74
  export {};
@@ -3,6 +3,7 @@ import { useEffect, useMemo, useState } from 'react';
3
3
  import { CheckCircle2, Loader2 } from 'lucide-react';
4
4
  import taskforceStyles from '../../Taskforce.module.css';
5
5
  import styles from './PlansPage.module.css';
6
+ import { isCommercialEntitlementActive } from '../../utils/commercialLifecyclePresentation';
6
7
  function isDebugModeEnabled() {
7
8
  const runtimeOverride = globalThis.__DEBUG_MODE__;
8
9
  if (typeof runtimeOverride === 'boolean')
@@ -60,11 +61,7 @@ function getPlanSortRank(plan) {
60
61
  return Math.min(...numericAmounts);
61
62
  return Number.POSITIVE_INFINITY;
62
63
  }
63
- function isActiveEntitlementState(raw) {
64
- const value = String(raw || '').trim().toLowerCase();
65
- return value === 'active' || value === 'trialing' || value === 'grace';
66
- }
67
- export function PlanComparisonPage({ heading, subtitle, variant = 'app', chrome, footer, isAuthenticated, authSessionResolved = true, currentPlanId, currentPlanVersionId, currentEntitlementState, canManageCurrentPlan = true, pricingEndpoint, statusBanner, onBack, backLabel, topActions, shellOwnsScroll = false, showPageBackButton = true, fallbackPricingSource = null, onSelectPlan }) {
64
+ export function PlanComparisonPage({ heading, subtitle, variant = 'app', chrome, footer, isAuthenticated, authSessionResolved = true, currentPlanId, currentPlanVersionId, currentEntitlementState, canManageCurrentPlan = true, pricingEndpoint, statusBanner, onBack, backLabel, backDisabled = false, topActions, shellOwnsScroll = false, showPageBackButton = true, fallbackPricingSource = null, onSelectPlan }) {
68
65
  const [plans, setPlans] = useState([]);
69
66
  const [pricingSource, setPricingSource] = useState(null);
70
67
  const [loading, setLoading] = useState(true);
@@ -130,17 +127,19 @@ export function PlanComparisonPage({ heading, subtitle, variant = 'app', chrome,
130
127
  if (error) {
131
128
  return wrapPage(_jsx(_Fragment, { children: _jsx("div", { className: contentClassName, children: _jsx("div", { className: styles.contentFrame, children: _jsxs("div", { className: styles.emptyState, children: [_jsx("h2", { children: "Connecting to plan pricing..." }), _jsx("p", { children: error }), _jsx("button", { className: styles.backBtn, onClick: () => setRetryNonce((value) => value + 1), children: "Retry" })] }) }) }) }));
132
129
  }
133
- return wrapPage(_jsx(_Fragment, { children: _jsx("div", { className: contentClassName, children: _jsxs("div", { className: styles.contentFrame, children: [_jsxs("div", { className: styles.header, children: [!chrome && (showPageBackButton || topActions) && (_jsxs("div", { className: styles.headerBar, children: [_jsx("div", { children: showPageBackButton ? (_jsx("button", { className: styles.backBtn, onClick: onBack, children: backLabel })) : null }), _jsx("div", { className: styles.headerActions, children: topActions })] })), _jsx("h1", { className: styles.title, children: heading }), subtitle && _jsx("p", { className: styles.subtitle, children: subtitle }), isDebugModeEnabled() && pricingSourceLabel ? (_jsxs("p", { className: styles.debugMeta, children: ["Pricing source: ", pricingSourceLabel] })) : null, statusBanner && (_jsx("div", { className: `${styles.statusBanner} ${statusBanner.type === 'success' ? styles.successBanner : styles.errorBanner}`, children: statusBanner.message }))] }), sortedPlans.length === 0 ? (_jsxs("div", { className: `${styles.emptyState} ${styles.marketingEmptyState}`, children: [_jsx("span", { className: styles.emptyBadge, children: "Coming Soon" }), _jsx("h2", { children: "Paid plans are getting their final polish." }), _jsx("p", { children: "Taskforce pricing is on the way with flexible options for solo operators, teams, and larger rollouts. Check back soon for launch tiers, feature bundles, and early access details." }), _jsxs("div", { className: styles.emptyHighlights, "aria-label": "Upcoming pricing highlights", children: [_jsx("span", { children: "Launch-ready tiers" }), _jsx("span", { children: "Team billing controls" }), _jsx("span", { children: "Feature-based packaging" })] })] })) : (_jsx("div", { className: styles.grid, children: sortedPlans.map((plan) => {
130
+ return wrapPage(_jsx(_Fragment, { children: _jsx("div", { className: contentClassName, children: _jsxs("div", { className: styles.contentFrame, children: [_jsxs("div", { className: styles.header, children: [!chrome && (showPageBackButton || topActions) && (_jsxs("div", { className: styles.headerBar, children: [_jsx("div", { children: showPageBackButton ? (_jsx("button", { className: styles.backBtn, onClick: onBack, disabled: backDisabled, children: backLabel })) : null }), _jsx("div", { className: styles.headerActions, children: topActions })] })), _jsx("h1", { className: styles.title, children: heading }), subtitle && _jsx("p", { className: styles.subtitle, children: subtitle }), isDebugModeEnabled() && pricingSourceLabel ? (_jsxs("p", { className: styles.debugMeta, children: ["Pricing source: ", pricingSourceLabel] })) : null, statusBanner && (_jsx("div", { className: `${styles.statusBanner} ${statusBanner.type === 'success'
131
+ ? styles.successBanner
132
+ : (statusBanner.type === 'info' ? styles.infoBanner : styles.errorBanner)}`, children: statusBanner.message }))] }), sortedPlans.length === 0 ? (_jsxs("div", { className: `${styles.emptyState} ${styles.marketingEmptyState}`, children: [_jsx("span", { className: styles.emptyBadge, children: "Coming Soon" }), _jsx("h2", { children: "Paid plans are getting their final polish." }), _jsx("p", { children: "Taskforce pricing is on the way with flexible options for solo operators, teams, and larger rollouts. Check back soon for launch tiers, feature bundles, and early access details." }), _jsxs("div", { className: styles.emptyHighlights, "aria-label": "Upcoming pricing highlights", children: [_jsx("span", { children: "Launch-ready tiers" }), _jsx("span", { children: "Team billing controls" }), _jsx("span", { children: "Feature-based packaging" })] })] })) : (_jsx("div", { className: styles.grid, children: sortedPlans.map((plan) => {
134
133
  const monthPrice = plan.pricing.month;
135
134
  const yearPrice = plan.pricing.year;
136
135
  const hasMonth = isSelectablePrice(monthPrice);
137
136
  const hasYear = isSelectablePrice(yearPrice);
138
137
  const planVersionId = String(plan.defaultVersion?.planVersionId || '').trim();
139
- const isCurrent = Boolean(planVersionId
138
+ const hasActiveEntitlement = isCommercialEntitlementActive(currentEntitlementState);
139
+ const isCurrent = hasActiveEntitlement && (Boolean(planVersionId
140
140
  && currentPlanVersionId
141
- && currentPlanVersionId === planVersionId
142
- && isActiveEntitlementState(currentEntitlementState)) || (!currentPlanVersionId
143
- && Boolean(currentPlanId && currentPlanId === plan.planId));
141
+ && currentPlanVersionId === planVersionId) || (!currentPlanVersionId
142
+ && Boolean(currentPlanId && currentPlanId === plan.planId)));
144
143
  const defaultInterval = hasMonth ? 'month' : (hasYear ? 'year' : null);
145
144
  const defaultPrice = defaultInterval === 'year' ? yearPrice : monthPrice;
146
145
  const canSelectCard = Boolean(planVersionId) && (isCurrent ? canManageCurrentPlan : Boolean(defaultInterval));
@@ -15,11 +15,11 @@ describe('PlanComparisonPage', () => {
15
15
  },
16
16
  plans: [
17
17
  {
18
- planId: 'starter',
19
- displayName: 'Starter',
18
+ planId: 'free',
19
+ displayName: 'Free',
20
20
  status: 'active',
21
21
  defaultVersion: {
22
- planVersionId: 'starter-v1',
22
+ planVersionId: 'free-v1',
23
23
  versionNumber: 1,
24
24
  seatLimit: null,
25
25
  metadata: {}
@@ -31,19 +31,19 @@ describe('PlanComparisonPage', () => {
31
31
  }
32
32
  },
33
33
  {
34
- planId: 'collab',
35
- displayName: 'Collab',
34
+ planId: 'team-5',
35
+ displayName: 'Team 5',
36
36
  status: 'active',
37
37
  defaultVersion: {
38
- planVersionId: 'collab-v2',
38
+ planVersionId: 'team-5-v2',
39
39
  versionNumber: 2,
40
40
  seatLimit: 5,
41
41
  metadata: {}
42
42
  },
43
43
  features: [],
44
44
  pricing: {
45
- month: { pricingType: 'stripe', stripePriceId: 'price_collab_month', unitAmount: 2000, currency: 'usd', interval: 'month' },
46
- year: { pricingType: 'stripe', stripePriceId: 'price_collab_year', unitAmount: 20000, currency: 'usd', interval: 'year' }
45
+ month: { pricingType: 'stripe', stripePriceId: 'price_team_5_month', unitAmount: 2000, currency: 'usd', interval: 'month' },
46
+ year: { pricingType: 'stripe', stripePriceId: 'price_team_5_year', unitAmount: 20000, currency: 'usd', interval: 'year' }
47
47
  }
48
48
  }
49
49
  ]
@@ -66,11 +66,11 @@ describe('PlanComparisonPage', () => {
66
66
  json: async () => ({
67
67
  plans: [
68
68
  {
69
- planId: 'starter',
70
- displayName: 'Starter',
69
+ planId: 'free',
70
+ displayName: 'Free',
71
71
  status: 'active',
72
72
  defaultVersion: {
73
- planVersionId: 'starter-v1',
73
+ planVersionId: 'free-v1',
74
74
  versionNumber: 1,
75
75
  seatLimit: null,
76
76
  metadata: {}
@@ -93,24 +93,38 @@ describe('PlanComparisonPage', () => {
93
93
  expect(screen.queryByText('Pricing source: production (cloud)')).not.toBeInTheDocument();
94
94
  });
95
95
  it('does not mark a plan current when only the plan id matches but the version does not', async () => {
96
- render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: true, currentPlanId: "collab", currentPlanVersionId: "collab-v1", currentEntitlementState: "active", onBack: () => { }, backLabel: "Back", onSelectPlan: () => { } }));
96
+ render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: true, currentPlanId: "team-5", currentPlanVersionId: "team-5-v1", currentEntitlementState: "active", onBack: () => { }, backLabel: "Back", onSelectPlan: () => { } }));
97
97
  expect(await screen.findByRole('heading', { name: 'Subscription Plans' })).toBeInTheDocument();
98
98
  expect(screen.queryByText('Current Plan')).not.toBeInTheDocument();
99
99
  });
100
+ it('marks a trialing entitlement as the current plan', async () => {
101
+ render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: true, currentPlanId: "team-5", currentPlanVersionId: "team-5-v2", currentEntitlementState: "trialing", onBack: () => { }, backLabel: "Back", onSelectPlan: () => { } }));
102
+ expect(await screen.findByRole('heading', { name: 'Subscription Plans' })).toBeInTheDocument();
103
+ expect(screen.getByText('Current Plan')).toBeInTheDocument();
104
+ });
105
+ it('does not mark a canceled entitlement as current through the plan-id fallback path', async () => {
106
+ render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: true, currentPlanId: "team-5", currentPlanVersionId: null, currentEntitlementState: "canceled", onBack: () => { }, backLabel: "Back", onSelectPlan: () => { } }));
107
+ expect(await screen.findByRole('heading', { name: 'Subscription Plans' })).toBeInTheDocument();
108
+ expect(screen.queryByText('Current Plan')).not.toBeInTheDocument();
109
+ });
110
+ it('can disable the page back button while onboarding remains blocked', async () => {
111
+ render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: true, onBack: () => { }, backLabel: "Back to App", backDisabled: true, onSelectPlan: () => { } }));
112
+ expect(await screen.findByRole('button', { name: 'Back to App' })).toBeDisabled();
113
+ });
100
114
  it('selects the whole plan card using the default available interval', async () => {
101
115
  const onSelectPlan = vi.fn();
102
116
  render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: false, onBack: () => { }, backLabel: "Back", onSelectPlan: onSelectPlan }));
103
117
  await screen.findByRole('heading', { name: 'Subscription Plans' });
104
- const starterHeading = screen.getByRole('heading', { name: 'Starter' });
105
- const starterCard = starterHeading.closest('[role="button"]');
106
- expect(starterCard).toBeTruthy();
107
- expect(within(starterCard).getByText('$0.00')).toBeInTheDocument();
108
- expect(within(starterCard).getByText('/ month')).toBeInTheDocument();
109
- fireEvent.click(starterCard);
118
+ const freeHeading = screen.getByRole('heading', { name: 'Free' });
119
+ const freeCard = freeHeading.closest('[role="button"]');
120
+ expect(freeCard).toBeTruthy();
121
+ expect(within(freeCard).getByText('$0.00')).toBeInTheDocument();
122
+ expect(within(freeCard).getByText('/ month')).toBeInTheDocument();
123
+ fireEvent.click(freeCard);
110
124
  await waitFor(() => {
111
125
  expect(onSelectPlan).toHaveBeenCalledWith({
112
- planId: 'starter',
113
- planVersionId: 'starter-v1',
126
+ planId: 'free',
127
+ planVersionId: 'free-v1',
114
128
  interval: 'month',
115
129
  pricingType: 'free',
116
130
  isCurrentPlan: false
@@ -119,7 +133,7 @@ describe('PlanComparisonPage', () => {
119
133
  });
120
134
  it('does not trigger current-plan actions when the current plan is not Stripe-managed', async () => {
121
135
  const onSelectPlan = vi.fn();
122
- render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: true, currentPlanId: "starter", currentPlanVersionId: "starter-v1", currentEntitlementState: "active", canManageCurrentPlan: false, onBack: () => { }, backLabel: "Back", onSelectPlan: onSelectPlan }));
136
+ render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: true, currentPlanId: "free", currentPlanVersionId: "free-v1", currentEntitlementState: "active", canManageCurrentPlan: false, onBack: () => { }, backLabel: "Back", onSelectPlan: onSelectPlan }));
123
137
  await screen.findByRole('heading', { name: 'Subscription Plans' });
124
138
  const currentButton = screen.getByRole('button', { name: 'Current Plan' });
125
139
  expect(currentButton).toBeDisabled();
@@ -135,11 +149,11 @@ describe('PlanComparisonPage', () => {
135
149
  },
136
150
  plans: [
137
151
  {
138
- planId: 'starter',
139
- displayName: 'Starter',
152
+ planId: 'free',
153
+ displayName: 'Free',
140
154
  status: 'active',
141
155
  defaultVersion: {
142
- planVersionId: 'starter-v1',
156
+ planVersionId: 'free-v1',
143
157
  versionNumber: 1,
144
158
  seatLimit: null,
145
159
  metadata: {}
@@ -155,7 +169,7 @@ describe('PlanComparisonPage', () => {
155
169
  });
156
170
  vi.stubGlobal('fetch', fetchMock);
157
171
  render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: false, pricingEndpoint: "https://performance-app.example/api/taskforce/public/pricing", onBack: () => { }, backLabel: "Back", onSelectPlan: () => { } }));
158
- expect(await screen.findByRole('heading', { name: 'Starter' })).toBeInTheDocument();
172
+ expect(await screen.findByRole('heading', { name: 'Free' })).toBeInTheDocument();
159
173
  expect(fetchMock).toHaveBeenCalledTimes(1);
160
174
  expect(fetchMock).toHaveBeenCalledWith('https://performance-app.example/api/taskforce/public/pricing', {
161
175
  method: 'GET',
@@ -173,27 +187,27 @@ describe('PlanComparisonPage', () => {
173
187
  },
174
188
  plans: [
175
189
  {
176
- planId: 'enterprise',
177
- displayName: 'Enterprise',
190
+ planId: 'team-5',
191
+ displayName: 'Team 5',
178
192
  status: 'active',
179
193
  defaultVersion: {
180
- planVersionId: 'enterprise-v3',
194
+ planVersionId: 'team-5-v2',
181
195
  versionNumber: 3,
182
- seatLimit: 100,
196
+ seatLimit: 5,
183
197
  metadata: {}
184
198
  },
185
199
  features: [],
186
200
  pricing: {
187
- month: { pricingType: 'stripe', stripePriceId: 'price_enterprise_month', unitAmount: 12000, currency: 'usd', interval: 'month' },
188
- year: { pricingType: 'stripe', stripePriceId: 'price_enterprise_year', unitAmount: 120000, currency: 'usd', interval: 'year' }
201
+ month: { pricingType: 'stripe', stripePriceId: 'price_team_5_month', unitAmount: 12000, currency: 'usd', interval: 'month' },
202
+ year: { pricingType: 'stripe', stripePriceId: 'price_team_5_year', unitAmount: 120000, currency: 'usd', interval: 'year' }
189
203
  }
190
204
  },
191
205
  {
192
- planId: 'starter',
193
- displayName: 'Starter',
206
+ planId: 'free',
207
+ displayName: 'Free',
194
208
  status: 'active',
195
209
  defaultVersion: {
196
- planVersionId: 'starter-v1',
210
+ planVersionId: 'free-v1',
197
211
  versionNumber: 1,
198
212
  seatLimit: null,
199
213
  metadata: {}
@@ -205,19 +219,19 @@ describe('PlanComparisonPage', () => {
205
219
  }
206
220
  },
207
221
  {
208
- planId: 'pro',
209
- displayName: 'Pro',
222
+ planId: 'basic',
223
+ displayName: 'Basic',
210
224
  status: 'active',
211
225
  defaultVersion: {
212
- planVersionId: 'pro-v2',
226
+ planVersionId: 'basic-v1',
213
227
  versionNumber: 2,
214
- seatLimit: 10,
228
+ seatLimit: 1,
215
229
  metadata: {}
216
230
  },
217
231
  features: [],
218
232
  pricing: {
219
- month: { pricingType: 'stripe', stripePriceId: 'price_pro_month', unitAmount: 3000, currency: 'usd', interval: 'month' },
220
- year: { pricingType: 'stripe', stripePriceId: 'price_pro_year', unitAmount: 30000, currency: 'usd', interval: 'year' }
233
+ month: { pricingType: 'stripe', stripePriceId: 'price_basic_month', unitAmount: 3000, currency: 'usd', interval: 'month' },
234
+ year: { pricingType: 'stripe', stripePriceId: 'price_basic_year', unitAmount: 30000, currency: 'usd', interval: 'year' }
221
235
  }
222
236
  }
223
237
  ]
@@ -227,7 +241,7 @@ describe('PlanComparisonPage', () => {
227
241
  render(_jsx(PlanComparisonPage, { heading: "Subscription Plans", isAuthenticated: false, onBack: () => { }, backLabel: "Back", onSelectPlan: () => { } }));
228
242
  await screen.findByRole('heading', { name: 'Subscription Plans' });
229
243
  const planNames = screen.getAllByRole('heading', { level: 3 }).map((node) => node.textContent);
230
- expect(planNames).toEqual(['Starter', 'Pro', 'Enterprise']);
244
+ expect(planNames).toEqual(['Free', 'Basic', 'Team 5']);
231
245
  });
232
246
  it('defaults to the same-origin pricing endpoint', async () => {
233
247
  const fetchMock = vi.fn().mockResolvedValue({
@@ -1,3 +1,4 @@
1
+ import { type AccountProfileSummary } from '../../utils/accountProfileSummaryCache';
1
2
  interface PlansPageProps {
2
3
  isAuthenticated: boolean;
3
4
  authUserId?: string | null;
@@ -11,6 +12,9 @@ interface PlansPageProps {
11
12
  resolveCloudAuthUrl?: (path: string) => string;
12
13
  embedded?: boolean;
13
14
  shellOwnsScroll?: boolean;
15
+ onAccountProfileSummaryChange?: (summary: AccountProfileSummary | null) => void;
16
+ onContinueToTaskforce?: () => void | Promise<void>;
17
+ continueBusy?: boolean;
14
18
  }
15
- export declare function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessionResolved, currentTheme, projectName, currentWorkspaceId, apiBaseUrl, connectedEnvironmentSource, resolveCloudAuthUrl, embedded, shellOwnsScroll }: PlansPageProps): import("react/jsx-runtime").JSX.Element;
19
+ export declare function PlansPage({ isAuthenticated, authUserId, runtimeMode, authSessionResolved, currentTheme, projectName, currentWorkspaceId, apiBaseUrl, connectedEnvironmentSource, resolveCloudAuthUrl, embedded, shellOwnsScroll, onAccountProfileSummaryChange, onContinueToTaskforce, continueBusy }: PlansPageProps): import("react/jsx-runtime").JSX.Element;
16
20
  export {};