@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,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
  }
@@ -1,8 +1,8 @@
1
- import React from 'react';
2
- import type { TaskItem, CategoryConfig, Comment, AttachmentItem, TaskAssignee, ChecklistItem, InitiativeItem } from '../../types';
3
- import type { TaxonomyDefinition } from '../../types';
4
- import { type TaskAssigneeOption } from '../../utils/assignees';
5
- import type { WorkstreamItem } from '../../types';
1
+ import React from "react";
2
+ import type { TaskItem, CategoryConfig, Comment, AttachmentItem, TaskAssignee, ChecklistItem, InitiativeItem } from "../../types";
3
+ import type { TaxonomyDefinition } from "../../types";
4
+ import { type TaskAssigneeOption } from "../../utils/assignees";
5
+ import type { WorkstreamItem } from "../../types";
6
6
  interface TaskFormProps {
7
7
  editingTaskId: string | null;
8
8
  error: string;
@@ -36,7 +36,7 @@ interface TaskFormProps {
36
36
  label: string;
37
37
  color?: string;
38
38
  icon?: string;
39
- status?: 'active' | 'retired';
39
+ status?: "active" | "retired";
40
40
  }[];
41
41
  priorities: Array<{
42
42
  value: number;
@@ -78,7 +78,7 @@ interface TaskFormProps {
78
78
  onShowMarkdownHelpChange: (value: boolean) => void;
79
79
  onShowChecklistChange?: (value: boolean) => void;
80
80
  onShowCommentsChange: (value: boolean) => void;
81
- onOpenSettings?: (section: 'categories' | 'types') => void;
81
+ onOpenSettings?: (section: "categories" | "types") => void;
82
82
  onSubmit: (e: React.FormEvent) => void;
83
83
  onAddComment: () => void;
84
84
  onAddContextFile: (file: AttachmentItem) => void;
@@ -89,7 +89,7 @@ interface TaskFormProps {
89
89
  onToggleReview?: (task: TaskItem) => void;
90
90
  onToggleComplete?: (task: TaskItem) => void;
91
91
  onToggleCancel?: (task: TaskItem) => void;
92
- onSetStatus?: (task: TaskItem, status: TaskItem['status']) => void;
92
+ onSetStatus?: (task: TaskItem, status: TaskItem["status"]) => void;
93
93
  onArchiveTask?: (task: TaskItem) => void;
94
94
  onUnarchive?: (taskId: string) => void;
95
95
  onOpenTaskById?: (taskId: string) => void;