@taskforcehq/taskforce 0.3.306 → 0.3.308

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 (232) hide show
  1. package/README.md +0 -2
  2. package/dist/Taskforce.module.css +317 -27
  3. package/dist/TaskforceCore.js +1 -0
  4. package/dist/TaskforceCore.test.js +178 -0
  5. package/dist/components/activity/EntityActivityTimeline.d.ts +34 -0
  6. package/dist/components/activity/EntityActivityTimeline.js +81 -0
  7. package/dist/components/context/ContextAttachmentManager.js +15 -3
  8. package/dist/components/features/AgentsModule.d.ts +5 -1
  9. package/dist/components/features/AgentsModule.js +142 -39
  10. package/dist/components/features/AgentsModule.test.js +260 -11
  11. package/dist/components/features/AnnotatedAttachmentWorkspace.d.ts +3 -1
  12. package/dist/components/features/AnnotatedAttachmentWorkspace.js +118 -4
  13. package/dist/components/features/AnnotatedAttachmentWorkspace.test.js +52 -0
  14. package/dist/components/features/DocumentIndex.d.ts +2 -2
  15. package/dist/components/features/DocumentIndex.js +3 -4
  16. package/dist/components/features/DocumentViewer.d.ts +3 -1
  17. package/dist/components/features/DocumentViewer.js +6 -5
  18. package/dist/components/features/DocumentWorkspace.d.ts +10 -2
  19. package/dist/components/features/DocumentWorkspace.js +15 -4
  20. package/dist/components/features/DocumentWorkspace.test.js +20 -3
  21. package/dist/components/features/TaskSettings.d.ts +2 -0
  22. package/dist/components/features/TaskSettings.js +83 -78
  23. package/dist/components/features/TaskSettings.test.js +171 -82
  24. package/dist/components/task/TaskActionHeader.js +11 -5
  25. package/dist/components/task/TaskActionHeader.test.js +10 -0
  26. package/dist/components/task/TaskCard.js +6 -2
  27. package/dist/components/task/TaskContextUpload.test.js +3 -3
  28. package/dist/components/task/TaskForm.js +14 -64
  29. package/dist/components/task/TaskKanban.js +0 -8
  30. package/dist/components/task/TaskList.js +5 -1
  31. package/dist/components/task/TaskList.test.js +4 -0
  32. package/dist/components/ui/HierarchyActionBadge.d.ts +10 -0
  33. package/dist/components/ui/HierarchyActionBadge.js +5 -0
  34. package/dist/components/views/AppShellHeader.d.ts +3 -1
  35. package/dist/components/views/AppShellHeader.js +27 -11
  36. package/dist/components/views/AppShellHeader.test.js +18 -1
  37. package/dist/components/views/PlanComparisonPage.d.ts +20 -15
  38. package/dist/components/views/PlanComparisonPage.js +221 -82
  39. package/dist/components/views/PlanComparisonPage.test.js +268 -14
  40. package/dist/components/views/PlansPage.js +16 -10
  41. package/dist/components/views/PlansPage.test.js +4 -2
  42. package/dist/components/views/StandaloneLayout.js +256 -69
  43. package/dist/components/views/WidgetView.js +10 -8
  44. package/dist/components/views/panels/PlanningDrawer.d.ts +19 -6
  45. package/dist/components/views/panels/PlanningDrawer.js +259 -51
  46. package/dist/components/views/panels/PlanningDrawer.test.js +392 -4
  47. package/dist/config/envSchema.js +1 -0
  48. package/dist/core/AiProfileService.d.ts +7 -0
  49. package/dist/core/AiProfileService.js +460 -35
  50. package/dist/core/AiProfiles.test.js +648 -2
  51. package/dist/core/AttachmentLinkService.d.ts +3 -0
  52. package/dist/core/AttachmentLinkService.js +58 -13
  53. package/dist/core/GlobalSettingsService.js +30 -0
  54. package/dist/core/GlobalSettingsService.test.d.ts +1 -0
  55. package/dist/core/GlobalSettingsService.test.js +45 -0
  56. package/dist/core/McpTokenService.d.ts +12 -0
  57. package/dist/core/McpTokenService.js +44 -1
  58. package/dist/core/PlanEntitlementService.d.ts +20 -0
  59. package/dist/core/PlanEntitlementService.js +215 -19
  60. package/dist/core/PlanFeatureCatalog.test.js +55 -0
  61. package/dist/core/PlanningEntities.test.js +366 -4
  62. package/dist/core/TaskActivityService.d.ts +28 -1
  63. package/dist/core/TaskActivityService.js +227 -46
  64. package/dist/core/TaskActivitySync.test.d.ts +1 -0
  65. package/dist/core/TaskActivitySync.test.js +90 -0
  66. package/dist/core/TaskAuditTimeline.test.js +96 -0
  67. package/dist/core/Taskforce.d.ts +204 -26
  68. package/dist/core/Taskforce.ids.test.js +58 -0
  69. package/dist/core/Taskforce.js +781 -71
  70. package/dist/core/Taskforce.mcpAuth.test.js +109 -0
  71. package/dist/core/types.d.ts +10 -0
  72. package/dist/hooks/auth/useTaskforceAuthBootstrap.js +2 -1
  73. package/dist/hooks/bootstrapTimeouts.d.ts +4 -0
  74. package/dist/hooks/bootstrapTimeouts.js +8 -0
  75. package/dist/hooks/bootstrapTimeouts.test.d.ts +1 -0
  76. package/dist/hooks/bootstrapTimeouts.test.js +12 -0
  77. package/dist/hooks/sync/orchestratorShared.d.ts +3 -3
  78. package/dist/hooks/sync/orchestratorShared.js +61 -1
  79. package/dist/hooks/sync/recovery.js +8 -0
  80. package/dist/hooks/sync/recovery.test.js +5 -5
  81. package/dist/hooks/sync/transfers.d.ts +2 -1
  82. package/dist/hooks/sync/transfers.js +36 -9
  83. package/dist/hooks/sync/transfers.test.js +534 -2
  84. package/dist/hooks/useFilterSort.js +13 -13
  85. package/dist/hooks/useFilterSort.test.js +87 -1
  86. package/dist/hooks/useSyncOrchestrator.js +50 -5
  87. package/dist/hooks/useTaskforce.d.ts +85 -50
  88. package/dist/hooks/useTaskforce.js +44 -14
  89. package/dist/hooks/useTaskforce.runtime-routing.test.js +94 -0
  90. package/dist/hooks/useTaskforce.sync-behavior.test.js +99 -0
  91. package/dist/hooks/useWorkspaceSyncController.js +7 -1
  92. package/dist/hooks/useWorkspaceSyncController.test.js +48 -0
  93. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +14 -7
  94. package/dist/mcp/canonicalAssetHelpers.d.ts +16 -4
  95. package/dist/mcp/canonicalAssetHelpers.js +18 -10
  96. package/dist/mcp/canonicalAssetHelpers.test.d.ts +1 -0
  97. package/dist/mcp/canonicalAssetHelpers.test.js +67 -0
  98. package/dist/mcp/clientIntegrations.d.ts +1 -0
  99. package/dist/mcp/clientIntegrations.js +25 -0
  100. package/dist/mcp/clientIntegrations.test.js +14 -3
  101. package/dist/mcp/clientProfileDefaults.js +3 -3
  102. package/dist/mcp/collaborationRegistrar.js +7 -7
  103. package/dist/mcp/documentAssetRegistrar.js +113 -7
  104. package/dist/mcp/runtime.d.ts +1 -0
  105. package/dist/mcp/runtime.js +969 -122
  106. package/dist/mcp/runtime.test.js +1083 -11
  107. package/dist/mcp/taskAttachmentTypes.d.ts +1 -1
  108. package/dist/mcp/taskPlanningRegistrar.js +48 -0
  109. package/dist/mcp/toolRegistry.d.ts +56 -0
  110. package/dist/mcp/toolRegistry.js +8 -0
  111. package/dist/mcp/toolRegistry.test.js +4 -0
  112. package/dist/migrations/taskSchemaMigrations.js +58 -15
  113. package/dist/server/aiProfileAvatarAssets.d.ts +49 -0
  114. package/dist/server/aiProfileAvatarAssets.js +319 -0
  115. package/dist/server/aiProfileAvatarAssets.test.d.ts +1 -0
  116. package/dist/server/aiProfileAvatarAssets.test.js +213 -0
  117. package/dist/server/annotatedAttachmentsRoutes.test.js +66 -7
  118. package/dist/server/index.js +4 -0
  119. package/dist/server/index.test.js +6 -1
  120. package/dist/server/routes/admin.js +328 -9
  121. package/dist/server/routes/annotatedAttachments.js +51 -0
  122. package/dist/server/routes/auth.d.ts +11 -0
  123. package/dist/server/routes/auth.js +189 -27
  124. package/dist/server/routes/authSupport.d.ts +5 -0
  125. package/dist/server/routes/authSupport.js +13 -1
  126. package/dist/server/routes/billing.d.ts +1 -0
  127. package/dist/server/routes/billing.js +116 -63
  128. package/dist/server/routes/billing.test.js +162 -11
  129. package/dist/server/routes/documents.js +10 -0
  130. package/dist/server/routes/shared.js +0 -10
  131. package/dist/server/routes/sync.integration.test.js +221 -0
  132. package/dist/server/routes/sync.js +13 -3
  133. package/dist/server/routes/syncSnapshotRoutes.js +2 -0
  134. package/dist/server/routes/tasks.js +12 -9
  135. package/dist/server/routes.js +87 -8
  136. package/dist/server/routes.test.js +972 -23
  137. package/dist/shared/aiProfileSurfaceType.d.ts +1 -1
  138. package/dist/shared/aiProfileSurfaceType.js +10 -8
  139. package/dist/storage/objectStorage.d.ts +1 -0
  140. package/dist/storage/objectStorage.js +2 -1
  141. package/dist/storage/objectStorageClient.d.ts +1 -0
  142. package/dist/storage/objectStorageClient.js +41 -8
  143. package/dist/storage/objectStorageClient.test.js +26 -1
  144. package/dist/storage/objectStorageConfig.js +3 -1
  145. package/dist/storage/objectStorageConfig.test.js +13 -1
  146. package/dist/sync/collaborationSyncPayload.js +2 -0
  147. package/dist/sync/collaborationSyncPayload.test.js +1 -0
  148. package/dist/sync/collaborationSyncState.d.ts +3 -3
  149. package/dist/sync/collaborationSyncState.js +19 -12
  150. package/dist/sync/contentSyncPayload.d.ts +5 -1
  151. package/dist/sync/contentSyncPayload.js +9 -0
  152. package/dist/sync/contentSyncPayload.test.js +39 -0
  153. package/dist/sync/contentSyncState.d.ts +5 -1
  154. package/dist/sync/contentSyncState.js +231 -37
  155. package/dist/sync/planningSyncPayload.js +5 -0
  156. package/dist/sync/planningSyncPayload.test.js +24 -0
  157. package/dist/sync/syncApplyHandlers.d.ts +4 -4
  158. package/dist/sync/syncApplyHandlers.js +89 -31
  159. package/dist/sync/syncApplyHandlers.test.js +184 -4
  160. package/dist/sync/syncResourceAdapters.d.ts +2 -0
  161. package/dist/sync/syncResourceAdapters.js +2 -0
  162. package/dist/sync/syncService.d.ts +1 -0
  163. package/dist/sync/syncService.js +13 -1
  164. package/dist/sync/syncService.test.js +39 -0
  165. package/dist/sync/workspacePullFeed.d.ts +4 -0
  166. package/dist/sync/workspacePullFeed.js +129 -70
  167. package/dist/sync/workspacePullFeed.test.js +49 -0
  168. package/dist/sync/workspaceSyncModel.d.ts +28 -6
  169. package/dist/sync/workspaceSyncModel.js +159 -45
  170. package/dist/sync/workspaceSyncModel.test.js +269 -3
  171. package/dist/types.d.ts +33 -2
  172. package/dist/ui/agent-logos/ChatGPT.png +0 -0
  173. package/dist/ui/agent-logos/Gemini CLI.jpeg +0 -0
  174. package/dist/ui/agent-logos/antigravity.jpeg +0 -0
  175. package/dist/ui/agent-logos/claude-code.jpeg +0 -0
  176. package/dist/ui/agent-logos/codex.jpeg +0 -0
  177. package/dist/ui/agent-logos/cursor.png +0 -0
  178. package/dist/ui/agent-logos/openclaw.jpeg +0 -0
  179. package/dist/ui/agent-logos/windsurf.png +0 -0
  180. package/dist/ui/assets/AgentsModule-BS4Pi_nC.js +1 -0
  181. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BVKew-mH.css +1 -0
  182. package/dist/ui/assets/AnnotatedAttachmentWorkspace-CCckzWYZ.js +3 -0
  183. package/dist/ui/assets/ContextAttachmentManager-CfG_ER7C.js +3 -0
  184. package/dist/ui/assets/DocumentWorkspace-BVaWPA25.js +252 -0
  185. package/dist/ui/assets/DocumentWorkspace-D4rJKXzd.css +1 -0
  186. package/dist/ui/assets/EntityActivityTimeline-DSj0ThaK.js +1 -0
  187. package/dist/ui/assets/EntityActivityTimeline-DyqvvhuF.css +1 -0
  188. package/dist/ui/assets/{InitiativesModule-9E6ParrY.js → InitiativesModule-AxMkWtxH.js} +1 -1
  189. package/dist/ui/assets/PlansPage-B_z-D6Nh.css +1 -0
  190. package/dist/ui/assets/PlansPage-Ndt7mYfo.js +1 -0
  191. package/dist/ui/assets/TaskContextUpload-Dw4rTF4i.js +1 -0
  192. package/dist/ui/assets/TaskSettings-f2ga42_V.js +9 -0
  193. package/dist/ui/assets/{WorkflowsModule-BA7jcEpH.js → WorkflowsModule-E4UL3mov.js} +4 -4
  194. package/dist/ui/assets/documentReferences-BOUcJm6-.js +1 -0
  195. package/dist/ui/assets/index-BvAbqx5Q.css +1 -0
  196. package/dist/ui/assets/index-MAHKvFqp.js +4 -0
  197. package/dist/ui/assets/{vendor-icons-DuEd_65c.js → vendor-icons-B32hGuF2.js} +1 -1
  198. package/dist/ui/index.html +3 -3
  199. package/dist/ui/og-image.png +0 -0
  200. package/dist/ui/product/agent manager.png +0 -0
  201. package/dist/ui/product/agent_manager_02.png +0 -0
  202. package/dist/utils/aiProfileEvents.d.ts +7 -0
  203. package/dist/utils/aiProfileEvents.js +6 -0
  204. package/dist/utils/assignees.d.ts +6 -0
  205. package/dist/utils/assignees.js +8 -1
  206. package/dist/utils/assignees.test.d.ts +1 -0
  207. package/dist/utils/assignees.test.js +25 -0
  208. package/dist/utils/avatarDisplay.d.ts +1 -0
  209. package/dist/utils/avatarDisplay.js +15 -0
  210. package/dist/utils/contextFiles.d.ts +3 -1
  211. package/dist/utils/contextFiles.js +2 -1
  212. package/dist/utils/taskActivity.d.ts +7 -1
  213. package/dist/utils/taskActivity.js +63 -1
  214. package/dist/utils/taskActivity.test.js +23 -1
  215. package/dist/utils/taskSearch.d.ts +22 -0
  216. package/dist/utils/taskSearch.js +87 -0
  217. package/dist/utils/taskSearch.test.d.ts +1 -0
  218. package/dist/utils/taskSearch.test.js +69 -0
  219. package/dist/utils/taskUtils.js +10 -3
  220. package/dist/utils/taskUtils.test.d.ts +1 -0
  221. package/dist/utils/taskUtils.test.js +19 -0
  222. package/package.json +1 -1
  223. package/dist/ui/assets/AgentsModule-DrLawwNl.js +0 -1
  224. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BaS2VwIr.css +0 -1
  225. package/dist/ui/assets/AnnotatedAttachmentWorkspace-Z9_whf7F.js +0 -3
  226. package/dist/ui/assets/DocumentWorkspace-B03MaSkw.js +0 -252
  227. package/dist/ui/assets/DocumentWorkspace-Dhdso07p.css +0 -1
  228. package/dist/ui/assets/PlansPage-CvfnMiWq.css +0 -1
  229. package/dist/ui/assets/PlansPage-DRXscYxH.js +0 -1
  230. package/dist/ui/assets/TaskSettings-DZX4jk7e.js +0 -9
  231. package/dist/ui/assets/index-9eT8e0Lu.css +0 -1
  232. package/dist/ui/assets/index-C6k75jr8.js +0 -6
@@ -910,6 +910,48 @@ describe('TaskforceCore Integration', () => {
910
910
  });
911
911
  expect(container.querySelector('[aria-pressed]')).not.toBeInTheDocument();
912
912
  });
913
+ it('renders the cloud login route even while protected startup config is pending', async () => {
914
+ const hangingConfig = new Promise(() => { });
915
+ const fetchMock = vi.fn((url) => {
916
+ if (url.includes('/api/taskforce/auth/runtime-config')) {
917
+ return Promise.resolve({
918
+ ok: true,
919
+ json: () => Promise.resolve({
920
+ config: {
921
+ runtimeMode: 'cloud',
922
+ workspaceMode: 'multi-cloud',
923
+ authSource: 'cloud',
924
+ workspaceSwitchingEnabled: true
925
+ }
926
+ })
927
+ });
928
+ }
929
+ if (url.includes('/api/taskforce/auth/session')) {
930
+ return Promise.resolve({
931
+ ok: true,
932
+ json: () => Promise.resolve({
933
+ authenticated: false,
934
+ runtimeMode: 'cloud'
935
+ })
936
+ });
937
+ }
938
+ if (url.includes('/api/taskforce/config')) {
939
+ return hangingConfig;
940
+ }
941
+ if (url.includes('/api/taskforce/auth/providers')) {
942
+ return Promise.resolve({ ok: true, json: () => Promise.resolve({ providers: [] }) });
943
+ }
944
+ return Promise.resolve({ ok: true, json: () => Promise.resolve({}) });
945
+ });
946
+ vi.stubGlobal('fetch', fetchMock);
947
+ render(_jsx(MemoryRouter, { initialEntries: ['/login?mode=login&next=%2Ftaskforce%2F'], children: _jsx(TaskforceCore, {}) }));
948
+ await waitFor(() => {
949
+ expect(screen.getByPlaceholderText('Email')).toBeInTheDocument();
950
+ expect(screen.getByPlaceholderText('Password')).toBeInTheDocument();
951
+ expect(screen.getByRole('button', { name: 'Sign In' })).toBeInTheDocument();
952
+ });
953
+ expect(screen.queryByText('Loading Taskforce')).not.toBeInTheDocument();
954
+ });
913
955
  it('allows public access to /pricing in cloud mode without login redirect', async () => {
914
956
  const fetchMock = vi.fn((url) => {
915
957
  if (url.includes('/api/taskforce/auth/session')) {
@@ -6002,6 +6044,142 @@ describe('TaskforceCore Integration', () => {
6002
6044
  await user.click(screen.getByTitle(/Account/i));
6003
6045
  expect(await screen.findByText('Sign In / Register')).toBeInTheDocument();
6004
6046
  });
6047
+ it('returns to the login screen after signing out from the cloud plans screen', async () => {
6048
+ const user = userEvent.setup();
6049
+ let signedIn = true;
6050
+ const fetchMock = vi.fn((url) => {
6051
+ if (url.includes('/api/taskforce/auth/runtime-config')) {
6052
+ return jsonResponse({ config: { runtimeMode: 'cloud', workspaceMode: 'team', authSource: 'cloud' } });
6053
+ }
6054
+ if (url.includes('/api/taskforce/auth/session')) {
6055
+ return jsonResponse({
6056
+ authenticated: signedIn,
6057
+ runtimeMode: 'cloud',
6058
+ authRequiredForApi: true,
6059
+ email: signedIn ? 'member@example.com' : '',
6060
+ userId: signedIn ? 'user-member' : 'anonymous',
6061
+ workspaceId: signedIn ? 'workspace-cloud-active' : '',
6062
+ betaAccess: true
6063
+ });
6064
+ }
6065
+ if (url.includes('/api/taskforce/auth/logout')) {
6066
+ signedIn = false;
6067
+ return jsonResponse({ success: true });
6068
+ }
6069
+ if (url.includes('/api/taskforce/config')) {
6070
+ return jsonResponse({
6071
+ ...mockConfig,
6072
+ runtimeMode: 'cloud',
6073
+ authRequiredForApi: true,
6074
+ workspaceId: 'workspace-cloud-active',
6075
+ workspaceSwitchingEnabled: true,
6076
+ setupState: {
6077
+ globalSetupState: 'present',
6078
+ workspaceSetupState: 'present',
6079
+ runtimeMode: 'cloud',
6080
+ workspaceId: 'workspace-cloud-active',
6081
+ mode: 'core',
6082
+ forceSetup: false,
6083
+ forceGlobalSetup: false,
6084
+ forceWorkspaceSetup: false
6085
+ }
6086
+ });
6087
+ }
6088
+ if (url.includes('/api/taskforce/account/access-status')) {
6089
+ return jsonResponse({
6090
+ gate: 'plan_selection_required',
6091
+ hasEntitlement: false,
6092
+ canAccessApp: false,
6093
+ canAccessPlans: true
6094
+ });
6095
+ }
6096
+ if (url.includes('/api/taskforce/public/pricing')) {
6097
+ return jsonResponse({
6098
+ plans: [
6099
+ {
6100
+ planId: 'free',
6101
+ displayName: 'Free',
6102
+ status: 'active',
6103
+ features: [],
6104
+ pricing: {
6105
+ month: { pricingType: 'free', stripePriceId: null, unitAmount: 0, currency: null, interval: 'month' },
6106
+ year: null
6107
+ },
6108
+ defaultVersion: {
6109
+ planVersionId: 'free-v1',
6110
+ versionNumber: 1,
6111
+ seatLimit: null,
6112
+ metadata: {}
6113
+ }
6114
+ }
6115
+ ]
6116
+ });
6117
+ }
6118
+ if (url.includes('/api/taskforce/account/profile-summary')) {
6119
+ return jsonResponse({
6120
+ planId: 'free',
6121
+ planName: 'Free',
6122
+ planVersionId: 'free-v1',
6123
+ entitlementState: 'pending_plan_selection',
6124
+ gate: 'plan_selection_required',
6125
+ planSelectionRequired: true
6126
+ });
6127
+ }
6128
+ if (url.includes('/api/taskforce/workspaces')) {
6129
+ return jsonResponse({ workspaces: [] });
6130
+ }
6131
+ if (url.includes('/api/taskforce/ui-state?key=app')) {
6132
+ return jsonResponse({ success: true, state: {} });
6133
+ }
6134
+ if (url.includes('/api/taskforce/ui-state?key=workspace-sync')) {
6135
+ return jsonResponse({ success: true, state: {} });
6136
+ }
6137
+ if (url.includes('/api/taskforce/categories')) {
6138
+ return jsonResponse(mockCategories);
6139
+ }
6140
+ if (url.includes('/api/taskforce/tasks')) {
6141
+ return jsonResponse({ tasks: mockTasks });
6142
+ }
6143
+ if (url.includes('/api/taskforce/archive')) {
6144
+ return jsonResponse({ archived: [] });
6145
+ }
6146
+ if (url.includes('/api/taskforce/types')) {
6147
+ return jsonResponse({ types: [] });
6148
+ }
6149
+ if (url.includes('/api/taskforce/priorities')) {
6150
+ return jsonResponse({ priorities: [] });
6151
+ }
6152
+ if (url.includes('/api/taskforce/approaches')) {
6153
+ return jsonResponse({ approaches: [] });
6154
+ }
6155
+ if (url.includes('/api/taskforce/specialists')) {
6156
+ return jsonResponse({ specialists: [] });
6157
+ }
6158
+ if (url.includes('/api/taskforce/workflow-templates')) {
6159
+ return jsonResponse({ templates: [] });
6160
+ }
6161
+ if (url.includes('/api/taskforce/workspace/assignee-options')) {
6162
+ return jsonResponse({ assignees: [] });
6163
+ }
6164
+ if (url.includes('/api/taskforce/planning/bootstrap')) {
6165
+ return jsonResponse({
6166
+ initiatives: [],
6167
+ workstreams: [],
6168
+ workstreamTaskSummaries: [],
6169
+ });
6170
+ }
6171
+ return jsonResponse({});
6172
+ });
6173
+ vi.stubGlobal('fetch', fetchMock);
6174
+ render(_jsx(MemoryRouter, { initialEntries: ['/?screen=plans&gate=plan_selection_required'], children: _jsx(TaskforceCore, { config: { cloudAuthBaseUrl: 'https://cloud.example.com' } }) }));
6175
+ expect(await screen.findByRole('heading', { name: 'Subscription Plans' })).toBeInTheDocument();
6176
+ await user.click(screen.getByTitle(/Account/i));
6177
+ await user.click(await screen.findByRole('menuitem', { name: 'Sign Out' }));
6178
+ await waitFor(() => {
6179
+ expect(fetchMock.mock.calls.some((call) => String(call[0]).includes('/api/taskforce/auth/logout'))).toBe(true);
6180
+ expect(screen.getByText('Sign in with your account credentials.')).toBeInTheDocument();
6181
+ });
6182
+ });
6005
6183
  it('uses an explicit cloud sign-out redirect and broader cloud logout reset path', () => {
6006
6184
  const standaloneLayoutSource = fs.readFileSync(path.join(__dirname, 'components/views/StandaloneLayout.tsx'), 'utf8');
6007
6185
  const useTaskforceSource = fs.readFileSync(path.join(__dirname, 'hooks/useTaskforce.ts'), 'utf8');
@@ -0,0 +1,34 @@
1
+ import React from 'react';
2
+ import { type TaskEventValueFormatter } from '../../utils/taskActivity';
3
+ import type { EntityActivityItem, TaskActor } from '../../types';
4
+ export type ActivityActorPresentation = {
5
+ kind: 'member' | 'agent' | 'system';
6
+ label: string;
7
+ color?: string;
8
+ ActorIcon: React.ComponentType<{
9
+ size?: number;
10
+ strokeWidth?: number;
11
+ }>;
12
+ };
13
+ export declare function EntityActivityTimeline({ activity, comments, formatFieldValue, resolveActorPresentation, onOpenTaskById, emptyMessage, listClassName, emptyClassName, endRef, }: {
14
+ activity?: EntityActivityItem[];
15
+ comments?: Array<{
16
+ id: string;
17
+ author: string;
18
+ text: string;
19
+ timestamp: string;
20
+ actor?: TaskActor | null;
21
+ }>;
22
+ formatFieldValue?: TaskEventValueFormatter;
23
+ resolveActorPresentation: (input: {
24
+ actorId?: string | null;
25
+ actorType?: 'human' | 'ai' | 'system' | null;
26
+ actorProfile?: TaskActor | null;
27
+ fallbackKind?: 'member' | 'agent' | 'system';
28
+ }) => ActivityActorPresentation;
29
+ onOpenTaskById?: (taskId: string) => void;
30
+ emptyMessage?: string;
31
+ listClassName?: string;
32
+ emptyClassName?: string;
33
+ endRef?: React.Ref<HTMLDivElement>;
34
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,81 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import { Markdown } from '../ui/Markdown';
4
+ import { formatDate } from '../../utils/formatting';
5
+ import { getEntityActivityItems, getEntityEventPrimaryChangeField, summarizeEntityEvent, summarizeTaskChange, } from '../../utils/taskActivity';
6
+ import timelineStyles from './EntityActivityTimeline.module.css';
7
+ function hexToRgba(hex, opacity) {
8
+ const normalized = hex.replace('#', '').trim();
9
+ if (normalized.length !== 3 && normalized.length !== 6)
10
+ return '';
11
+ const expanded = normalized.length === 3
12
+ ? normalized.split('').map((part) => part + part).join('')
13
+ : normalized;
14
+ const int = Number.parseInt(expanded, 16);
15
+ if (Number.isNaN(int))
16
+ return '';
17
+ const red = (int >> 16) & 255;
18
+ const green = (int >> 8) & 255;
19
+ const blue = int & 255;
20
+ return `rgba(${red}, ${green}, ${blue}, ${opacity})`;
21
+ }
22
+ export function EntityActivityTimeline({ activity, comments, formatFieldValue, resolveActorPresentation, onOpenTaskById, emptyMessage = 'No activity yet.', listClassName, emptyClassName, endRef, }) {
23
+ const items = React.useMemo(() => getEntityActivityItems({ activity, comments }), [activity, comments]);
24
+ return (_jsxs("div", { className: [timelineStyles.thread, listClassName].filter(Boolean).join(' '), children: [items.length === 0 ? (_jsx("div", { className: [timelineStyles.empty, emptyClassName].filter(Boolean).join(' '), children: emptyMessage })) : null, items.map((item) => {
25
+ if (item.type === 'comment') {
26
+ const actorPresentation = resolveActorPresentation({
27
+ actorId: item.comment.author,
28
+ actorType: item.comment.actor?.kind === 'ai'
29
+ ? 'ai'
30
+ : item.comment.actor?.kind === 'human'
31
+ ? 'human'
32
+ : null,
33
+ actorProfile: item.comment.actor || null,
34
+ });
35
+ const commentKind = actorPresentation.kind === 'agent' ? 'agent' : 'member';
36
+ const { ActorIcon } = actorPresentation;
37
+ const authorColor = actorPresentation.color;
38
+ const commentAccentStyle = authorColor && hexToRgba(authorColor, 0.35)
39
+ ? {
40
+ background: `linear-gradient(135deg, ${hexToRgba(authorColor, 0.18)} 0%, ${hexToRgba(authorColor, 0.1)} 100%)`,
41
+ borderColor: hexToRgba(authorColor, 0.35),
42
+ }
43
+ : undefined;
44
+ return (_jsxs("div", { className: [
45
+ timelineStyles.item,
46
+ timelineStyles.comment,
47
+ commentKind === 'agent' ? timelineStyles.commentAgent : timelineStyles.commentMember,
48
+ ].join(' '), children: [_jsxs("div", { className: timelineStyles.header, children: [_jsxs("span", { className: timelineStyles.author, style: authorColor ? { color: authorColor } : undefined, children: [_jsx(ActorIcon, { size: 12, strokeWidth: 1.5 }), actorPresentation.label] }), _jsx("span", { className: timelineStyles.time, children: formatDate(item.comment.timestamp, {
49
+ month: 'short',
50
+ day: 'numeric',
51
+ hour: '2-digit',
52
+ minute: '2-digit',
53
+ }) })] }), _jsx("div", { className: timelineStyles.commentText, style: commentAccentStyle, children: _jsx(Markdown, { onTaskIdClick: onOpenTaskById, children: item.comment.text }) })] }, item.id));
54
+ }
55
+ const actorPresentation = resolveActorPresentation({
56
+ actorId: item.event.actor,
57
+ actorType: item.event.actorType,
58
+ actorProfile: item.event.actorProfile || null,
59
+ fallbackKind: 'system',
60
+ });
61
+ const { ActorIcon } = actorPresentation;
62
+ const authorColor = actorPresentation.color;
63
+ const changeEntries = Object.entries(item.event.details?.changes || {});
64
+ const primaryChangeField = getEntityEventPrimaryChangeField(item.event);
65
+ const displayedChangeEntries = changeEntries.length > 1 && primaryChangeField
66
+ ? changeEntries.filter(([field]) => field !== primaryChangeField)
67
+ : changeEntries.length > 1
68
+ ? changeEntries
69
+ : [];
70
+ return (_jsxs("div", { className: [
71
+ timelineStyles.item,
72
+ timelineStyles.event,
73
+ actorPresentation.kind === 'system' ? timelineStyles.eventSystem : '',
74
+ ].filter(Boolean).join(' '), children: [_jsxs("div", { className: [timelineStyles.header, timelineStyles.eventHeader].join(' '), children: [_jsxs("span", { className: timelineStyles.author, style: authorColor ? { color: authorColor } : undefined, children: [_jsx(ActorIcon, { size: 12, strokeWidth: 1.5 }), actorPresentation.label] }), _jsx("span", { className: timelineStyles.time, children: formatDate(item.event.createdAt, {
75
+ month: 'short',
76
+ day: 'numeric',
77
+ hour: '2-digit',
78
+ minute: '2-digit',
79
+ }) })] }), _jsxs("div", { className: timelineStyles.eventText, children: [_jsx("div", { children: summarizeEntityEvent(item.event, formatFieldValue) }), displayedChangeEntries.length > 0 ? (_jsx("div", { className: timelineStyles.eventChanges, children: displayedChangeEntries.map(([field, change]) => (_jsx("div", { className: timelineStyles.eventChange, children: summarizeTaskChange(field, change, formatFieldValue) }, field))) })) : null] })] }, item.id));
80
+ }), _jsx("div", { ref: endRef })] }));
81
+ }
@@ -299,7 +299,9 @@ export function ContextAttachmentManager(props) {
299
299
  referenceNumber: typeof data.referenceNumber === 'number' ? data.referenceNumber : null,
300
300
  referenceLabel: typeof data.referenceLabel === 'string' ? data.referenceLabel : undefined,
301
301
  taskId: ownerType === 'task' && typeof data.taskId === 'string' ? data.taskId : null,
302
- timestamp: new Date().toISOString()
302
+ timestamp: typeof data.timestamp === 'string' && data.timestamp.trim().length > 0
303
+ ? data.timestamp
304
+ : new Date().toISOString()
303
305
  });
304
306
  dispatchTaskforceContextAssetsMutated({
305
307
  workspaceId: trimmedWorkspaceId || 'default',
@@ -507,7 +509,12 @@ export function ContextAttachmentManager(props) {
507
509
  e.target.style.display = 'none';
508
510
  e.target.parentElement.classList.add(styles.brokenImage);
509
511
  } })) : (_jsxs("button", { type: "button", className: styles.contextFileLink, onClick: () => {
510
- if (dispatchOpenMarkdownDocument(item, fsPath))
512
+ const markdownTarget = ownerType === 'task'
513
+ ? (typeof item === 'string'
514
+ ? { path: item, taskId: trimmedOwnerId }
515
+ : { ...item, taskId: trimmedOwnerId })
516
+ : item;
517
+ if (dispatchOpenMarkdownDocument(markdownTarget, fsPath))
511
518
  return;
512
519
  window.open(path, '_blank');
513
520
  }, title: "Open file", children: [_jsx(FileUp, { size: 16 }), _jsx("span", { children: caption || fsPath || path.split('/').pop() || 'Context file' })] })), _jsxs("div", { className: styles.brokenImagePlaceholder, children: [_jsx(AlertTriangle, { size: 16 }), _jsx("span", { children: "Preview unavailable" })] }), _jsxs("div", { className: styles.attachmentActions, children: [canAnnotate && (_jsx("button", { type: "button", className: styles.attachmentActionBtn, onClick: (e) => {
@@ -537,7 +544,12 @@ export function ContextAttachmentManager(props) {
537
544
  const documentReferenceLabel = typeof item === 'string' ? '' : getDocumentReferenceLabel(item);
538
545
  const isExternalUrl = /^https?:\/\//i.test(path);
539
546
  return (_jsxs("div", { className: styles.documentAttachmentItem, children: [_jsxs("div", { className: styles.documentAttachmentRow, children: [_jsxs("button", { type: "button", className: styles.documentAttachmentLink, onClick: () => {
540
- if (dispatchOpenMarkdownDocument(item, fsPath))
547
+ const markdownTarget = ownerType === 'task'
548
+ ? (typeof item === 'string'
549
+ ? { path: item, taskId: trimmedOwnerId }
550
+ : { ...item, taskId: trimmedOwnerId })
551
+ : item;
552
+ if (dispatchOpenMarkdownDocument(markdownTarget, fsPath))
541
553
  return;
542
554
  window.open(path, '_blank');
543
555
  }, title: displayName, children: [_jsxs("span", { className: styles.documentAttachmentMain, children: [_jsx("span", { className: styles.documentAttachmentIcon, "aria-hidden": "true", children: _jsx(File, { size: 13 }) }), _jsxs("span", { className: styles.documentAttachmentText, children: [_jsx("span", { className: styles.documentAttachmentName, children: displayName }), documentReferenceLabel && (_jsx("span", { className: styles.taskIdBadge, children: documentReferenceLabel }))] })] }), _jsx("span", { className: styles.documentAttachmentType, children: fileType })] }), _jsxs("div", { className: styles.documentAttachmentActions, children: [fsPath && (_jsx("button", { type: "button", className: styles.documentAttachmentActionBtn, onClick: () => {
@@ -1,3 +1,4 @@
1
+ import React from 'react';
1
2
  type AiProfileSeatUsage = {
2
3
  used: number;
3
4
  limit: number | null;
@@ -9,6 +10,9 @@ interface AgentsModuleProps {
9
10
  authSessionResolved?: boolean;
10
11
  isAuthenticated?: boolean;
11
12
  cloudAiProfileSeatUsage?: AiProfileSeatUsage | null;
13
+ agentTrayOpen?: boolean;
14
+ onCloseAgentTray?: () => void;
15
+ mcpSettingsNode?: React.ReactNode;
12
16
  }
13
- export declare function AgentsModule({ workspaceId, cloudAuthConfigured, authSessionResolved, isAuthenticated, cloudAiProfileSeatUsage, }: AgentsModuleProps): import("react/jsx-runtime").JSX.Element;
17
+ export declare function AgentsModule({ workspaceId, cloudAuthConfigured, authSessionResolved, isAuthenticated, cloudAiProfileSeatUsage, agentTrayOpen, onCloseAgentTray, mcpSettingsNode, }: AgentsModuleProps): import("react/jsx-runtime").JSX.Element;
14
18
  export {};