@taskforcehq/taskforce 0.3.302 → 0.3.304

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 (192) hide show
  1. package/dist/Taskforce.module.css +113 -5
  2. package/dist/TaskforceCore.js +560 -208
  3. package/dist/TaskforceCore.test.js +1833 -91
  4. package/dist/annotatedAttachments/service.d.ts +1 -1
  5. package/dist/annotatedAttachments/types.d.ts +1 -1
  6. package/dist/components/features/AgentsModule.js +1 -1
  7. package/dist/components/features/AgentsModule.test.js +1 -1
  8. package/dist/components/features/TaskSettings.js +58 -38
  9. package/dist/components/features/TaskSettings.test.js +139 -40
  10. package/dist/components/task/TaskActionHeader.d.ts +2 -1
  11. package/dist/components/task/TaskActionHeader.js +3 -3
  12. package/dist/components/task/TaskActionHeader.test.js +8 -0
  13. package/dist/components/task/TaskCard.js +16 -1
  14. package/dist/components/task/TaskCard.test.js +31 -0
  15. package/dist/components/task/TaskForm.d.ts +2 -1
  16. package/dist/components/task/TaskForm.js +22 -4
  17. package/dist/components/task/TaskForm.test.js +46 -0
  18. package/dist/components/task/TaskKanban.d.ts +1 -1
  19. package/dist/components/task/TaskKanban.js +31 -160
  20. package/dist/components/task/TaskKanban.test.js +17 -0
  21. package/dist/components/task/TaskStatusActions.d.ts +6 -1
  22. package/dist/components/task/TaskStatusActions.js +8 -3
  23. package/dist/components/task/TaskStatusActions.test.js +9 -0
  24. package/dist/components/task/taskKanbanDropRules.d.ts +58 -0
  25. package/dist/components/task/taskKanbanDropRules.js +187 -0
  26. package/dist/components/task/taskKanbanDropRules.test.d.ts +1 -0
  27. package/dist/components/task/taskKanbanDropRules.test.js +114 -0
  28. package/dist/components/ui/Modal.d.ts +1 -1
  29. package/dist/components/ui/Modal.js +1 -0
  30. package/dist/components/views/AppShellHeader.js +5 -1
  31. package/dist/components/views/AppShellHeader.test.js +4 -0
  32. package/dist/components/views/PlanComparisonPage.d.ts +3 -2
  33. package/dist/components/views/PlanComparisonPage.js +4 -2
  34. package/dist/components/views/PlanComparisonPage.test.js +4 -0
  35. package/dist/components/views/PlansPage.d.ts +7 -1
  36. package/dist/components/views/PlansPage.js +139 -53
  37. package/dist/components/views/PlansPage.test.d.ts +1 -0
  38. package/dist/components/views/PlansPage.test.js +157 -0
  39. package/dist/components/views/StandaloneLayout.d.ts +1 -0
  40. package/dist/components/views/StandaloneLayout.js +216 -186
  41. package/dist/components/views/WidgetView.js +11 -2
  42. package/dist/components/views/standalone/modals/AccountHubModal.d.ts +8 -3
  43. package/dist/components/views/standalone/modals/AccountHubModal.js +16 -2
  44. package/dist/components/views/standalone/modals/AccountHubModal.test.d.ts +1 -0
  45. package/dist/components/views/standalone/modals/AccountHubModal.test.js +26 -0
  46. package/dist/components/views/standalone/modals/SyncStatusModal.js +1 -1
  47. package/dist/core/DeletedTaskLifecycleService.d.ts +2 -1
  48. package/dist/core/EntitlementsPolicy.test.js +2 -2
  49. package/dist/core/GlobalSettingsService.js +78 -18
  50. package/dist/core/PlanEntitlementService.d.ts +31 -5
  51. package/dist/core/PlanEntitlementService.js +350 -222
  52. package/dist/core/SignupMonetizationSettings.test.js +208 -49
  53. package/dist/core/SystemAdmin.test.js +186 -96
  54. package/dist/core/TaskActivityService.d.ts +4 -1
  55. package/dist/core/TaskActivityService.js +45 -0
  56. package/dist/core/TaskAuditTimeline.test.js +52 -1
  57. package/dist/core/Taskforce.d.ts +65 -20
  58. package/dist/core/Taskforce.js +261 -51
  59. package/dist/core/Taskforce.mcpAuth.test.js +0 -2
  60. package/dist/core/UserProfileAvatarDrafts.test.js +12 -3
  61. package/dist/core/WorkspacePlanMode.test.js +65 -0
  62. package/dist/core/types.d.ts +11 -12
  63. package/dist/documentReviews/service.d.ts +1 -1
  64. package/dist/documentReviews/types.d.ts +1 -1
  65. package/dist/hooks/auth/useTaskforceAuthBootstrap.d.ts +48 -0
  66. package/dist/hooks/auth/useTaskforceAuthBootstrap.js +219 -0
  67. package/dist/hooks/sync/auth.d.ts +37 -0
  68. package/dist/hooks/sync/auth.js +61 -0
  69. package/dist/hooks/sync/bootstrap.d.ts +34 -0
  70. package/dist/hooks/sync/bootstrap.js +52 -0
  71. package/dist/hooks/sync/orchestratorShared.d.ts +36 -0
  72. package/dist/hooks/sync/orchestratorShared.js +209 -0
  73. package/dist/hooks/sync/orchestratorShared.test.d.ts +1 -0
  74. package/dist/hooks/sync/orchestratorShared.test.js +49 -0
  75. package/dist/hooks/sync/realtime.d.ts +25 -0
  76. package/dist/hooks/sync/realtime.js +60 -0
  77. package/dist/hooks/sync/recovery.d.ts +69 -0
  78. package/dist/hooks/sync/recovery.js +118 -0
  79. package/dist/hooks/sync/transfers.d.ts +122 -0
  80. package/dist/hooks/sync/transfers.js +431 -0
  81. package/dist/hooks/sync/useDataVersionRefresh.d.ts +16 -0
  82. package/dist/hooks/sync/useDataVersionRefresh.js +73 -0
  83. package/dist/hooks/ui/useResourceExport.d.ts +3 -1
  84. package/dist/hooks/ui/useResourceExport.js +5 -2
  85. package/dist/hooks/ui/useWorkflowTemplates.js +11 -6
  86. package/dist/hooks/useRealtimeSync.js +2 -1
  87. package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +8 -0
  88. package/dist/hooks/useSyncOrchestrator.context-assets.test.d.ts +1 -0
  89. package/dist/hooks/useSyncOrchestrator.context-assets.test.js +228 -0
  90. package/dist/hooks/useSyncOrchestrator.d.ts +5 -4
  91. package/dist/hooks/useSyncOrchestrator.js +315 -860
  92. package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +665 -8
  93. package/dist/hooks/useTaskMutations.js +45 -6
  94. package/dist/hooks/useTaskMutations.test.js +147 -0
  95. package/dist/hooks/useTaskforce.d.ts +11 -2
  96. package/dist/hooks/useTaskforce.js +290 -812
  97. package/dist/hooks/useWorkspaceSyncController.d.ts +1 -0
  98. package/dist/hooks/useWorkspaceSyncController.js +22 -10
  99. package/dist/hooks/workspace/useTaskforceApiRouting.test.js +17 -0
  100. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.d.ts +166 -0
  101. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +434 -0
  102. package/dist/hooks/workspace/workspaceLocalState.d.ts +19 -0
  103. package/dist/hooks/workspace/workspaceLocalState.js +100 -0
  104. package/dist/hooks/workspace/workspaceLocalState.test.d.ts +1 -0
  105. package/dist/hooks/workspace/workspaceLocalState.test.js +59 -0
  106. package/dist/localization/locales/en-US.js +2 -2
  107. package/dist/mcp/canonicalAssetHelpers.d.ts +70 -0
  108. package/dist/mcp/canonicalAssetHelpers.js +259 -0
  109. package/dist/mcp/clientIntegrations.d.ts +12 -1
  110. package/dist/mcp/clientIntegrations.js +161 -6
  111. package/dist/mcp/clientIntegrations.test.js +76 -4
  112. package/dist/mcp/documentHelpers.d.ts +100 -0
  113. package/dist/mcp/documentHelpers.js +161 -0
  114. package/dist/mcp/runtime.js +264 -505
  115. package/dist/mcp/runtime.test.js +353 -89
  116. package/dist/mcp/taskAttachmentHelpers.d.ts +41 -0
  117. package/dist/mcp/taskAttachmentHelpers.js +60 -0
  118. package/dist/mcp/taskAttachmentTypes.d.ts +37 -0
  119. package/dist/mcp/taskAttachmentTypes.js +1 -0
  120. package/dist/migrations/billingSchemaParity.test.js +3 -0
  121. package/dist/migrations/taskSchemaMigrations.js +15 -0
  122. package/dist/plugins/vite.js +1 -1
  123. package/dist/runtime/appGateDefinitions.d.ts +1 -1
  124. package/dist/runtime/appGateDefinitions.js +1 -1
  125. package/dist/server/index.cookieProxy.test.js +1 -0
  126. package/dist/server/index.d.ts +1 -0
  127. package/dist/server/index.js +48 -3
  128. package/dist/server/index.test.js +14 -2
  129. package/dist/server/mockStripe.d.ts +1 -0
  130. package/dist/server/mockStripe.js +2 -0
  131. package/dist/server/routes/admin.js +91 -40
  132. package/dist/server/routes/auth.d.ts +1 -0
  133. package/dist/server/routes/auth.js +231 -55
  134. package/dist/server/routes/billing.js +473 -39
  135. package/dist/server/routes/billing.test.js +972 -37
  136. package/dist/server/routes/shared.d.ts +30 -0
  137. package/dist/server/routes/shared.js +31 -3
  138. package/dist/server/routes/sync.integration.test.js +180 -0
  139. package/dist/server/routes/sync.js +125 -242
  140. package/dist/server/routes/tasks.js +49 -7
  141. package/dist/server/routes.js +11 -22
  142. package/dist/server/routes.test.js +530 -81
  143. package/dist/shared/taskActor.d.ts +10 -0
  144. package/dist/shared/taskActor.js +1 -0
  145. package/dist/sync/cloudSyncApi.d.ts +1 -0
  146. package/dist/sync/collaborationSyncPayload.js +4 -0
  147. package/dist/sync/collaborationSyncPayload.test.js +8 -0
  148. package/dist/sync/collaborationSyncState.d.ts +3 -1
  149. package/dist/sync/collaborationSyncState.js +19 -0
  150. package/dist/sync/contentSyncState.d.ts +10 -0
  151. package/dist/sync/contentSyncState.js +277 -14
  152. package/dist/sync/syncApplyHandlers.d.ts +87 -1
  153. package/dist/sync/syncApplyHandlers.js +370 -8
  154. package/dist/sync/syncApplyHandlers.test.d.ts +1 -0
  155. package/dist/sync/syncApplyHandlers.test.js +377 -0
  156. package/dist/sync/syncService.d.ts +9 -1
  157. package/dist/sync/syncService.js +57 -10
  158. package/dist/sync/syncService.test.js +48 -0
  159. package/dist/sync/workspacePullFeed.d.ts +11 -0
  160. package/dist/sync/workspacePullFeed.js +123 -68
  161. package/dist/sync/workspacePullFeed.test.js +180 -0
  162. package/dist/sync/workspaceSyncModel.d.ts +22 -1
  163. package/dist/sync/workspaceSyncModel.js +65 -0
  164. package/dist/sync/workspaceSyncModel.test.js +119 -0
  165. package/dist/types.d.ts +2 -10
  166. package/dist/ui/assets/AgentsModule-BLWVbuKP.js +1 -0
  167. package/dist/ui/assets/{AnnotatedAttachmentWorkspace-Dvi02Y7q.js → AnnotatedAttachmentWorkspace-BlS-cqnl.js} +1 -1
  168. package/dist/ui/assets/{DocumentWorkspace-iys3zfca.js → DocumentWorkspace-BH_6DF6x.js} +1 -1
  169. package/dist/ui/assets/{InitiativesModule-DJvLJI3A.js → InitiativesModule-BjR6iBf9.js} +1 -1
  170. package/dist/ui/assets/{PlansPage-BlVC_lRq.css → PlansPage-C2dd2n1X.css} +1 -1
  171. package/dist/ui/assets/PlansPage-CSDQ4sLa.js +1 -0
  172. package/dist/ui/assets/TaskSettings-CEDy34Jo.js +9 -0
  173. package/dist/ui/assets/{WorkflowsModule-BguHeQaV.js → WorkflowsModule-DnFqdUME.js} +1 -1
  174. package/dist/ui/assets/index-DXUdtH1B.js +6 -0
  175. package/dist/ui/assets/index-Ii0B0rTO.css +1 -0
  176. package/dist/ui/assets/{vendor-icons-C8EED3Oh.js → vendor-icons-I7ZwG1z_.js} +1 -1
  177. package/dist/ui/index.html +4 -4
  178. package/dist/utils/accountProfileSummaryCache.d.ts +31 -0
  179. package/dist/utils/accountProfileSummaryCache.js +97 -0
  180. package/dist/utils/accountProfileSummaryCache.test.d.ts +1 -0
  181. package/dist/utils/accountProfileSummaryCache.test.js +63 -0
  182. package/dist/utils/taskActivity.js +4 -0
  183. package/dist/utils/taskActivity.test.js +25 -1
  184. package/package.json +5 -3
  185. package/scripts/playwright-auth.sh +4 -0
  186. package/dist/ui/assets/AgentsModule-JG5jc3he.js +0 -1
  187. package/dist/ui/assets/PlansPage-BMPlpFpw.js +0 -1
  188. package/dist/ui/assets/TaskSettings-Bqd4cCzW.js +0 -8
  189. package/dist/ui/assets/index-MXeWoebC.css +0 -1
  190. package/dist/ui/assets/index-YJ4k5QNa.js +0 -6
  191. package/dist/utils/billingStatusCache.d.ts +0 -21
  192. package/dist/utils/billingStatusCache.js +0 -70
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import React, { useMemo, useCallback, useState, useEffect, useRef, useLayoutEffect, Suspense } from 'react';
3
3
  import { createPortal } from 'react-dom';
4
4
  import { useLocation, useNavigate } from 'react-router-dom';
5
- import { Settings, Plus, Filter, Layers, User, Maximize2, Minimize2, Check, ChevronLeft, ArrowUp, ArrowDown, ArrowUpDown, AlertTriangle, Save, Loader2, Folder, FileText, LogOut, NotebookTabs, ClipboardCheck, Cloud, CloudOff, Users, ChevronsUp, ChevronsDown, EyeOff, Zap, HelpCircle, Bot, Image, Workflow } from 'lucide-react';
5
+ import { Settings, Plus, Filter, Layers, User, Maximize2, Minimize2, Check, ChevronLeft, ArrowUp, ArrowDown, ArrowUpDown, AlertTriangle, Save, Loader2, Folder, FileText, LogOut, NotebookTabs, ClipboardCheck, Cloud, CloudOff, Users, ClockAlert, ChevronsUp, ChevronsDown, EyeOff, Zap, HelpCircle, Bot, Image, Workflow } from 'lucide-react';
6
6
  import { STATUS_OPTIONS, getStatusDefinition } from '../../utils/constants';
7
7
  import styles from '../../Taskforce.module.css';
8
8
  import shellStyles from './WorkspaceShell.module.css';
@@ -33,11 +33,11 @@ import { getImageReferenceLabel } from '../../utils/imageReferences';
33
33
  import { buildCustomTaxonomySortOptions } from '../../utils/taxonomySorting.js';
34
34
  import { getLocale, t } from '../../localization';
35
35
  import { resolveAnnotatedAttachmentDetail } from '../../utils/annotatedAttachments';
36
- import { invalidateBillingStatusCache, loadBillingStatusCached } from '../../utils/billingStatusCache';
36
+ import { ACCOUNT_PROFILE_SUMMARY_PATH, invalidateAccountProfileSummaryCache, loadAccountProfileSummaryCached } from '../../utils/accountProfileSummaryCache';
37
37
  import { fetchTaskforceApi } from '../../utils/taskforceApiClient';
38
38
  import { AppShellHeader } from './AppShellHeader';
39
39
  import { getTaskforceCloudEnvironmentConfig, parseTaskforceCloudEnvironment, resolveTaskforceCloudEnvironmentFromBaseUrl } from '../../config/cloudEnvironment';
40
- import { logBootstrapDebug } from '../../hooks/workspace/workspaceLocalState';
40
+ import { logBootstrapDebug, persistRemoteUiState } from '../../hooks/workspace/workspaceLocalState';
41
41
  import { FilterToolbar } from './panels/FilterToolbar';
42
42
  import { DocumentFilterToolbar } from './panels/DocumentFilterToolbar';
43
43
  import { PlanningDrawer, getPlanningDrawerWidthPx, } from './panels/PlanningDrawer';
@@ -56,8 +56,10 @@ const WorkflowsModule = React.lazy(() => import('../features/WorkflowsModule').t
56
56
  const AgentsModule = React.lazy(() => import('../features/AgentsModule').then(m => ({ default: m.AgentsModule })));
57
57
  const InitiativesModule = React.lazy(() => import('../features/InitiativesModule').then(m => ({ default: m.InitiativesModule })));
58
58
  const PlansPage = React.lazy(() => import('./PlansPage').then(m => ({ default: m.PlansPage })));
59
+ const ACTIVE_COMMERCIAL_STATES = new Set(['active', 'trialing', 'grace']);
59
60
  const PROFILE_AVATAR_ACCEPT = 'image/png,image/jpeg,image/webp,image/gif';
60
61
  const PROFILE_AVATAR_MAX_BYTES = 5 * 1024 * 1024;
62
+ const resolveSameOriginTaskforcePath = (path) => path;
61
63
  function getSyncEventStableKey(event, index = 0) {
62
64
  const explicitId = String(event.id ?? '').trim();
63
65
  if (explicitId)
@@ -191,9 +193,6 @@ export function StandaloneLayout(props) {
191
193
  const nextQuery = params.toString();
192
194
  navigate(`${location.pathname === '/' ? '/' : location.pathname}${nextQuery ? `?${nextQuery}` : ''}${location.hash || ''}`);
193
195
  }, [location.hash, location.pathname, location.search, navigate]);
194
- const handlePlansBack = useCallback(() => {
195
- closePlansScreen();
196
- }, [closePlansScreen]);
197
196
  const {
198
197
  // State
199
198
  activeTab, setActiveTab, activeCategories, groupBy, setGroupBy, activeWorkspaceModule, setActiveWorkspaceModule, emptyColumnMode, setEmptyColumnMode, zenMode, setZenMode, filterStatus, setFilterStatus,
@@ -215,7 +214,7 @@ export function StandaloneLayout(props) {
215
214
  // clearFilters, // This was duplicated, removed one instance
216
215
  // activeTypes, // This was duplicated, removed one instance
217
216
  // Settings State & Props
218
- settingsModel, configLoaded, currentTheme, setCurrentTheme, pathSaved, saveSettings, keyShortcut, setKeyShortcut, globalWeekStartsOn, locale, jsonBackupEnabled, setJsonBackupEnabled, mcpHostRoot, setMcpHostRoot, settingsSection, setSettingsSection, runtimeMode, workspaceSwitchingEnabled, cloudAuthConfigured, authRequiredForApi, authBlocked, isAuthenticated, authUserId, authWorkspaceId, authUserEmail, authUserDisplayName, authUserAvatarUrl, authSessionResolved, realtimeSyncEnabled, realtimeSyncFlagSource, workspaceCloudSyncEnabled, workspaceSyncPhase, workspaceSyncStatus, workspaceSyncSummary, workspaceSyncRecommendedAction, workspaceSyncBusy, workspaceSyncPendingChanges, saveWorkspaceCloudSyncSettings, pushNotice, userGlobalSyncStatus, workspaceLastSuccessfulSyncAt, workspaceLastPullAt, workspaceLastPushAt, workspaceLastErrorAt, userGlobalSyncError, workspaceLastErrorMessage, retryWorkspaceCloudSync, resetWorkspaceSyncCursorAndPull, getWorkspaceSyncDiagnostics, currentWorkspaceId, currentWorkspaceRole, availableWorkspaces, switchWorkspace, updateCurrentUserProfile, logout, projectRoot, projectName, mcpScriptPath, serverHostRoot,
217
+ settingsModel, configLoaded, currentTheme, setCurrentTheme, pathSaved, saveSettings, keyShortcut, setKeyShortcut, globalWeekStartsOn, locale, jsonBackupEnabled, setJsonBackupEnabled, mcpHostRoot, setMcpHostRoot, settingsSection, setSettingsSection, runtimeMode, workspaceSwitchingEnabled, cloudAuthConfigured, authRequiredForApi, authBlocked, isAuthenticated, authUserId, authWorkspaceId, authUserEmail, authUserDisplayName, authUserAvatarUrl, authSessionResolved, realtimeSyncEnabled, realtimeSyncFlagSource, workspaceCloudSyncEnabled, workspaceSyncPhase, workspaceSyncStatus, workspaceSyncSummary, workspaceSyncRecommendedAction, workspaceSyncBusy, workspaceSyncPendingChanges, saveWorkspaceCloudSyncSettings, pushNotice, userGlobalSyncStatus, workspaceLastSuccessfulSyncAt, workspaceLastPullAt, workspaceLastPushAt, workspaceLastErrorAt, userGlobalSyncError, workspaceLastErrorMessage, retryWorkspaceCloudSync, resetWorkspaceSyncCursorAndPull, getWorkspaceSyncDiagnostics, currentWorkspaceId, currentWorkspaceRole, availableWorkspaces, switchWorkspace, updateCurrentUserProfile, resolveCloudAuthUrl = resolveSameOriginTaskforcePath, logout, projectRoot, projectName, mcpScriptPath, serverHostRoot,
219
218
  // Browser Props
220
219
  showFolderBrowser, setShowFolderBrowser, folders, files, currentBrowsePath, fetchFolders, browserTarget, setBrowserTarget, handleSelectPath, handleAddPath, handleRemovePath,
221
220
  // Settings Managers
@@ -503,34 +502,31 @@ export function StandaloneLayout(props) {
503
502
  return;
504
503
  const timeoutId = window.setTimeout(async () => {
505
504
  try {
506
- await fetch('/api/taskforce/ui-state', {
507
- method: 'POST',
508
- headers: { 'Content-Type': 'application/json', ...workspaceUiStateHeaders },
509
- credentials: 'include',
510
- body: JSON.stringify({
511
- stateKey: 'layout',
512
- patch: {
513
- scheduleShowWeekends,
514
- scheduleShowBacklog,
515
- scheduleOnlyExpired,
516
- scheduleSidebarOpen,
517
- scheduleSelectedDate,
518
- scheduleCalendarMonth,
519
- scheduleScrollLeft,
520
- showFilters,
521
- documentTypeFilters,
522
- documentAttachmentFilters,
523
- planningDrawerOpen,
524
- planningTreeCollapsed,
525
- planningPrimaryCollapsed,
526
- planningSecondaryCollapsed,
527
- planningExpandedInitiativeIds: Array.from(expandedPlanningInitiativeIds),
528
- planningDrawerDetail,
529
- planningNestedWorkstreamDetailId,
530
- annotatedTarget: requestedAnnotatedTarget,
531
- annotatedSessionId: requestedAnnotatedSessionId
532
- }
533
- })
505
+ await persistRemoteUiState({
506
+ stateKey: 'layout',
507
+ workspaceId: currentWorkspaceId,
508
+ headers: workspaceUiStateHeaders,
509
+ patch: {
510
+ scheduleShowWeekends,
511
+ scheduleShowBacklog,
512
+ scheduleOnlyExpired,
513
+ scheduleSidebarOpen,
514
+ scheduleSelectedDate,
515
+ scheduleCalendarMonth,
516
+ scheduleScrollLeft,
517
+ showFilters,
518
+ documentTypeFilters,
519
+ documentAttachmentFilters,
520
+ planningDrawerOpen,
521
+ planningTreeCollapsed,
522
+ planningPrimaryCollapsed,
523
+ planningSecondaryCollapsed,
524
+ planningExpandedInitiativeIds: Array.from(expandedPlanningInitiativeIds),
525
+ planningDrawerDetail,
526
+ planningNestedWorkstreamDetailId,
527
+ annotatedTarget: requestedAnnotatedTarget,
528
+ annotatedSessionId: requestedAnnotatedSessionId
529
+ }
534
530
  });
535
531
  }
536
532
  catch {
@@ -804,9 +800,9 @@ export function StandaloneLayout(props) {
804
800
  if (taskScope === 'deleted')
805
801
  return deletedScopeAllTasks;
806
802
  if (!showArchive)
807
- return props.searchAgnosticTasks;
808
- return [...props.searchAgnosticTasks, ...archivedScopeAllTasks];
809
- }, [archivedScopeAllTasks, deletedScopeAllTasks, props.searchAgnosticTasks, showArchive, taskScope]);
803
+ return props.tasks;
804
+ return [...props.tasks, ...archivedScopeAllTasks];
805
+ }, [archivedScopeAllTasks, deletedScopeAllTasks, props.tasks, showArchive, taskScope]);
810
806
  const hierarchyTasks = useMemo(() => {
811
807
  const byId = new Map();
812
808
  for (const task of archivedScopeAllTasks)
@@ -827,8 +823,13 @@ export function StandaloneLayout(props) {
827
823
  assigneeOptions.forEach((option) => {
828
824
  map.set(String(option.value), option.label);
829
825
  });
826
+ const normalizedAuthUserId = String(authUserId || '').trim();
827
+ const normalizedAuthIdentityLabel = String(authUserDisplayName || authUserEmail || '').trim();
828
+ if (normalizedAuthUserId && normalizedAuthIdentityLabel) {
829
+ map.set(normalizedAuthUserId, normalizedAuthIdentityLabel);
830
+ }
830
831
  return map;
831
- }, [assigneeOptions]);
832
+ }, [assigneeOptions, authUserDisplayName, authUserEmail, authUserId]);
832
833
  const planningStructure = useMemo(() => {
833
834
  const planningScopedTasks = taskScope === 'archived'
834
835
  ? archivedScopeAllTasks
@@ -1036,6 +1037,11 @@ export function StandaloneLayout(props) {
1036
1037
  return boardVisibleTasks;
1037
1038
  return boardVisibleTasks.filter((task) => selectedPlanningTaskIds.has(task.id));
1038
1039
  }, [boardVisibleTasks, selectedPlanningTaskIds]);
1040
+ const scopedKanbanAllTasks = useMemo(() => {
1041
+ if (!selectedPlanningTaskIds || selectedPlanningTaskIds.size === 0)
1042
+ return kanbanAllTasks;
1043
+ return kanbanAllTasks.filter((task) => selectedPlanningTaskIds.has(task.id));
1044
+ }, [kanbanAllTasks, selectedPlanningTaskIds]);
1039
1045
  const expiredRecoveryCandidates = useMemo(() => {
1040
1046
  if (groupBy !== 'schedule')
1041
1047
  return [];
@@ -1218,11 +1224,12 @@ export function StandaloneLayout(props) {
1218
1224
  const [teamAuditEvents, setTeamAuditEvents] = useState([]);
1219
1225
  const [teamAuditHasMore, setTeamAuditHasMore] = useState(false);
1220
1226
  const [teamAuditPages, setTeamAuditPages] = useState(1);
1221
- const [billingStatus, setBillingStatus] = useState(null);
1227
+ const [accountProfileSummary, setAccountProfileSummary] = useState(null);
1222
1228
  const [billingLoading, setBillingLoading] = useState(false);
1223
1229
  const [billingError, setBillingError] = useState(null);
1224
1230
  const [billingActionBusy, setBillingActionBusy] = useState(false);
1225
1231
  const [billingActionError, setBillingActionError] = useState(null);
1232
+ const [plansNavigationBusy, setPlansNavigationBusy] = useState(false);
1226
1233
  const [billingNotice, setBillingNotice] = useState(null);
1227
1234
  const [billingIntervalChoice, setBillingIntervalChoice] = useState('month');
1228
1235
  const [profileDisplayNameDraft, setProfileDisplayNameDraft] = useState('');
@@ -1240,7 +1247,11 @@ export function StandaloneLayout(props) {
1240
1247
  billing: false,
1241
1248
  teamManagement: false
1242
1249
  });
1250
+ const accountProfileSummaryRef = useRef(null);
1243
1251
  // showSearch state removed - search always visible in actions area
1252
+ useEffect(() => {
1253
+ accountProfileSummaryRef.current = accountProfileSummary;
1254
+ }, [accountProfileSummary]);
1244
1255
  useEffect(() => {
1245
1256
  if (!showAccountMenu)
1246
1257
  return;
@@ -1291,33 +1302,17 @@ export function StandaloneLayout(props) {
1291
1302
  const authIdentityLabel = authDisplayName || authEmailLabel;
1292
1303
  const hasAuthIdentity = authIdentityLabel.length > 0;
1293
1304
  const hasAuthEmail = authEmailLabel.length > 0;
1294
- const accountBadgeLabel = (authIdentityLabel || authEmailLabel || 'U').trim();
1295
- const accountBadgeInitial = accountBadgeLabel.charAt(0).toUpperCase() || 'U';
1305
+ const accountBadgeLabel = (authIdentityLabel || authEmailLabel || '').trim();
1306
+ const shouldShowResolvedAccountInitial = isAuthenticated && authSessionResolved && accountBadgeLabel.length > 0;
1307
+ const accountBadgeInitial = shouldShowResolvedAccountInitial ? accountBadgeLabel.charAt(0).toUpperCase() : '';
1296
1308
  const accountAvatarUrl = authAvatarUrl;
1309
+ const shouldShowResolvedAccountAvatar = isAuthenticated && authSessionResolved && accountAvatarUrl.length > 0;
1297
1310
  const profileAvatarDisplayUrl = String(profileAvatarPreviewUrl || authAvatarUrl).trim();
1298
- const subscriptionLabel = String(billingStatus?.planName || billingStatus?.planId || '').trim();
1311
+ const subscriptionLabel = String(accountProfileSummary?.planName || accountProfileSummary?.planId || '').trim();
1299
1312
  const hasSubscription = subscriptionLabel.length > 0;
1300
- const teamManagementWorkspaceId = String(authWorkspaceId || currentWorkspaceId || '').trim();
1313
+ const teamManagementWorkspaceId = String(accountProfileSummary?.workspaceId || authWorkspaceId || currentWorkspaceId || '').trim();
1301
1314
  const runtimeLabel = runtimeMode === 'cloud' ? 'CLOUD' : 'LOCAL';
1302
1315
  const apiBaseUrl = props.config?.apiBaseUrl || '';
1303
- const accountCapabilityApiBaseUrl = useMemo(() => {
1304
- const preferredBase = runtimeMode === 'local'
1305
- ? (props.config?.cloudAuthBaseUrl || props.config?.apiBaseUrl || '')
1306
- : (props.config?.apiBaseUrl || props.config?.cloudAuthBaseUrl || '');
1307
- return String(preferredBase || '').trim().replace(/\/+$/, '');
1308
- }, [props.config?.apiBaseUrl, props.config?.cloudAuthBaseUrl, runtimeMode]);
1309
- const billingApiBaseUrl = useMemo(() => {
1310
- const preferredBase = runtimeMode === 'local'
1311
- ? (props.config?.cloudAuthBaseUrl || props.config?.apiBaseUrl || '')
1312
- : (props.config?.apiBaseUrl || props.config?.cloudAuthBaseUrl || '');
1313
- return String(preferredBase || '').trim().replace(/\/+$/, '');
1314
- }, [props.config?.apiBaseUrl, props.config?.cloudAuthBaseUrl, runtimeMode]);
1315
- const buildBillingApiUrl = useCallback((path) => {
1316
- const normalizedPath = String(path || '').trim();
1317
- if (!accountCapabilityApiBaseUrl)
1318
- return normalizedPath;
1319
- return `${accountCapabilityApiBaseUrl}${normalizedPath.startsWith('/') ? normalizedPath : `/${normalizedPath}`}`;
1320
- }, [accountCapabilityApiBaseUrl]);
1321
1316
  const connectedEnvironmentLabel = useMemo(() => resolveConnectedEnvironmentLabel(props.config?.cloudEnvironment, [
1322
1317
  String(props.config?.cloudBaseUrl || ''),
1323
1318
  String(props.config?.cloudAuthBaseUrl || ''),
@@ -1501,14 +1496,15 @@ export function StandaloneLayout(props) {
1501
1496
  const workspaceId = String(teamManagementWorkspaceId || '').trim();
1502
1497
  if (workspaceId)
1503
1498
  headers['x-taskforce-workspace-id'] = workspaceId;
1504
- if (currentWorkspaceRole === 'owner'
1505
- || currentWorkspaceRole === 'admin'
1506
- || currentWorkspaceRole === 'member'
1507
- || currentWorkspaceRole === 'read-only') {
1508
- headers['x-taskforce-workspace-role'] = currentWorkspaceRole;
1499
+ const workspaceRole = teamWorkspaceRole || currentWorkspaceRole;
1500
+ if (workspaceRole === 'owner'
1501
+ || workspaceRole === 'admin'
1502
+ || workspaceRole === 'member'
1503
+ || workspaceRole === 'read-only') {
1504
+ headers['x-taskforce-workspace-role'] = workspaceRole;
1509
1505
  }
1510
1506
  return headers;
1511
- }, [currentWorkspaceRole, teamManagementWorkspaceId]);
1507
+ }, [currentWorkspaceRole, teamManagementWorkspaceId, teamWorkspaceRole]);
1512
1508
  const startAccountSurfaceTiming = useCallback((surface) => {
1513
1509
  const expectsBilling = isAuthenticated;
1514
1510
  const expectsTeamManagement = canAccessCloudTeamManagement;
@@ -1544,59 +1540,117 @@ export function StandaloneLayout(props) {
1544
1540
  surface: showAccountHub ? 'account_hub' : (showAccountMenu ? 'account_menu' : 'closed'),
1545
1541
  durationMs: Math.round(getTimingNow() - startedAt),
1546
1542
  teamManagementVisible: canOpenTeamManagement,
1547
- billingPlanId: String(billingStatus?.planId || '').trim() || null
1543
+ billingPlanId: String(accountProfileSummary?.planId || '').trim() || null
1548
1544
  });
1549
1545
  accountSurfaceOpenStartedAtRef.current = null;
1550
- }, [billingStatus?.planId, canOpenTeamManagement, showAccountHub, showAccountMenu]);
1551
- const loadBillingStatus = useCallback(async () => {
1552
- const billingStatusPath = '/api/taskforce/billing/status';
1553
- const billingStatusUrl = buildBillingApiUrl(billingStatusPath);
1546
+ }, [accountProfileSummary?.planId, canOpenTeamManagement, showAccountHub, showAccountMenu]);
1547
+ const loadAccountProfileSummary = useCallback(async (options) => {
1548
+ const accountProfileSummaryUrl = resolveCloudAuthUrl(ACCOUNT_PROFILE_SUMMARY_PATH);
1554
1549
  if (!isAuthenticated) {
1555
- setBillingStatus(null);
1550
+ setAccountProfileSummary(null);
1556
1551
  setBillingError(null);
1557
- invalidateBillingStatusCache(billingStatusUrl);
1552
+ setTeamWorkspaceRole(null);
1553
+ setTeamPlanMode('unknown');
1554
+ setTeamManagementAccessLoading(false);
1555
+ setTeamManagementAccessError(null);
1556
+ invalidateAccountProfileSummaryCache(accountProfileSummaryUrl, { identityKey: authUserId });
1558
1557
  markAccountSurfaceLoadSettled('billing');
1558
+ markAccountSurfaceLoadSettled('teamManagement');
1559
1559
  return null;
1560
1560
  }
1561
1561
  const startedAt = getTimingNow();
1562
1562
  setBillingLoading(true);
1563
1563
  setBillingError(null);
1564
+ setTeamManagementAccessLoading(canAccessCloudTeamManagement);
1565
+ setTeamManagementAccessError(null);
1564
1566
  try {
1565
- const payload = await loadBillingStatusCached(billingStatusUrl);
1566
- setBillingStatus(payload);
1567
- logBootstrapDebug('account_billing_status_resolved', {
1567
+ const payload = await loadAccountProfileSummaryCached(accountProfileSummaryUrl, {
1568
+ identityKey: authUserId,
1569
+ force: options?.force === true
1570
+ });
1571
+ const nextRole = payload?.workspaceRole === 'owner'
1572
+ || payload?.workspaceRole === 'admin'
1573
+ || payload?.workspaceRole === 'member'
1574
+ || payload?.workspaceRole === 'read-only'
1575
+ ? payload.workspaceRole
1576
+ : null;
1577
+ const nextMode = payload?.teamPlanMode === 'team' || payload?.teamPlanMode === 'personal'
1578
+ ? payload.teamPlanMode
1579
+ : 'unknown';
1580
+ setAccountProfileSummary(payload);
1581
+ setTeamWorkspaceRole(nextRole);
1582
+ setTeamPlanMode(nextMode);
1583
+ setTeamManagementAccessError(null);
1584
+ logBootstrapDebug('account_profile_summary_resolved', {
1568
1585
  durationMs: Math.round(getTimingNow() - startedAt),
1569
1586
  planId: String(payload?.planId || '').trim() || null,
1570
- gate: String(payload?.gate || '').trim() || null
1587
+ gate: String(payload?.gate || '').trim() || null,
1588
+ teamManagementAllowed: payload?.teamManagementAllowed === true
1571
1589
  });
1572
1590
  return payload;
1573
1591
  }
1574
1592
  catch (error) {
1575
- setBillingStatus(null);
1576
- setBillingError(error instanceof Error ? error.message : 'Failed to load billing status.');
1577
- logBootstrapDebug('account_billing_status_failed', {
1593
+ const message = error instanceof Error ? error.message : 'Failed to load account summary.';
1594
+ const hasPreviousSummary = Boolean(accountProfileSummaryRef.current);
1595
+ setBillingError(message);
1596
+ if (!hasPreviousSummary) {
1597
+ setTeamWorkspaceRole(null);
1598
+ setTeamPlanMode('unknown');
1599
+ setTeamManagementAccessError(message);
1600
+ }
1601
+ else {
1602
+ setTeamManagementAccessError(null);
1603
+ }
1604
+ logBootstrapDebug('account_profile_summary_failed', {
1578
1605
  durationMs: Math.round(getTimingNow() - startedAt),
1579
- error: error instanceof Error ? error.message : 'Failed to load billing status.'
1606
+ error: message,
1607
+ preservedSummary: hasPreviousSummary
1580
1608
  });
1581
- return null;
1609
+ return accountProfileSummaryRef.current;
1582
1610
  }
1583
1611
  finally {
1584
1612
  setBillingLoading(false);
1613
+ setTeamManagementAccessLoading(false);
1585
1614
  markAccountSurfaceLoadSettled('billing');
1615
+ markAccountSurfaceLoadSettled('teamManagement');
1586
1616
  }
1587
- }, [buildBillingApiUrl, isAuthenticated, markAccountSurfaceLoadSettled]);
1617
+ }, [authUserId, canAccessCloudTeamManagement, isAuthenticated, markAccountSurfaceLoadSettled, resolveCloudAuthUrl]);
1618
+ const applyPlansAccountProfileSummary = useCallback((payload) => {
1619
+ setAccountProfileSummary(payload);
1620
+ const nextRole = payload?.workspaceRole === 'owner'
1621
+ || payload?.workspaceRole === 'admin'
1622
+ || payload?.workspaceRole === 'member'
1623
+ || payload?.workspaceRole === 'read-only'
1624
+ ? payload.workspaceRole
1625
+ : null;
1626
+ const nextMode = payload?.teamPlanMode === 'team' || payload?.teamPlanMode === 'personal'
1627
+ ? payload.teamPlanMode
1628
+ : 'unknown';
1629
+ setTeamWorkspaceRole(nextRole);
1630
+ setTeamPlanMode(nextMode);
1631
+ }, []);
1632
+ const hasActiveCommercialEntitlement = useMemo(() => {
1633
+ const entitlementState = String(accountProfileSummary?.entitlementState || '').trim().toLowerCase();
1634
+ return ACTIVE_COMMERCIAL_STATES.has(entitlementState);
1635
+ }, [accountProfileSummary?.entitlementState]);
1588
1636
  const handleStartCheckout = useCallback(async () => {
1589
1637
  const params = new URLSearchParams();
1590
1638
  params.set('screen', 'plans');
1591
1639
  params.set('interval', billingIntervalChoice);
1640
+ const planId = String(accountProfileSummary?.planId || '').trim();
1641
+ const planVersionId = String(accountProfileSummary?.planVersionId || '').trim();
1642
+ if (planId)
1643
+ params.set('planId', planId);
1644
+ if (planVersionId)
1645
+ params.set('planVersionId', planVersionId);
1592
1646
  navigate(`/?${params.toString()}`);
1593
- }, [billingIntervalChoice, navigate]);
1647
+ }, [accountProfileSummary?.planId, accountProfileSummary?.planVersionId, billingIntervalChoice, navigate]);
1594
1648
  const handleOpenBillingPortal = useCallback(async () => {
1595
1649
  setBillingActionError(null);
1596
1650
  setBillingNotice(null);
1597
1651
  setBillingActionBusy(true);
1598
1652
  try {
1599
- const res = await fetch(buildBillingApiUrl('/api/taskforce/billing/portal-session'), {
1653
+ const res = await fetch(resolveCloudAuthUrl('/api/taskforce/billing/portal-session'), {
1600
1654
  method: 'POST',
1601
1655
  credentials: 'include'
1602
1656
  });
@@ -1618,18 +1672,18 @@ export function StandaloneLayout(props) {
1618
1672
  finally {
1619
1673
  setBillingActionBusy(false);
1620
1674
  }
1621
- }, [buildBillingApiUrl]);
1675
+ }, [resolveCloudAuthUrl]);
1622
1676
  const handleSwitchSubscriptionInterval = useCallback(async () => {
1623
1677
  setBillingActionError(null);
1624
1678
  setBillingNotice(null);
1625
1679
  setBillingActionBusy(true);
1626
1680
  try {
1627
- const currentPlanVersionId = String(billingStatus?.planVersionId || '').trim();
1681
+ const currentPlanVersionId = String(accountProfileSummary?.planVersionId || '').trim();
1628
1682
  if (!currentPlanVersionId) {
1629
1683
  setBillingActionError('No active plan version is linked to this account.');
1630
1684
  return;
1631
1685
  }
1632
- const res = await fetch(buildBillingApiUrl('/api/taskforce/billing/subscription'), {
1686
+ const res = await fetch(resolveCloudAuthUrl('/api/taskforce/billing/subscription'), {
1633
1687
  method: 'POST',
1634
1688
  credentials: 'include',
1635
1689
  headers: { 'Content-Type': 'application/json' },
@@ -1644,8 +1698,8 @@ export function StandaloneLayout(props) {
1644
1698
  return;
1645
1699
  }
1646
1700
  setBillingNotice('Subscription updated.');
1647
- invalidateBillingStatusCache(buildBillingApiUrl('/api/taskforce/billing/status'));
1648
- await loadBillingStatus();
1701
+ invalidateAccountProfileSummaryCache(resolveCloudAuthUrl(ACCOUNT_PROFILE_SUMMARY_PATH), { identityKey: authUserId });
1702
+ await loadAccountProfileSummary();
1649
1703
  }
1650
1704
  catch {
1651
1705
  setBillingActionError('Failed to update subscription interval.');
@@ -1653,94 +1707,17 @@ export function StandaloneLayout(props) {
1653
1707
  finally {
1654
1708
  setBillingActionBusy(false);
1655
1709
  }
1656
- }, [billingIntervalChoice, billingStatus?.planVersionId, buildBillingApiUrl, loadBillingStatus]);
1657
- const loadTeamManagementAccess = useCallback(async () => {
1658
- if (!canAccessCloudTeamManagement) {
1659
- setTeamWorkspaceRole(null);
1660
- setTeamPlanMode('unknown');
1661
- setTeamManagementAccessLoading(false);
1662
- setTeamManagementAccessError(null);
1663
- markAccountSurfaceLoadSettled('teamManagement');
1664
- return { role: null, teamPlanMode: 'unknown', allowed: false };
1665
- }
1666
- const startedAt = getTimingNow();
1667
- setTeamManagementAccessLoading(true);
1668
- setTeamManagementAccessError(null);
1669
- try {
1670
- const res = await fetchTaskforceApi('/api/taskforce/account/team-management-access', {
1671
- method: 'GET',
1672
- credentials: 'include',
1673
- headers: teamAdminHeaders()
1674
- }, accountCapabilityApiBaseUrl);
1675
- const payload = await res.json().catch(() => ({}));
1676
- if (!res.ok) {
1677
- setTeamWorkspaceRole(null);
1678
- setTeamPlanMode('unknown');
1679
- setTeamManagementAccessError(String(payload?.error || 'Failed to load team management access.'));
1680
- logBootstrapDebug('team_management_access_failed', {
1681
- durationMs: Math.round(getTimingNow() - startedAt),
1682
- status: res.status
1683
- });
1684
- return { role: null, teamPlanMode: 'unknown', allowed: false };
1685
- }
1686
- const nextRole = payload?.role === 'owner' || payload?.role === 'admin' || payload?.role === 'member' || payload?.role === 'read-only'
1687
- ? payload.role
1688
- : null;
1689
- const nextMode = payload?.teamPlanMode === 'team' || payload?.teamPlanMode === 'personal'
1690
- ? payload.teamPlanMode
1691
- : 'unknown';
1692
- const allowed = payload?.allowed === true;
1693
- setTeamWorkspaceRole(nextRole);
1694
- setTeamPlanMode(nextMode);
1695
- setTeamManagementAccessError(null);
1696
- logBootstrapDebug('team_management_access_loaded', {
1697
- durationMs: Math.round(getTimingNow() - startedAt),
1698
- role: nextRole,
1699
- teamPlanMode: nextMode,
1700
- allowed
1701
- });
1702
- return { role: nextRole, teamPlanMode: nextMode, allowed };
1703
- }
1704
- catch (error) {
1705
- setTeamWorkspaceRole(null);
1706
- setTeamPlanMode('unknown');
1707
- setTeamManagementAccessError(error instanceof Error ? error.message : 'Failed to load team management access.');
1708
- logBootstrapDebug('team_management_access_failed', {
1709
- durationMs: Math.round(getTimingNow() - startedAt),
1710
- error: error instanceof Error ? error.message : 'Failed to load team management access.'
1711
- });
1712
- return { role: null, teamPlanMode: 'unknown', allowed: false };
1713
- }
1714
- finally {
1715
- setTeamManagementAccessLoading(false);
1716
- markAccountSurfaceLoadSettled('teamManagement');
1717
- }
1718
- }, [accountCapabilityApiBaseUrl, canAccessCloudTeamManagement, markAccountSurfaceLoadSettled, teamAdminHeaders]);
1719
- useEffect(() => {
1720
- if (!showAccountMenu && !showTeamManagementModal && !showAccountHub)
1721
- return;
1722
- void loadTeamManagementAccess();
1723
- }, [showAccountHub, showAccountMenu, showTeamManagementModal, loadTeamManagementAccess]);
1710
+ }, [accountProfileSummary?.planVersionId, authUserId, billingIntervalChoice, loadAccountProfileSummary, resolveCloudAuthUrl]);
1724
1711
  useEffect(() => {
1725
1712
  if (!isAuthenticated || !authSessionResolved)
1726
1713
  return;
1727
- if (!canAccessCloudTeamManagement) {
1728
- setTeamWorkspaceRole(null);
1729
- setTeamPlanMode('unknown');
1730
- return;
1731
- }
1732
- void loadTeamManagementAccess();
1733
- }, [authSessionResolved, canAccessCloudTeamManagement, isAuthenticated, loadTeamManagementAccess]);
1734
- useEffect(() => {
1735
- if (!isAuthenticated || !authSessionResolved)
1736
- return;
1737
- void loadBillingStatus();
1738
- }, [authSessionResolved, isAuthenticated, loadBillingStatus]);
1714
+ void loadAccountProfileSummary();
1715
+ }, [authSessionResolved, isAuthenticated, loadAccountProfileSummary]);
1739
1716
  useEffect(() => {
1740
1717
  if (!showAccountHub && !showAccountMenu)
1741
1718
  return;
1742
- void loadBillingStatus();
1743
- }, [loadBillingStatus, showAccountHub, showAccountMenu]);
1719
+ void loadAccountProfileSummary();
1720
+ }, [loadAccountProfileSummary, showAccountHub, showAccountMenu]);
1744
1721
  const loadTeamUsers = useCallback(async () => {
1745
1722
  if (!canManageTeamWorkspace)
1746
1723
  return;
@@ -1843,6 +1820,47 @@ export function StandaloneLayout(props) {
1843
1820
  }
1844
1821
  navigate(`/setup?${params.toString()}`, { replace: true });
1845
1822
  }, [navigate]);
1823
+ const handlePlansBack = useCallback(async () => {
1824
+ if (plansNavigationBusy)
1825
+ return;
1826
+ if (!isAuthenticated) {
1827
+ closePlansScreen();
1828
+ return;
1829
+ }
1830
+ const summary = await loadAccountProfileSummary({ force: true });
1831
+ const entitlementState = String(summary?.entitlementState || '').trim().toLowerCase();
1832
+ if (!ACTIVE_COMMERCIAL_STATES.has(entitlementState)) {
1833
+ return;
1834
+ }
1835
+ setPlansNavigationBusy(true);
1836
+ try {
1837
+ const result = await props.continueAfterCommercialOnboarding();
1838
+ if (!result.success) {
1839
+ pushNotice(result.error || 'Unable to finish onboarding.', 'error');
1840
+ if (result.destination === 'login') {
1841
+ navigate('/login', { replace: true });
1842
+ }
1843
+ return;
1844
+ }
1845
+ if (result.destination === 'setup') {
1846
+ openWorkspaceSetup();
1847
+ return;
1848
+ }
1849
+ closePlansScreen();
1850
+ }
1851
+ finally {
1852
+ setPlansNavigationBusy(false);
1853
+ }
1854
+ }, [
1855
+ closePlansScreen,
1856
+ isAuthenticated,
1857
+ loadAccountProfileSummary,
1858
+ navigate,
1859
+ openWorkspaceSetup,
1860
+ plansNavigationBusy,
1861
+ props,
1862
+ pushNotice
1863
+ ]);
1846
1864
  const handleSwitchWorkspace = useCallback(async (workspaceId) => {
1847
1865
  if (!workspaceId || workspaceActionBusy)
1848
1866
  return;
@@ -1869,12 +1887,12 @@ export function StandaloneLayout(props) {
1869
1887
  setShowAccountMenu(false);
1870
1888
  setShowTeamManagementModal(true);
1871
1889
  setTeamManagementTab('members');
1872
- const access = await loadTeamManagementAccess();
1873
- if (!access.allowed)
1890
+ const summary = await loadAccountProfileSummary();
1891
+ if (!(summary?.teamManagementAllowed ?? canOpenTeamManagement))
1874
1892
  return;
1875
1893
  await loadTeamUsers();
1876
1894
  await loadTeamAuditPage(0);
1877
- }, [loadTeamAuditPage, loadTeamManagementAccess, loadTeamUsers]);
1895
+ }, [canOpenTeamManagement, loadAccountProfileSummary, loadTeamAuditPage, loadTeamUsers]);
1878
1896
  const executeTeamUserAction = useCallback(async (userId, fn) => {
1879
1897
  setTeamMgmtError(null);
1880
1898
  setTeamActionBusyUserId(userId);
@@ -2544,7 +2562,7 @@ export function StandaloneLayout(props) {
2544
2562
  }, [groupBy, activeCategories, activeTypes, priorities, approaches, assigneeOptions, scheduleColumns]);
2545
2563
  // === SECTION: AccountMenuControl ===
2546
2564
  // Not extracted: ~25 distinct props from local state would be needed.
2547
- // References: isAuthenticated, authIdentityLabel, billingStatus, runtimeLabel,
2565
+ // References: isAuthenticated, authIdentityLabel, accountProfileSummary, runtimeLabel,
2548
2566
  // connectedEnvironmentLabel, canManageCloudWorkspaces, workspaceActionBusy,
2549
2567
  // setWorkspacePanelOpen, canOpenTeamManagement, openTeamManagementModal, and more.
2550
2568
  const accountMenuControl = (_jsxs("div", { className: accountStyles.accountMenuWrap, ref: accountMenuRef, children: [_jsx("button", { className: `tf-control-icon ${accountStyles.avatarBtn}`, onClick: () => {
@@ -2559,7 +2577,7 @@ export function StandaloneLayout(props) {
2559
2577
  }
2560
2578
  return next;
2561
2579
  });
2562
- }, title: isAuthenticated ? 'Account' : 'Account (Not signed in)', "aria-label": isAuthenticated ? 'Account' : 'Account (Not signed in)', "aria-haspopup": "menu", "aria-expanded": showAccountMenu, children: _jsx("span", { className: accountStyles.avatarBadge, "aria-hidden": "true", children: isAuthenticated && accountAvatarUrl ? (_jsx("img", { src: accountAvatarUrl, alt: "", className: accountStyles.avatarImage })) : (isAuthenticated ? accountBadgeInitial : '?') }) }), showAccountMenu && (_jsxs("div", { className: accountStyles.accountMenu, role: "menu", "aria-label": "Account menu", children: [_jsxs("div", { className: accountStyles.accountMenuSection, children: [_jsx("div", { className: accountStyles.accountMenuSectionLabel, children: "Account" }), _jsx("div", { className: accountStyles.accountMenuHint, children: isAuthBootstrapPending
2580
+ }, title: isAuthenticated ? 'Account' : 'Account (Not signed in)', "aria-label": isAuthenticated ? 'Account' : 'Account (Not signed in)', "aria-haspopup": "menu", "aria-expanded": showAccountMenu, children: _jsx("span", { className: accountStyles.avatarBadge, "aria-hidden": "true", children: shouldShowResolvedAccountAvatar ? (_jsx("img", { src: accountAvatarUrl, alt: "", className: accountStyles.avatarImage })) : accountBadgeInitial ? (accountBadgeInitial) : (_jsx(User, { size: 14, className: accountStyles.avatarIcon })) }) }), showAccountMenu && (_jsxs("div", { className: accountStyles.accountMenu, role: "menu", "aria-label": "Account menu", children: [_jsxs("div", { className: accountStyles.accountMenuSection, children: [_jsx("div", { className: accountStyles.accountMenuSectionLabel, children: "Account" }), _jsx("div", { className: accountStyles.accountMenuHint, children: isAuthBootstrapPending
2563
2581
  ? 'Checking sign-in status...'
2564
2582
  : isAuthenticated
2565
2583
  ? (_jsx(_Fragment, { children: hasAuthIdentity
@@ -2590,6 +2608,9 @@ export function StandaloneLayout(props) {
2590
2608
  }, role: "menuitem", children: [_jsx(User, { size: 15 }), "Sign In / Register"] })), isAuthenticated && (_jsxs("button", { className: accountStyles.accountMenuItem, onClick: async () => {
2591
2609
  setShowAccountMenu(false);
2592
2610
  await logout();
2611
+ if (runtimeMode === 'cloud') {
2612
+ navigate('/login', { replace: true });
2613
+ }
2593
2614
  }, role: "menuitem", children: [_jsx(LogOut, { size: 15 }), "Sign Out"] }))] }))] }));
2594
2615
  const cycleEmptyColumnVisibility = useCallback(() => {
2595
2616
  setEmptyColumnMode((prev) => {
@@ -3213,7 +3234,7 @@ export function StandaloneLayout(props) {
3213
3234
  const workspacePrimaryAction = workspaceChromeDefinition.primaryAction
3214
3235
  ? primaryActionRegistry[workspaceChromeDefinition.primaryAction]
3215
3236
  : null;
3216
- return (_jsxs("div", { className: `${shellStyles.standaloneWrapper} ${zenMode ? styles.zenModeEnabled : ''}`, "data-theme": currentTheme, children: [_jsx(AppShellHeader, { projectName: projectName, currentWorkspaceId: currentWorkspaceId, runtimeMode: runtimeMode, theme: currentTheme, meta: isPlansScreen ? null : (_jsxs(_Fragment, { children: [_jsx("span", { className: styles.taskCountBadge, title: activeCountTitle, children: activeCountLabel }), normalizedAuthUserId && normalizedAuthUserId !== 'anonymous' && (_jsxs(_Fragment, { children: [_jsxs("span", { className: styles.taskCountBadge, title: "Open tasks assigned to you", children: ["Mine ", assignedTaskCount] }), _jsxs("span", { className: styles.taskCountBadge, title: "Your open tasks with overdue due dates", children: ["Overdue ", assignedOverdueTaskCount] })] })), shouldShowSyncStatus && (_jsx("button", { className: "tf-control-icon", onClick: () => setShowSyncStatusModal(true), title: `Sync manager: ${syncStatusMeta.label} | Last success: ${formattedLastSyncTime}`, style: {
3237
+ return (_jsxs("div", { className: `${shellStyles.standaloneWrapper} ${zenMode ? styles.zenModeEnabled : ''}`, "data-theme": currentTheme, children: [_jsx(AppShellHeader, { projectName: projectName, currentWorkspaceId: currentWorkspaceId, runtimeMode: runtimeMode, theme: currentTheme, meta: isPlansScreen ? null : (_jsxs(_Fragment, { children: [_jsx("span", { className: styles.taskCountBadge, title: activeCountTitle, children: activeCountLabel }), normalizedAuthUserId && normalizedAuthUserId !== 'anonymous' && (_jsxs(_Fragment, { children: [_jsxs("span", { className: styles.taskCountBadge, title: "Tasks assigned to me", children: [_jsx(User, { size: 13, className: styles.taskCountBadgeIcon, "aria-hidden": "true" }), assignedTaskCount] }), _jsxs("span", { className: `${styles.taskCountBadge} ${assignedOverdueTaskCount > 0 ? styles.taskCountBadgeAlert : ''}`.trim(), title: "Tasks overdue", children: [_jsx(ClockAlert, { size: 13, className: styles.taskCountBadgeIcon, "aria-hidden": "true" }), assignedOverdueTaskCount] })] })), shouldShowSyncStatus && (_jsx("button", { className: "tf-control-icon", onClick: () => setShowSyncStatusModal(true), title: `Sync manager: ${syncStatusMeta.label} | Last success: ${formattedLastSyncTime}`, style: {
3217
3238
  marginLeft: '6px',
3218
3239
  height: '24px',
3219
3240
  width: '24px',
@@ -3225,7 +3246,7 @@ export function StandaloneLayout(props) {
3225
3246
  display: 'inline-flex',
3226
3247
  alignItems: 'center',
3227
3248
  justifyContent: 'center'
3228
- }, children: syncStatusMeta.icon === 'off' ? (_jsx(CloudOff, { size: 16 })) : (_jsx(Cloud, { size: 16 })) }))] })), actions: (_jsxs(_Fragment, { children: [isPlansScreen && (_jsx("button", { className: "tf-control-icon", onClick: handlePlansBack, title: "Back", children: "Back" })), !isPlansScreen && (_jsxs(_Fragment, { children: [workspaceHeaderSections, workspacePrimaryAction] })), !isPlansScreen && _jsx(WorkspaceHeaderActions, { actions: universalDisplayActions }), !isPlansScreen && _jsx(WorkspaceHeaderActions, { actions: universalFilterActions }), accountMenuControl] })) }), _jsx(TopNoticeLayer, { notice: uiNotice, onDismiss: clearNotice }), authBlocked && (_jsx("div", { className: authStyles.authBlockedBanner, children: "Authentication required for this environment. Use the Account menu to sign in." })), !isPlansScreen && showFilters && workspaceFilterBar, isPlansScreen ? (_jsx("div", { className: `${shellStyles.standalonePage} ${shellStyles.standaloneContent} ${styles.appScrollbar} tf-scrollbar`, style: { position: 'relative', display: 'flex', flex: 1, minHeight: 0, overflowY: 'auto', overflowX: 'hidden', scrollbarGutter: 'stable' }, children: _jsx(Suspense, { fallback: _jsx("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', flex: 1 }, children: _jsx(Loader2, { size: 20, className: styles.spinner }) }), children: _jsx(PlansPage, { ...props, currentTheme: currentTheme, projectName: projectName, currentWorkspaceId: currentWorkspaceId, apiBaseUrl: billingApiBaseUrl, connectedEnvironmentSource: props.config?.cloudAuthBaseUrl || props.config?.apiBaseUrl || '', embedded: true, shellOwnsScroll: true }) }) })) : resolvedWorkspaceModule === 'docs' && documentsWorkspaceEnabled ? (_jsxs("div", { className: `${shellStyles.standalonePage} ${shellStyles.standaloneContent}`, style: { position: 'relative', display: 'flex', flex: 1, minHeight: 0, overflow: 'hidden', paddingLeft: `${WORKSPACE_TOOL_RAIL_WIDTH}px` }, children: [workspaceToolRail, _jsx(Suspense, { fallback: _jsx("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', flex: 1 }, children: _jsx(Loader2, { size: 20, className: styles.spinner }) }), children: _jsx(DocumentWorkspaceShell, { tasks: tasks, runtimeMode: runtimeMode, apiBaseUrl: props.config?.apiBaseUrl || '', cloudAuthBaseUrl: props.config?.cloudAuthBaseUrl || '', typeFilters: documentTypeFilters, attachmentFilters: documentAttachmentFilters, onTypeFiltersChange: setDocumentTypeFilters, onAttachmentFiltersChange: setDocumentAttachmentFilters, requestedDocPath: requestedDocPath, requestedDocAssetId: requestedDocAssetId, onRequestedDocHandled: () => {
3249
+ }, children: syncStatusMeta.icon === 'off' ? (_jsx(CloudOff, { size: 16 })) : (_jsx(Cloud, { size: 16 })) }))] })), actions: (_jsxs(_Fragment, { children: [isPlansScreen && (_jsx("button", { className: "tf-control-icon", onClick: () => { void handlePlansBack(); }, title: isAuthenticated && !hasActiveCommercialEntitlement ? 'Choose a plan to continue.' : 'Continue to Taskforce', disabled: plansNavigationBusy || (isAuthenticated && !hasActiveCommercialEntitlement), children: hasActiveCommercialEntitlement ? 'Take Me to Taskforce' : 'Back' })), !isPlansScreen && (_jsxs(_Fragment, { children: [workspaceHeaderSections, workspacePrimaryAction] })), !isPlansScreen && _jsx(WorkspaceHeaderActions, { actions: universalDisplayActions }), !isPlansScreen && _jsx(WorkspaceHeaderActions, { actions: universalFilterActions }), accountMenuControl] })) }), _jsx(TopNoticeLayer, { notice: uiNotice, onDismiss: clearNotice }), authBlocked && (_jsx("div", { className: authStyles.authBlockedBanner, children: "Authentication required for this environment. Use the Account menu to sign in." })), !isPlansScreen && showFilters && workspaceFilterBar, isPlansScreen ? (_jsx("div", { className: `${shellStyles.standalonePage} ${shellStyles.standaloneContent} ${styles.appScrollbar} tf-scrollbar`, style: { position: 'relative', display: 'flex', flex: 1, minHeight: 0, overflowY: 'auto', overflowX: 'hidden', scrollbarGutter: 'stable' }, children: _jsx(Suspense, { fallback: _jsx("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', flex: 1 }, children: _jsx(Loader2, { size: 20, className: styles.spinner }) }), children: _jsx(PlansPage, { ...props, currentTheme: currentTheme, projectName: projectName, currentWorkspaceId: currentWorkspaceId, authUserId: authUserId, apiBaseUrl: apiBaseUrl, connectedEnvironmentSource: props.config?.cloudAuthBaseUrl || props.config?.apiBaseUrl || '', resolveCloudAuthUrl: resolveCloudAuthUrl, embedded: true, shellOwnsScroll: true, onAccountProfileSummaryChange: applyPlansAccountProfileSummary, onContinueToTaskforce: handlePlansBack, continueBusy: plansNavigationBusy }) }) })) : resolvedWorkspaceModule === 'docs' && documentsWorkspaceEnabled ? (_jsxs("div", { className: `${shellStyles.standalonePage} ${shellStyles.standaloneContent}`, style: { position: 'relative', display: 'flex', flex: 1, minHeight: 0, overflow: 'hidden', paddingLeft: `${WORKSPACE_TOOL_RAIL_WIDTH}px` }, children: [workspaceToolRail, _jsx(Suspense, { fallback: _jsx("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', flex: 1 }, children: _jsx(Loader2, { size: 20, className: styles.spinner }) }), children: _jsx(DocumentWorkspaceShell, { tasks: tasks, runtimeMode: runtimeMode, apiBaseUrl: props.config?.apiBaseUrl || '', cloudAuthBaseUrl: props.config?.cloudAuthBaseUrl || '', typeFilters: documentTypeFilters, attachmentFilters: documentAttachmentFilters, onTypeFiltersChange: setDocumentTypeFilters, onAttachmentFiltersChange: setDocumentAttachmentFilters, requestedDocPath: requestedDocPath, requestedDocAssetId: requestedDocAssetId, onRequestedDocHandled: () => {
3229
3250
  setRequestedDocPath(null);
3230
3251
  setRequestedDocAssetId(null);
3231
3252
  }, enableTaskGeneration: true }) })] })) : resolvedWorkspaceModule === 'annotate' && annotatedAttachmentsWorkspaceEnabled ? (_jsxs("div", { className: `${shellStyles.standalonePage} ${shellStyles.standaloneContent}`, style: { position: 'relative', display: 'flex', flex: 1, minHeight: 0, overflow: 'hidden', paddingLeft: `${WORKSPACE_TOOL_RAIL_WIDTH}px` }, children: [workspaceToolRail, _jsx(Suspense, { fallback: _jsx("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', flex: 1 }, children: _jsx(Loader2, { size: 20, className: styles.spinner }) }), children: _jsx(AnnotatedAttachmentWorkspaceShell, { runtimeMode: runtimeMode, apiBaseUrl: props.config?.apiBaseUrl || '', cloudAuthBaseUrl: props.config?.cloudAuthBaseUrl || '', workspaceId: currentWorkspaceId, sessionLoadReady: annotatedWorkspaceReady, requestedTarget: requestedAnnotatedTarget, requestedSessionId: requestedAnnotatedSessionId, requestedOpenVersion: requestedAnnotatedOpenVersion, resolveTaskReferenceLabel: resolveAnnotatedTaskReferenceLabel, resolveImageReferenceLabel: resolveAnnotatedImageReferenceLabel, onOpenTarget: handleAnnotatedAttachmentOpenTarget, onContextChange: handleAnnotatedAttachmentContextChange, onBackToTask: handleBackToTaskFromAnnotatedAttachment }) })] })) : resolvedWorkspaceModule === 'workflows' ? (_jsxs("div", { className: `${shellStyles.standalonePage} ${shellStyles.standaloneContent}`, style: { position: 'relative', display: 'flex', flex: 1, minHeight: 0, overflow: 'hidden', paddingLeft: `${WORKSPACE_TOOL_RAIL_WIDTH}px` }, children: [workspaceToolRail, _jsx(Suspense, { fallback: _jsx("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', flex: 1 }, children: _jsx(Loader2, { size: 20, className: styles.spinner }) }), children: _jsx(WorkflowsModule, { availableWorkflows: availableWorkflows, availableEnvironments: availableEnvironments, exportEnvironment: exportEnvironment, exportWorkflowsPath: props.exportWorkflowsPath, exportingResource: exportingResource, exportResult: exportResult, onExportEnvironmentChange: props.setExportEnvironment, onExportWorkflows: onExportWorkflows, onRefreshWorkflows: fetchWorkflows, onFetchWorkflowTemplate: props.fetchWorkflowTemplate, onFetchWorkflowOverrideNames: props.fetchWorkflowOverrideNames, onSaveWorkflowTemplateDraft: props.saveWorkflowTemplateDraft, onResetWorkflowTemplateDraft: props.resetWorkflowTemplateDraft }) })] })) : resolvedWorkspaceModule === 'agents' ? (_jsxs("div", { className: `${shellStyles.standalonePage} ${shellStyles.standaloneContent}`, style: { position: 'relative', display: 'flex', flex: 1, minHeight: 0, overflow: 'hidden', paddingLeft: `${WORKSPACE_TOOL_RAIL_WIDTH}px` }, children: [workspaceToolRail, _jsx(Suspense, { fallback: _jsx("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', flex: 1 }, children: _jsx(Loader2, { size: 20, className: styles.spinner }) }), children: _jsx(AgentsModule, { workspaceId: currentWorkspaceId }) })] })) : (_jsxs("div", { className: `${shellStyles.standalonePage} ${shellStyles.standaloneContent} `, style: {
@@ -3244,7 +3265,7 @@ export function StandaloneLayout(props) {
3244
3265
  inset: 0,
3245
3266
  zIndex: 35,
3246
3267
  pointerEvents: 'none',
3247
- } }), _jsxs("div", { style: { position: 'relative', width: '100%', minWidth: 0, flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column', overflow: 'hidden' }, children: [props.loadingTasks && boardVisibleTasks.length > 0 && (_jsx("div", { className: styles.boardRefreshIndicator, "aria-live": "polite", "aria-label": "Refreshing tasks", children: _jsx(Loader2, { size: 14, className: styles.spinner }) })), _jsx(TaskKanban, { tasks: scopedBoardVisibleTasks, allTasks: [], columns: kanbanColumns, groupBy: groupBy, scheduleDates: scheduleDates, searchQuery: searchQuery, filterCategories: filterCategories, filterTypes: filterTypes, filterPriorities: filterPriorities, filterStatus: filterStatus, filterAssignees: filterAssignees, assigneeOptions: assigneeOptions, scheduleFilteredTaskIds: Array.from(scheduleFilteredTaskIds), copiedId: copiedId, taxonomies: taxonomies, types: activeTypes, priorities: priorities, onUpdateTask: handleUpdateTask, onTaskClick: (task) => handleEdit(task), onOpenTaskById: handleOpenTaskById, onCopyId: handleCopyId, onToggleInProgress: handleToggleInProgress, onToggleReview: handleToggleReview, onToggleComplete: handleToggleComplete, onToggleCancel: handleToggleCancel, onSetStatus: handleSetStatus, onArchiveTask: handleArchiveTask, onAddTaskToColumn: handleAddTaskToColumn, showTaskCardStatusLabel: showTaskCardStatusLabel, onScheduleDaySelected: (dateOnly) => {
3268
+ } }), _jsxs("div", { style: { position: 'relative', width: '100%', minWidth: 0, flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column', overflow: 'hidden' }, children: [props.loadingTasks && boardVisibleTasks.length > 0 && (_jsx("div", { className: styles.boardRefreshIndicator, "aria-live": "polite", "aria-label": "Refreshing tasks", children: _jsx(Loader2, { size: 14, className: styles.spinner }) })), _jsx(TaskKanban, { tasks: scopedBoardVisibleTasks, allTasks: scopedKanbanAllTasks, columns: kanbanColumns, groupBy: groupBy, scheduleDates: scheduleDates, searchQuery: searchQuery, filterCategories: filterCategories, filterTypes: filterTypes, filterPriorities: filterPriorities, filterStatus: filterStatus, filterAssignees: filterAssignees, assigneeOptions: assigneeOptions, scheduleFilteredTaskIds: Array.from(scheduleFilteredTaskIds), copiedId: copiedId, taxonomies: taxonomies, types: activeTypes, priorities: priorities, onUpdateTask: handleUpdateTask, onTaskClick: (task) => handleEdit(task), onOpenTaskById: handleOpenTaskById, onCopyId: handleCopyId, onToggleInProgress: handleToggleInProgress, onToggleReview: handleToggleReview, onToggleComplete: handleToggleComplete, onToggleCancel: handleToggleCancel, onSetStatus: handleSetStatus, onArchiveTask: handleArchiveTask, onAddTaskToColumn: handleAddTaskToColumn, showTaskCardStatusLabel: showTaskCardStatusLabel, onScheduleDaySelected: (dateOnly) => {
3248
3269
  setScheduleSelectedDate(dateOnly);
3249
3270
  const parsed = parseDateOnlyLocal(dateOnly);
3250
3271
  if (parsed) {
@@ -3285,7 +3306,16 @@ export function StandaloneLayout(props) {
3285
3306
  top: '10px',
3286
3307
  right: '10px',
3287
3308
  zIndex: 20,
3288
- }, children: _jsx(ChevronLeft, { size: 16 }) }))] }), groupBy === 'schedule' && (_jsx(ScheduleSidebar, { open: scheduleSidebarOpen, onClose: () => setScheduleSidebarOpen(false), scheduleSelectedDate: scheduleSelectedDate, setScheduleSelectedDate: setScheduleSelectedDate, scheduleCalendarMonth: scheduleCalendarMonth, setScheduleCalendarMonth: setScheduleCalendarMonth, scheduleShowWeekends: scheduleShowWeekends, setScheduleShowWeekends: setScheduleShowWeekends, scheduleShowBacklog: scheduleShowBacklog, setScheduleShowBacklog: setScheduleShowBacklog, scheduleOnlyExpired: scheduleOnlyExpired, setScheduleOnlyExpired: setScheduleOnlyExpired, expiredScheduledCount: expiredScheduledCount, overdueDueCount: overdueDueCount, expiredLeafCandidates: expiredLeafCandidates, expiredRecoveryCandidates: expiredRecoveryCandidates, onMoveExpiredToSelectedWeek: handleMoveExpiredToSelectedWeek, onMoveExpiredToBacklog: handleMoveExpiredToBacklog, scheduleBulkBusy: scheduleBulkBusy, globalWeekStartsOn: globalWeekStartsOn, resolvedLocale: resolvedLocale, todayDateOnly: todayDateOnly, scheduleBaseTasks: scheduleBaseTasks, scheduleWeekStart: scheduleWeekStart, scheduleWeekLabel: scheduleWeekLabel }))] })), _jsxs(Modal, { isOpen: activeTab === 'add', onClose: handleCloseModal, title: editingTaskId ? (currentTask?.isDeleted ? 'Deleted Task' : 'Edit Task') : 'New Task', size: taskModalFullscreen ? 'full' : 'xl', theme: currentTheme, headerActions: (_jsx("button", { className: "tf-control-icon", onClick: () => setTaskModalFullscreen((value) => !value), title: taskModalFullscreen ? 'Exit full screen' : 'Enter full screen', "aria-label": taskModalFullscreen ? 'Exit full screen' : 'Enter full screen', children: taskModalFullscreen ? _jsx(Minimize2, { size: 18 }) : _jsx(Maximize2, { size: 18 }) })), draggable: !taskModalFullscreen, closeOnOverlayClick: false, children: [_jsx(TaskActionHeader, { editingTaskId: editingTaskId, loading: loading, autoSaveState: autoSaveState, title: title, currentTask: currentTask, currentTaskWorkstream: currentTaskWorkstream, currentTaskInitiative: currentTaskInitiative, workstreamInput: workstreamInput, onWorkstreamInputChange: setWorkstreamInput, onSetWorkstreamForCurrentTask: handleSetWorkstreamForCurrentTask, handleSubmit: handleSubmit, resetForm: resetForm, handleCopyId: handleCopyId, copiedId: copiedId, tasks: tasks, handleToggleInProgress: handleToggleInProgress, handleToggleReview: handleToggleReview, handleToggleComplete: handleToggleComplete, handleToggleCancel: handleToggleCancel, handleSetStatus: handleSetStatus, handleArchiveTask: handleArchiveTask, handleRestoreDeletedTask: currentTask?.deletedRecordId
3309
+ }, children: _jsx(ChevronLeft, { size: 16 }) }))] }), groupBy === 'schedule' && (_jsx(ScheduleSidebar, { open: scheduleSidebarOpen, onClose: () => setScheduleSidebarOpen(false), scheduleSelectedDate: scheduleSelectedDate, setScheduleSelectedDate: setScheduleSelectedDate, scheduleCalendarMonth: scheduleCalendarMonth, setScheduleCalendarMonth: setScheduleCalendarMonth, scheduleShowWeekends: scheduleShowWeekends, setScheduleShowWeekends: setScheduleShowWeekends, scheduleShowBacklog: scheduleShowBacklog, setScheduleShowBacklog: setScheduleShowBacklog, scheduleOnlyExpired: scheduleOnlyExpired, setScheduleOnlyExpired: setScheduleOnlyExpired, expiredScheduledCount: expiredScheduledCount, overdueDueCount: overdueDueCount, expiredLeafCandidates: expiredLeafCandidates, expiredRecoveryCandidates: expiredRecoveryCandidates, onMoveExpiredToSelectedWeek: handleMoveExpiredToSelectedWeek, onMoveExpiredToBacklog: handleMoveExpiredToBacklog, scheduleBulkBusy: scheduleBulkBusy, globalWeekStartsOn: globalWeekStartsOn, resolvedLocale: resolvedLocale, todayDateOnly: todayDateOnly, scheduleBaseTasks: scheduleBaseTasks, scheduleWeekStart: scheduleWeekStart, scheduleWeekLabel: scheduleWeekLabel }))] })), _jsxs(Modal, { isOpen: activeTab === 'add', onClose: handleCloseModal, title: editingTaskId ? (currentTask?.isDeleted ? 'Deleted Task' : 'Edit Task') : 'New Task', size: taskModalFullscreen ? 'full' : 'xl', theme: currentTheme, headerActions: (_jsx("button", { className: "tf-control-icon", onClick: () => setTaskModalFullscreen((value) => !value), title: taskModalFullscreen ? 'Exit full screen' : 'Enter full screen', "aria-label": taskModalFullscreen ? 'Exit full screen' : 'Enter full screen', children: taskModalFullscreen ? _jsx(Minimize2, { size: 18 }) : _jsx(Maximize2, { size: 18 }) })), draggable: !taskModalFullscreen, closeOnOverlayClick: false, children: [_jsx(TaskActionHeader, { editingTaskId: editingTaskId, loading: loading, autoSaveState: autoSaveState, title: title, currentTask: currentTask, currentTaskWorkstream: currentTaskWorkstream, currentTaskInitiative: currentTaskInitiative, workstreamInput: workstreamInput, onWorkstreamInputChange: setWorkstreamInput, onSetWorkstreamForCurrentTask: handleSetWorkstreamForCurrentTask, handleSubmit: handleSubmit, resetForm: resetForm, handleCopyId: handleCopyId, copiedId: copiedId, tasks: tasks, handleToggleInProgress: handleToggleInProgress, handleToggleReview: handleToggleReview, handleToggleComplete: handleToggleComplete, handleToggleCancel: handleToggleCancel, handleSetStatus: handleSetStatus, handleArchiveTask: handleArchiveTask, handleUnarchiveTask: (taskId) => {
3310
+ if (currentTask?.isDeleted) {
3311
+ const deletedRecord = deletedTaskRecordByTaskId.get(taskId);
3312
+ if (!deletedRecord)
3313
+ return;
3314
+ void handleRestoreDeletedTask(deletedRecord.id);
3315
+ return;
3316
+ }
3317
+ void handleUnarchive(taskId);
3318
+ }, handleRestoreDeletedTask: currentTask?.deletedRecordId
3289
3319
  ? (deletedRecordId) => {
3290
3320
  void handleRestoreDeletedTask(deletedRecordId);
3291
3321
  }
@@ -3298,7 +3328,7 @@ export function StandaloneLayout(props) {
3298
3328
  resetForm();
3299
3329
  setActiveTab('tasks');
3300
3330
  }
3301
- : undefined }), _jsx(TaskForm, { editingTaskId: editingTaskId, error: error, title: title, description: description, checklistItems: checklistItems, category: category, type: type, priority: priority, complexity: complexity, manualComplexityEnabled: manualComplexityEnabled, approach: approach, assignee: assignee, scheduledDate: scheduledDate, dueDate: dueDate, workstreamInput: workstreamInput, formTaxonomies: formTaxonomies, onTaxonomyChange: (id, val) => setFormTaxonomies(prev => ({ ...prev, [id]: val })), taxonomies: taxonomies, comments: comments, newCommentText: newCommentText, contextFiles: attachments, currentWorkspaceId: currentWorkspaceId, apiBaseUrl: apiBaseUrl, descriptionFocused: descriptionFocused, showMarkdownHelp: showMarkdownHelp, showChecklist: showChecklist, checklistEnabled: checklistDropdownEnabled, showComments: showComments, categories: activeCategories, types: activeTypes, priorities: priorities, taxonomyDisplayLabels: taxonomyDisplayLabels, assigneeOptions: assigneeOptions, workstreams: props.workstreams, copiedId: copiedId, onTitleChange: setTitle, onDescriptionChange: setDescription, onChecklistItemsChange: setChecklistItems, onCategoryChange: setCategory, onTypeChange: setType, onPriorityChange: setPriority, onComplexityChange: setComplexity, onApproachChange: (val) => { setApproach(val); setFormTaxonomies(prev => ({ ...prev, approach: val })); }, onAssigneeChange: setAssignee, onScheduledDateChange: setScheduledDate, onDueDateChange: setDueDate, onWorkstreamInputChange: setWorkstreamInput, onNewCommentTextChange: setNewCommentText, onDescriptionFocusedChange: setDescriptionFocused, onShowMarkdownHelpChange: setShowMarkdownHelp, onShowChecklistChange: setShowChecklist, onShowCommentsChange: setShowComments, onOpenSettings: (section) => {
3331
+ : undefined }), _jsx(TaskForm, { editingTaskId: editingTaskId, error: error, title: title, description: description, checklistItems: checklistItems, category: category, type: type, priority: priority, complexity: complexity, manualComplexityEnabled: manualComplexityEnabled, approach: approach, assignee: assignee, scheduledDate: scheduledDate, dueDate: dueDate, workstreamInput: workstreamInput, formTaxonomies: formTaxonomies, onTaxonomyChange: (id, val) => setFormTaxonomies(prev => ({ ...prev, [id]: val })), taxonomies: taxonomies, comments: comments, newCommentText: newCommentText, contextFiles: attachments, currentWorkspaceId: currentWorkspaceId, apiBaseUrl: apiBaseUrl, descriptionFocused: descriptionFocused, showMarkdownHelp: showMarkdownHelp, showChecklist: showChecklist, checklistEnabled: checklistDropdownEnabled, showComments: showComments, categories: activeCategories, types: activeTypes, priorities: priorities, taxonomyDisplayLabels: taxonomyDisplayLabels, assigneeOptions: assigneeOptions, workstreams: props.workstreams, initiatives: props.initiatives, copiedId: copiedId, onTitleChange: setTitle, onDescriptionChange: setDescription, onChecklistItemsChange: setChecklistItems, onCategoryChange: setCategory, onTypeChange: setType, onPriorityChange: setPriority, onComplexityChange: setComplexity, onApproachChange: (val) => { setApproach(val); setFormTaxonomies(prev => ({ ...prev, approach: val })); }, onAssigneeChange: setAssignee, onScheduledDateChange: setScheduledDate, onDueDateChange: setDueDate, onWorkstreamInputChange: setWorkstreamInput, onNewCommentTextChange: setNewCommentText, onDescriptionFocusedChange: setDescriptionFocused, onShowMarkdownHelpChange: setShowMarkdownHelp, onShowChecklistChange: setShowChecklist, onShowCommentsChange: setShowComments, onOpenSettings: (section) => {
3302
3332
  setSettingsSection(section);
3303
3333
  setActiveTab('settings');
3304
3334
  }, onSubmit: handleSubmit, commentsEndRef: commentsEndRef, onAddComment: () => handleAddComment(newCommentText), onOpenTaskById: handleOpenTaskById, onAddContextFile: (file) => {
@@ -3350,11 +3380,11 @@ export function StandaloneLayout(props) {
3350
3380
  setShowHelpModal(false);
3351
3381
  setActiveTab('settings');
3352
3382
  setSettingsSection('general');
3353
- } }), _jsx(EditProfileModal, { isOpen: showEditProfileModal, theme: currentTheme, onClose: closeEditProfileModal, onSave: () => { void handleSaveProfile(); }, displayName: profileDisplayNameDraft, email: authEmailLabel, avatarDisplayUrl: profileAvatarDisplayUrl, accountBadgeInitial: accountBadgeInitial, avatarInputRef: profileAvatarInputRef, avatarAccept: PROFILE_AVATAR_ACCEPT, avatarDraftId: profileAvatarDraftId, saveBusy: profileSaveBusy, avatarBusy: profileAvatarBusy, saveError: profileSaveError, saveNotice: profileSaveNotice, onDisplayNameChange: setProfileDisplayNameDraft, onAvatarInputChange: (file) => { void handleProfileAvatarSelected(file); }, onStartAvatarUpload: () => profileAvatarInputRef.current?.click(), onDiscardUpload: handleDiscardPendingProfileAvatar, onRemovePhoto: handleRemoveProfileAvatar }), _jsx(AccountHubModal, { isOpen: showAccountHub, theme: currentTheme, runtimeMode: runtimeMode, authRequiredForApi: authRequiredForApi, isAuthenticated: isAuthenticated, hasAuthIdentity: hasAuthIdentity, authIdentityLabel: authIdentityLabel, billingLoading: billingLoading, billingError: billingError, billingActionError: billingActionError, billingNotice: billingNotice, billingActionBusy: billingActionBusy, billingIntervalChoice: billingIntervalChoice, billingStatus: billingStatus, currentWorkspaceId: currentWorkspaceId, canOpenTeamManagement: canOpenTeamManagement, canManageWorkspaceSync: canManageWorkspaceSync, workspaceCloudSyncEnabled: workspaceCloudSyncEnabled, syncStatusLabel: syncStatusMeta.label, workspaceSyncError: workspaceSyncError, syncControlBusy: syncControlBusy, onClose: () => setShowAccountHub(false), onOpenWorkspaceAudit: () => {
3383
+ } }), _jsx(EditProfileModal, { isOpen: showEditProfileModal, theme: currentTheme, onClose: closeEditProfileModal, onSave: () => { void handleSaveProfile(); }, displayName: profileDisplayNameDraft, email: authEmailLabel, avatarDisplayUrl: profileAvatarDisplayUrl, accountBadgeInitial: accountBadgeInitial, avatarInputRef: profileAvatarInputRef, avatarAccept: PROFILE_AVATAR_ACCEPT, avatarDraftId: profileAvatarDraftId, saveBusy: profileSaveBusy, avatarBusy: profileAvatarBusy, saveError: profileSaveError, saveNotice: profileSaveNotice, onDisplayNameChange: setProfileDisplayNameDraft, onAvatarInputChange: (file) => { void handleProfileAvatarSelected(file); }, onStartAvatarUpload: () => profileAvatarInputRef.current?.click(), onDiscardUpload: handleDiscardPendingProfileAvatar, onRemovePhoto: handleRemoveProfileAvatar }), _jsx(AccountHubModal, { isOpen: showAccountHub, theme: currentTheme, runtimeMode: runtimeMode, authRequiredForApi: authRequiredForApi, isAuthenticated: isAuthenticated, hasAuthIdentity: hasAuthIdentity, authIdentityLabel: authIdentityLabel, billingLoading: billingLoading, billingError: billingError, billingActionError: billingActionError, billingNotice: billingNotice, billingActionBusy: billingActionBusy, billingIntervalChoice: billingIntervalChoice, accountProfileSummary: accountProfileSummary, currentWorkspaceId: currentWorkspaceId, canOpenTeamManagement: canOpenTeamManagement, canManageWorkspaceSync: canManageWorkspaceSync, workspaceCloudSyncEnabled: workspaceCloudSyncEnabled, syncStatusLabel: syncStatusMeta.label, workspaceSyncError: workspaceSyncError, syncControlBusy: syncControlBusy, onClose: () => setShowAccountHub(false), onOpenWorkspaceAudit: () => {
3354
3384
  setShowAccountHub(false);
3355
3385
  void openTeamManagementModal();
3356
3386
  setTeamManagementTab('audit');
3357
- }, onBillingIntervalChange: setBillingIntervalChoice, onRefreshBilling: () => { void loadBillingStatus(); }, onUpdateInterval: () => { void handleSwitchSubscriptionInterval(); }, onManageBilling: () => { void handleOpenBillingPortal(); }, onStartCheckout: () => { void handleStartCheckout(); }, onToggleWorkspaceSync: (enabled) => { void handleWorkspaceSyncToggle(enabled); }, onOpenHelp: () => {
3387
+ }, onBillingIntervalChange: setBillingIntervalChoice, onRefreshBilling: () => { void loadAccountProfileSummary(); }, onUpdateInterval: () => { void handleSwitchSubscriptionInterval(); }, onManageBilling: () => { void handleOpenBillingPortal(); }, onStartCheckout: () => { void handleStartCheckout(); }, onToggleWorkspaceSync: (enabled) => { void handleWorkspaceSyncToggle(enabled); }, onOpenHelp: () => {
3358
3388
  setShowAccountHub(false);
3359
3389
  setShowHelpModal(true);
3360
3390
  } }), _jsx(TeamManagementModal, { isOpen: showTeamManagementModal, theme: currentTheme, teamPlanMode: teamPlanMode, teamMgmtError: teamMgmtError, teamManagementTab: teamManagementTab, teamUsersLoading: teamUsersLoading, teamUsers: teamUsers, teamActionBusyUserId: teamActionBusyUserId, teamInviteFeedback: teamInviteFeedback, teamInviteEmail: teamInviteEmail, teamInviteRole: teamInviteRole, teamInvitePermissionMode: teamInvitePermissionMode, teamInviteBusy: teamInviteBusy, pendingInvites: pendingInvites, teamAuditLoading: teamAuditLoading, teamAuditEvents: teamAuditEvents, teamAuditPage: teamAuditPage, teamAuditPages: teamAuditPages, teamAuditHasMore: teamAuditHasMore, onClose: () => setShowTeamManagementModal(false), onOpenMembersTab: () => {