@taskforcehq/taskforce 0.3.305 → 0.3.307

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (440) hide show
  1. package/README.md +0 -2
  2. package/dist/Taskforce.module.css +603 -107
  3. package/dist/TaskforceCore.js +216 -43
  4. package/dist/TaskforceCore.test.js +611 -28
  5. package/dist/assets/fonts/CourierPrime-Bold.woff2 +0 -0
  6. package/dist/assets/fonts/CourierPrime-BoldItalic.woff2 +0 -0
  7. package/dist/assets/fonts/CourierPrime-Italic.woff2 +0 -0
  8. package/dist/assets/fonts/CourierPrime-Regular.woff2 +0 -0
  9. package/dist/assets/fonts/Noir_medium.woff2 +0 -0
  10. package/dist/assets/fonts/Noir_regular.woff2 +0 -0
  11. package/dist/assets/fonts/RussoOne-Regular.woff2 +0 -0
  12. package/dist/assets/fonts/SpecialElite-Regular.woff2 +0 -0
  13. package/dist/compat/workspaceSyncCompat.js +46 -2
  14. package/dist/compat/workspaceSyncCompat.test.js +38 -1
  15. package/dist/components/activity/EntityActivityTimeline.d.ts +34 -0
  16. package/dist/components/activity/EntityActivityTimeline.js +81 -0
  17. package/dist/components/context/ContextAttachmentManager.d.ts +14 -0
  18. package/dist/components/context/ContextAttachmentManager.js +561 -0
  19. package/dist/components/features/AgentsModule.d.ts +14 -1
  20. package/dist/components/features/AgentsModule.js +366 -18
  21. package/dist/components/features/AgentsModule.test.js +507 -8
  22. package/dist/components/features/AnnotatedAttachmentWorkspace.d.ts +3 -1
  23. package/dist/components/features/AnnotatedAttachmentWorkspace.js +118 -4
  24. package/dist/components/features/AnnotatedAttachmentWorkspace.test.js +52 -0
  25. package/dist/components/features/DocumentIndex.d.ts +2 -2
  26. package/dist/components/features/DocumentIndex.js +3 -4
  27. package/dist/components/features/DocumentViewer.d.ts +7 -1
  28. package/dist/components/features/DocumentViewer.js +62 -4
  29. package/dist/components/features/DocumentWorkspace.d.ts +10 -2
  30. package/dist/components/features/DocumentWorkspace.js +15 -4
  31. package/dist/components/features/DocumentWorkspace.test.js +51 -1
  32. package/dist/components/features/TaskSettings.d.ts +2 -0
  33. package/dist/components/features/TaskSettings.js +83 -78
  34. package/dist/components/features/TaskSettings.test.js +171 -82
  35. package/dist/components/features/documentWorkspaceModel.d.ts +1 -1
  36. package/dist/components/task/TaskActionHeader.js +11 -5
  37. package/dist/components/task/TaskActionHeader.test.js +10 -0
  38. package/dist/components/task/TaskCard.js +24 -29
  39. package/dist/components/task/TaskCard.test.js +38 -3
  40. package/dist/components/task/TaskContextUpload.js +4 -526
  41. package/dist/components/task/TaskContextUpload.test.js +3 -3
  42. package/dist/components/task/TaskForm.js +61 -116
  43. package/dist/components/task/TaskForm.test.js +110 -8
  44. package/dist/components/task/TaskKanban.d.ts +2 -1
  45. package/dist/components/task/TaskKanban.js +94 -21
  46. package/dist/components/task/TaskKanban.test.js +36 -0
  47. package/dist/components/task/TaskList.js +5 -1
  48. package/dist/components/task/TaskList.test.js +4 -0
  49. package/dist/components/ui/EditableAvatarButton.d.ts +18 -0
  50. package/dist/components/ui/EditableAvatarButton.js +18 -0
  51. package/dist/components/ui/HierarchyActionBadge.d.ts +10 -0
  52. package/dist/components/ui/HierarchyActionBadge.js +5 -0
  53. package/dist/components/views/AppShellHeader.d.ts +3 -1
  54. package/dist/components/views/AppShellHeader.js +27 -11
  55. package/dist/components/views/AppShellHeader.test.js +18 -1
  56. package/dist/components/views/PlanComparisonPage.d.ts +9 -1
  57. package/dist/components/views/PlanComparisonPage.js +78 -14
  58. package/dist/components/views/PlanComparisonPage.test.js +257 -0
  59. package/dist/components/views/PlansPage.js +127 -36
  60. package/dist/components/views/PlansPage.test.js +294 -12
  61. package/dist/components/views/StandaloneLayout.js +529 -592
  62. package/dist/components/views/WidgetView.js +10 -8
  63. package/dist/components/views/panels/PlanningDrawer.d.ts +25 -5
  64. package/dist/components/views/panels/PlanningDrawer.js +270 -55
  65. package/dist/components/views/panels/PlanningDrawer.test.d.ts +1 -0
  66. package/dist/components/views/panels/PlanningDrawer.test.js +529 -0
  67. package/dist/components/views/planningScope.d.ts +20 -0
  68. package/dist/components/views/planningScope.js +25 -0
  69. package/dist/components/views/planningScope.test.d.ts +1 -0
  70. package/dist/components/views/planningScope.test.js +60 -0
  71. package/dist/components/views/standalone/modals/AccountHubModal.d.ts +26 -1
  72. package/dist/components/views/standalone/modals/AccountHubModal.js +76 -2
  73. package/dist/components/views/standalone/modals/AccountHubModal.test.js +20 -3
  74. package/dist/components/views/standalone/modals/AvatarImageManagerModal.d.ts +20 -0
  75. package/dist/components/views/standalone/modals/AvatarImageManagerModal.js +127 -0
  76. package/dist/components/views/standalone/modals/EditProfileModal.d.ts +2 -9
  77. package/dist/components/views/standalone/modals/EditProfileModal.js +3 -2
  78. package/dist/components/views/standalone/modals/SyncEnableWarningModal.d.ts +9 -0
  79. package/dist/components/views/standalone/modals/SyncEnableWarningModal.js +6 -0
  80. package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.d.ts +1 -0
  81. package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.js +24 -0
  82. package/dist/components/views/standalone/modals/SyncStatusModal.d.ts +2 -1
  83. package/dist/components/views/standalone/modals/SyncStatusModal.js +2 -2
  84. package/dist/config/envSchema.js +1 -0
  85. package/dist/core/AiProfileService.d.ts +46 -2
  86. package/dist/core/AiProfileService.js +1073 -82
  87. package/dist/core/AiProfileService.test.js +19 -1
  88. package/dist/core/AiProfiles.test.js +1249 -44
  89. package/dist/core/AttachmentLinkService.d.ts +3 -0
  90. package/dist/core/AttachmentLinkService.js +110 -23
  91. package/dist/core/AuthIdentityService.d.ts +107 -0
  92. package/dist/core/AuthIdentityService.js +284 -0
  93. package/dist/core/AuthTokenService.d.ts +4 -0
  94. package/dist/core/AuthTokenService.js +34 -6
  95. package/dist/core/AuthTokenService.test.js +3 -3
  96. package/dist/core/EntitlementsPolicy.test.js +2 -2
  97. package/dist/core/GlobalSettingsService.js +127 -6
  98. package/dist/core/McpTokenService.d.ts +12 -0
  99. package/dist/core/McpTokenService.js +44 -1
  100. package/dist/core/PlanEntitlementService.d.ts +23 -2
  101. package/dist/core/PlanEntitlementService.js +343 -57
  102. package/dist/core/PlanFeatureCatalog.test.d.ts +1 -0
  103. package/dist/core/PlanFeatureCatalog.test.js +84 -0
  104. package/dist/core/PlanVersionPolicy.test.js +35 -2
  105. package/dist/core/PlanningEntities.test.js +418 -4
  106. package/dist/core/SignupMonetizationSettings.test.js +199 -27
  107. package/dist/core/SyncReconciliationService.js +2 -65
  108. package/dist/core/SystemAdmin.test.js +42 -42
  109. package/dist/core/TaskActivityService.d.ts +28 -1
  110. package/dist/core/TaskActivityService.js +227 -46
  111. package/dist/core/TaskActivitySync.test.d.ts +1 -0
  112. package/dist/core/TaskActivitySync.test.js +90 -0
  113. package/dist/core/TaskAttachmentsCanonical.test.js +51 -1
  114. package/dist/core/TaskAuditTimeline.test.js +96 -0
  115. package/dist/core/Taskforce.d.ts +415 -40
  116. package/dist/core/Taskforce.ids.test.js +58 -0
  117. package/dist/core/Taskforce.js +1543 -266
  118. package/dist/core/Taskforce.listTasksSlim.test.d.ts +1 -0
  119. package/dist/core/Taskforce.listTasksSlim.test.js +91 -0
  120. package/dist/core/Taskforce.mcpAuth.test.js +109 -0
  121. package/dist/core/UserProfileAvatarDrafts.test.js +30 -3
  122. package/dist/core/WorkspaceLifecycleService.js +0 -5
  123. package/dist/core/WorkspacePermissions.test.js +25 -1
  124. package/dist/core/WorkspacePlanMode.test.js +117 -16
  125. package/dist/core/shared.d.ts +1 -1
  126. package/dist/core/shared.js +5 -1
  127. package/dist/core/types.d.ts +75 -2
  128. package/dist/hooks/auth/useTaskforceAuthBootstrap.js +28 -2
  129. package/dist/hooks/bootstrapTimeouts.d.ts +4 -0
  130. package/dist/hooks/bootstrapTimeouts.js +8 -0
  131. package/dist/hooks/bootstrapTimeouts.test.d.ts +1 -0
  132. package/dist/hooks/bootstrapTimeouts.test.js +12 -0
  133. package/dist/hooks/sync/bootstrap.js +2 -0
  134. package/dist/hooks/sync/controlPlane.d.ts +37 -0
  135. package/dist/hooks/sync/controlPlane.js +78 -0
  136. package/dist/hooks/sync/controlPlane.test.d.ts +1 -0
  137. package/dist/hooks/sync/controlPlane.test.js +121 -0
  138. package/dist/hooks/sync/lifecyclePolicy.d.ts +45 -0
  139. package/dist/hooks/sync/lifecyclePolicy.js +93 -0
  140. package/dist/hooks/sync/lifecyclePolicy.test.d.ts +1 -0
  141. package/dist/hooks/sync/lifecyclePolicy.test.js +124 -0
  142. package/dist/hooks/sync/orchestratorShared.d.ts +13 -4
  143. package/dist/hooks/sync/orchestratorShared.js +129 -48
  144. package/dist/hooks/sync/orchestratorShared.test.js +50 -1
  145. package/dist/hooks/sync/pullLifecycle.d.ts +31 -0
  146. package/dist/hooks/sync/pullLifecycle.js +24 -0
  147. package/dist/hooks/sync/pullLifecycle.test.d.ts +1 -0
  148. package/dist/hooks/sync/pullLifecycle.test.js +80 -0
  149. package/dist/hooks/sync/recovery.d.ts +16 -2
  150. package/dist/hooks/sync/recovery.js +179 -53
  151. package/dist/hooks/sync/recovery.test.d.ts +1 -0
  152. package/dist/hooks/sync/recovery.test.js +292 -0
  153. package/dist/hooks/sync/transfers.d.ts +16 -3
  154. package/dist/hooks/sync/transfers.js +210 -66
  155. package/dist/hooks/sync/transfers.test.d.ts +1 -0
  156. package/dist/hooks/sync/transfers.test.js +928 -0
  157. package/dist/hooks/sync/useRecentSyncEvents.d.ts +21 -0
  158. package/dist/hooks/sync/useRecentSyncEvents.js +92 -0
  159. package/dist/hooks/sync/useRecentSyncEvents.test.d.ts +1 -0
  160. package/dist/hooks/sync/useRecentSyncEvents.test.js +124 -0
  161. package/dist/hooks/sync/useSyncStatusActions.d.ts +30 -0
  162. package/dist/hooks/sync/useSyncStatusActions.js +88 -0
  163. package/dist/hooks/sync/useSyncStatusActions.test.d.ts +1 -0
  164. package/dist/hooks/sync/useSyncStatusActions.test.js +133 -0
  165. package/dist/hooks/sync/useSyncStatusControls.d.ts +25 -0
  166. package/dist/hooks/sync/useSyncStatusControls.js +60 -0
  167. package/dist/hooks/sync/useSyncStatusControls.test.d.ts +1 -0
  168. package/dist/hooks/sync/useSyncStatusControls.test.js +88 -0
  169. package/dist/hooks/useFilterSort.js +13 -13
  170. package/dist/hooks/useFilterSort.test.js +87 -1
  171. package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +12 -0
  172. package/dist/hooks/useSyncOrchestrator.d.ts +9 -2
  173. package/dist/hooks/useSyncOrchestrator.js +409 -183
  174. package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +407 -0
  175. package/dist/hooks/useTaskData.js +8 -3
  176. package/dist/hooks/useTaskData.test.js +45 -0
  177. package/dist/hooks/useTaskforce.d.ts +145 -52
  178. package/dist/hooks/useTaskforce.js +592 -253
  179. package/dist/hooks/useTaskforce.runtime-routing.test.d.ts +1 -0
  180. package/dist/hooks/useTaskforce.runtime-routing.test.js +246 -0
  181. package/dist/hooks/useTaskforce.sync-behavior.test.js +2468 -201
  182. package/dist/hooks/useWorkspaceSyncController.d.ts +1 -0
  183. package/dist/hooks/useWorkspaceSyncController.js +13 -2
  184. package/dist/hooks/useWorkspaceSyncController.test.js +48 -0
  185. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.d.ts +16 -0
  186. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +328 -40
  187. package/dist/localization/locales/en-US.d.ts +0 -1
  188. package/dist/localization/locales/en-US.js +0 -1
  189. package/dist/localization/locales/es-419.js +0 -1
  190. package/dist/localization/locales/pt-BR.js +0 -1
  191. package/dist/mcp/canonicalAssetHelpers.d.ts +16 -4
  192. package/dist/mcp/canonicalAssetHelpers.js +18 -10
  193. package/dist/mcp/canonicalAssetHelpers.test.d.ts +1 -0
  194. package/dist/mcp/canonicalAssetHelpers.test.js +67 -0
  195. package/dist/mcp/clientIntegrations.d.ts +1 -0
  196. package/dist/mcp/clientIntegrations.js +25 -0
  197. package/dist/mcp/clientIntegrations.test.js +14 -3
  198. package/dist/mcp/clientProfileDefaults.js +3 -3
  199. package/dist/mcp/collaborationRegistrar.js +7 -7
  200. package/dist/mcp/documentAssetRegistrar.js +116 -10
  201. package/dist/mcp/runtime.d.ts +3 -0
  202. package/dist/mcp/runtime.js +1099 -185
  203. package/dist/mcp/runtime.test.js +1491 -140
  204. package/dist/mcp/taskAttachmentTypes.d.ts +1 -1
  205. package/dist/mcp/taskPlanningRegistrar.js +48 -0
  206. package/dist/mcp/toolRegistry.d.ts +56 -0
  207. package/dist/mcp/toolRegistry.js +8 -0
  208. package/dist/mcp/toolRegistry.test.js +4 -0
  209. package/dist/migrations/taskSchemaMigrations.d.ts +1 -1
  210. package/dist/migrations/taskSchemaMigrations.js +192 -61
  211. package/dist/migrations/taskSchemaMigrations.test.js +15 -0
  212. package/dist/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
  213. package/dist/resources/templates/workflows/collaborate.yaml +1 -1
  214. package/dist/resources/templates/workflows/evaluate.yaml +2 -2
  215. package/dist/resources/templates/workflows/plan.yaml +1 -1
  216. package/dist/resources/templates/workflows/review.yaml +2 -2
  217. package/dist/server/aiProfileAvatarAssets.d.ts +49 -0
  218. package/dist/server/aiProfileAvatarAssets.js +319 -0
  219. package/dist/server/aiProfileAvatarAssets.test.d.ts +1 -0
  220. package/dist/server/aiProfileAvatarAssets.test.js +213 -0
  221. package/dist/server/annotatedAttachmentsRoutes.test.js +69 -10
  222. package/dist/server/auth/providers/apple.d.ts +33 -0
  223. package/dist/server/auth/providers/apple.js +82 -0
  224. package/dist/server/auth/providers/appleClientSecret.d.ts +37 -0
  225. package/dist/server/auth/providers/appleClientSecret.js +65 -0
  226. package/dist/server/auth/providers/github.d.ts +26 -0
  227. package/dist/server/auth/providers/github.js +86 -0
  228. package/dist/server/auth/providers/google.d.ts +21 -0
  229. package/dist/server/auth/providers/google.js +56 -0
  230. package/dist/server/auth/providers/types.d.ts +21 -0
  231. package/dist/server/auth/providers/types.js +1 -0
  232. package/dist/server/auth.d.ts +2 -0
  233. package/dist/server/auth.js +6 -3
  234. package/dist/server/documentReviewRoutes.test.js +36 -3
  235. package/dist/server/index.cookieProxy.test.js +1 -0
  236. package/dist/server/index.d.ts +12 -0
  237. package/dist/server/index.js +124 -9
  238. package/dist/server/index.rateLimit.test.js +3 -0
  239. package/dist/server/index.test.js +111 -3
  240. package/dist/server/routes/admin.d.ts +3 -0
  241. package/dist/server/routes/admin.js +459 -28
  242. package/dist/server/routes/annotatedAttachments.js +51 -0
  243. package/dist/server/routes/auth.d.ts +26 -2
  244. package/dist/server/routes/auth.js +1170 -71
  245. package/dist/server/routes/authSupport.d.ts +5 -1
  246. package/dist/server/routes/authSupport.js +13 -2
  247. package/dist/server/routes/billing.js +372 -35
  248. package/dist/server/routes/billing.test.js +595 -12
  249. package/dist/server/routes/documents.d.ts +1 -0
  250. package/dist/server/routes/documents.js +182 -70
  251. package/dist/server/routes/shared.d.ts +28 -2
  252. package/dist/server/routes/shared.js +69 -14
  253. package/dist/server/routes/sync.integration.test.js +658 -39
  254. package/dist/server/routes/sync.js +74 -608
  255. package/dist/server/routes/syncAuxRoutes.d.ts +15 -0
  256. package/dist/server/routes/syncAuxRoutes.js +91 -0
  257. package/dist/server/routes/syncAuxRoutes.test.d.ts +1 -0
  258. package/dist/server/routes/syncAuxRoutes.test.js +158 -0
  259. package/dist/server/routes/syncPullApplyRoutes.d.ts +36 -0
  260. package/dist/server/routes/syncPullApplyRoutes.js +204 -0
  261. package/dist/server/routes/syncPushRoutes.d.ts +24 -0
  262. package/dist/server/routes/syncPushRoutes.js +212 -0
  263. package/dist/server/routes/syncRouteGuards.d.ts +36 -0
  264. package/dist/server/routes/syncRouteGuards.js +67 -0
  265. package/dist/server/routes/syncRouteGuards.test.d.ts +1 -0
  266. package/dist/server/routes/syncRouteGuards.test.js +94 -0
  267. package/dist/server/routes/syncRouteTypes.d.ts +13 -0
  268. package/dist/server/routes/syncRouteTypes.js +1 -0
  269. package/dist/server/routes/syncSnapshotRoutes.d.ts +66 -0
  270. package/dist/server/routes/syncSnapshotRoutes.js +182 -0
  271. package/dist/server/routes/tasks.js +55 -10
  272. package/dist/server/routes/workspaces.js +36 -5
  273. package/dist/server/routes.js +147 -11
  274. package/dist/server/routes.test.js +2704 -183
  275. package/dist/services/workflowExportSnapshots.test.js +2 -0
  276. package/dist/shared/aiProfileSeatScope.d.ts +5 -0
  277. package/dist/shared/aiProfileSeatScope.js +21 -0
  278. package/dist/shared/aiProfileSurfaceType.d.ts +1 -1
  279. package/dist/shared/aiProfileSurfaceType.js +10 -8
  280. package/dist/shared/passwordPolicy.d.ts +13 -0
  281. package/dist/shared/passwordPolicy.js +84 -0
  282. package/dist/shared/passwordPolicy.test.d.ts +1 -0
  283. package/dist/shared/passwordPolicy.test.js +34 -0
  284. package/dist/storage/objectStorage.d.ts +1 -0
  285. package/dist/storage/objectStorage.js +2 -1
  286. package/dist/storage/objectStorageClient.d.ts +1 -0
  287. package/dist/storage/objectStorageClient.js +41 -8
  288. package/dist/storage/objectStorageClient.test.js +26 -1
  289. package/dist/storage/objectStorageConfig.js +3 -1
  290. package/dist/storage/objectStorageConfig.test.js +13 -1
  291. package/dist/storage/workspaceAssetStore.d.ts +15 -3
  292. package/dist/storage/workspaceAssetStore.js +132 -44
  293. package/dist/storage/workspaceAssetStore.test.js +93 -6
  294. package/dist/styles/fonts.css +70 -0
  295. package/dist/sync/collaborationSyncPayload.d.ts +6 -1
  296. package/dist/sync/collaborationSyncPayload.js +19 -11
  297. package/dist/sync/collaborationSyncPayload.test.js +14 -1
  298. package/dist/sync/collaborationSyncState.d.ts +3 -3
  299. package/dist/sync/collaborationSyncState.js +19 -12
  300. package/dist/sync/contentSyncPayload.d.ts +5 -1
  301. package/dist/sync/contentSyncPayload.js +9 -0
  302. package/dist/sync/contentSyncPayload.test.js +39 -0
  303. package/dist/sync/contentSyncState.d.ts +9 -9
  304. package/dist/sync/contentSyncState.js +248 -107
  305. package/dist/sync/planningSyncPayload.js +5 -0
  306. package/dist/sync/planningSyncPayload.test.js +24 -0
  307. package/dist/sync/syncApplyHandlers.d.ts +11 -4
  308. package/dist/sync/syncApplyHandlers.js +115 -42
  309. package/dist/sync/syncApplyHandlers.test.js +251 -4
  310. package/dist/sync/syncFieldSemantics.d.ts +12 -0
  311. package/dist/sync/syncFieldSemantics.js +55 -0
  312. package/dist/sync/syncResourceAdapters.d.ts +46 -0
  313. package/dist/sync/syncResourceAdapters.js +79 -0
  314. package/dist/sync/syncService.d.ts +6 -0
  315. package/dist/sync/syncService.js +65 -1
  316. package/dist/sync/syncService.test.js +96 -3
  317. package/dist/sync/taskSyncChangeKey.d.ts +2 -0
  318. package/dist/sync/taskSyncChangeKey.js +143 -0
  319. package/dist/sync/taskSyncPayload.js +3 -8
  320. package/dist/sync/workspacePullFeed.d.ts +4 -0
  321. package/dist/sync/workspacePullFeed.js +132 -72
  322. package/dist/sync/workspacePullFeed.test.js +92 -0
  323. package/dist/sync/workspaceRepair.js +5 -2
  324. package/dist/sync/workspaceSyncModel.d.ts +73 -6
  325. package/dist/sync/workspaceSyncModel.js +342 -73
  326. package/dist/sync/workspaceSyncModel.test.js +559 -14
  327. package/dist/sync/workspaceSyncState.d.ts +17 -0
  328. package/dist/sync/workspaceSyncState.js +2 -1
  329. package/dist/sync/workspaceSyncSurface.js +3 -8
  330. package/dist/types.d.ts +50 -2
  331. package/dist/ui/assets/AgentsModule-2y82_3DO.js +1 -0
  332. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BTLZZCiQ.js +3 -0
  333. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BVKew-mH.css +1 -0
  334. package/dist/ui/assets/ContextAttachmentManager-D2epuNnG.js +3 -0
  335. package/dist/ui/assets/CourierPrime-Bold-BuLj_dpw.woff2 +0 -0
  336. package/dist/ui/assets/CourierPrime-BoldItalic-BrK2pUkZ.woff2 +0 -0
  337. package/dist/ui/assets/CourierPrime-Italic-DFUZK5Ey.woff2 +0 -0
  338. package/dist/ui/assets/CourierPrime-Regular-BsKphzVf.woff2 +0 -0
  339. package/dist/ui/assets/DocumentWorkspace-D4rJKXzd.css +1 -0
  340. package/dist/ui/assets/DocumentWorkspace-sVa-3Do6.js +252 -0
  341. package/dist/ui/assets/EntityActivityTimeline-DyqvvhuF.css +1 -0
  342. package/dist/ui/assets/EntityActivityTimeline-Zods27y_.js +1 -0
  343. package/dist/ui/assets/{InitiativesModule-Dhm7M8e7.js → InitiativesModule-D4XseTwW.js} +1 -1
  344. package/dist/ui/assets/Noir_medium-bxQwKGzB.woff2 +0 -0
  345. package/dist/ui/assets/Noir_regular-ojf2kxlG.woff2 +0 -0
  346. package/dist/ui/assets/PlansPage-D5AcbO0L.js +1 -0
  347. package/dist/ui/assets/PlansPage-Dvqsz5zc.css +1 -0
  348. package/dist/ui/assets/RussoOne-Regular-Cu_qq_qC.woff2 +0 -0
  349. package/dist/ui/assets/SpecialElite-Regular-Di6gSvAS.woff2 +0 -0
  350. package/dist/ui/assets/TaskContextUpload-uC5qx4Bv.js +1 -0
  351. package/dist/ui/assets/TaskSettings-CqvPAsTv.js +9 -0
  352. package/dist/ui/assets/{WorkflowsModule-BcS4afRn.js → WorkflowsModule-oOA9bcdK.js} +4 -4
  353. package/dist/ui/assets/documentReferences-DPZuTgHh.js +1 -0
  354. package/dist/ui/assets/index-607WPo_X.js +4 -0
  355. package/dist/ui/assets/index-CYyodXsg.css +1 -0
  356. package/dist/ui/assets/{vendor-icons-BSUaRwF8.js → vendor-icons-B32hGuF2.js} +1 -1
  357. package/dist/ui/fonts/CourierPrime-Bold.ttf +0 -0
  358. package/dist/ui/fonts/CourierPrime-Bold.woff2 +0 -0
  359. package/dist/ui/fonts/CourierPrime-BoldItalic.ttf +0 -0
  360. package/dist/ui/fonts/CourierPrime-BoldItalic.woff2 +0 -0
  361. package/dist/ui/fonts/CourierPrime-Italic.ttf +0 -0
  362. package/dist/ui/fonts/CourierPrime-Italic.woff2 +0 -0
  363. package/dist/ui/fonts/CourierPrime-Regular.ttf +0 -0
  364. package/dist/ui/fonts/CourierPrime-Regular.woff2 +0 -0
  365. package/dist/ui/fonts/Noir_medium.otf +0 -0
  366. package/dist/ui/fonts/Noir_medium.woff2 +0 -0
  367. package/dist/ui/fonts/Noir_regular.otf +0 -0
  368. package/dist/ui/fonts/Noir_regular.woff2 +0 -0
  369. package/dist/ui/fonts/RussoOne-Regular.woff2 +0 -0
  370. package/dist/ui/fonts/SpecialElite-Regular.ttf +0 -0
  371. package/dist/ui/fonts/SpecialElite-Regular.woff2 +0 -0
  372. package/dist/ui/index.html +3 -3
  373. package/dist/ui/product/agent manager.png +0 -0
  374. package/dist/ui/product/agent_manager_02.png +0 -0
  375. package/dist/utils/accountProfileSummaryCache.d.ts +5 -0
  376. package/dist/utils/aiProfileEvents.d.ts +7 -0
  377. package/dist/utils/aiProfileEvents.js +6 -0
  378. package/dist/utils/assignees.d.ts +8 -0
  379. package/dist/utils/assignees.js +10 -1
  380. package/dist/utils/assignees.test.d.ts +1 -0
  381. package/dist/utils/assignees.test.js +25 -0
  382. package/dist/utils/avatarDisplay.d.ts +1 -0
  383. package/dist/utils/avatarDisplay.js +15 -0
  384. package/dist/utils/avatarUpload.d.ts +27 -0
  385. package/dist/utils/avatarUpload.js +132 -0
  386. package/dist/utils/avatarUpload.test.d.ts +1 -0
  387. package/dist/utils/avatarUpload.test.js +40 -0
  388. package/dist/utils/bootstrapTrace.d.ts +7 -0
  389. package/dist/utils/bootstrapTrace.js +29 -0
  390. package/dist/utils/commercialLifecyclePresentation.js +3 -0
  391. package/dist/utils/contextAssetEvents.d.ts +2 -0
  392. package/dist/utils/contextFiles.d.ts +3 -1
  393. package/dist/utils/contextFiles.js +2 -1
  394. package/dist/utils/syncEventDetails.d.ts +3 -0
  395. package/dist/utils/syncEventDetails.js +64 -0
  396. package/dist/utils/syncEventDetails.test.d.ts +1 -0
  397. package/dist/utils/syncEventDetails.test.js +23 -0
  398. package/dist/utils/syncEventPresentation.d.ts +15 -0
  399. package/dist/utils/syncEventPresentation.js +129 -0
  400. package/dist/utils/syncEventPresentation.test.d.ts +1 -0
  401. package/dist/utils/syncEventPresentation.test.js +64 -0
  402. package/dist/utils/syncStatusPresentation.d.ts +72 -0
  403. package/dist/utils/syncStatusPresentation.js +217 -0
  404. package/dist/utils/syncStatusPresentation.test.d.ts +1 -0
  405. package/dist/utils/syncStatusPresentation.test.js +164 -0
  406. package/dist/utils/taskActivity.d.ts +9 -1
  407. package/dist/utils/taskActivity.js +290 -22
  408. package/dist/utils/taskActivity.test.js +141 -8
  409. package/dist/utils/taskSearch.d.ts +22 -0
  410. package/dist/utils/taskSearch.js +87 -0
  411. package/dist/utils/taskSearch.test.d.ts +1 -0
  412. package/dist/utils/taskSearch.test.js +69 -0
  413. package/dist/utils/taskUtils.js +10 -3
  414. package/dist/utils/taskUtils.test.d.ts +1 -0
  415. package/dist/utils/taskUtils.test.js +19 -0
  416. package/dist/utils/workspaceSyncPresentation.d.ts +4 -0
  417. package/dist/utils/workspaceSyncPresentation.js +68 -2
  418. package/dist/utils/workspaceSyncPresentation.test.js +36 -1
  419. package/package.json +3 -2
  420. package/scripts/export-sqlite-to-postgres.mjs +7 -9
  421. package/scripts/run-e2e-realtime.sh +17 -3
  422. package/scripts/run-smoke.sh +17 -5
  423. package/scripts/run-soak.sh +17 -5
  424. package/src/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
  425. package/src/resources/templates/workflows/collaborate.yaml +1 -1
  426. package/src/resources/templates/workflows/evaluate.yaml +2 -2
  427. package/src/resources/templates/workflows/plan.yaml +1 -1
  428. package/src/resources/templates/workflows/review.yaml +2 -2
  429. package/dist/ui/assets/AgentsModule-N2MnQBZk.js +0 -1
  430. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BG6P_GVW.js +0 -3
  431. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BaS2VwIr.css +0 -1
  432. package/dist/ui/assets/DocumentWorkspace-B3nV_Gc5.css +0 -1
  433. package/dist/ui/assets/DocumentWorkspace-DRbDMwh8.js +0 -252
  434. package/dist/ui/assets/PlansPage-C2dd2n1X.css +0 -1
  435. package/dist/ui/assets/PlansPage-Cq0zXj3I.js +0 -1
  436. package/dist/ui/assets/RussoOne-Regular-C3BxZIj7.ttf +0 -0
  437. package/dist/ui/assets/TaskSettings-ln0aF7xc.js +0 -9
  438. package/dist/ui/assets/index-C2-OXZV7.css +0 -1
  439. package/dist/ui/assets/index-DcSI5F86.js +0 -6
  440. package/scripts/migrate-planning-model.ts +0 -233
@@ -5,11 +5,18 @@ import { AgentsModule } from './AgentsModule';
5
5
  describe('AgentsModule', () => {
6
6
  afterEach(() => {
7
7
  vi.restoreAllMocks();
8
+ vi.unstubAllGlobals();
8
9
  });
9
10
  it('groups registered AI profiles by surface type in a stable section order', async () => {
10
- const fetchMock = vi.fn().mockResolvedValue({
11
+ const fetchMock = vi.fn()
12
+ .mockResolvedValueOnce({
11
13
  ok: true,
12
14
  json: async () => ({
15
+ aiProfileSeatUsage: {
16
+ used: 2,
17
+ limit: null,
18
+ remaining: null
19
+ },
13
20
  assignees: [
14
21
  { value: 'member-1', label: 'Member One', kind: 'member' },
15
22
  {
@@ -20,6 +27,7 @@ describe('AgentsModule', () => {
20
27
  color: '#10a37f',
21
28
  kind: 'agent',
22
29
  surfaceType: 'chat_app',
30
+ seatScope: 'cloud_metered',
23
31
  description: 'General-purpose chat surface for planning and writing.',
24
32
  role: 'Product copilot',
25
33
  provider: 'OpenAI',
@@ -36,6 +44,7 @@ describe('AgentsModule', () => {
36
44
  color: '#0ea5e9',
37
45
  kind: 'agent',
38
46
  surfaceType: 'coding_tool',
47
+ seatScope: 'local_unmetered',
39
48
  description: 'Terminal-first coding agent.',
40
49
  role: 'Implementation partner',
41
50
  provider: 'OpenAI',
@@ -52,6 +61,7 @@ describe('AgentsModule', () => {
52
61
  color: '#0ea5e9',
53
62
  kind: 'agent',
54
63
  surfaceType: 'coding_tool',
64
+ seatScope: 'local_unmetered',
55
65
  description: 'Duplicate Codex profile.',
56
66
  role: 'Implementation partner',
57
67
  provider: 'OpenAI',
@@ -68,6 +78,7 @@ describe('AgentsModule', () => {
68
78
  color: '#64748b',
69
79
  kind: 'agent',
70
80
  surfaceType: null,
81
+ seatScope: 'cloud_metered',
71
82
  createdAt: '2026-03-28T08:00:00.000Z',
72
83
  updatedAt: '2026-04-01T08:00:00.000Z',
73
84
  lastActiveAt: null
@@ -76,27 +87,515 @@ describe('AgentsModule', () => {
76
87
  })
77
88
  });
78
89
  vi.stubGlobal('fetch', fetchMock);
79
- const { container } = render(_jsx(AgentsModule, { workspaceId: "workspace-1" }));
90
+ const { container } = render(_jsx(AgentsModule, { workspaceId: "workspace-1", cloudAuthConfigured: true, authSessionResolved: true, isAuthenticated: true, cloudAiProfileSeatUsage: { used: 2, limit: 5, remaining: 3 } }));
80
91
  await waitFor(() => expect(fetchMock).toHaveBeenCalledTimes(1));
81
92
  expect((await screen.findAllByText('Chat Apps')).length).toBeGreaterThan(0);
82
93
  expect(screen.getAllByText('Coding Tools').length).toBeGreaterThan(0);
83
- expect(screen.getByText('Unclassified')).toBeInTheDocument();
94
+ expect(screen.getAllByText('Unclassified').length).toBeGreaterThan(0);
84
95
  expect(screen.getAllByText('Codex')).toHaveLength(1);
85
- expect(screen.getByText(/2 duplicates/i)).toBeInTheDocument();
86
- expect(screen.getByText('Coding tool')).toBeInTheDocument();
96
+ expect(screen.getByText(/1 duplicate/i)).toBeInTheDocument();
97
+ expect(screen.getAllByTitle('Cloud MCP').length).toBeGreaterThan(0);
98
+ expect(screen.getAllByTitle('Local MCP').length).toBeGreaterThan(0);
99
+ expect(screen.getByText('Registered Cloud Agents: 2/5')).toBeInTheDocument();
87
100
  expect(screen.getAllByText('General-purpose chat surface for planning and writing.').length).toBeGreaterThan(0);
88
101
  expect(screen.getAllByText('Product copilot').length).toBeGreaterThan(0);
89
- expect(screen.getByText('OpenAI · gpt-5.4')).toBeInTheDocument();
90
- expect(screen.getByText(/Profile instances/i)).toBeInTheDocument();
102
+ expect(screen.getAllByText('OpenAI').length).toBeGreaterThan(0);
103
+ expect(screen.getAllByText('gpt-5.4').length).toBeGreaterThan(0);
104
+ expect(screen.queryByText(/Profile instances/i)).not.toBeInTheDocument();
105
+ expect(screen.queryByText(/Choose a keeper here if duplicates need to be merged/i)).not.toBeInTheDocument();
91
106
  const text = container.textContent || '';
92
107
  expect(text.indexOf('Chat Apps')).toBeLessThan(text.indexOf('Coding Tools'));
93
108
  expect(text.indexOf('Coding Tools')).toBeLessThan(text.indexOf('Unclassified'));
94
109
  fireEvent.click(screen.getByRole('button', { name: /codex/i }));
110
+ expect(screen.getByText('Coding Tool')).toBeInTheDocument();
95
111
  expect(screen.getAllByText('Terminal-first coding agent.').length).toBeGreaterThan(0);
96
112
  expect(screen.getAllByText('Implementation partner')[0]).toBeInTheDocument();
97
- expect(screen.getByText('OpenAI · gpt-5-codex')).toBeInTheDocument();
113
+ expect(screen.getAllByText('OpenAI').length).toBeGreaterThan(0);
114
+ expect(screen.getAllByText('gpt-5-codex').length).toBeGreaterThan(0);
98
115
  expect(screen.getByText(/2 linked/i)).toBeInTheDocument();
116
+ expect(screen.getByText(/Profile instances/i)).toBeInTheDocument();
117
+ expect(screen.getByText(/Choose a keeper here if duplicates need to be merged/i)).toBeInTheDocument();
99
118
  expect(screen.getAllByTitle('Keep this profile, merge others into it')).toHaveLength(2);
100
119
  expect(screen.getByText('@codex-duplicate')).toBeInTheDocument();
120
+ expect(screen.getAllByTitle('Cloud MCP').length).toBeGreaterThan(0);
121
+ expect(screen.getAllByTitle('Local MCP').length).toBeGreaterThan(0);
122
+ });
123
+ it('does not mark local and cloud profiles with the same name as duplicates', async () => {
124
+ const fetchMock = vi.fn()
125
+ .mockResolvedValueOnce({
126
+ ok: true,
127
+ json: async () => ({
128
+ aiProfileSeatUsage: {
129
+ used: 1,
130
+ limit: null,
131
+ remaining: null
132
+ },
133
+ assignees: [
134
+ {
135
+ value: 'ai-codex-local',
136
+ label: 'Codex',
137
+ username: 'codex',
138
+ icon: 'Bot',
139
+ color: '#0ea5e9',
140
+ kind: 'agent',
141
+ surfaceType: 'cli',
142
+ seatScope: 'local_unmetered',
143
+ description: 'Terminal-first coding agent.',
144
+ role: 'Coding Agent',
145
+ provider: 'OpenAI',
146
+ model: 'Codex',
147
+ createdAt: '2026-04-02T09:00:00.000Z',
148
+ updatedAt: '2026-04-04T13:15:00.000Z',
149
+ lastActiveAt: '2026-04-04T13:45:00.000Z'
150
+ },
151
+ {
152
+ value: 'ai-codex-cloud',
153
+ label: 'Codex',
154
+ username: 'codex',
155
+ icon: 'Bot',
156
+ color: '#0ea5e9',
157
+ kind: 'agent',
158
+ surfaceType: 'cli',
159
+ seatScope: 'cloud_metered',
160
+ description: 'Cloud MCP coding profile.',
161
+ role: 'Coding Agent',
162
+ provider: 'OpenAI',
163
+ model: 'Codex',
164
+ createdAt: '2026-04-02T10:00:00.000Z',
165
+ updatedAt: '2026-04-04T13:16:00.000Z',
166
+ lastActiveAt: '2026-04-04T13:46:00.000Z'
167
+ }
168
+ ]
169
+ })
170
+ });
171
+ vi.stubGlobal('fetch', fetchMock);
172
+ render(_jsx(AgentsModule, { workspaceId: "workspace-1", cloudAuthConfigured: true, authSessionResolved: true, isAuthenticated: true, cloudAiProfileSeatUsage: { used: 1, limit: 5, remaining: 4 } }));
173
+ await waitFor(() => expect(fetchMock).toHaveBeenCalledTimes(1));
174
+ expect(screen.getAllByRole('button', { name: /codex/i })).toHaveLength(2);
175
+ expect(screen.queryByText(/\d+ duplicate/i)).not.toBeInTheDocument();
176
+ expect(screen.queryByText(/Profile instances/i)).not.toBeInTheDocument();
177
+ expect(screen.getAllByTitle('Cloud MCP').length).toBeGreaterThan(0);
178
+ expect(screen.getAllByTitle('Local MCP').length).toBeGreaterThan(0);
179
+ });
180
+ it('keeps a duplicate group avatar visible when the newest duplicate has no photo', async () => {
181
+ const avatarUrl = '/api/taskforce/context/workspaces%2Fworkspace-1%2Fassets%2Fimages%2Fai-profiles%2Fai-codex-old%2Favatar%2Fcropped.webp';
182
+ const fetchMock = vi.fn()
183
+ .mockResolvedValueOnce({
184
+ ok: true,
185
+ json: async () => ({
186
+ aiProfileSeatUsage: {
187
+ used: 2,
188
+ limit: null,
189
+ remaining: null
190
+ },
191
+ assignees: [
192
+ {
193
+ value: 'ai-codex-new',
194
+ label: 'Codex',
195
+ username: 'codex-new',
196
+ icon: 'Bot',
197
+ color: '#0ea5e9',
198
+ kind: 'agent',
199
+ surfaceType: 'coding_tool',
200
+ seatScope: 'local_unmetered',
201
+ createdAt: '2026-04-02T10:00:00.000Z',
202
+ updatedAt: '2026-04-04T16:00:00.000Z',
203
+ lastActiveAt: '2026-04-04T16:30:00.000Z',
204
+ avatarUrl: null,
205
+ avatarSourceUrl: null
206
+ },
207
+ {
208
+ value: 'ai-codex-old',
209
+ label: 'Codex',
210
+ username: 'codex-old',
211
+ icon: 'Bot',
212
+ color: '#0ea5e9',
213
+ kind: 'agent',
214
+ surfaceType: 'coding_tool',
215
+ seatScope: 'local_unmetered',
216
+ createdAt: '2026-04-02T09:00:00.000Z',
217
+ updatedAt: '2026-04-04T13:15:00.000Z',
218
+ lastActiveAt: '2026-04-04T13:45:00.000Z',
219
+ avatarUrl,
220
+ avatarSourceUrl: avatarUrl
221
+ }
222
+ ]
223
+ })
224
+ });
225
+ vi.stubGlobal('fetch', fetchMock);
226
+ render(_jsx(AgentsModule, { workspaceId: "workspace-1", cloudAuthConfigured: true, authSessionResolved: true, isAuthenticated: true, cloudAiProfileSeatUsage: { used: 2, limit: 5, remaining: 3 } }));
227
+ const codexButton = await screen.findByRole('button', { name: /codex/i });
228
+ expect(codexButton.querySelector('img')).toHaveAttribute('src', avatarUrl);
229
+ expect(screen.getByLabelText('Edit AI profile photo').querySelector('img')).toHaveAttribute('src', avatarUrl);
230
+ });
231
+ it('uploads AI profile avatars through the stable avatar endpoint', async () => {
232
+ const avatarUrl = '/api/taskforce/context/workspaces%2Fworkspace-1%2Fassets%2Fimages%2Fai-profiles%2Fai-codex%2Favatar%2Fdisplay.gif';
233
+ const fetchMock = vi.fn(async (input, init) => {
234
+ const url = String(input);
235
+ if (url.startsWith('/api/taskforce/workspace/assignee-options')) {
236
+ return {
237
+ ok: true,
238
+ json: async () => ({
239
+ aiProfileSeatUsage: {
240
+ used: 1,
241
+ limit: null,
242
+ remaining: null
243
+ },
244
+ assignees: [
245
+ {
246
+ value: 'ai-codex',
247
+ label: 'Codex',
248
+ username: 'codex',
249
+ icon: 'Bot',
250
+ color: '#0ea5e9',
251
+ kind: 'agent',
252
+ surfaceType: 'coding_tool',
253
+ seatScope: 'cloud_metered',
254
+ createdAt: '2026-04-02T09:00:00.000Z',
255
+ updatedAt: '2026-04-04T13:15:00.000Z',
256
+ lastActiveAt: '2026-04-04T13:45:00.000Z',
257
+ avatarUrl: null,
258
+ avatarSourceUrl: null
259
+ }
260
+ ]
261
+ })
262
+ };
263
+ }
264
+ if (url === '/api/taskforce/workspace/ai-profiles/avatar/upload') {
265
+ return {
266
+ ok: true,
267
+ json: async () => ({
268
+ profile: {
269
+ id: 'ai-codex',
270
+ avatarUrl,
271
+ avatarSourceUrl: '/api/taskforce/context/workspaces%2Fworkspace-1%2Fassets%2Fimages%2Fai-profiles%2Fai-codex%2Favatar%2Fsource.gif',
272
+ avatarRevision: 1,
273
+ avatarUpdatedAt: '2026-04-28T00:00:00.000Z'
274
+ }
275
+ })
276
+ };
277
+ }
278
+ throw new Error(`Unexpected fetch ${url}: ${String(init?.body || '')}`);
279
+ });
280
+ vi.stubGlobal('fetch', fetchMock);
281
+ vi.stubGlobal('URL', {
282
+ ...URL,
283
+ createObjectURL: vi.fn(() => 'blob:avatar-preview'),
284
+ revokeObjectURL: vi.fn()
285
+ });
286
+ render(_jsx(AgentsModule, { workspaceId: "workspace-1", cloudAuthConfigured: true, authSessionResolved: true, isAuthenticated: true, cloudAiProfileSeatUsage: { used: 1, limit: 5, remaining: 4 } }));
287
+ fireEvent.click(await screen.findByLabelText('Edit AI profile photo'));
288
+ const input = await screen.findByLabelText('Choose profile photo');
289
+ const file = new File(['avatar'], 'avatar.gif', { type: 'image/gif' });
290
+ fireEvent.change(input, { target: { files: [file] } });
291
+ fireEvent.click(screen.getByRole('button', { name: 'Apply Photo' }));
292
+ await waitFor(() => {
293
+ expect(fetchMock).toHaveBeenCalledWith('/api/taskforce/workspace/ai-profiles/avatar/upload', expect.objectContaining({ method: 'POST' }));
294
+ });
295
+ const uploadBody = JSON.parse(String(fetchMock.mock.calls.find((call) => call[0] === '/api/taskforce/workspace/ai-profiles/avatar/upload')?.[1]?.body || '{}'));
296
+ expect(uploadBody).toEqual(expect.objectContaining({
297
+ profileId: 'ai-codex',
298
+ displayImage: expect.objectContaining({
299
+ mimeType: 'image/gif',
300
+ originalName: 'avatar.gif'
301
+ })
302
+ }));
303
+ expect(String(uploadBody.displayImage.dataUrl)).toMatch(new RegExp('^data:image/gif;base64,'));
304
+ expect(fetchMock.mock.calls.some((call) => call[0] === '/api/taskforce/context-upload/init')).toBe(false);
305
+ expect(fetchMock.mock.calls.some((call) => call[0] === '/api/taskforce/context-upload/finalize')).toBe(false);
306
+ expect(fetchMock.mock.calls.some((call) => call[0] === '/api/taskforce/context-upload' && String(call[1]?.method || '').toUpperCase() === 'POST')).toBe(false);
307
+ });
308
+ it('removes a profile from the active roster and reloads the list', async () => {
309
+ const confirmMock = vi.fn().mockReturnValue(true);
310
+ const fetchMock = vi.fn()
311
+ .mockResolvedValueOnce({
312
+ ok: true,
313
+ json: async () => ({
314
+ aiProfileSeatUsage: {
315
+ used: 1,
316
+ limit: null,
317
+ remaining: null
318
+ },
319
+ assignees: [
320
+ {
321
+ value: 'ai-codex',
322
+ label: 'Codex',
323
+ username: 'codex',
324
+ icon: 'Bot',
325
+ color: '#0ea5e9',
326
+ kind: 'agent',
327
+ surfaceType: 'coding_tool',
328
+ description: 'Terminal-first coding agent.',
329
+ role: 'Implementation partner',
330
+ provider: 'OpenAI',
331
+ model: 'gpt-5-codex',
332
+ createdAt: '2026-04-02T09:00:00.000Z',
333
+ updatedAt: '2026-04-04T13:15:00.000Z',
334
+ lastActiveAt: '2026-04-04T13:45:00.000Z'
335
+ }
336
+ ]
337
+ })
338
+ })
339
+ .mockResolvedValueOnce({
340
+ ok: true,
341
+ json: async () => ({
342
+ profile: {
343
+ id: 'ai-codex',
344
+ archivedReason: 'manual_archive'
345
+ }
346
+ })
347
+ })
348
+ .mockResolvedValueOnce({
349
+ ok: true,
350
+ json: async () => ({
351
+ aiProfileSeatUsage: {
352
+ used: 0,
353
+ limit: null,
354
+ remaining: null
355
+ },
356
+ assignees: []
357
+ })
358
+ });
359
+ vi.stubGlobal('fetch', fetchMock);
360
+ vi.stubGlobal('confirm', confirmMock);
361
+ render(_jsx(AgentsModule, { workspaceId: "workspace-1", cloudAuthConfigured: true, authSessionResolved: true, isAuthenticated: true, cloudAiProfileSeatUsage: { used: 1, limit: 3, remaining: 2 } }));
362
+ expect(await screen.findByRole('button', { name: /codex/i })).toBeInTheDocument();
363
+ fireEvent.change(screen.getByLabelText('Agent roster status'), { target: { value: 'retire' } });
364
+ await waitFor(() => expect(confirmMock).toHaveBeenCalledTimes(1));
365
+ expect(fetchMock).toHaveBeenNthCalledWith(2, '/api/taskforce/workspace/ai-profiles/archive', expect.objectContaining({
366
+ method: 'POST',
367
+ credentials: 'include'
368
+ }));
369
+ expect(fetchMock).toHaveBeenNthCalledWith(3, '/api/taskforce/workspace/assignee-options?workspaceId=workspace-1&kind=agent', expect.objectContaining({
370
+ credentials: 'include'
371
+ }));
372
+ expect(await screen.findByText('AI profile removed from active roster.')).toBeInTheDocument();
373
+ expect(await screen.findByText('No AI profiles registered yet.')).toBeInTheDocument();
374
+ });
375
+ it('updates an AI profile category from the detail dropdown', async () => {
376
+ const fetchMock = vi.fn(async (input, init) => {
377
+ const url = String(input);
378
+ if (url.startsWith('/api/taskforce/workspace/assignee-options')) {
379
+ return {
380
+ ok: true,
381
+ json: async () => ({
382
+ aiProfileSeatUsage: {
383
+ used: 1,
384
+ limit: null,
385
+ remaining: null
386
+ },
387
+ assignees: [
388
+ {
389
+ value: 'ai-chatgpt',
390
+ label: 'ChatGPT',
391
+ username: 'chatgpt',
392
+ icon: 'Bot',
393
+ color: '#10a37f',
394
+ kind: 'agent',
395
+ surfaceType: 'chat_app',
396
+ seatScope: 'cloud_metered',
397
+ provider: 'OpenAI',
398
+ model: 'GPT-5',
399
+ createdAt: '2026-04-02T09:00:00.000Z',
400
+ updatedAt: '2026-04-04T13:15:00.000Z',
401
+ lastActiveAt: '2026-04-04T13:45:00.000Z'
402
+ }
403
+ ]
404
+ })
405
+ };
406
+ }
407
+ if (url === '/api/taskforce/workspace/ai-profiles/surface-type') {
408
+ return {
409
+ ok: true,
410
+ json: async () => ({
411
+ profile: {
412
+ id: 'ai-chatgpt',
413
+ surfaceType: 'cli',
414
+ updatedAt: '2026-04-28T00:00:00.000Z'
415
+ }
416
+ })
417
+ };
418
+ }
419
+ throw new Error(`Unexpected fetch ${url}: ${String(init?.body || '')}`);
420
+ });
421
+ vi.stubGlobal('fetch', fetchMock);
422
+ render(_jsx(AgentsModule, { workspaceId: "workspace-1", cloudAuthConfigured: true, authSessionResolved: true, isAuthenticated: true, cloudAiProfileSeatUsage: { used: 1, limit: 3, remaining: 2 } }));
423
+ const categorySelect = await screen.findByLabelText('Agent category');
424
+ fireEvent.change(categorySelect, { target: { value: 'cli' } });
425
+ await waitFor(() => {
426
+ expect(fetchMock).toHaveBeenCalledWith('/api/taskforce/workspace/ai-profiles/surface-type', expect.objectContaining({
427
+ method: 'POST',
428
+ credentials: 'include',
429
+ body: JSON.stringify({
430
+ profileId: 'ai-chatgpt',
431
+ surfaceType: 'cli'
432
+ })
433
+ }));
434
+ });
435
+ expect(await screen.findByText('AI profile category updated.')).toBeInTheDocument();
436
+ expect(screen.getByLabelText('Agent category').value).toBe('cli');
437
+ expect(screen.getAllByText('CLI').length).toBeGreaterThan(0);
438
+ });
439
+ it('shows archive permission errors inline near the roster status control', async () => {
440
+ const confirmMock = vi.fn().mockReturnValue(true);
441
+ const fetchMock = vi.fn()
442
+ .mockResolvedValueOnce({
443
+ ok: true,
444
+ json: async () => ({
445
+ aiProfileSeatUsage: {
446
+ used: 1,
447
+ limit: null,
448
+ remaining: null
449
+ },
450
+ assignees: [
451
+ {
452
+ value: 'ai-codex',
453
+ label: 'Codex',
454
+ username: 'codex',
455
+ icon: 'Bot',
456
+ color: '#0ea5e9',
457
+ kind: 'agent',
458
+ surfaceType: 'coding_tool',
459
+ description: 'Terminal-first coding agent.',
460
+ role: 'Implementation partner',
461
+ provider: 'OpenAI',
462
+ model: 'gpt-5-codex',
463
+ createdAt: '2026-04-02T09:00:00.000Z',
464
+ updatedAt: '2026-04-04T13:15:00.000Z',
465
+ lastActiveAt: '2026-04-04T13:45:00.000Z'
466
+ }
467
+ ]
468
+ })
469
+ })
470
+ .mockResolvedValueOnce({
471
+ ok: false,
472
+ json: async () => ({
473
+ error: 'Forbidden: owner or admin role required.'
474
+ })
475
+ });
476
+ vi.stubGlobal('fetch', fetchMock);
477
+ vi.stubGlobal('confirm', confirmMock);
478
+ render(_jsx(AgentsModule, { workspaceId: "workspace-1", cloudAuthConfigured: true, authSessionResolved: true, isAuthenticated: true, cloudAiProfileSeatUsage: { used: 1, limit: 3, remaining: 2 } }));
479
+ expect(await screen.findByRole('button', { name: /codex/i })).toBeInTheDocument();
480
+ fireEvent.change(screen.getByLabelText('Agent roster status'), { target: { value: 'retire' } });
481
+ const inlineError = await screen.findByRole('alert');
482
+ expect(inlineError).toHaveTextContent('Forbidden: owner or admin role required.');
483
+ expect(screen.getByLabelText('Agent roster status')).toBeInTheDocument();
484
+ });
485
+ it('falls back to local seat usage only when cloud auth is not configured', async () => {
486
+ const fetchMock = vi.fn()
487
+ .mockResolvedValueOnce({
488
+ ok: true,
489
+ json: async () => ({
490
+ aiProfileSeatUsage: {
491
+ used: 1,
492
+ limit: 3,
493
+ remaining: 2
494
+ },
495
+ assignees: [
496
+ {
497
+ value: 'ai-codex',
498
+ label: 'Codex',
499
+ username: 'codex',
500
+ icon: 'Bot',
501
+ color: '#0ea5e9',
502
+ kind: 'agent',
503
+ surfaceType: 'coding_tool',
504
+ seatScope: 'local_unmetered',
505
+ createdAt: '2026-04-02T09:00:00.000Z',
506
+ updatedAt: '2026-04-04T13:15:00.000Z',
507
+ lastActiveAt: '2026-04-04T13:45:00.000Z'
508
+ }
509
+ ]
510
+ })
511
+ });
512
+ vi.stubGlobal('fetch', fetchMock);
513
+ render(_jsx(AgentsModule, { workspaceId: "workspace-1" }));
514
+ expect(await screen.findByText('Registered Cloud Agents: 1/3')).toBeInTheDocument();
515
+ });
516
+ it('shows no cloud seat label when cloud auth is configured but cloud seat usage is unavailable', async () => {
517
+ const fetchMock = vi.fn()
518
+ .mockResolvedValueOnce({
519
+ ok: true,
520
+ json: async () => ({
521
+ aiProfileSeatUsage: {
522
+ used: 0,
523
+ limit: null,
524
+ remaining: null
525
+ },
526
+ assignees: [
527
+ {
528
+ value: 'ai-codex',
529
+ label: 'Codex',
530
+ username: 'codex',
531
+ icon: 'Bot',
532
+ color: '#0ea5e9',
533
+ kind: 'agent',
534
+ surfaceType: 'coding_tool',
535
+ seatScope: 'cloud_metered',
536
+ createdAt: '2026-04-02T09:00:00.000Z',
537
+ updatedAt: '2026-04-04T13:15:00.000Z',
538
+ lastActiveAt: '2026-04-04T13:45:00.000Z'
539
+ }
540
+ ]
541
+ })
542
+ });
543
+ vi.stubGlobal('fetch', fetchMock);
544
+ render(_jsx(AgentsModule, { workspaceId: "workspace-1", cloudAuthConfigured: true, authSessionResolved: true, isAuthenticated: true }));
545
+ await screen.findByRole('button', { name: /codex/i });
546
+ expect(screen.queryByText(/Registered Cloud Agents:/i)).not.toBeInTheDocument();
547
+ expect(screen.queryByText('Registered Cloud Agents: 0/Unlimited')).not.toBeInTheDocument();
548
+ });
549
+ it('shows resolved cloud seat usage when the account summary updates after mount', async () => {
550
+ const fetchMock = vi.fn()
551
+ .mockResolvedValueOnce({
552
+ ok: true,
553
+ json: async () => ({
554
+ aiProfileSeatUsage: {
555
+ used: 0,
556
+ limit: null,
557
+ remaining: null
558
+ },
559
+ assignees: [
560
+ {
561
+ value: 'ai-codex',
562
+ label: 'Codex',
563
+ username: 'codex',
564
+ icon: 'Bot',
565
+ color: '#0ea5e9',
566
+ kind: 'agent',
567
+ surfaceType: 'coding_tool',
568
+ seatScope: 'cloud_metered',
569
+ createdAt: '2026-04-02T09:00:00.000Z',
570
+ updatedAt: '2026-04-04T13:15:00.000Z',
571
+ lastActiveAt: '2026-04-04T13:45:00.000Z'
572
+ }
573
+ ]
574
+ })
575
+ });
576
+ vi.stubGlobal('fetch', fetchMock);
577
+ const { rerender } = render(_jsx(AgentsModule, { workspaceId: "workspace-1", cloudAuthConfigured: true, authSessionResolved: true, isAuthenticated: true, cloudAiProfileSeatUsage: null }));
578
+ await screen.findByRole('button', { name: /codex/i });
579
+ expect(screen.queryByText(/Registered Cloud Agents:/i)).not.toBeInTheDocument();
580
+ rerender(_jsx(AgentsModule, { workspaceId: "workspace-1", cloudAuthConfigured: true, authSessionResolved: true, isAuthenticated: true, cloudAiProfileSeatUsage: { used: 0, limit: 20, remaining: 20 } }));
581
+ expect(await screen.findByText('Registered Cloud Agents: 0/20')).toBeInTheDocument();
582
+ });
583
+ it('shows a cloud login prompt instead of unlimited when cloud auth is configured but the user is signed out', async () => {
584
+ const fetchMock = vi.fn()
585
+ .mockResolvedValueOnce({
586
+ ok: true,
587
+ json: async () => ({
588
+ aiProfileSeatUsage: {
589
+ used: 0,
590
+ limit: null,
591
+ remaining: null
592
+ },
593
+ assignees: []
594
+ })
595
+ });
596
+ vi.stubGlobal('fetch', fetchMock);
597
+ render(_jsx(AgentsModule, { workspaceId: "workspace-1", cloudAuthConfigured: true, authSessionResolved: true, isAuthenticated: false }));
598
+ expect(await screen.findByText('Log into account for Cloud agents')).toBeInTheDocument();
599
+ expect(screen.queryByText('Registered Cloud Agents: 0/Unlimited')).not.toBeInTheDocument();
101
600
  });
102
601
  });
@@ -8,6 +8,8 @@ type ShellProps = {
8
8
  requestedTarget?: OpenAnnotatedAttachmentDetail | null;
9
9
  requestedSessionId?: string | null;
10
10
  requestedOpenVersion?: number;
11
+ imageTrayOpen?: boolean;
12
+ onCloseImageTray?: () => void;
11
13
  resolveTaskReferenceLabel?: (taskId: string) => string;
12
14
  resolveImageReferenceLabel?: (assetId: string) => string;
13
15
  onRequestedTargetHandled?: () => void;
@@ -20,5 +22,5 @@ type ShellProps = {
20
22
  }) => void;
21
23
  onBackToTask?: (taskId: string) => void;
22
24
  };
23
- export declare function AnnotatedAttachmentWorkspaceShell({ runtimeMode, apiBaseUrl, cloudAuthBaseUrl, workspaceId, sessionLoadReady, requestedTarget, requestedSessionId, requestedOpenVersion, resolveTaskReferenceLabel, resolveImageReferenceLabel, onRequestedTargetHandled, onOpenTarget, onContextChange, onBackToTask, }: ShellProps): import("react/jsx-runtime").JSX.Element;
25
+ export declare function AnnotatedAttachmentWorkspaceShell({ runtimeMode, apiBaseUrl, cloudAuthBaseUrl, workspaceId, sessionLoadReady, requestedTarget, requestedSessionId, requestedOpenVersion, imageTrayOpen, onCloseImageTray, resolveTaskReferenceLabel, resolveImageReferenceLabel, onRequestedTargetHandled, onOpenTarget, onContextChange, onBackToTask, }: ShellProps): import("react/jsx-runtime").JSX.Element;
24
26
  export {};