@taskforcehq/taskforce 0.3.304 → 0.3.306

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 (383) hide show
  1. package/README.md +140 -247
  2. package/dist/Taskforce.module.css +295 -89
  3. package/dist/TaskforceCore.js +378 -111
  4. package/dist/TaskforceCore.test.js +1221 -107
  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 +52 -2
  14. package/dist/compat/workspaceSyncCompat.test.js +38 -1
  15. package/dist/components/context/ContextAttachmentManager.d.ts +14 -0
  16. package/dist/components/context/ContextAttachmentManager.js +549 -0
  17. package/dist/components/features/AgentsModule.d.ts +10 -1
  18. package/dist/components/features/AgentsModule.js +260 -15
  19. package/dist/components/features/AgentsModule.test.js +255 -5
  20. package/dist/components/features/DocumentIndex.d.ts +1 -1
  21. package/dist/components/features/DocumentIndex.js +1 -1
  22. package/dist/components/features/DocumentViewer.d.ts +6 -2
  23. package/dist/components/features/DocumentViewer.js +90 -10
  24. package/dist/components/features/DocumentWorkspace.d.ts +5 -22
  25. package/dist/components/features/DocumentWorkspace.js +12 -155
  26. package/dist/components/features/DocumentWorkspace.test.js +226 -6
  27. package/dist/components/features/TaskSettings.js +29 -3
  28. package/dist/components/features/TaskSettings.test.js +42 -1
  29. package/dist/components/features/documentWorkspaceModel.d.ts +24 -0
  30. package/dist/components/features/documentWorkspaceModel.js +57 -0
  31. package/dist/components/features/useDocumentWorkspaceController.d.ts +34 -0
  32. package/dist/components/features/useDocumentWorkspaceController.js +113 -0
  33. package/dist/components/task/TaskCard.js +19 -28
  34. package/dist/components/task/TaskCard.test.js +38 -3
  35. package/dist/components/task/TaskContextUpload.js +4 -526
  36. package/dist/components/task/TaskForm.d.ts +8 -8
  37. package/dist/components/task/TaskForm.js +362 -230
  38. package/dist/components/task/TaskForm.test.js +558 -381
  39. package/dist/components/task/TaskKanban.d.ts +2 -1
  40. package/dist/components/task/TaskKanban.js +96 -14
  41. package/dist/components/task/TaskKanban.test.js +36 -0
  42. package/dist/components/ui/EditableAvatarButton.d.ts +18 -0
  43. package/dist/components/ui/EditableAvatarButton.js +18 -0
  44. package/dist/components/views/PlanComparisonPage.d.ts +9 -1
  45. package/dist/components/views/PlanComparisonPage.js +70 -17
  46. package/dist/components/views/PlanComparisonPage.test.js +289 -41
  47. package/dist/components/views/PlansPage.js +239 -106
  48. package/dist/components/views/PlansPage.test.js +593 -42
  49. package/dist/components/views/StandaloneLayout.js +310 -554
  50. package/dist/components/views/panels/FilterToolbar.test.js +6 -4
  51. package/dist/components/views/panels/PlanningDrawer.d.ts +8 -1
  52. package/dist/components/views/panels/PlanningDrawer.js +18 -11
  53. package/dist/components/views/panels/PlanningDrawer.test.d.ts +1 -0
  54. package/dist/components/views/panels/PlanningDrawer.test.js +141 -0
  55. package/dist/components/views/planningScope.d.ts +20 -0
  56. package/dist/components/views/planningScope.js +25 -0
  57. package/dist/components/views/planningScope.test.d.ts +1 -0
  58. package/dist/components/views/planningScope.test.js +60 -0
  59. package/dist/components/views/standalone/modals/AccountHubModal.d.ts +27 -14
  60. package/dist/components/views/standalone/modals/AccountHubModal.js +87 -15
  61. package/dist/components/views/standalone/modals/AccountHubModal.test.js +42 -2
  62. package/dist/components/views/standalone/modals/AvatarImageManagerModal.d.ts +20 -0
  63. package/dist/components/views/standalone/modals/AvatarImageManagerModal.js +127 -0
  64. package/dist/components/views/standalone/modals/EditProfileModal.d.ts +2 -9
  65. package/dist/components/views/standalone/modals/EditProfileModal.js +3 -2
  66. package/dist/components/views/standalone/modals/SyncEnableWarningModal.d.ts +9 -0
  67. package/dist/components/views/standalone/modals/SyncEnableWarningModal.js +6 -0
  68. package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.d.ts +1 -0
  69. package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.js +24 -0
  70. package/dist/components/views/standalone/modals/SyncStatusModal.d.ts +2 -1
  71. package/dist/components/views/standalone/modals/SyncStatusModal.js +2 -2
  72. package/dist/config/envSchema.js +1 -1
  73. package/dist/core/AiProfileService.d.ts +45 -3
  74. package/dist/core/AiProfileService.js +774 -63
  75. package/dist/core/AiProfileService.test.js +22 -2
  76. package/dist/core/AiProfiles.test.js +761 -2
  77. package/dist/core/AttachmentLinkService.js +57 -15
  78. package/dist/core/AuthIdentityService.d.ts +107 -0
  79. package/dist/core/AuthIdentityService.js +284 -0
  80. package/dist/core/AuthTokenService.d.ts +4 -0
  81. package/dist/core/AuthTokenService.js +34 -6
  82. package/dist/core/AuthTokenService.test.d.ts +1 -0
  83. package/dist/core/AuthTokenService.test.js +78 -0
  84. package/dist/core/EntitlementsPolicy.test.js +77 -15
  85. package/dist/core/GlobalSettingsService.js +115 -6
  86. package/dist/core/PlanEntitlementService.d.ts +30 -3
  87. package/dist/core/PlanEntitlementService.js +454 -93
  88. package/dist/core/PlanFeatureCatalog.test.d.ts +1 -0
  89. package/dist/core/PlanFeatureCatalog.test.js +84 -0
  90. package/dist/core/PlanVersionPolicy.test.js +54 -28
  91. package/dist/core/PlanningEntities.test.js +52 -0
  92. package/dist/core/SignupMonetizationSettings.test.js +241 -44
  93. package/dist/core/SyncReconciliationService.js +2 -65
  94. package/dist/core/SystemAdmin.test.js +244 -88
  95. package/dist/core/TaskAttachmentsCanonical.test.js +51 -1
  96. package/dist/core/TaskTaxonomyValidation.test.js +53 -0
  97. package/dist/core/Taskforce.d.ts +228 -14
  98. package/dist/core/Taskforce.js +814 -201
  99. package/dist/core/Taskforce.listTasksSlim.test.d.ts +1 -0
  100. package/dist/core/Taskforce.listTasksSlim.test.js +91 -0
  101. package/dist/core/UserProfileAvatarDrafts.test.js +30 -3
  102. package/dist/core/WorkspaceLifecycleService.js +0 -5
  103. package/dist/core/WorkspacePermissions.test.js +25 -1
  104. package/dist/core/WorkspacePlanMode.test.js +128 -27
  105. package/dist/core/shared.d.ts +3 -1
  106. package/dist/core/shared.js +16 -1
  107. package/dist/core/types.d.ts +68 -2
  108. package/dist/hooks/auth/useTaskforceAuthBootstrap.js +26 -1
  109. package/dist/hooks/sync/auth.js +3 -1
  110. package/dist/hooks/sync/bootstrap.js +2 -0
  111. package/dist/hooks/sync/controlPlane.d.ts +37 -0
  112. package/dist/hooks/sync/controlPlane.js +78 -0
  113. package/dist/hooks/sync/controlPlane.test.d.ts +1 -0
  114. package/dist/hooks/sync/controlPlane.test.js +121 -0
  115. package/dist/hooks/sync/lifecyclePolicy.d.ts +45 -0
  116. package/dist/hooks/sync/lifecyclePolicy.js +93 -0
  117. package/dist/hooks/sync/lifecyclePolicy.test.d.ts +1 -0
  118. package/dist/hooks/sync/lifecyclePolicy.test.js +124 -0
  119. package/dist/hooks/sync/orchestratorShared.d.ts +10 -1
  120. package/dist/hooks/sync/orchestratorShared.js +68 -47
  121. package/dist/hooks/sync/orchestratorShared.test.js +50 -1
  122. package/dist/hooks/sync/pullLifecycle.d.ts +31 -0
  123. package/dist/hooks/sync/pullLifecycle.js +24 -0
  124. package/dist/hooks/sync/pullLifecycle.test.d.ts +1 -0
  125. package/dist/hooks/sync/pullLifecycle.test.js +80 -0
  126. package/dist/hooks/sync/recovery.d.ts +16 -2
  127. package/dist/hooks/sync/recovery.js +171 -53
  128. package/dist/hooks/sync/recovery.test.d.ts +1 -0
  129. package/dist/hooks/sync/recovery.test.js +292 -0
  130. package/dist/hooks/sync/transfers.d.ts +16 -3
  131. package/dist/hooks/sync/transfers.js +186 -65
  132. package/dist/hooks/sync/transfers.test.d.ts +1 -0
  133. package/dist/hooks/sync/transfers.test.js +396 -0
  134. package/dist/hooks/sync/useRecentSyncEvents.d.ts +21 -0
  135. package/dist/hooks/sync/useRecentSyncEvents.js +92 -0
  136. package/dist/hooks/sync/useRecentSyncEvents.test.d.ts +1 -0
  137. package/dist/hooks/sync/useRecentSyncEvents.test.js +124 -0
  138. package/dist/hooks/sync/useSyncStatusActions.d.ts +30 -0
  139. package/dist/hooks/sync/useSyncStatusActions.js +88 -0
  140. package/dist/hooks/sync/useSyncStatusActions.test.d.ts +1 -0
  141. package/dist/hooks/sync/useSyncStatusActions.test.js +133 -0
  142. package/dist/hooks/sync/useSyncStatusControls.d.ts +25 -0
  143. package/dist/hooks/sync/useSyncStatusControls.js +60 -0
  144. package/dist/hooks/sync/useSyncStatusControls.test.d.ts +1 -0
  145. package/dist/hooks/sync/useSyncStatusControls.test.js +88 -0
  146. package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +12 -0
  147. package/dist/hooks/useSyncOrchestrator.d.ts +16 -6
  148. package/dist/hooks/useSyncOrchestrator.js +424 -175
  149. package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +487 -10
  150. package/dist/hooks/useTaskData.js +8 -3
  151. package/dist/hooks/useTaskData.test.js +45 -0
  152. package/dist/hooks/useTaskMutations.d.ts +2 -1
  153. package/dist/hooks/useTaskMutations.js +12 -1
  154. package/dist/hooks/useTaskMutations.test.js +30 -1
  155. package/dist/hooks/useTaskforce.d.ts +65 -4
  156. package/dist/hooks/useTaskforce.js +564 -243
  157. package/dist/hooks/useTaskforce.runtime-routing.test.d.ts +1 -0
  158. package/dist/hooks/useTaskforce.runtime-routing.test.js +152 -0
  159. package/dist/hooks/useTaskforce.sync-behavior.test.js +2454 -208
  160. package/dist/hooks/useWorkspaceSyncController.d.ts +4 -1
  161. package/dist/hooks/useWorkspaceSyncController.js +17 -2
  162. package/dist/hooks/useWorkspaceSyncController.test.js +1 -0
  163. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.d.ts +16 -0
  164. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +316 -35
  165. package/dist/localization/locales/en-US.d.ts +0 -1
  166. package/dist/localization/locales/en-US.js +0 -1
  167. package/dist/localization/locales/es-419.js +0 -1
  168. package/dist/localization/locales/pt-BR.js +0 -1
  169. package/dist/mcp/adminWorkspaceRegistrar.d.ts +2 -0
  170. package/dist/mcp/adminWorkspaceRegistrar.js +154 -0
  171. package/dist/mcp/collaborationRegistrar.d.ts +2 -0
  172. package/dist/mcp/collaborationRegistrar.js +71 -0
  173. package/dist/mcp/documentAssetRegistrar.d.ts +2 -0
  174. package/dist/mcp/documentAssetRegistrar.js +346 -0
  175. package/dist/mcp/runtime.d.ts +2 -0
  176. package/dist/mcp/runtime.js +2433 -3534
  177. package/dist/mcp/runtime.test.js +440 -2
  178. package/dist/mcp/taskPlanningRegistrar.d.ts +2 -0
  179. package/dist/mcp/taskPlanningRegistrar.js +418 -0
  180. package/dist/mcp/toolCatalog.d.ts +35 -0
  181. package/dist/mcp/toolCatalog.js +3 -0
  182. package/dist/migrations/taskSchemaMigrations.d.ts +1 -1
  183. package/dist/migrations/taskSchemaMigrations.js +171 -61
  184. package/dist/migrations/taskSchemaMigrations.test.js +15 -0
  185. package/dist/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
  186. package/dist/resources/templates/workflows/collaborate.yaml +1 -1
  187. package/dist/resources/templates/workflows/evaluate.yaml +2 -2
  188. package/dist/resources/templates/workflows/plan.yaml +1 -1
  189. package/dist/resources/templates/workflows/review.yaml +2 -2
  190. package/dist/server/annotatedAttachmentsRoutes.test.js +3 -3
  191. package/dist/server/auth/providers/apple.d.ts +33 -0
  192. package/dist/server/auth/providers/apple.js +82 -0
  193. package/dist/server/auth/providers/appleClientSecret.d.ts +37 -0
  194. package/dist/server/auth/providers/appleClientSecret.js +65 -0
  195. package/dist/server/auth/providers/github.d.ts +26 -0
  196. package/dist/server/auth/providers/github.js +86 -0
  197. package/dist/server/auth/providers/google.d.ts +21 -0
  198. package/dist/server/auth/providers/google.js +56 -0
  199. package/dist/server/auth/providers/types.d.ts +21 -0
  200. package/dist/server/auth/providers/types.js +1 -0
  201. package/dist/server/auth.d.ts +2 -0
  202. package/dist/server/auth.js +6 -3
  203. package/dist/server/documentReviewRoutes.test.js +36 -3
  204. package/dist/server/index.cookieProxy.test.js +1 -0
  205. package/dist/server/index.d.ts +12 -0
  206. package/dist/server/index.js +120 -9
  207. package/dist/server/index.rateLimit.test.js +3 -0
  208. package/dist/server/index.test.js +106 -3
  209. package/dist/server/routes/admin.d.ts +4 -5
  210. package/dist/server/routes/admin.js +410 -80
  211. package/dist/server/routes/annotatedAttachments.d.ts +1 -1
  212. package/dist/server/routes/annotatedAttachments.js +1 -1
  213. package/dist/server/routes/auth.d.ts +16 -6
  214. package/dist/server/routes/auth.js +1015 -118
  215. package/dist/server/routes/authSupport.d.ts +30 -0
  216. package/dist/server/routes/authSupport.js +81 -0
  217. package/dist/server/routes/billing.d.ts +1 -1
  218. package/dist/server/routes/billing.js +276 -34
  219. package/dist/server/routes/billing.test.js +760 -52
  220. package/dist/server/routes/documentReviews.d.ts +1 -1
  221. package/dist/server/routes/documentReviews.js +1 -1
  222. package/dist/server/routes/documents.d.ts +5 -2
  223. package/dist/server/routes/documents.js +242 -74
  224. package/dist/server/routes/primitives.d.ts +11 -0
  225. package/dist/server/routes/primitives.js +73 -0
  226. package/dist/server/routes/resources.d.ts +1 -1
  227. package/dist/server/routes/resources.js +1 -1
  228. package/dist/server/routes/shared.d.ts +29 -3
  229. package/dist/server/routes/shared.js +69 -4
  230. package/dist/server/routes/sync.d.ts +1 -1
  231. package/dist/server/routes/sync.integration.test.js +437 -39
  232. package/dist/server/routes/sync.js +62 -606
  233. package/dist/server/routes/syncAuxRoutes.d.ts +15 -0
  234. package/dist/server/routes/syncAuxRoutes.js +91 -0
  235. package/dist/server/routes/syncAuxRoutes.test.d.ts +1 -0
  236. package/dist/server/routes/syncAuxRoutes.test.js +158 -0
  237. package/dist/server/routes/syncPullApplyRoutes.d.ts +36 -0
  238. package/dist/server/routes/syncPullApplyRoutes.js +204 -0
  239. package/dist/server/routes/syncPushRoutes.d.ts +24 -0
  240. package/dist/server/routes/syncPushRoutes.js +212 -0
  241. package/dist/server/routes/syncRouteGuards.d.ts +36 -0
  242. package/dist/server/routes/syncRouteGuards.js +67 -0
  243. package/dist/server/routes/syncRouteGuards.test.d.ts +1 -0
  244. package/dist/server/routes/syncRouteGuards.test.js +94 -0
  245. package/dist/server/routes/syncRouteTypes.d.ts +13 -0
  246. package/dist/server/routes/syncRouteTypes.js +1 -0
  247. package/dist/server/routes/syncSnapshotRoutes.d.ts +66 -0
  248. package/dist/server/routes/syncSnapshotRoutes.js +180 -0
  249. package/dist/server/routes/tasks.d.ts +1 -1
  250. package/dist/server/routes/tasks.js +44 -2
  251. package/dist/server/routes/workspaces.d.ts +1 -1
  252. package/dist/server/routes/workspaces.js +37 -6
  253. package/dist/server/routes.d.ts +2 -9
  254. package/dist/server/routes.js +136 -165
  255. package/dist/server/routes.test.js +2457 -162
  256. package/dist/services/workflowExportSnapshots.test.js +2 -0
  257. package/dist/shared/aiProfileSeatScope.d.ts +5 -0
  258. package/dist/shared/aiProfileSeatScope.js +21 -0
  259. package/dist/shared/passwordPolicy.d.ts +13 -0
  260. package/dist/shared/passwordPolicy.js +84 -0
  261. package/dist/shared/passwordPolicy.test.d.ts +1 -0
  262. package/dist/shared/passwordPolicy.test.js +34 -0
  263. package/dist/storage/workspaceAssetStore.d.ts +15 -3
  264. package/dist/storage/workspaceAssetStore.js +132 -44
  265. package/dist/storage/workspaceAssetStore.test.js +93 -6
  266. package/dist/styles/fonts.css +70 -0
  267. package/dist/sync/collaborationSyncPayload.d.ts +6 -1
  268. package/dist/sync/collaborationSyncPayload.js +17 -11
  269. package/dist/sync/collaborationSyncPayload.test.js +13 -1
  270. package/dist/sync/contentSyncState.d.ts +4 -8
  271. package/dist/sync/contentSyncState.js +33 -77
  272. package/dist/sync/syncApplyHandlers.d.ts +7 -0
  273. package/dist/sync/syncApplyHandlers.js +28 -13
  274. package/dist/sync/syncApplyHandlers.test.js +72 -3
  275. package/dist/sync/syncFieldSemantics.d.ts +12 -0
  276. package/dist/sync/syncFieldSemantics.js +55 -0
  277. package/dist/sync/syncResourceAdapters.d.ts +44 -0
  278. package/dist/sync/syncResourceAdapters.js +77 -0
  279. package/dist/sync/syncService.d.ts +6 -0
  280. package/dist/sync/syncService.js +60 -0
  281. package/dist/sync/syncService.test.js +71 -3
  282. package/dist/sync/taskSyncChangeKey.d.ts +2 -0
  283. package/dist/sync/taskSyncChangeKey.js +143 -0
  284. package/dist/sync/taskSyncPayload.js +3 -8
  285. package/dist/sync/workspacePullFeed.js +4 -3
  286. package/dist/sync/workspacePullFeed.test.js +43 -0
  287. package/dist/sync/workspaceRepair.js +5 -2
  288. package/dist/sync/workspaceSyncModel.d.ts +48 -0
  289. package/dist/sync/workspaceSyncModel.js +195 -31
  290. package/dist/sync/workspaceSyncModel.test.js +325 -12
  291. package/dist/sync/workspaceSyncState.d.ts +19 -0
  292. package/dist/sync/workspaceSyncState.js +3 -1
  293. package/dist/sync/workspaceSyncSurface.js +3 -8
  294. package/dist/types.d.ts +17 -0
  295. package/dist/ui/assets/AgentsModule-DrLawwNl.js +1 -0
  296. package/dist/ui/assets/{AnnotatedAttachmentWorkspace-BlS-cqnl.js → AnnotatedAttachmentWorkspace-Z9_whf7F.js} +1 -1
  297. package/dist/ui/assets/CourierPrime-Bold-BuLj_dpw.woff2 +0 -0
  298. package/dist/ui/assets/CourierPrime-BoldItalic-BrK2pUkZ.woff2 +0 -0
  299. package/dist/ui/assets/CourierPrime-Italic-DFUZK5Ey.woff2 +0 -0
  300. package/dist/ui/assets/CourierPrime-Regular-BsKphzVf.woff2 +0 -0
  301. package/dist/ui/assets/DocumentWorkspace-B03MaSkw.js +252 -0
  302. package/dist/ui/assets/DocumentWorkspace-Dhdso07p.css +1 -0
  303. package/dist/ui/assets/{InitiativesModule-BjR6iBf9.js → InitiativesModule-9E6ParrY.js} +1 -1
  304. package/dist/ui/assets/Noir_medium-bxQwKGzB.woff2 +0 -0
  305. package/dist/ui/assets/Noir_regular-ojf2kxlG.woff2 +0 -0
  306. package/dist/ui/assets/PlansPage-CvfnMiWq.css +1 -0
  307. package/dist/ui/assets/PlansPage-DRXscYxH.js +1 -0
  308. package/dist/ui/assets/RussoOne-Regular-Cu_qq_qC.woff2 +0 -0
  309. package/dist/ui/assets/SpecialElite-Regular-Di6gSvAS.woff2 +0 -0
  310. package/dist/ui/assets/TaskSettings-DZX4jk7e.js +9 -0
  311. package/dist/ui/assets/{WorkflowsModule-DnFqdUME.js → WorkflowsModule-BA7jcEpH.js} +1 -1
  312. package/dist/ui/assets/index-9eT8e0Lu.css +1 -0
  313. package/dist/ui/assets/index-C6k75jr8.js +6 -0
  314. package/dist/ui/assets/{vendor-icons-I7ZwG1z_.js → vendor-icons-DuEd_65c.js} +1 -1
  315. package/dist/ui/fonts/CourierPrime-Bold.ttf +0 -0
  316. package/dist/ui/fonts/CourierPrime-Bold.woff2 +0 -0
  317. package/dist/ui/fonts/CourierPrime-BoldItalic.ttf +0 -0
  318. package/dist/ui/fonts/CourierPrime-BoldItalic.woff2 +0 -0
  319. package/dist/ui/fonts/CourierPrime-Italic.ttf +0 -0
  320. package/dist/ui/fonts/CourierPrime-Italic.woff2 +0 -0
  321. package/dist/ui/fonts/CourierPrime-Regular.ttf +0 -0
  322. package/dist/ui/fonts/CourierPrime-Regular.woff2 +0 -0
  323. package/dist/ui/fonts/Noir_medium.otf +0 -0
  324. package/dist/ui/fonts/Noir_medium.woff2 +0 -0
  325. package/dist/ui/fonts/Noir_regular.otf +0 -0
  326. package/dist/ui/fonts/Noir_regular.woff2 +0 -0
  327. package/dist/ui/fonts/RussoOne-Regular.woff2 +0 -0
  328. package/dist/ui/fonts/SpecialElite-Regular.ttf +0 -0
  329. package/dist/ui/fonts/SpecialElite-Regular.woff2 +0 -0
  330. package/dist/ui/index.html +3 -3
  331. package/dist/utils/accountProfileSummaryCache.d.ts +5 -0
  332. package/dist/utils/assignees.d.ts +2 -0
  333. package/dist/utils/assignees.js +2 -0
  334. package/dist/utils/avatarUpload.d.ts +27 -0
  335. package/dist/utils/avatarUpload.js +132 -0
  336. package/dist/utils/avatarUpload.test.d.ts +1 -0
  337. package/dist/utils/avatarUpload.test.js +40 -0
  338. package/dist/utils/bootstrapTrace.d.ts +7 -0
  339. package/dist/utils/bootstrapTrace.js +29 -0
  340. package/dist/utils/commercialLifecyclePresentation.d.ts +19 -0
  341. package/dist/utils/commercialLifecyclePresentation.js +199 -0
  342. package/dist/utils/contextAssetEvents.d.ts +2 -0
  343. package/dist/utils/syncEventDetails.d.ts +3 -0
  344. package/dist/utils/syncEventDetails.js +64 -0
  345. package/dist/utils/syncEventDetails.test.d.ts +1 -0
  346. package/dist/utils/syncEventDetails.test.js +23 -0
  347. package/dist/utils/syncEventPresentation.d.ts +15 -0
  348. package/dist/utils/syncEventPresentation.js +129 -0
  349. package/dist/utils/syncEventPresentation.test.d.ts +1 -0
  350. package/dist/utils/syncEventPresentation.test.js +64 -0
  351. package/dist/utils/syncStatusPresentation.d.ts +72 -0
  352. package/dist/utils/syncStatusPresentation.js +217 -0
  353. package/dist/utils/syncStatusPresentation.test.d.ts +1 -0
  354. package/dist/utils/syncStatusPresentation.test.js +164 -0
  355. package/dist/utils/taskActivity.d.ts +2 -0
  356. package/dist/utils/taskActivity.js +228 -22
  357. package/dist/utils/taskActivity.test.js +119 -8
  358. package/dist/utils/workspaceSyncPresentation.d.ts +4 -0
  359. package/dist/utils/workspaceSyncPresentation.js +68 -2
  360. package/dist/utils/workspaceSyncPresentation.test.js +36 -1
  361. package/package.json +10 -2
  362. package/scripts/check-cloud-mcp.mjs +83 -0
  363. package/scripts/export-sqlite-to-postgres.mjs +7 -9
  364. package/scripts/playwright-auth.sh +5 -1
  365. package/scripts/run-billing-performance-smoke.sh +24 -0
  366. package/scripts/run-e2e-realtime.sh +17 -3
  367. package/scripts/run-smoke.sh +17 -5
  368. package/scripts/run-soak.sh +17 -5
  369. package/src/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
  370. package/src/resources/templates/workflows/collaborate.yaml +1 -1
  371. package/src/resources/templates/workflows/evaluate.yaml +2 -2
  372. package/src/resources/templates/workflows/plan.yaml +1 -1
  373. package/src/resources/templates/workflows/review.yaml +2 -2
  374. package/dist/ui/assets/AgentsModule-BLWVbuKP.js +0 -1
  375. package/dist/ui/assets/DocumentWorkspace-BH_6DF6x.js +0 -250
  376. package/dist/ui/assets/DocumentWorkspace-C_8T8oz-.css +0 -1
  377. package/dist/ui/assets/PlansPage-C2dd2n1X.css +0 -1
  378. package/dist/ui/assets/PlansPage-CSDQ4sLa.js +0 -1
  379. package/dist/ui/assets/RussoOne-Regular-C3BxZIj7.ttf +0 -0
  380. package/dist/ui/assets/TaskSettings-CEDy34Jo.js +0 -9
  381. package/dist/ui/assets/index-DXUdtH1B.js +0 -6
  382. package/dist/ui/assets/index-Ii0B0rTO.css +0 -1
  383. package/scripts/migrate-planning-model.ts +0 -233
@@ -1,12 +1,78 @@
1
+ function resolveBlockedReasonPresentation(reason) {
2
+ switch (reason) {
3
+ case 'auth-required':
4
+ return {
5
+ summary: 'Sync is paused until you sign in again.',
6
+ recommendedAction: 'Sign in, then press Sync to retry.'
7
+ };
8
+ case 'attach-cloud':
9
+ return {
10
+ summary: 'This workspace still needs its first cloud pull before local pushes can run.',
11
+ recommendedAction: 'Keep this window open for the first cloud pull. If it seems stuck, press Repair.'
12
+ };
13
+ case 'provision-local':
14
+ return {
15
+ summary: 'This workspace is still doing its first cloud upload before normal pulls can run.',
16
+ recommendedAction: 'Keep this window open until the first cloud upload finishes.'
17
+ };
18
+ case 'repair-active':
19
+ return {
20
+ summary: 'Repair is already running for this workspace.',
21
+ recommendedAction: 'Wait for repair to finish before retrying sync.'
22
+ };
23
+ case 'retry-pending':
24
+ return {
25
+ summary: 'Sync hit a temporary problem and is waiting for its scheduled retry.',
26
+ recommendedAction: 'Wait for the automatic retry, or press Sync to retry now.'
27
+ };
28
+ case 'push-in-flight':
29
+ case 'pull-in-flight':
30
+ return {
31
+ summary: 'A sync request is already running for this workspace.',
32
+ recommendedAction: 'Wait for the current sync request to finish.'
33
+ };
34
+ case 'lease-held':
35
+ return {
36
+ summary: 'Another local window is already syncing this workspace.',
37
+ recommendedAction: 'Use a single local window for sync, or close the other syncing window.'
38
+ };
39
+ case 'invalid-workspace':
40
+ return {
41
+ summary: 'Workspace setup is required before sync can run.',
42
+ recommendedAction: 'Open or create a named workspace before retrying sync.'
43
+ };
44
+ case 'cloud-auth-unconfigured':
45
+ return {
46
+ summary: 'Cloud sync is unavailable because cloud authentication is not configured.',
47
+ recommendedAction: 'Configure cloud authentication before turning on sync.'
48
+ };
49
+ case 'runtime-not-local':
50
+ return {
51
+ summary: 'Workspace sync controls are only available in the local runtime.',
52
+ recommendedAction: 'Open this workspace in the local app to manage sync.'
53
+ };
54
+ case 'sync-disabled':
55
+ return {
56
+ summary: 'Workspace sync is currently turned off.',
57
+ recommendedAction: 'Turn on sync when you are ready to connect this workspace to cloud.'
58
+ };
59
+ default:
60
+ return null;
61
+ }
62
+ }
1
63
  export function resolveHeaderWorkspaceSyncPresentation(input) {
2
64
  const actionable = input.runtimeMode === 'local' && input.isAuthenticated;
3
65
  if (actionable) {
66
+ const blockedReasonPresentation = resolveBlockedReasonPresentation(input.retryBlockedReason
67
+ || input.pullBlockedReason
68
+ || input.pushBlockedReason
69
+ || null);
4
70
  return {
5
71
  actionable,
6
72
  status: input.workspaceSyncStatus,
7
73
  syncEnabledLabel: input.workspaceCloudSyncEnabled ? 'yes' : 'no',
8
- summary: input.workspaceSyncSummary,
9
- recommendedAction: input.workspaceSyncRecommendedAction,
74
+ summary: blockedReasonPresentation?.summary || input.workspaceSyncSummary,
75
+ recommendedAction: blockedReasonPresentation?.recommendedAction || input.workspaceSyncRecommendedAction,
10
76
  lastError: input.workspaceSyncError
11
77
  };
12
78
  }
@@ -25,7 +25,10 @@ describe('resolveHeaderWorkspaceSyncPresentation', () => {
25
25
  workspaceCloudSyncEnabled: true,
26
26
  workspaceSyncSummary: 'Sync needs attention before it can continue.',
27
27
  workspaceSyncRecommendedAction: 'Press Sync to retry.',
28
- workspaceSyncError: 'Retry later'
28
+ workspaceSyncError: 'Retry later',
29
+ pushBlockedReason: null,
30
+ pullBlockedReason: null,
31
+ retryBlockedReason: null
29
32
  });
30
33
  expect(result.actionable).toBe(true);
31
34
  expect(result.status).toBe('attention');
@@ -33,4 +36,36 @@ describe('resolveHeaderWorkspaceSyncPresentation', () => {
33
36
  expect(result.summary).toBe('Sync needs attention before it can continue.');
34
37
  expect(result.lastError).toBe('Retry later');
35
38
  });
39
+ it('surfaces the highest-priority blocked sync reason in the visible summary', () => {
40
+ const result = resolveHeaderWorkspaceSyncPresentation({
41
+ runtimeMode: 'local',
42
+ isAuthenticated: true,
43
+ workspaceSyncStatus: 'attention',
44
+ workspaceCloudSyncEnabled: true,
45
+ workspaceSyncSummary: 'Sync needs attention before it can continue.',
46
+ workspaceSyncRecommendedAction: 'Press Sync to retry.',
47
+ workspaceSyncError: 'Retry later',
48
+ pushBlockedReason: 'attach-cloud',
49
+ pullBlockedReason: 'retry-pending',
50
+ retryBlockedReason: 'auth-required'
51
+ });
52
+ expect(result.summary).toBe('Sync is paused until you sign in again.');
53
+ expect(result.recommendedAction).toBe('Sign in, then press Sync to retry.');
54
+ });
55
+ it('explains when another local window holds the sync lease', () => {
56
+ const result = resolveHeaderWorkspaceSyncPresentation({
57
+ runtimeMode: 'local',
58
+ isAuthenticated: true,
59
+ workspaceSyncStatus: 'attention',
60
+ workspaceCloudSyncEnabled: true,
61
+ workspaceSyncSummary: 'Sync needs attention before it can continue.',
62
+ workspaceSyncRecommendedAction: 'Press Sync to retry.',
63
+ workspaceSyncError: 'Retry later',
64
+ pushBlockedReason: 'lease-held',
65
+ pullBlockedReason: null,
66
+ retryBlockedReason: null
67
+ });
68
+ expect(result.summary).toBe('Another local window is already syncing this workspace.');
69
+ expect(result.recommendedAction).toBe('Use a single local window for sync, or close the other syncing window.');
70
+ });
36
71
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taskforcehq/taskforce",
3
- "version": "0.3.304",
3
+ "version": "0.3.306",
4
4
  "description": "Mission Command center for AI-powered task management (beta - under active development)",
5
5
  "author": "Taskforce HQ <hello@taskforcehq.ai> (https://taskforcehq.ai)",
6
6
  "license": "MIT",
@@ -54,7 +54,7 @@
54
54
  "build:ui": "npm run build:app",
55
55
  "check:deploy-preflight": "npm run build",
56
56
  "hooks:install": "git config core.hooksPath .githooks",
57
- "build": "shx rm -rf dist && tsc && shx cp src/Taskforce.module.css dist/Taskforce.module.css && shx mkdir -p dist/resources && shx cp -r src/resources/* dist/resources/ && shx rm -f dist/resources/templates/workflows/release.yaml && shx mkdir -p dist/public && shx cp -r src/assets/images/* dist/public/ && shx cp -r src/assets/favicon/* dist/public/ && shx chmod +x dist/cli.js && npm run build:ui",
57
+ "build": "shx rm -rf dist && tsc && shx cp src/Taskforce.module.css dist/Taskforce.module.css && shx mkdir -p dist/styles && shx cp src/styles/fonts.css dist/styles/fonts.css && shx mkdir -p dist/assets/fonts && shx cp src/assets/fonts/*.woff2 dist/assets/fonts/ && shx mkdir -p dist/resources && shx cp -r src/resources/* dist/resources/ && shx rm -f dist/resources/templates/workflows/release.yaml && shx mkdir -p dist/public && shx cp -r src/assets/images/* dist/public/ && shx cp -r src/assets/favicon/* dist/public/ && shx chmod +x dist/cli.js && npm run build:ui",
58
58
  "mcp": "node dist/mcp/server.js",
59
59
  "gen:workflows": "node scripts/generate-workflow-templates.mjs",
60
60
  "check:workflows": "node scripts/generate-workflow-templates.mjs --check",
@@ -76,6 +76,12 @@
76
76
  "test:e2e:realtime:attachments": "npm run test:e2e:realtime -- tests/e2e/attachment-sync.spec.ts",
77
77
  "test:e2e:realtime:multiclient": "npm run test:e2e:realtime -- tests/e2e/realtime-multiclient.spec.ts",
78
78
  "test:e2e:realtime:reconnect": "npm run test:e2e:realtime -- tests/e2e/realtime-reconnect.spec.ts",
79
+ "test:e2e:onboarding": "npx playwright test -c playwright.e2e.config.ts tests/e2e/auth-runtime.spec.ts tests/e2e/billing-runtime.spec.ts",
80
+ "test:billing:deterministic": "npx vitest run src/server/routes/billing.test.ts src/components/views/PlansPage.test.tsx src/components/views/PlanComparisonPage.test.tsx src/migrations/billingSchemaParity.test.ts",
81
+ "test:billing:runtime:mock": "npx playwright test -c playwright.e2e.config.ts tests/e2e/billing-runtime.spec.ts",
82
+ "test:billing:local": "npm run test:billing:deterministic && npm run test:billing:runtime:mock",
83
+ "test:billing:performance:smoke": "sh scripts/run-billing-performance-smoke.sh",
84
+ "test:billing:performance:smoke:live": "TASKFORCE_BILLING_ENABLE_LIVE_PURCHASE=1 sh scripts/run-billing-performance-smoke.sh",
79
85
  "playwright:auth:bootstrap": "node scripts/bootstrap-playwright-auth.mjs",
80
86
  "playwright:auth": "sh scripts/playwright-auth.sh",
81
87
  "playwright:interactive": "playwright test -c playwright.interactive.config.ts tests/e2e/interactive.smoke.spec.ts",
@@ -83,6 +89,7 @@
83
89
  "qa:open": "node scripts/qa-open.mjs",
84
90
  "check:env": "node --import tsx scripts/check-env.ts --target=server --strict=true",
85
91
  "check:env:soak": "node --import tsx scripts/check-env.ts --target=soak --strict=true",
92
+ "check:mcp-smoke": "node scripts/check-cloud-mcp.mjs",
86
93
  "check:compat": "node scripts/check-compat-boundaries.mjs",
87
94
  "gen:env-example": "node --import tsx scripts/generate-env-example.ts",
88
95
  "check:sync-smoke-preflight": "node --import tsx src/soak/preflight.cli.ts",
@@ -104,6 +111,7 @@
104
111
  "js-yaml": "^4.1.1",
105
112
  "nodemailer": "^6.10.1",
106
113
  "pg": "^8.18.0",
114
+ "react-avatar-editor": "^15.1.0",
107
115
  "rehype-sanitize": "^6.0.0",
108
116
  "stripe": "^20.3.1",
109
117
  "ws": "^8.18.0"
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env node
2
+
3
+ const DEFAULT_ENDPOINTS = {
4
+ production: 'https://mcp.taskforcehq.ai/mcp',
5
+ staging: 'https://staging-mcp.taskforcehq.ai/mcp',
6
+ performance: 'https://performance-mcp.taskforcehq.ai/mcp'
7
+ };
8
+
9
+ const REQUEST_TIMEOUT_MS = 10000;
10
+
11
+ function normalizeTargets(argv) {
12
+ const values = argv.length > 0 ? argv : Object.keys(DEFAULT_ENDPOINTS);
13
+ return values.map((value) => {
14
+ const normalized = String(value || '').trim().toLowerCase();
15
+ if (DEFAULT_ENDPOINTS[normalized]) {
16
+ return {
17
+ label: normalized,
18
+ url: DEFAULT_ENDPOINTS[normalized]
19
+ };
20
+ }
21
+ return {
22
+ label: normalized || 'custom',
23
+ url: String(value || '').trim()
24
+ };
25
+ });
26
+ }
27
+
28
+ async function checkEndpoint(target) {
29
+ const controller = new AbortController();
30
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
31
+ try {
32
+ const response = await fetch(target.url, {
33
+ method: 'GET',
34
+ headers: {
35
+ Accept: 'application/json'
36
+ },
37
+ signal: controller.signal
38
+ });
39
+ const contentType = String(response.headers.get('content-type') || '');
40
+ const responseText = await response.text();
41
+ let payload = null;
42
+ try {
43
+ payload = responseText ? JSON.parse(responseText) : null;
44
+ } catch {
45
+ payload = null;
46
+ }
47
+ const message = typeof payload?.error?.message === 'string'
48
+ ? payload.error.message.trim()
49
+ : '';
50
+
51
+ if (response.status !== 401) {
52
+ throw new Error(`expected HTTP 401 but received ${response.status}`);
53
+ }
54
+ if (!contentType.includes('application/json')) {
55
+ throw new Error(`expected application/json response but received ${contentType || 'unknown content-type'}`);
56
+ }
57
+ if (message !== 'Unauthorized.') {
58
+ throw new Error(`expected MCP Unauthorized. payload but received message=${JSON.stringify(message || responseText.slice(0, 200))}`);
59
+ }
60
+
61
+ console.log(`[mcp-smoke] ${target.label} ok ${target.url} -> 401 Unauthorized.`);
62
+ } catch (error) {
63
+ const message = error instanceof Error ? error.message : String(error);
64
+ throw new Error(`[mcp-smoke] ${target.label} failed ${target.url}: ${message}`);
65
+ } finally {
66
+ clearTimeout(timeout);
67
+ }
68
+ }
69
+
70
+ async function main() {
71
+ const targets = normalizeTargets(process.argv.slice(2));
72
+ for (const target of targets) {
73
+ if (!target.url) {
74
+ throw new Error(`[mcp-smoke] ${target.label} has no URL to check.`);
75
+ }
76
+ await checkEndpoint(target);
77
+ }
78
+ }
79
+
80
+ main().catch((error) => {
81
+ console.error(error instanceof Error ? error.message : String(error));
82
+ process.exitCode = 1;
83
+ });
@@ -49,19 +49,19 @@ lines.push('');
49
49
 
50
50
  for (const t of tasks) {
51
51
  lines.push(`INSERT INTO tasks (
52
- id, tenant_id, title, description, status, priority, complexity, type, category,
52
+ id, tenant_id, workspace_id, title, description, status, priority, complexity, type, category,
53
53
  approach, created_at, updated_at, completed_at, canceled_reason,
54
54
  is_archived, specialists, taxonomies, created_by,
55
- scheduled_date, due_date, scheduled_week_key, order_in_day,
56
- parent_task_id, child_display_order
55
+ scheduled_date, due_date, scheduled_week_key, order_in_day
57
56
  ) VALUES (
58
- ${sqlString(t.id)}, ${sqlString(t.tenant_id || 'default')}, ${sqlString(t.title)}, ${sqlString(t.description)}, ${sqlString(t.status)}, ${sqlNumber(t.priority)}, ${sqlNumber(t.complexity)}, ${sqlString(t.type)}, ${sqlString(t.category)},
57
+ ${sqlString(t.id)}, ${sqlString(t.tenant_id || 'default')}, ${sqlString(t.workspace_id || 'default')}, ${sqlString(t.title)}, ${sqlString(t.description)}, ${sqlString(t.status)}, ${sqlNumber(t.priority)}, ${sqlNumber(t.complexity)}, ${sqlString(t.type)}, ${sqlString(t.category)},
59
58
  ${sqlString(t.approach)}, ${sqlString(t.created_at)}, ${sqlString(t.updated_at)}, ${sqlString(t.completed_at)}, ${sqlString(t.canceled_reason)},
60
59
  ${sqlBool(t.is_archived)}, ${sqlString(t.specialists)}, ${sqlString(t.taxonomies)}, ${sqlString(t.created_by)},
61
- ${sqlString(t.scheduled_date)}, ${sqlString(t.due_date)}, ${sqlString(t.scheduled_week_key)}, ${sqlNumber(t.order_in_day)},
62
- ${sqlString(t.parent_task_id)}, ${sqlNumber(t.child_display_order)}
60
+ ${sqlString(t.scheduled_date)}, ${sqlString(t.due_date)}, ${sqlString(t.scheduled_week_key)}, ${sqlNumber(t.order_in_day)}
63
61
  )
64
62
  ON CONFLICT (id) DO UPDATE SET
63
+ tenant_id = EXCLUDED.tenant_id,
64
+ workspace_id = EXCLUDED.workspace_id,
65
65
  title = EXCLUDED.title,
66
66
  description = EXCLUDED.description,
67
67
  status = EXCLUDED.status,
@@ -81,9 +81,7 @@ ON CONFLICT (id) DO UPDATE SET
81
81
  scheduled_date = EXCLUDED.scheduled_date,
82
82
  due_date = EXCLUDED.due_date,
83
83
  scheduled_week_key = EXCLUDED.scheduled_week_key,
84
- order_in_day = EXCLUDED.order_in_day,
85
- parent_task_id = EXCLUDED.parent_task_id,
86
- child_display_order = EXCLUDED.child_display_order;`);
84
+ order_in_day = EXCLUDED.order_in_day;`);
87
85
  }
88
86
 
89
87
  for (const c of comments) {
@@ -1,15 +1,19 @@
1
1
  #!/usr/bin/env sh
2
2
  set -eu
3
3
 
4
- LOCAL_ENV_FILE="${TASKFORCE_PLAYWRIGHT_ENV_FILE:-/Users/rossburke/.codex/taskforce-playwright.env}"
4
+ LOCAL_ENV_FILE="${TASKFORCE_PLAYWRIGHT_ENV_FILE:-$HOME/.codex/taskforce-playwright.env}"
5
5
  REPO_E2E_ENV_FILE="${TASKFORCE_PLAYWRIGHT_REPO_E2E_ENV_FILE:-.env.e2e}"
6
6
 
7
7
  if [ -f "$LOCAL_ENV_FILE" ]; then
8
+ set -a
8
9
  # shellcheck disable=SC1090
9
10
  . "$LOCAL_ENV_FILE"
11
+ set +a
10
12
  elif [ -f "$REPO_E2E_ENV_FILE" ]; then
13
+ set -a
11
14
  # shellcheck disable=SC1090
12
15
  . "$REPO_E2E_ENV_FILE"
16
+ set +a
13
17
  fi
14
18
 
15
19
  exec node scripts/bootstrap-playwright-auth.mjs "$@"
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env sh
2
+ set -eu
3
+
4
+ LOCAL_ENV_FILE="${TASKFORCE_PLAYWRIGHT_ENV_FILE:-$HOME/.codex/taskforce-playwright.env}"
5
+ REPO_E2E_ENV_FILE="${TASKFORCE_PLAYWRIGHT_REPO_E2E_ENV_FILE:-.env.e2e}"
6
+
7
+ if [ -f "$LOCAL_ENV_FILE" ]; then
8
+ set -a
9
+ # shellcheck disable=SC1090
10
+ . "$LOCAL_ENV_FILE"
11
+ set +a
12
+ elif [ -f "$REPO_E2E_ENV_FILE" ]; then
13
+ set -a
14
+ # shellcheck disable=SC1090
15
+ . "$REPO_E2E_ENV_FILE"
16
+ set +a
17
+ fi
18
+
19
+ TASKFORCE_PLAYWRIGHT_CLOUD_BASE_URL="${TASKFORCE_PLAYWRIGHT_CLOUD_BASE_URL:-https://performance-app.taskforcehq.ai}"
20
+ export TASKFORCE_PLAYWRIGHT_CLOUD_BASE_URL
21
+ export TASKFORCE_PLAYWRIGHT_BASE_URL="${TASKFORCE_PLAYWRIGHT_BASE_URL:-$TASKFORCE_PLAYWRIGHT_CLOUD_BASE_URL}"
22
+
23
+ node scripts/bootstrap-playwright-auth.mjs
24
+ exec npx playwright test -c playwright.interactive.config.ts tests/e2e/billing-performance.smoke.spec.ts "$@"
@@ -1,16 +1,30 @@
1
1
  #!/bin/sh
2
2
  set -eu
3
3
 
4
- if [ -f .env.e2e ]; then
4
+ LOCAL_ENV_FILE="${TASKFORCE_PLAYWRIGHT_ENV_FILE:-$HOME/.codex/taskforce-playwright.env}"
5
+ REPO_E2E_ENV_FILE="${TASKFORCE_PLAYWRIGHT_REPO_E2E_ENV_FILE:-.env.e2e}"
6
+
7
+ if [ -f "$LOCAL_ENV_FILE" ]; then
8
+ set -a
9
+ # shellcheck disable=SC1090
10
+ . "$LOCAL_ENV_FILE"
11
+ set +a
12
+ elif [ -f "$REPO_E2E_ENV_FILE" ]; then
5
13
  set -a
6
- . ./.env.e2e
14
+ # shellcheck disable=SC1090
15
+ . "$REPO_E2E_ENV_FILE"
7
16
  set +a
8
17
  fi
9
18
 
10
19
  # Mirror soak defaults so realtime e2e runs are plug-compatible with existing env setup.
11
20
  export SYNC_SOAK_LOCAL_BASE_URL="${SYNC_SOAK_LOCAL_BASE_URL:-http://localhost:5174}"
12
- export SYNC_SOAK_CLOUD_BASE_URL="${SYNC_SOAK_CLOUD_BASE_URL:-https://performance-app.taskforcehq.ai}"
21
+ export SYNC_SOAK_CLOUD_BASE_URL="${SYNC_SOAK_CLOUD_BASE_URL:-${TASKFORCE_PLAYWRIGHT_CLOUD_BASE_URL:-https://performance-app.taskforcehq.ai}}"
13
22
  export SYNC_SOAK_WORKSPACE_ID="${SYNC_SOAK_WORKSPACE_ID:-test-smoke}"
23
+ export SYNC_SOAK_EMAIL="${SYNC_SOAK_EMAIL:-${TASKFORCE_E2E_EMAIL:-}}"
24
+ export SYNC_SOAK_PASSWORD="${SYNC_SOAK_PASSWORD:-${TASKFORCE_E2E_PASSWORD:-}}"
25
+ PLAYWRIGHT_AUTH_STORAGE_STATE="${PLAYWRIGHT_AUTH_STORAGE_STATE:-${TASKFORCE_PLAYWRIGHT_STORAGE_STATE:-}}"
26
+ unset TASKFORCE_E2E_EMAIL TASKFORCE_E2E_PASSWORD TASKFORCE_PLAYWRIGHT_STORAGE_STATE TASKFORCE_PLAYWRIGHT_CLOUD_BASE_URL
14
27
 
15
28
  node --import tsx scripts/check-env.ts --target=soak --strict=true
29
+ export PLAYWRIGHT_AUTH_STORAGE_STATE
16
30
  npx playwright test -c playwright.e2e.config.ts "$@"
@@ -1,22 +1,34 @@
1
1
  #!/bin/sh
2
2
  set -eu
3
3
 
4
- if [ -f .env.e2e ]; then
4
+ LOCAL_ENV_FILE="${TASKFORCE_PLAYWRIGHT_ENV_FILE:-$HOME/.codex/taskforce-playwright.env}"
5
+ REPO_E2E_ENV_FILE="${TASKFORCE_PLAYWRIGHT_REPO_E2E_ENV_FILE:-.env.e2e}"
6
+
7
+ if [ -f "$LOCAL_ENV_FILE" ]; then
8
+ set -a
9
+ # shellcheck disable=SC1090
10
+ . "$LOCAL_ENV_FILE"
11
+ set +a
12
+ elif [ -f "$REPO_E2E_ENV_FILE" ]; then
5
13
  set -a
6
- . ./.env.e2e
14
+ # shellcheck disable=SC1090
15
+ . "$REPO_E2E_ENV_FILE"
7
16
  set +a
8
17
  fi
9
18
 
10
19
  # Provide safe defaults for non-secret settings; allow caller/.env.e2e overrides.
11
20
  export SYNC_SOAK_LOCAL_BASE_URL="${SYNC_SOAK_LOCAL_BASE_URL:-http://localhost:5174}"
12
- export SYNC_SOAK_CLOUD_BASE_URL="${SYNC_SOAK_CLOUD_BASE_URL:-https://performance-app.taskforcehq.ai}"
21
+ export SYNC_SOAK_CLOUD_BASE_URL="${SYNC_SOAK_CLOUD_BASE_URL:-${TASKFORCE_PLAYWRIGHT_CLOUD_BASE_URL:-https://performance-app.taskforcehq.ai}}"
13
22
  export SYNC_SOAK_WORKSPACE_ID="${SYNC_SOAK_WORKSPACE_ID:-test-smoke}"
23
+ export SYNC_SOAK_EMAIL="${SYNC_SOAK_EMAIL:-${TASKFORCE_E2E_EMAIL:-}}"
24
+ export SYNC_SOAK_PASSWORD="${SYNC_SOAK_PASSWORD:-${TASKFORCE_E2E_PASSWORD:-}}"
25
+ unset TASKFORCE_E2E_EMAIL TASKFORCE_E2E_PASSWORD TASKFORCE_PLAYWRIGHT_STORAGE_STATE TASKFORCE_PLAYWRIGHT_CLOUD_BASE_URL
14
26
 
15
27
  node --import tsx scripts/check-env.ts --target=soak --strict=true
16
28
 
17
- # Shared credentials are required and must come from env/.env.e2e.
29
+ # Shared credentials are required and may come from the local Playwright auth env file or repo .env.e2e.
18
30
  if [ -z "${SYNC_SOAK_ACCOUNTS_JSON:-}" ] && { [ -z "${SYNC_SOAK_EMAIL:-}" ] || [ -z "${SYNC_SOAK_PASSWORD:-}" ]; }; then
19
- echo "Missing credentials. Set SYNC_SOAK_ACCOUNTS_JSON or SYNC_SOAK_EMAIL+SYNC_SOAK_PASSWORD in env/.env.e2e." >&2
31
+ echo "Missing credentials. Set SYNC_SOAK_ACCOUNTS_JSON or SYNC_SOAK_EMAIL+SYNC_SOAK_PASSWORD in $TASKFORCE_PLAYWRIGHT_ENV_FILE or .env.e2e." >&2
20
32
  exit 1
21
33
  fi
22
34
 
@@ -1,23 +1,35 @@
1
1
  #!/bin/sh
2
2
  set -eu
3
3
 
4
- if [ -f .env.e2e ]; then
4
+ LOCAL_ENV_FILE="${TASKFORCE_PLAYWRIGHT_ENV_FILE:-$HOME/.codex/taskforce-playwright.env}"
5
+ REPO_E2E_ENV_FILE="${TASKFORCE_PLAYWRIGHT_REPO_E2E_ENV_FILE:-.env.e2e}"
6
+
7
+ if [ -f "$LOCAL_ENV_FILE" ]; then
8
+ set -a
9
+ # shellcheck disable=SC1090
10
+ . "$LOCAL_ENV_FILE"
11
+ set +a
12
+ elif [ -f "$REPO_E2E_ENV_FILE" ]; then
5
13
  set -a
6
- . ./.env.e2e
14
+ # shellcheck disable=SC1090
15
+ . "$REPO_E2E_ENV_FILE"
7
16
  set +a
8
17
  fi
9
18
 
10
19
  # Provide safe defaults for non-secret settings; allow caller/.env.e2e overrides.
11
20
  # Soak runs target the dedicated performance cloud by default.
12
21
  export SYNC_SOAK_LOCAL_BASE_URL="${SYNC_SOAK_LOCAL_BASE_URL:-http://localhost:5174}"
13
- export SYNC_SOAK_CLOUD_BASE_URL="${SYNC_SOAK_CLOUD_BASE_URL:-https://performance-app.taskforcehq.ai}"
22
+ export SYNC_SOAK_CLOUD_BASE_URL="${SYNC_SOAK_CLOUD_BASE_URL:-${TASKFORCE_PLAYWRIGHT_CLOUD_BASE_URL:-https://performance-app.taskforcehq.ai}}"
14
23
  export SYNC_SOAK_WORKSPACE_ID="${SYNC_SOAK_WORKSPACE_ID:-test-smoke}"
24
+ export SYNC_SOAK_EMAIL="${SYNC_SOAK_EMAIL:-${TASKFORCE_E2E_EMAIL:-}}"
25
+ export SYNC_SOAK_PASSWORD="${SYNC_SOAK_PASSWORD:-${TASKFORCE_E2E_PASSWORD:-}}"
26
+ unset TASKFORCE_E2E_EMAIL TASKFORCE_E2E_PASSWORD TASKFORCE_PLAYWRIGHT_STORAGE_STATE TASKFORCE_PLAYWRIGHT_CLOUD_BASE_URL
15
27
 
16
28
  node --import tsx scripts/check-env.ts --target=soak --strict=true
17
29
 
18
- # Shared credentials are required and must come from env/.env.e2e.
30
+ # Shared credentials are required and may come from the local Playwright auth env file or repo .env.e2e.
19
31
  if [ -z "${SYNC_SOAK_ACCOUNTS_JSON:-}" ] && { [ -z "${SYNC_SOAK_EMAIL:-}" ] || [ -z "${SYNC_SOAK_PASSWORD:-}" ]; }; then
20
- echo "Missing credentials. Set SYNC_SOAK_ACCOUNTS_JSON or SYNC_SOAK_EMAIL+SYNC_SOAK_PASSWORD in env/.env.e2e." >&2
32
+ echo "Missing credentials. Set SYNC_SOAK_ACCOUNTS_JSON or SYNC_SOAK_EMAIL+SYNC_SOAK_PASSWORD in $TASKFORCE_PLAYWRIGHT_ENV_FILE or .env.e2e." >&2
21
33
  exit 1
22
34
  fi
23
35
 
@@ -284,7 +284,7 @@ export const workflowDocs = [
284
284
  ' - `### Next Action`',
285
285
  '6. Ask whether to save as `{artifacts.implementationPlan.path}`.',
286
286
  '7. If user confirms, persist task-specific content via `{{MCP_PREFIX}}save_task_attachment` using `filename: "implementation-plan.md"`.',
287
- ' - Use `{{MCP_PREFIX}}link_task_context` only for linking existing files/URLs (for example, shared docs under `docs/`).',
287
+ ' - Use `{{MCP_PREFIX}}link_task_context` only for external http(s) URLs that should stay as references.',
288
288
  '8. If setting status to `task` or `on-hold`, add explicit comment justification using `{{MCP_PREFIX}}add_comment`.',
289
289
  '9. Never set `cancelled`, and never call `{{MCP_PREFIX}}archive_task`, unless explicitly instructed by the user.',
290
290
  '10. Print `prompts.handoffPrompt` and stop.'
@@ -358,7 +358,7 @@ export const workflowDocs = [
358
358
  ' - `### Next Step`',
359
359
  '4. Ask whether to save as `{artifacts.collaborationBlueprint.path}`.',
360
360
  '5. If user confirms, persist task-specific content via `{{MCP_PREFIX}}save_task_attachment` using `filename: "collaboration-blueprint.md"`.',
361
- ' - Use `{{MCP_PREFIX}}link_task_context` only for linking existing files/URLs (for example, shared docs under `docs/`).',
361
+ ' - Use `{{MCP_PREFIX}}link_task_context` only for external http(s) URLs that should stay as references.',
362
362
  '6. Ask concise clarification questions only if required fields above are missing.',
363
363
  '7. If setting status to `task` or `on-hold`, add explicit comment justification using `{{MCP_PREFIX}}add_comment`.',
364
364
  '8. Never set `cancelled`, and never call `{{MCP_PREFIX}}archive_task`, unless explicitly instructed by the user.',
@@ -435,14 +435,14 @@ export const workflowDocs = [
435
435
  ' - `### Next Step`',
436
436
  '4. Ask whether to save as `{artifacts.evaluationReport.path}`.',
437
437
  '5. If user confirms, persist task-specific content via `{{MCP_PREFIX}}save_task_attachment` using `filename: "evaluation.md"`.',
438
- ' - Use `{{MCP_PREFIX}}link_task_context` only for linking existing files/URLs (for example, shared docs under `docs/`).',
438
+ ' - Use `{{MCP_PREFIX}}link_task_context` only for external http(s) URLs that should stay as references.',
439
439
  '6. Never set `cancelled`, and never call `{{MCP_PREFIX}}archive_task`, unless explicitly instructed by the user.',
440
440
  '',
441
441
  '## 3. Optional Report Artifact',
442
442
  '',
443
443
  '1. Use report files only when user opts in.',
444
444
  '2. Save to `task attachment "evaluation.md"` and attach to task context when approved.',
445
- ' - If the document is not task-specific, store it under `docs/` and optionally link it with `{{MCP_PREFIX}}link_task_context`.',
445
+ ' - If the document should become a shared durable document, save it through the canonical document/document-manager flow instead of a raw `docs/` file.',
446
446
  '3. Stop.'
447
447
  ].join('\n')
448
448
  }
@@ -513,7 +513,7 @@ export const workflowDocs = [
513
513
  ' - `### Next Status`',
514
514
  '3. Ask whether to save as `{artifacts.reviewReport.path}`.',
515
515
  '4. If user confirms, persist task-specific content via `{{MCP_PREFIX}}save_task_attachment` using `filename: "review.md"`.',
516
- ' - Use `{{MCP_PREFIX}}link_task_context` only for linking existing files/URLs (for example, shared docs under `docs/`).',
516
+ ' - Use `{{MCP_PREFIX}}link_task_context` only for external http(s) URLs that should stay as references.',
517
517
  '5. Keep status within allowed statuses (`task`, `on-hold`, `in-progress`, `review`, `done`) unless user explicitly instructs otherwise.',
518
518
  ' - If setting status to `task` or `on-hold`, add explicit comment justification using `{{MCP_PREFIX}}add_comment`.',
519
519
  '6. Never set `cancelled`, and never call `{{MCP_PREFIX}}archive_task`, unless explicitly instructed by the user.',
@@ -522,7 +522,7 @@ export const workflowDocs = [
522
522
  '',
523
523
  '1. Use report files only when user opts in.',
524
524
  '2. Save to `task attachment "review.md"` and attach to task context when approved.',
525
- ' - If the document is not task-specific, store it under `docs/` and optionally link it with `{{MCP_PREFIX}}link_task_context`.',
525
+ ' - If the document should become a shared durable document, save it through the canonical document/document-manager flow instead of a raw `docs/` file.',
526
526
  '3. Stop.'
527
527
  ].join('\n')
528
528
  }
@@ -102,7 +102,7 @@ content:
102
102
  - `### Next Step`
103
103
  4. Ask whether to save as `{artifacts.collaborationBlueprint.path}`.
104
104
  5. If user confirms, persist task-specific content via `{{MCP_PREFIX}}save_task_attachment` using `filename: "collaboration-blueprint.md"`.
105
- - Use `{{MCP_PREFIX}}link_task_context` only for linking existing files/URLs (for example, shared docs under `docs/`).
105
+ - Use `{{MCP_PREFIX}}link_task_context` only for external http(s) URLs that should stay as references.
106
106
  6. Ask concise clarification questions only if required fields above are missing.
107
107
  7. If setting status to `task` or `on-hold`, add explicit comment justification using `{{MCP_PREFIX}}add_comment`.
108
108
  8. Never set `cancelled`, and never call `{{MCP_PREFIX}}archive_task`, unless explicitly instructed by the user.
@@ -106,12 +106,12 @@ content:
106
106
  - `### Next Step`
107
107
  4. Ask whether to save as `{artifacts.evaluationReport.path}`.
108
108
  5. If user confirms, persist task-specific content via `{{MCP_PREFIX}}save_task_attachment` using `filename: "evaluation.md"`.
109
- - Use `{{MCP_PREFIX}}link_task_context` only for linking existing files/URLs (for example, shared docs under `docs/`).
109
+ - Use `{{MCP_PREFIX}}link_task_context` only for external http(s) URLs that should stay as references.
110
110
  6. Never set `cancelled`, and never call `{{MCP_PREFIX}}archive_task`, unless explicitly instructed by the user.
111
111
 
112
112
  ## 3. Optional Report Artifact
113
113
 
114
114
  1. Use report files only when user opts in.
115
115
  2. Save to `task attachment "evaluation.md"` and attach to task context when approved.
116
- - If the document is not task-specific, store it under `docs/` and optionally link it with `{{MCP_PREFIX}}link_task_context`.
116
+ - If the document should become a shared durable document, save it through the canonical document/document-manager flow instead of a raw `docs/` file.
117
117
  3. Stop.
@@ -113,7 +113,7 @@ content:
113
113
  - `### Next Action`
114
114
  6. Ask whether to save as `{artifacts.implementationPlan.path}`.
115
115
  7. If user confirms, persist task-specific content via `{{MCP_PREFIX}}save_task_attachment` using `filename: "implementation-plan.md"`.
116
- - Use `{{MCP_PREFIX}}link_task_context` only for linking existing files/URLs (for example, shared docs under `docs/`).
116
+ - Use `{{MCP_PREFIX}}link_task_context` only for external http(s) URLs that should stay as references.
117
117
  8. If setting status to `task` or `on-hold`, add explicit comment justification using `{{MCP_PREFIX}}add_comment`.
118
118
  9. Never set `cancelled`, and never call `{{MCP_PREFIX}}archive_task`, unless explicitly instructed by the user.
119
119
  10. Print `prompts.handoffPrompt` and stop.
@@ -102,7 +102,7 @@ content:
102
102
  - `### Next Status`
103
103
  3. Ask whether to save as `{artifacts.reviewReport.path}`.
104
104
  4. If user confirms, persist task-specific content via `{{MCP_PREFIX}}save_task_attachment` using `filename: "review.md"`.
105
- - Use `{{MCP_PREFIX}}link_task_context` only for linking existing files/URLs (for example, shared docs under `docs/`).
105
+ - Use `{{MCP_PREFIX}}link_task_context` only for external http(s) URLs that should stay as references.
106
106
  5. Keep status within allowed statuses (`task`, `on-hold`, `in-progress`, `review`, `done`) unless user explicitly instructs otherwise.
107
107
  - If setting status to `task` or `on-hold`, add explicit comment justification using `{{MCP_PREFIX}}add_comment`.
108
108
  6. Never set `cancelled`, and never call `{{MCP_PREFIX}}archive_task`, unless explicitly instructed by the user.
@@ -111,5 +111,5 @@ content:
111
111
 
112
112
  1. Use report files only when user opts in.
113
113
  2. Save to `task attachment "review.md"` and attach to task context when approved.
114
- - If the document is not task-specific, store it under `docs/` and optionally link it with `{{MCP_PREFIX}}link_task_context`.
114
+ - If the document should become a shared durable document, save it through the canonical document/document-manager flow instead of a raw `docs/` file.
115
115
  3. Stop.
@@ -1 +0,0 @@
1
- import{r as n,j as e}from"./vendor-react-CKJs5o3c.js";import{p as T,u as C,v as w,w as S,t as s,x as M}from"./index-DXUdtH1B.js";import{h as L,B as A,k as I,aa as B,aI as H,aJ as D,b as R}from"./vendor-icons-I7ZwG1z_.js";import"./vendor-markdown-BUxTU7dS.js";import"./vendor-dnd-DRzYolkg.js";import"./vendor-router-BbWMxlnO.js";function F({workspaceId:h}){const[x,k]=n.useState([]),[j,y]=n.useState(!1),[c,P]=n.useState(null),[p,m]=n.useState(null),[d,g]=n.useState(null),N=n.useCallback(async()=>{if(h){y(!0);try{const a=await(await fetch(`/api/taskforce/workspace/assignee-options?workspaceId=${encodeURIComponent(h)}`,{credentials:"include"})).json().catch(()=>({})),t=Array.isArray(a?.assignees)?a.assignees.filter(i=>i.kind==="agent").map(i=>({id:String(i.value||""),name:String(i.label||i.value||"Unknown Agent"),username:String(i.username||i.value||""),icon:String(i.icon||"Bot"),color:String(i.color||"#6B7280"),kind:String(i.kind||"agent"),description:typeof i.description=="string"?i.description:null,role:typeof i.role=="string"?i.role:null,provider:typeof i.provider=="string"?i.provider:null,model:typeof i.model=="string"?i.model:null,surfaceType:T(i.surfaceType),createdAt:String(i.createdAt||""),updatedAt:String(i.updatedAt||i.createdAt||""),lastActiveAt:typeof i.lastActiveAt=="string"?i.lastActiveAt:null})):[];k(t)}finally{y(!1)}}},[h]);n.useEffect(()=>{N()},[N]);const f=n.useMemo(()=>{const r=new Map;for(const a of x){const t=C(a.surfaceType);r.has(t)||r.set(t,new Map);const i=r.get(t),v=a.name.toLowerCase();i.has(v)||i.set(v,[]),i.get(v).push(a)}return w.map(a=>({section:a,label:S(a),groups:Array.from(r.get(a)?.entries()||[]).map(([t,i])=>({groupId:`${a}:${t}`,section:a,sectionLabel:S(a),profiles:i,primaryProfile:i[0]}))})).filter(a=>a.groups.length>0)},[x]),o=n.useMemo(()=>f.flatMap(r=>r.groups),[f]),l=n.useMemo(()=>o.find(r=>r.groupId===d)||o[0]||null,[o,d]);n.useEffect(()=>{if(!o.length){d!==null&&g(null);return}(!d||!o.some(r=>r.groupId===d))&&g(o[0].groupId)},[o,d]);const b=async(r,a)=>{m(null);try{const t=await fetch("/api/taskforce/workspace/ai-profiles/merge",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({keepId:r,mergeId:a})}),i=await t.json().catch(()=>({}));if(!t.ok){m({type:"error",message:String(i?.error||"Failed to merge AI profiles.")});return}P(null),m({type:"success",message:"AI profiles merged."}),await N()}catch{m({type:"error",message:"Failed to merge AI profiles."})}},u=r=>{const a=String(r||"").trim();if(!a)return"Unknown";const t=Date.parse(a);return Number.isFinite(t)?new Date(t).toLocaleString(void 0,{dateStyle:"medium",timeStyle:"short"}):a};return e.jsx("div",{className:`${s.standalonePage} ${s.standaloneContent}`,style:{overflow:"auto"},children:e.jsx("div",{className:s.settingsContent,style:{maxWidth:1080,margin:"0 auto",width:"100%"},children:e.jsx("div",{className:s.settingGroup,children:e.jsxs("div",{children:[e.jsx("h4",{className:s.settingSubTitle,children:"Registered AI Profiles"}),e.jsx("p",{className:`${s.settingsHint} ${s.marginBottom12}`,children:"AI agents register profiles when connecting via MCP. Merge duplicates created when a token was lost."}),j&&e.jsxs("div",{className:s.settingsHint,children:[e.jsx(L,{size:13,className:s.spinner})," Loading profiles…"]}),!j&&x.length===0&&e.jsx("div",{className:s.settingsHint,children:"No AI profiles registered yet."}),!j&&f.length>0&&e.jsxs("div",{className:s.aiProfilesExplorer,children:[e.jsx("div",{className:s.aiProfilesListPane,children:e.jsx("div",{className:s.aiProfilesList,children:f.map(r=>e.jsxs("div",{className:s.aiProfilesSection,children:[e.jsx("div",{className:s.aiProfilesSectionHeader,children:r.label}),r.groups.map(a=>{const t=l?.groupId===a.groupId,i=a.primaryProfile;return e.jsxs("button",{type:"button",className:`${s.aiProfileGroup} ${a.profiles.length>1?s.aiProfileGroupDuplicate:""} ${t?s.aiProfileGroupSelected:""}`,onClick:()=>g(a.groupId),"aria-pressed":t,children:[e.jsxs("div",{className:s.aiProfileGroupHeader,children:[e.jsx(A,{size:13,style:{color:i.color}}),e.jsx("span",{className:s.aiProfileName,children:i.name}),a.profiles.length>1&&e.jsxs("span",{className:s.aiProfileDuplicateBadge,children:[e.jsx(I,{size:11})," ",a.profiles.length," duplicates"]})]}),e.jsxs("div",{className:s.settingsHint,style:{marginTop:6},children:["@",i.username]}),(i.surfaceType||i.role||i.provider||i.model)&&e.jsxs("div",{className:s.aiProfileMetaRow,children:[i.surfaceType&&e.jsx("span",{className:s.aiProfileSurfaceBadge,children:M(i.surfaceType)}),i.role&&e.jsx("span",{children:i.role}),i.provider&&e.jsx("span",{children:i.provider}),i.model&&e.jsx("span",{children:i.model})]}),i.description&&e.jsx("div",{className:s.settingsHint,style:{marginTop:4},children:i.description})]},a.groupId)})]},r.section))})}),l&&e.jsx("div",{className:s.aiProfileDetailPane,children:e.jsxs("div",{className:s.aiProfileDetailCard,children:[e.jsxs("div",{className:s.aiProfileDetailHero,children:[e.jsx("div",{className:s.aiProfileDetailIcon,style:{color:l.primaryProfile.color},children:e.jsx(A,{size:18})}),e.jsxs("div",{className:s.aiProfileDetailHeading,children:[e.jsx("div",{className:s.aiProfileDetailTitleRow,children:e.jsx("h5",{className:s.aiProfileDetailTitle,children:l.primaryProfile.name})}),e.jsxs("div",{className:s.aiProfileDetailMetaRow,children:[e.jsxs("span",{className:s.aiProfileDetailHandle,children:["@",l.primaryProfile.username]}),e.jsx("span",{className:s.aiProfileDetailSectionBadge,children:l.sectionLabel}),l.profiles.length>1&&e.jsxs("span",{className:s.aiProfileDetailLinkedCount,children:[l.profiles.length," linked"]})]})]})]}),l.primaryProfile.description&&e.jsx("div",{className:s.aiProfileDetailDescription,children:l.primaryProfile.description}),e.jsxs("div",{className:s.aiProfileDetailGrid,children:[e.jsxs("div",{className:s.aiProfileDetailStat,children:[e.jsxs("span",{className:s.aiProfileDetailStatLabel,children:[e.jsx(B,{size:12})," Role"]}),e.jsx("span",{className:s.aiProfileDetailStatValue,children:l.primaryProfile.role||"Not set"})]}),e.jsxs("div",{className:s.aiProfileDetailStat,children:[e.jsxs("span",{className:s.aiProfileDetailStatLabel,children:[e.jsx(H,{size:12})," Provider"]}),e.jsx("span",{className:s.aiProfileDetailStatValue,children:[l.primaryProfile.provider,l.primaryProfile.model].filter(Boolean).join(" · ")||"Not set"})]}),e.jsxs("div",{className:s.aiProfileDetailStat,children:[e.jsxs("span",{className:s.aiProfileDetailStatLabel,children:[e.jsx(D,{size:12})," Last active"]}),e.jsx("span",{className:s.aiProfileDetailStatValue,children:u(l.primaryProfile.lastActiveAt)})]}),e.jsxs("div",{className:s.aiProfileDetailStat,children:[e.jsxs("span",{className:s.aiProfileDetailStatLabel,children:[e.jsx(D,{size:12})," Updated"]}),e.jsx("span",{className:s.aiProfileDetailStatValue,children:u(l.primaryProfile.updatedAt)})]})]}),e.jsxs("div",{className:s.aiProfileInstanceSection,children:[e.jsxs("div",{className:s.aiProfileInstanceSectionHeader,children:[e.jsx("span",{children:"Profile instances"}),e.jsx("span",{className:s.settingsHint,children:"Choose a keeper here if duplicates need to be merged."})]}),e.jsx("div",{className:s.aiProfileInstanceList,children:l.profiles.map(r=>e.jsxs("div",{className:s.aiProfileInstanceCard,children:[e.jsxs("div",{className:s.aiProfileInstanceTopRow,children:[e.jsxs("div",{children:[e.jsxs("div",{className:s.aiProfileInstanceName,children:["@",r.username]}),e.jsx("div",{className:s.aiProfileIdChip,children:r.id})]}),l.profiles.length>1&&c?.keepId===r.id&&e.jsx("span",{className:s.aiProfileKeepBadge,children:"Keeping"})]}),e.jsxs("div",{className:s.aiProfileInstanceMeta,children:[e.jsxs("span",{children:["Created ",u(r.createdAt)]}),e.jsxs("span",{children:["Updated ",u(r.updatedAt)]})]}),l.profiles.length>1&&c?.keepId!==r.id&&e.jsx("button",{className:s.secondaryHeaderBtn,title:"Keep this profile, merge others into it",onClick:()=>{const a=l.profiles.find(t=>t.id!==r.id)?.id;a&&P({keepId:r.id,mergeId:a})},children:"Keep this"})]},r.id))}),c&&l.profiles.some(r=>r.id===c.keepId)&&e.jsxs("div",{className:s.aiProfileMergeActions,children:[e.jsx("button",{className:s.dangerBtn,onClick:()=>{b(c.keepId,c.mergeId)},children:"Merge duplicates"}),e.jsx("button",{className:s.secondaryHeaderBtn,onClick:()=>P(null),children:"Cancel"})]})]})]})})]}),p&&e.jsxs("div",{className:`${p.type==="success"?s.successMessage:s.errorMessage} ${s.marginTop12}`,children:[p.type==="success"?e.jsx(R,{size:14}):e.jsx(I,{size:14}),p.message]})]})})})})}export{F as AgentsModule};