@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
@@ -1,528 +1,6 @@
1
- import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useEffect, useMemo, useRef, useState } from 'react';
3
- import { AlertTriangle, Copy, Download, File, FileUp, Loader2, PencilLine, Trash2, ChevronDown, ChevronRight } from 'lucide-react';
4
- import styles from '../../Taskforce.module.css';
5
- import { dispatchOpenMarkdownDocument } from '../../utils/contextFiles';
6
- import { canOpenAnnotatedAttachment, dispatchOpenAnnotatedAttachment } from '../../utils/annotatedAttachments';
7
- import { dispatchTaskforceContextAssetsMutated } from '../../utils/contextAssetEvents';
8
- import { getDocumentReferenceLabel } from '../../utils/documentReferences';
9
- const ACCEPTED_CONTEXT_FILE_TYPES = [
10
- '.png', '.jpg', '.jpeg', '.webp', '.gif',
11
- '.pdf', '.txt', '.md', '.csv', '.json', '.doc', '.docx',
12
- '.html', '.js', '.ts', '.tsx', '.css', '.py', '.java', '.go', '.rs', '.sh'
13
- ].join(',');
14
- const SUPPORTED_CLIPBOARD_IMAGE_TYPES = new Set(['image/png', 'image/jpeg', 'image/webp']);
15
- const ACCEPTED_CONTEXT_EXTENSIONS = new Set(ACCEPTED_CONTEXT_FILE_TYPES.split(',').map((ext) => ext.trim().toLowerCase()));
16
- const MAX_CONTEXT_FILE_SIZE_BYTES = 10 * 1024 * 1024; // 10 MB per file
17
- const CONTEXT_NOTICE_TIMEOUT_MS = 3500;
18
- function getFileExtension(fileName) {
19
- const trimmed = fileName.trim().toLowerCase();
20
- const dotIdx = trimmed.lastIndexOf('.');
21
- if (dotIdx === -1)
22
- return '';
23
- return trimmed.slice(dotIdx);
24
- }
25
- function formatFileList(fileNames) {
26
- if (fileNames.length === 0)
27
- return '';
28
- const shown = fileNames.slice(0, 3).join(', ');
29
- const extra = fileNames.length - 3;
30
- return extra > 0 ? `${shown}, +${extra} more` : shown;
31
- }
32
- function getLocalFileFingerprint(file) {
33
- return `${file.name.trim().toLowerCase()}::${file.size}::${file.lastModified}`;
34
- }
35
- function readFileAsDataUrl(file) {
36
- return new Promise((resolve, reject) => {
37
- const reader = new FileReader();
38
- reader.onload = () => resolve(String(reader.result || ''));
39
- reader.onerror = () => reject(reader.error || new Error('Failed to read file'));
40
- reader.readAsDataURL(file);
41
- });
42
- }
43
- function isImagePath(path) {
44
- return /\.(png|jpe?g|webp|gif)(\?|#|$)/i.test(path);
45
- }
46
- function getClipboardImageType(item) {
47
- const rawTypes = item.types;
48
- if (!rawTypes)
49
- return null;
50
- for (const type of Array.from(rawTypes)) {
51
- const normalizedType = String(type || '').trim().toLowerCase();
52
- if (SUPPORTED_CLIPBOARD_IMAGE_TYPES.has(normalizedType)) {
53
- return normalizedType;
54
- }
55
- }
56
- return null;
57
- }
58
- function buildDownloadUrl(pathValue, displayName) {
59
- const separator = pathValue.includes('?') ? '&' : '?';
60
- return `${pathValue}${separator}download=1&filename=${encodeURIComponent(displayName)}`;
61
- }
62
- function getAttachmentDisplayName(item) {
63
- if (typeof item === 'string')
64
- return item.split('/').pop() || 'Context file';
65
- return item.displayName || item.originalFilename || item.caption || item.fsPath || item.path.split('/').pop() || 'Context file';
66
- }
67
- function getAttachmentTypeLabel(item) {
68
- const candidates = typeof item === 'string'
69
- ? [item]
70
- : [item.originalFilename, item.displayName, item.caption, item.fsPath, item.path];
71
- for (const candidate of candidates) {
72
- if (!candidate)
73
- continue;
74
- const ext = getFileExtension(candidate);
75
- if (ext)
76
- return ext.replace('.', '').slice(0, 5).toUpperCase();
77
- }
78
- const path = typeof item === 'string' ? item : item.path;
79
- return /^https?:\/\//i.test(path) ? 'LINK' : 'FILE';
80
- }
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { ContextAttachmentManager } from '../context/ContextAttachmentManager';
81
3
  export function TaskContextUpload(props) {
82
- const { taskId, taskReferenceLabel, workspaceId, contextFiles, onAddContextFile, onRemoveContextFile, onUpdateContextCaption } = props;
83
- const inputRef = useRef(null);
84
- const [uploading, setUploading] = useState(false);
85
- const [uploadError, setUploadError] = useState(null);
86
- const [linkValue, setLinkValue] = useState('');
87
- const [linkError, setLinkError] = useState(null);
88
- const [contextNotice, setContextNotice] = useState(null);
89
- const [showContextUpload, setShowContextUpload] = useState(false);
90
- const [isDropActive, setIsDropActive] = useState(false);
91
- const [dragDepth, setDragDepth] = useState(0);
92
- const contextKeyRef = useRef(new Set());
93
- const localUploadFingerprintRef = useRef(new Set());
94
- const normalizeKey = (value) => (value || '').trim();
95
- const getContextKeys = (path, fsPath) => {
96
- const keys = [];
97
- const normalizedPath = normalizeKey(path);
98
- const normalizedFsPath = normalizeKey(fsPath);
99
- if (normalizedPath)
100
- keys.push(`path:${normalizedPath}`);
101
- if (normalizedFsPath)
102
- keys.push(`fs:${normalizedFsPath}`);
103
- return keys;
104
- };
105
- const keySetFromFiles = useMemo(() => {
106
- const next = new Set();
107
- contextFiles.forEach((item) => {
108
- if (typeof item === 'string') {
109
- getContextKeys(item).forEach((key) => next.add(key));
110
- return;
111
- }
112
- getContextKeys(item.path, item.fsPath).forEach((key) => next.add(key));
113
- });
114
- return next;
115
- }, [contextFiles]);
116
- useEffect(() => {
117
- contextKeyRef.current = new Set(keySetFromFiles);
118
- }, [keySetFromFiles]);
119
- const hasAnyKey = (set, keys) => keys.some((key) => set.has(key));
120
- const addKeys = (set, keys) => keys.forEach((key) => set.add(key));
121
- const trimmedWorkspaceId = String(workspaceId || '').trim();
122
- const buildApiHeaders = (contentType = 'application/json') => {
123
- const headers = { 'Content-Type': contentType };
124
- if (trimmedWorkspaceId)
125
- headers['x-taskforce-workspace-id'] = trimmedWorkspaceId;
126
- return headers;
127
- };
128
- const addLink = (rawValue, clearInput = true, contextKeySet = contextKeyRef.current) => {
129
- const trimmed = rawValue.trim();
130
- if (!trimmed)
131
- return 'invalid';
132
- const isHttp = /^https?:\/\//i.test(trimmed);
133
- if (!isHttp)
134
- return 'invalid';
135
- const normalizedPath = trimmed;
136
- const keys = getContextKeys(normalizedPath);
137
- if (hasAnyKey(contextKeySet, keys))
138
- return 'duplicate';
139
- const nameFromPath = trimmed.split(/[\\/]/).pop() || trimmed;
140
- onAddContextFile({
141
- path: normalizedPath,
142
- caption: nameFromPath,
143
- timestamp: new Date().toISOString()
144
- });
145
- addKeys(contextKeySet, keys);
146
- if (clearInput)
147
- setLinkValue('');
148
- setLinkError(null);
149
- return 'added';
150
- };
151
- useEffect(() => {
152
- if (!contextNotice)
153
- return;
154
- const timeoutId = window.setTimeout(() => {
155
- setContextNotice(null);
156
- }, CONTEXT_NOTICE_TIMEOUT_MS);
157
- return () => window.clearTimeout(timeoutId);
158
- }, [contextNotice]);
159
- const handleSelectedFiles = async (selectedFilesInput) => {
160
- if (selectedFilesInput.length === 0)
161
- return;
162
- setUploadError(null);
163
- setContextNotice(null);
164
- const selectedFiles = selectedFilesInput;
165
- const unsupportedFiles = [];
166
- const oversizedFiles = [];
167
- const localDuplicateFiles = [];
168
- const uploadCandidates = [];
169
- const localFingerprintSet = new Set(localUploadFingerprintRef.current);
170
- selectedFiles.forEach((file) => {
171
- const ext = getFileExtension(file.name);
172
- if (!ACCEPTED_CONTEXT_EXTENSIONS.has(ext)) {
173
- unsupportedFiles.push(file.name);
174
- return;
175
- }
176
- if (file.size > MAX_CONTEXT_FILE_SIZE_BYTES) {
177
- oversizedFiles.push(file.name);
178
- return;
179
- }
180
- const fingerprint = getLocalFileFingerprint(file);
181
- if (localFingerprintSet.has(fingerprint)) {
182
- localDuplicateFiles.push(file.name);
183
- return;
184
- }
185
- localFingerprintSet.add(fingerprint);
186
- uploadCandidates.push({ file, fingerprint });
187
- });
188
- const validationNotices = [];
189
- if (unsupportedFiles.length > 0) {
190
- validationNotices.push(`${unsupportedFiles.length} unsupported file${unsupportedFiles.length === 1 ? '' : 's'} skipped: ${formatFileList(unsupportedFiles)}.`);
191
- }
192
- if (oversizedFiles.length > 0) {
193
- validationNotices.push(`${oversizedFiles.length} file${oversizedFiles.length === 1 ? '' : 's'} over 10 MB skipped: ${formatFileList(oversizedFiles)}.`);
194
- }
195
- if (localDuplicateFiles.length > 0) {
196
- validationNotices.push(`${localDuplicateFiles.length} local duplicate file${localDuplicateFiles.length === 1 ? '' : 's'} skipped before upload: ${formatFileList(localDuplicateFiles)}.`);
197
- }
198
- if (uploadCandidates.length === 0) {
199
- if (validationNotices.length > 0)
200
- setContextNotice(validationNotices.join(' '));
201
- if (inputRef.current)
202
- inputRef.current.value = '';
203
- return;
204
- }
205
- setUploading(true);
206
- const contextKeySet = new Set(contextKeyRef.current);
207
- let duplicateCount = 0;
208
- try {
209
- for (const { file, fingerprint } of uploadCandidates) {
210
- let data = null;
211
- // Keep uploads same-origin so local runtime never routes attachments through the cloud API base.
212
- const initRes = await fetch('/api/taskforce/context-upload/init', {
213
- method: 'POST',
214
- headers: buildApiHeaders(),
215
- body: JSON.stringify({
216
- originalName: file.name,
217
- mimeType: file.type || 'application/octet-stream',
218
- size: file.size,
219
- taskId: taskId || null,
220
- workspaceId: trimmedWorkspaceId || null
221
- })
222
- });
223
- if (initRes.ok) {
224
- const initData = await initRes.json();
225
- if (initData?.success && typeof initData?.uploadUrl === 'string' && typeof initData?.path === 'string') {
226
- const uploadRes = await fetch(initData.uploadUrl, {
227
- method: String(initData.method || 'PUT'),
228
- headers: initData.headers || { 'Content-Type': file.type || 'application/octet-stream' },
229
- body: file
230
- });
231
- if (!uploadRes.ok) {
232
- throw new Error(`Upload failed for ${file.name}`);
233
- }
234
- const finalizeRes = await fetch('/api/taskforce/context-upload/finalize', {
235
- method: 'POST',
236
- headers: buildApiHeaders(),
237
- body: JSON.stringify({
238
- relativePath: initData.relativePath,
239
- mimeType: file.type || 'application/octet-stream',
240
- originalName: file.name,
241
- size: file.size,
242
- taskId: taskId || null,
243
- workspaceId: trimmedWorkspaceId || null
244
- })
245
- });
246
- if (!finalizeRes.ok) {
247
- const finalizeError = await finalizeRes.json().catch(() => ({}));
248
- throw new Error(finalizeError?.error || `Upload failed for ${file.name}`);
249
- }
250
- data = await finalizeRes.json().catch(() => null);
251
- }
252
- else if (initData?.success && typeof initData?.path === 'string') {
253
- data = initData;
254
- }
255
- }
256
- if (!data) {
257
- const encoded = await readFileAsDataUrl(file);
258
- const res = await fetch('/api/taskforce/context-upload', {
259
- method: 'POST',
260
- headers: buildApiHeaders(),
261
- body: JSON.stringify({
262
- file: encoded,
263
- originalName: file.name,
264
- taskId: taskId || null,
265
- workspaceId: trimmedWorkspaceId || null
266
- })
267
- });
268
- if (!res.ok) {
269
- throw new Error(`Upload failed for ${file.name}`);
270
- }
271
- data = await res.json();
272
- }
273
- if (!data?.success || !data?.path) {
274
- throw new Error(`Upload failed for ${file.name}`);
275
- }
276
- const keys = getContextKeys(data.path, data.fsPath);
277
- if (hasAnyKey(contextKeySet, keys)) {
278
- duplicateCount += 1;
279
- continue;
280
- }
281
- onAddContextFile({
282
- path: data.path,
283
- fsPath: data.fsPath,
284
- caption: typeof data.caption === 'string' && data.caption.trim().length > 0 ? data.caption : file.name,
285
- displayName: typeof data.displayName === 'string' ? data.displayName : undefined,
286
- originalFilename: typeof data.originalFilename === 'string' ? data.originalFilename : file.name,
287
- assetId: typeof data.assetId === 'string' ? data.assetId : undefined,
288
- referenceNumber: typeof data.referenceNumber === 'number' ? data.referenceNumber : null,
289
- referenceLabel: typeof data.referenceLabel === 'string' ? data.referenceLabel : undefined,
290
- taskId: typeof data.taskId === 'string' ? data.taskId : null,
291
- timestamp: new Date().toISOString()
292
- });
293
- dispatchTaskforceContextAssetsMutated({
294
- workspaceId: trimmedWorkspaceId || 'default',
295
- taskId: taskId || null,
296
- reason: 'upload'
297
- });
298
- addKeys(contextKeySet, keys);
299
- localUploadFingerprintRef.current.add(fingerprint);
300
- }
301
- const notices = [...validationNotices];
302
- if (duplicateCount > 0) {
303
- notices.push(`${duplicateCount} duplicate file${duplicateCount === 1 ? '' : 's'} skipped.`);
304
- }
305
- setContextNotice(notices.length > 0 ? notices.join(' ') : null);
306
- contextKeyRef.current = contextKeySet;
307
- }
308
- catch (error) {
309
- setUploadError(error instanceof Error ? error.message : 'Failed to upload context file');
310
- }
311
- finally {
312
- setUploading(false);
313
- if (inputRef.current)
314
- inputRef.current.value = '';
315
- }
316
- };
317
- const handleFilesSelected = async (files) => {
318
- if (!files || files.length === 0)
319
- return;
320
- await handleSelectedFiles(Array.from(files));
321
- };
322
- const handlePasteImage = async () => {
323
- setUploadError(null);
324
- setContextNotice(null);
325
- if (!navigator.clipboard || typeof navigator.clipboard.read !== 'function') {
326
- setUploadError('Clipboard image paste is not available in this browser.');
327
- return;
328
- }
329
- try {
330
- const clipboardItems = await navigator.clipboard.read();
331
- const imageFiles = [];
332
- for (const item of clipboardItems) {
333
- const imageType = getClipboardImageType(item);
334
- if (!imageType)
335
- continue;
336
- const blob = await item.getType(imageType);
337
- const extension = imageType.toLowerCase() === 'image/png'
338
- ? 'png'
339
- : imageType.toLowerCase() === 'image/webp'
340
- ? 'webp'
341
- : 'jpg';
342
- imageFiles.push(new globalThis.File([blob], `pasted-image-${Date.now()}.${extension}`, { type: imageType }));
343
- }
344
- if (imageFiles.length === 0) {
345
- setUploadError('Clipboard does not currently contain a supported image.');
346
- return;
347
- }
348
- await handleSelectedFiles(imageFiles);
349
- }
350
- catch (error) {
351
- setUploadError(error?.message || 'Failed to read an image from the clipboard.');
352
- }
353
- };
354
- const parseDroppedLinks = (event) => {
355
- const droppedLinks = new Set();
356
- const rawUriList = event.dataTransfer.getData('text/uri-list') || '';
357
- const rawText = event.dataTransfer.getData('text/plain') || '';
358
- const candidates = `${rawUriList}\n${rawText}`
359
- .split('\n')
360
- .map((line) => line.trim())
361
- .filter((line) => !!line && !line.startsWith('#'));
362
- for (const candidate of candidates) {
363
- if (/^file:\/\//i.test(candidate)) {
364
- try {
365
- const fileUrl = new URL(candidate);
366
- const fsPath = decodeURIComponent(fileUrl.pathname || '').trim();
367
- if (fsPath)
368
- droppedLinks.add(fsPath);
369
- }
370
- catch {
371
- // Ignore malformed file URL drops
372
- }
373
- continue;
374
- }
375
- droppedLinks.add(candidate);
376
- }
377
- return Array.from(droppedLinks);
378
- };
379
- const handleDrop = (event) => {
380
- event.preventDefault();
381
- event.stopPropagation();
382
- setIsDropActive(false);
383
- setDragDepth(0);
384
- setUploadError(null);
385
- setLinkError(null);
386
- setContextNotice(null);
387
- if (event.dataTransfer.files && event.dataTransfer.files.length > 0) {
388
- void handleFilesSelected(event.dataTransfer.files);
389
- return;
390
- }
391
- const droppedLinks = parseDroppedLinks(event);
392
- if (droppedLinks.length === 0) {
393
- setLinkError('Drop a file or URL.');
394
- return;
395
- }
396
- const contextKeySet = new Set(contextKeyRef.current);
397
- let duplicateCount = 0;
398
- let addedCount = 0;
399
- let invalidCount = 0;
400
- droppedLinks.forEach((link) => {
401
- const result = addLink(link, false, contextKeySet);
402
- if (result === 'duplicate')
403
- duplicateCount += 1;
404
- if (result === 'added')
405
- addedCount += 1;
406
- if (result === 'invalid')
407
- invalidCount += 1;
408
- });
409
- const notices = [];
410
- if (duplicateCount > 0) {
411
- notices.push(`${duplicateCount} duplicate link${duplicateCount === 1 ? '' : 's'} skipped.`);
412
- }
413
- if (invalidCount > 0) {
414
- notices.push(`${invalidCount} local path${invalidCount === 1 ? '' : 's'} skipped. Upload files to attach them, or drop an http(s) URL to link.`);
415
- }
416
- setContextNotice(notices.length > 0 ? notices.join(' ') : (addedCount > 0 ? null : contextNotice));
417
- contextKeyRef.current = contextKeySet;
418
- };
419
- const handleDragEnter = (event) => {
420
- event.preventDefault();
421
- event.stopPropagation();
422
- setDragDepth((depth) => depth + 1);
423
- setIsDropActive(true);
424
- };
425
- const handleDragLeave = (event) => {
426
- event.preventDefault();
427
- event.stopPropagation();
428
- setDragDepth((depth) => {
429
- const nextDepth = Math.max(0, depth - 1);
430
- if (nextDepth === 0)
431
- setIsDropActive(false);
432
- return nextDepth;
433
- });
434
- };
435
- const handleDragOver = (event) => {
436
- event.preventDefault();
437
- event.stopPropagation();
438
- event.dataTransfer.dropEffect = 'copy';
439
- };
440
- const imageFiles = contextFiles.filter((item) => {
441
- const path = typeof item === 'string' ? item : item.path;
442
- return isImagePath(path);
443
- });
444
- const documentFiles = contextFiles.filter((item) => {
445
- const path = typeof item === 'string' ? item : item.path;
446
- return !isImagePath(path);
447
- });
448
- return (_jsxs("div", { className: styles.specialistSection, children: [_jsxs("div", { className: styles.toggleHeading, onClick: () => setShowContextUpload(!showContextUpload), title: showContextUpload ? 'Hide context documents' : 'Show context documents', children: [_jsxs("label", { className: styles.label, children: ["Context Documents ", contextFiles.length > 0 && `(${contextFiles.length})`] }), showContextUpload ? _jsx(ChevronDown, { size: 14 }) : _jsx(ChevronRight, { size: 14 })] }), showContextUpload && (_jsxs(_Fragment, { children: [_jsx("p", { className: styles.settingsHint, children: "Upload files into task context storage, or add an external http(s) URL." }), _jsxs("div", { className: styles.contextUploadPanel, children: [_jsxs("div", { className: styles.contextUploadActions, children: [_jsxs("button", { type: "button", className: styles.secondaryHeaderBtn, onClick: () => inputRef.current?.click(), disabled: uploading, children: [uploading ? _jsx(Loader2, { size: 12, className: styles.spinner }) : _jsx(FileUp, { size: 12 }), uploading ? 'Uploading...' : 'Upload File'] }), _jsxs("button", { type: "button", className: styles.secondaryHeaderBtn, onClick: () => {
449
- void handlePasteImage();
450
- }, disabled: uploading, children: [_jsx(Copy, { size: 12 }), "Paste Image from Clipboard"] })] }), _jsx("input", { ref: inputRef, type: "file", accept: ACCEPTED_CONTEXT_FILE_TYPES, multiple: true, className: styles.hiddenInput, onChange: (e) => {
451
- void handleFilesSelected(e.target.files);
452
- } }), uploadError && _jsx("div", { className: styles.error, children: uploadError }), _jsxs("div", { className: styles.contextLinkRow, children: [_jsx("input", { type: "text", className: styles.input, placeholder: "Add external URL (https://...)", value: linkValue, onChange: (e) => {
453
- setLinkValue(e.target.value);
454
- if (linkError)
455
- setLinkError(null);
456
- if (contextNotice)
457
- setContextNotice(null);
458
- } }), _jsx("button", { type: "button", className: styles.secondaryHeaderBtn, onClick: () => {
459
- if (!linkValue.trim()) {
460
- setLinkError('Enter an http(s) URL to link.');
461
- return;
462
- }
463
- const result = addLink(linkValue, true);
464
- if (result === 'invalid') {
465
- setLinkError('Only external http(s) URLs can be linked here. Upload files to attach them.');
466
- return;
467
- }
468
- if (result === 'duplicate') {
469
- setContextNotice('Link already exists in task context.');
470
- }
471
- else if (result === 'added') {
472
- setContextNotice(null);
473
- }
474
- }, children: "Add URL" })] }), _jsxs("div", { className: `${styles.contextDropzone} ${isDropActive ? styles.contextDropzoneActive : ''}`, onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, onDragOver: handleDragOver, onDrop: handleDrop, children: [_jsx(FileUp, { size: 14 }), _jsx("span", { children: "Drop files or URLs here" })] })] }), contextNotice && _jsx("div", { className: styles.contextNotice, children: contextNotice }), linkError && _jsx("div", { className: styles.error, children: linkError }), imageFiles.length > 0 && (_jsx("div", { className: styles.attachmentGrid, children: contextFiles.map((item, idx) => {
475
- const path = typeof item === 'string' ? item : item.path;
476
- if (!isImagePath(path))
477
- return null;
478
- const fsPath = typeof item === 'string' ? undefined : item.fsPath;
479
- const caption = typeof item === 'string' ? '' : item.caption || '';
480
- const displayName = getAttachmentDisplayName(item);
481
- const isImage = isImagePath(path);
482
- const isExternalUrl = /^https?:\/\//i.test(path);
483
- const canAnnotate = canOpenAnnotatedAttachment(item, { taskId });
484
- return (_jsxs("div", { className: styles.attachmentCard, children: [_jsxs("div", { className: styles.attachmentPreviewContainer, children: [isImage ? (_jsx("img", { src: path, alt: caption || `Context file ${idx}`, onClick: () => {
485
- if (dispatchOpenAnnotatedAttachment(item, { taskId, taskReferenceLabel }))
486
- return;
487
- window.open(path, '_blank');
488
- }, onError: (e) => {
489
- e.target.style.display = 'none';
490
- e.target.parentElement.classList.add(styles.brokenImage);
491
- } })) : (_jsxs("button", { type: "button", className: styles.contextFileLink, onClick: () => {
492
- if (dispatchOpenMarkdownDocument(item, fsPath))
493
- return;
494
- window.open(path, '_blank');
495
- }, title: "Open file", children: [_jsx(FileUp, { size: 16 }), _jsx("span", { children: caption || fsPath || path.split('/').pop() || 'Context file' })] })), _jsxs("div", { className: styles.brokenImagePlaceholder, children: [_jsx(AlertTriangle, { size: 16 }), _jsx("span", { children: "Preview unavailable" })] }), _jsxs("div", { className: styles.attachmentActions, children: [canAnnotate && (_jsx("button", { type: "button", className: styles.attachmentActionBtn, onClick: (e) => {
496
- e.stopPropagation();
497
- dispatchOpenAnnotatedAttachment(item, { taskId, taskReferenceLabel });
498
- }, title: "Annotate", children: _jsx(PencilLine, { size: 12 }) })), fsPath && (_jsx("button", { type: "button", className: styles.attachmentActionBtn, onClick: (e) => {
499
- e.stopPropagation();
500
- navigator.clipboard.writeText(fsPath);
501
- }, title: `Copy path: ${fsPath}`, children: _jsx(Copy, { size: 12 }) })), !isExternalUrl && (_jsx("button", { type: "button", className: styles.attachmentActionBtn, onClick: (e) => {
502
- e.stopPropagation();
503
- window.open(buildDownloadUrl(path, caption || displayName), '_blank');
504
- }, title: "Download", children: _jsx(Download, { size: 12 }) })), _jsx("button", { type: "button", className: styles.attachmentActionBtn, onClick: (e) => {
505
- e.stopPropagation();
506
- onRemoveContextFile(idx);
507
- }, title: "Delete", children: _jsx(Trash2, { size: 12 }) })] })] }), _jsx("input", { type: "text", className: styles.attachmentCaptionInput, placeholder: "Add a label...", value: caption, onChange: (e) => onUpdateContextCaption(idx, e.target.value) })] }, idx));
508
- }) })), documentFiles.length > 0 && (_jsx("div", { className: styles.documentAttachmentList, children: contextFiles.map((item, idx) => {
509
- const path = typeof item === 'string' ? item : item.path;
510
- if (isImagePath(path))
511
- return null;
512
- const fsPath = typeof item === 'string' ? undefined : item.fsPath;
513
- const caption = typeof item === 'string' ? '' : item.caption || '';
514
- const displayName = getAttachmentDisplayName(item);
515
- const fileType = getAttachmentTypeLabel(item);
516
- const documentReferenceLabel = typeof item === 'string' ? '' : getDocumentReferenceLabel(item);
517
- const isExternalUrl = /^https?:\/\//i.test(path);
518
- return (_jsxs("div", { className: styles.documentAttachmentItem, children: [_jsxs("div", { className: styles.documentAttachmentRow, children: [_jsxs("button", { type: "button", className: styles.documentAttachmentLink, onClick: () => {
519
- if (dispatchOpenMarkdownDocument(item, fsPath))
520
- return;
521
- window.open(path, '_blank');
522
- }, title: displayName, children: [_jsxs("span", { className: styles.documentAttachmentMain, children: [_jsx("span", { className: styles.documentAttachmentIcon, "aria-hidden": "true", children: _jsx(File, { size: 13 }) }), _jsxs("span", { className: styles.documentAttachmentText, children: [_jsx("span", { className: styles.documentAttachmentName, children: displayName }), documentReferenceLabel && (_jsx("span", { className: styles.taskIdBadge, children: documentReferenceLabel }))] })] }), _jsx("span", { className: styles.documentAttachmentType, children: fileType })] }), _jsxs("div", { className: styles.documentAttachmentActions, children: [fsPath && (_jsx("button", { type: "button", className: styles.documentAttachmentActionBtn, onClick: () => {
523
- navigator.clipboard.writeText(fsPath);
524
- }, title: `Copy path: ${fsPath}`, children: _jsx(Copy, { size: 12 }) })), !isExternalUrl && (_jsx("button", { type: "button", className: styles.documentAttachmentActionBtn, onClick: () => {
525
- window.open(buildDownloadUrl(path, caption || displayName), '_blank');
526
- }, title: "Download", children: _jsx(Download, { size: 12 }) })), _jsx("button", { type: "button", className: styles.documentAttachmentActionBtn, onClick: () => onRemoveContextFile(idx), title: "Delete", children: _jsx(Trash2, { size: 12 }) })] })] }), _jsx("input", { type: "text", className: styles.documentAttachmentCaptionInput, placeholder: "Add a label...", value: caption, onChange: (e) => onUpdateContextCaption(idx, e.target.value) })] }, idx));
527
- }) }))] }))] }));
4
+ const { taskId, taskReferenceLabel, workspaceId, apiBaseUrl, contextFiles, onAddContextFile, onRemoveContextFile, onUpdateContextCaption, } = props;
5
+ return (_jsx(ContextAttachmentManager, { ownerType: "task", ownerId: taskId, ownerReferenceLabel: taskReferenceLabel, workspaceId: workspaceId, apiBaseUrl: apiBaseUrl, attachments: contextFiles, onAddAttachment: onAddContextFile, onRemoveAttachment: onRemoveContextFile, onUpdateAttachmentCaption: onUpdateContextCaption }));
528
6
  }
@@ -32,11 +32,11 @@ describe('TaskContextUpload drag and drop', () => {
32
32
  const renderUpload = (contextFiles = [], taskId, extraProps) => render(_jsx(TaskContextUpload, { taskId: taskId, contextFiles: contextFiles, onAddContextFile: onAddContextFile, onRemoveContextFile: onRemoveContextFile, onUpdateContextCaption: onUpdateContextCaption, ...extraProps }));
33
33
  const openSection = async (user) => {
34
34
  const localUser = user ?? userEvent.setup();
35
- const showToggle = screen.queryByTitle('Show context documents');
36
- if (showToggle) {
35
+ if (!screen.queryByText('Drop files or URLs here')) {
36
+ const showToggle = await screen.findByTitle('Show context documents');
37
37
  await localUser.click(showToggle);
38
38
  }
39
- return screen.getByText('Drop files or URLs here');
39
+ return screen.findByText('Drop files or URLs here');
40
40
  };
41
41
  beforeEach(() => {
42
42
  vi.clearAllMocks();