@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
@@ -17,6 +17,8 @@ describe('Workflow export snapshots', () => {
17
17
  for (const workflowName of workflowNames) {
18
18
  it(`${envId}/${workflowName} export snapshot`, () => {
19
19
  const result = engine.processTemplate(workflowName, envId);
20
+ expect(result.content).not.toContain('shared docs under `docs/`');
21
+ expect(result.content).not.toContain('store it under `docs/`');
20
22
  expect({
21
23
  filename: result.filename,
22
24
  strategy: result.strategy,
@@ -0,0 +1,5 @@
1
+ export declare const AI_PROFILE_SEAT_SCOPES: readonly ["cloud_metered", "local_unmetered"];
2
+ export type AiProfileSeatScope = typeof AI_PROFILE_SEAT_SCOPES[number];
3
+ export declare function isAiProfileSeatScope(value: unknown): value is AiProfileSeatScope;
4
+ export declare function parseAiProfileSeatScope(value: unknown): AiProfileSeatScope | null;
5
+ export declare function formatAiProfileSeatScopeLabel(value: AiProfileSeatScope): string;
@@ -0,0 +1,21 @@
1
+ export const AI_PROFILE_SEAT_SCOPES = [
2
+ 'cloud_metered',
3
+ 'local_unmetered',
4
+ ];
5
+ const AI_PROFILE_SEAT_SCOPE_LABELS = {
6
+ cloud_metered: 'Cloud MCP',
7
+ local_unmetered: 'Local MCP',
8
+ };
9
+ export function isAiProfileSeatScope(value) {
10
+ return typeof value === 'string'
11
+ && AI_PROFILE_SEAT_SCOPES.includes(value);
12
+ }
13
+ export function parseAiProfileSeatScope(value) {
14
+ if (typeof value !== 'string')
15
+ return null;
16
+ const normalized = value.trim();
17
+ return isAiProfileSeatScope(normalized) ? normalized : null;
18
+ }
19
+ export function formatAiProfileSeatScopeLabel(value) {
20
+ return AI_PROFILE_SEAT_SCOPE_LABELS[value];
21
+ }
@@ -1,4 +1,4 @@
1
- export declare const AI_PROFILE_SURFACE_TYPES: readonly ["chat_app", "ide", "coding_tool", "agent", "other"];
1
+ export declare const AI_PROFILE_SURFACE_TYPES: readonly ["chat_app", "ide", "cli", "coding_tool", "agent"];
2
2
  export type AiProfileSurfaceType = typeof AI_PROFILE_SURFACE_TYPES[number];
3
3
  export type AiProfileSurfaceTypeSection = AiProfileSurfaceType | 'unclassified';
4
4
  export declare const AI_PROFILE_SURFACE_TYPE_SECTION_ORDER: AiProfileSurfaceTypeSection[];
@@ -1,31 +1,31 @@
1
1
  export const AI_PROFILE_SURFACE_TYPES = [
2
2
  'chat_app',
3
3
  'ide',
4
+ 'cli',
4
5
  'coding_tool',
5
- 'agent',
6
- 'other'
6
+ 'agent'
7
7
  ];
8
8
  export const AI_PROFILE_SURFACE_TYPE_SECTION_ORDER = [
9
9
  'chat_app',
10
10
  'ide',
11
+ 'cli',
11
12
  'coding_tool',
12
13
  'agent',
13
- 'other',
14
14
  'unclassified'
15
15
  ];
16
16
  const AI_PROFILE_SURFACE_TYPE_LABELS = {
17
- chat_app: 'Chat app',
17
+ chat_app: 'Chat App',
18
18
  ide: 'IDE',
19
- coding_tool: 'Coding tool',
20
- agent: 'Agent',
21
- other: 'Other'
19
+ cli: 'CLI',
20
+ coding_tool: 'Coding Tool',
21
+ agent: 'Agent'
22
22
  };
23
23
  const AI_PROFILE_SURFACE_TYPE_SECTION_LABELS = {
24
24
  chat_app: 'Chat Apps',
25
25
  ide: 'IDEs',
26
+ cli: 'CLI',
26
27
  coding_tool: 'Coding Tools',
27
28
  agent: 'Agents',
28
- other: 'Other',
29
29
  unclassified: 'Unclassified'
30
30
  };
31
31
  export function isAiProfileSurfaceType(value) {
@@ -36,6 +36,8 @@ export function parseAiProfileSurfaceType(value) {
36
36
  if (typeof value !== 'string')
37
37
  return null;
38
38
  const normalized = value.trim();
39
+ if (normalized === 'other')
40
+ return 'agent';
39
41
  return isAiProfileSurfaceType(normalized) ? normalized : null;
40
42
  }
41
43
  export function formatAiProfileSurfaceTypeLabel(surfaceType) {
@@ -0,0 +1,13 @@
1
+ export declare const MIN_PASSWORD_LENGTH = 12;
2
+ export type PasswordPolicyCode = 'PASSWORD_REQUIRED' | 'PASSWORD_TOO_SHORT' | 'PASSWORD_TOO_COMMON' | 'PASSWORD_CONTAINS_PERSONAL_INFO';
3
+ export interface PasswordPolicyResult {
4
+ ok: boolean;
5
+ code?: PasswordPolicyCode;
6
+ message?: string;
7
+ }
8
+ export interface PasswordPolicyContext {
9
+ email?: string | null;
10
+ displayName?: string | null;
11
+ }
12
+ export declare function getPasswordPolicyGuidance(): string[];
13
+ export declare function validatePasswordPolicy(password: string, context?: PasswordPolicyContext): PasswordPolicyResult;
@@ -0,0 +1,84 @@
1
+ export const MIN_PASSWORD_LENGTH = 12;
2
+ const COMMON_PASSWORDS = new Set([
3
+ '12345678',
4
+ '123456789',
5
+ '1234567890',
6
+ 'admin123',
7
+ 'changeme',
8
+ 'letmein',
9
+ 'letmein123',
10
+ 'password',
11
+ 'password1',
12
+ 'password12',
13
+ 'password123',
14
+ 'password1234',
15
+ 'qwerty',
16
+ 'qwerty123',
17
+ 'welcome',
18
+ 'welcome123'
19
+ ]);
20
+ const normalizeForComparison = (value) => (String(value || '')
21
+ .trim()
22
+ .toLowerCase()
23
+ .replace(/[^a-z0-9]/g, ''));
24
+ function extractPersonalInfoTokens(context) {
25
+ const tokens = new Set();
26
+ const email = String(context?.email || '').trim().toLowerCase();
27
+ const displayName = String(context?.displayName || '').trim().toLowerCase();
28
+ if (email.includes('@')) {
29
+ const localPart = email.split('@')[0] || '';
30
+ const compactLocalPart = localPart.replace(/[^a-z0-9]/g, '');
31
+ if (compactLocalPart.length >= 4)
32
+ tokens.add(compactLocalPart);
33
+ for (const part of localPart.split(/[^a-z0-9]+/)) {
34
+ if (part.length >= 4)
35
+ tokens.add(part);
36
+ }
37
+ }
38
+ for (const part of displayName.split(/[^a-z0-9]+/)) {
39
+ if (part.length >= 4)
40
+ tokens.add(part);
41
+ }
42
+ return [...tokens];
43
+ }
44
+ export function getPasswordPolicyGuidance() {
45
+ return [
46
+ `Use at least ${MIN_PASSWORD_LENGTH} characters.`,
47
+ 'Avoid common passwords or obvious patterns.',
48
+ 'Do not include your email or display name.'
49
+ ];
50
+ }
51
+ export function validatePasswordPolicy(password, context) {
52
+ const rawPassword = String(password || '');
53
+ if (!rawPassword) {
54
+ return {
55
+ ok: false,
56
+ code: 'PASSWORD_REQUIRED',
57
+ message: 'Password is required.'
58
+ };
59
+ }
60
+ if (rawPassword.length < MIN_PASSWORD_LENGTH) {
61
+ return {
62
+ ok: false,
63
+ code: 'PASSWORD_TOO_SHORT',
64
+ message: `Password must be at least ${MIN_PASSWORD_LENGTH} characters.`
65
+ };
66
+ }
67
+ const normalizedPassword = normalizeForComparison(rawPassword);
68
+ if (COMMON_PASSWORDS.has(normalizedPassword)) {
69
+ return {
70
+ ok: false,
71
+ code: 'PASSWORD_TOO_COMMON',
72
+ message: 'Choose a less common password.'
73
+ };
74
+ }
75
+ const personalTokens = extractPersonalInfoTokens(context);
76
+ if (personalTokens.some((token) => normalizedPassword.includes(token))) {
77
+ return {
78
+ ok: false,
79
+ code: 'PASSWORD_CONTAINS_PERSONAL_INFO',
80
+ message: 'Password cannot contain your email or display name.'
81
+ };
82
+ }
83
+ return { ok: true };
84
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,34 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { getPasswordPolicyGuidance, MIN_PASSWORD_LENGTH, validatePasswordPolicy } from './passwordPolicy';
3
+ describe('passwordPolicy', () => {
4
+ it('describes the active password policy guidance', () => {
5
+ expect(getPasswordPolicyGuidance()).toEqual([
6
+ `Use at least ${MIN_PASSWORD_LENGTH} characters.`,
7
+ 'Avoid common passwords or obvious patterns.',
8
+ 'Do not include your email or display name.'
9
+ ]);
10
+ });
11
+ it('rejects common passwords even when padded with punctuation', () => {
12
+ expect(validatePasswordPolicy('Password123!')).toEqual({
13
+ ok: false,
14
+ code: 'PASSWORD_TOO_COMMON',
15
+ message: 'Choose a less common password.'
16
+ });
17
+ });
18
+ it('rejects passwords containing personal information', () => {
19
+ expect(validatePasswordPolicy('RossBurkeSecure!2026', {
20
+ email: 'ross@example.com',
21
+ displayName: 'Ross Burke'
22
+ })).toEqual({
23
+ ok: false,
24
+ code: 'PASSWORD_CONTAINS_PERSONAL_INFO',
25
+ message: 'Password cannot contain your email or display name.'
26
+ });
27
+ });
28
+ it('accepts long passwords without common or personal tokens', () => {
29
+ expect(validatePasswordPolicy('MapleHarborOrbit!2026', {
30
+ email: 'ross@example.com',
31
+ displayName: 'Ross Burke'
32
+ })).toEqual({ ok: true });
33
+ });
34
+ });
@@ -8,6 +8,7 @@ export interface R2ObjectStorageConfig {
8
8
  keyPrefix: string;
9
9
  signedUploadTtlSeconds: number;
10
10
  signedDownloadTtlSeconds: number;
11
+ requestTimeoutMs?: number;
11
12
  }
12
13
  export interface ResolvedObjectStorageConfig {
13
14
  provider: ObjectStorageProvider;
@@ -9,7 +9,8 @@ export function toPublicObjectStorageConfig(config) {
9
9
  endpoint: config.r2.endpoint,
10
10
  keyPrefix: config.r2.keyPrefix,
11
11
  signedUploadTtlSeconds: config.r2.signedUploadTtlSeconds,
12
- signedDownloadTtlSeconds: config.r2.signedDownloadTtlSeconds
12
+ signedDownloadTtlSeconds: config.r2.signedDownloadTtlSeconds,
13
+ ...(typeof config.r2.requestTimeoutMs === 'number' ? { requestTimeoutMs: config.r2.requestTimeoutMs } : {})
13
14
  }
14
15
  };
15
16
  }
@@ -8,6 +8,7 @@ export declare class ObjectStorageClient {
8
8
  constructor(config: ResolvedObjectStorageConfig);
9
9
  provider(): ObjectStorageProvider;
10
10
  keyForRelativePath(relativePath: string): string;
11
+ private requestTimeoutMs;
11
12
  putObject(relativePath: string, body: Buffer, contentType: string): Promise<void>;
12
13
  getObject(relativePath: string): Promise<StoredObject | null>;
13
14
  objectExists(relativePath: string): Promise<boolean>;
@@ -4,6 +4,7 @@ const AWS_SERVICE = 's3';
4
4
  const AWS_REGION = 'auto';
5
5
  const TRANSIENT_GET_OBJECT_STATUS_CODES = new Set([408, 425, 429, 500, 502, 503, 504]);
6
6
  const MAX_GET_OBJECT_ATTEMPTS = 3;
7
+ const DEFAULT_REQUEST_TIMEOUT_MS = 15000;
7
8
  function sha256Hex(value) {
8
9
  return createHash('sha256').update(value).digest('hex');
9
10
  }
@@ -77,6 +78,33 @@ function shouldRetryGetObjectError(error) {
77
78
  || message.includes('ecanceled')
78
79
  || message.includes('und_err');
79
80
  }
81
+ async function fetchWithTimeout(url, init, timeoutMsRaw) {
82
+ const timeoutMs = Number.isFinite(timeoutMsRaw) && timeoutMsRaw > 0
83
+ ? Math.floor(timeoutMsRaw)
84
+ : DEFAULT_REQUEST_TIMEOUT_MS;
85
+ const controller = new AbortController();
86
+ const timeout = setTimeout(() => {
87
+ controller.abort(new Error(`R2 request timed out after ${timeoutMs}ms`));
88
+ }, timeoutMs);
89
+ try {
90
+ return await fetch(url, {
91
+ ...init,
92
+ signal: controller.signal
93
+ });
94
+ }
95
+ catch (error) {
96
+ if (controller.signal.aborted) {
97
+ const reason = controller.signal.reason;
98
+ if (reason instanceof Error)
99
+ throw reason;
100
+ throw new Error(`R2 request timed out after ${timeoutMs}ms`);
101
+ }
102
+ throw error;
103
+ }
104
+ finally {
105
+ clearTimeout(timeout);
106
+ }
107
+ }
80
108
  function signRequest(params) {
81
109
  const amzDate = createAmzDate(params.now);
82
110
  const dateStamp = toDateStamp(amzDate);
@@ -117,6 +145,11 @@ export class ObjectStorageClient {
117
145
  keyForRelativePath(relativePath) {
118
146
  return buildObjectKey(this.config, relativePath);
119
147
  }
148
+ requestTimeoutMs() {
149
+ return this.config.provider === 'r2'
150
+ ? Number(this.config.r2?.requestTimeoutMs || DEFAULT_REQUEST_TIMEOUT_MS)
151
+ : DEFAULT_REQUEST_TIMEOUT_MS;
152
+ }
120
153
  async putObject(relativePath, body, contentType) {
121
154
  if (this.config.provider !== 'r2' || !this.config.r2) {
122
155
  throw new Error('R2 object storage is not configured.');
@@ -131,7 +164,7 @@ export class ObjectStorageClient {
131
164
  secretAccessKey: this.config.r2.secretAccessKey,
132
165
  payloadHash
133
166
  });
134
- const response = await fetch(url, {
167
+ const response = await fetchWithTimeout(url, {
135
168
  method: 'PUT',
136
169
  headers: {
137
170
  'authorization': signed.authorization,
@@ -140,7 +173,7 @@ export class ObjectStorageClient {
140
173
  'content-type': contentType
141
174
  },
142
175
  body: new Uint8Array(body)
143
- });
176
+ }, this.requestTimeoutMs());
144
177
  if (!response.ok) {
145
178
  const text = await response.text().catch(() => '');
146
179
  throw new Error(`Failed to upload object (${response.status}): ${text || response.statusText}`);
@@ -163,14 +196,14 @@ export class ObjectStorageClient {
163
196
  payloadHash
164
197
  });
165
198
  try {
166
- const response = await fetch(url, {
199
+ const response = await fetchWithTimeout(url, {
167
200
  method: 'GET',
168
201
  headers: {
169
202
  'authorization': signed.authorization,
170
203
  'x-amz-date': signed.amzDate,
171
204
  'x-amz-content-sha256': payloadHash
172
205
  }
173
- });
206
+ }, this.requestTimeoutMs());
174
207
  if (response.status === 404)
175
208
  return null;
176
209
  if (!response.ok) {
@@ -211,14 +244,14 @@ export class ObjectStorageClient {
211
244
  secretAccessKey: this.config.r2.secretAccessKey,
212
245
  payloadHash
213
246
  });
214
- const response = await fetch(url, {
247
+ const response = await fetchWithTimeout(url, {
215
248
  method: 'HEAD',
216
249
  headers: {
217
250
  'authorization': signed.authorization,
218
251
  'x-amz-date': signed.amzDate,
219
252
  'x-amz-content-sha256': payloadHash
220
253
  }
221
- });
254
+ }, this.requestTimeoutMs());
222
255
  if (response.status === 404)
223
256
  return false;
224
257
  if (!response.ok) {
@@ -241,14 +274,14 @@ export class ObjectStorageClient {
241
274
  secretAccessKey: this.config.r2.secretAccessKey,
242
275
  payloadHash
243
276
  });
244
- const response = await fetch(url, {
277
+ const response = await fetchWithTimeout(url, {
245
278
  method: 'DELETE',
246
279
  headers: {
247
280
  'authorization': signed.authorization,
248
281
  'x-amz-date': signed.amzDate,
249
282
  'x-amz-content-sha256': payloadHash
250
283
  }
251
- });
284
+ }, this.requestTimeoutMs());
252
285
  if (response.status === 404)
253
286
  return false;
254
287
  if (!response.ok) {
@@ -10,9 +10,34 @@ const TEST_CONFIG = {
10
10
  secretAccessKey: 'secret-key-1',
11
11
  keyPrefix: '',
12
12
  signedUploadTtlSeconds: 600,
13
- signedDownloadTtlSeconds: 300
13
+ signedDownloadTtlSeconds: 300,
14
+ requestTimeoutMs: 15000
14
15
  }
15
16
  };
17
+ describe('ObjectStorageClient.putObject', () => {
18
+ afterEach(() => {
19
+ vi.unstubAllGlobals();
20
+ vi.restoreAllMocks();
21
+ });
22
+ it('aborts stalled uploads before MCP tool calls can time out', async () => {
23
+ const fetchMock = vi.fn((_input, init) => (new Promise((_resolve, reject) => {
24
+ const signal = init?.signal;
25
+ signal?.addEventListener('abort', () => {
26
+ reject(signal.reason);
27
+ }, { once: true });
28
+ })));
29
+ vi.stubGlobal('fetch', fetchMock);
30
+ const client = new ObjectStorageClient({
31
+ ...TEST_CONFIG,
32
+ r2: {
33
+ ...TEST_CONFIG.r2,
34
+ requestTimeoutMs: 1
35
+ }
36
+ });
37
+ await expect(client.putObject('workspaces/workspace-1/assets/documents/doc-1.md', Buffer.from('# plan', 'utf8'), 'text/markdown')).rejects.toThrow('R2 request timed out after 1ms');
38
+ expect(fetchMock).toHaveBeenCalledTimes(1);
39
+ });
40
+ });
16
41
  describe('ObjectStorageClient.getObject', () => {
17
42
  afterEach(() => {
18
43
  vi.unstubAllGlobals();
@@ -31,6 +31,7 @@ export function resolveObjectStorageConfigFromEnv(env = process.env) {
31
31
  : '';
32
32
  const signedUploadTtlSeconds = readPositiveInteger(env.R2_SIGNED_UPLOAD_TTL_SECONDS, 600);
33
33
  const signedDownloadTtlSeconds = readPositiveInteger(env.R2_SIGNED_DOWNLOAD_TTL_SECONDS, 300);
34
+ const requestTimeoutMs = readPositiveInteger(env.R2_REQUEST_TIMEOUT_MS, 15000);
34
35
  return {
35
36
  provider: 'r2',
36
37
  r2: {
@@ -41,7 +42,8 @@ export function resolveObjectStorageConfigFromEnv(env = process.env) {
41
42
  secretAccessKey,
42
43
  keyPrefix,
43
44
  signedUploadTtlSeconds,
44
- signedDownloadTtlSeconds
45
+ signedDownloadTtlSeconds,
46
+ requestTimeoutMs
45
47
  }
46
48
  };
47
49
  }
@@ -20,7 +20,8 @@ describe('resolveObjectStorageConfigFromEnv', () => {
20
20
  secretAccessKey: 'secret-key-1',
21
21
  keyPrefix: '',
22
22
  signedUploadTtlSeconds: 600,
23
- signedDownloadTtlSeconds: 300
23
+ signedDownloadTtlSeconds: 300,
24
+ requestTimeoutMs: 15000
24
25
  }
25
26
  });
26
27
  });
@@ -35,4 +36,15 @@ describe('resolveObjectStorageConfigFromEnv', () => {
35
36
  });
36
37
  expect(config.r2?.keyPrefix).toBe('taskforce-assets');
37
38
  });
39
+ it('reads a bounded R2 request timeout', () => {
40
+ const config = resolveObjectStorageConfigFromEnv({
41
+ TASKFORCE_OBJECT_STORAGE_PROVIDER: 'r2',
42
+ R2_ACCOUNT_ID: 'acct-1',
43
+ R2_BUCKET: 'taskforce-dev-assets',
44
+ R2_ACCESS_KEY_ID: 'access-key-1',
45
+ R2_SECRET_ACCESS_KEY: 'secret-key-1',
46
+ R2_REQUEST_TIMEOUT_MS: '2500'
47
+ });
48
+ expect(config.r2?.requestTimeoutMs).toBe(2500);
49
+ });
38
50
  });
@@ -3,6 +3,7 @@ import type { ObjectStorageProvider } from './objectStorage.js';
3
3
  export type WorkspaceAssetKind = 'document' | 'image' | 'file';
4
4
  export type WorkspaceAssetScanStatus = 'pending' | 'clean' | 'infected' | 'failed';
5
5
  export type WorkspaceAssetLinkRole = 'attachment' | 'image' | 'reference';
6
+ export type WorkspaceAssetLinkTargetType = 'task' | 'initiative' | 'workstream';
6
7
  export interface WorkspaceAssetEntry {
7
8
  assetId: string;
8
9
  tenantId: string;
@@ -32,7 +33,9 @@ export interface WorkspaceAssetLinkEntry {
32
33
  tenantId: string;
33
34
  workspaceId: string;
34
35
  assetId: string;
35
- taskId: string;
36
+ targetType: WorkspaceAssetLinkTargetType;
37
+ targetId: string;
38
+ taskId: string | null;
36
39
  role: WorkspaceAssetLinkRole;
37
40
  displayName: string | null;
38
41
  sortOrder: number | null;
@@ -43,7 +46,9 @@ export interface WorkspaceAssetLinkEntry {
43
46
  export declare class WorkspaceAssetStore {
44
47
  private readonly db;
45
48
  private readonly tenantId;
49
+ private supportsTargetTypeCache;
46
50
  constructor(db: DatabaseAdapter, tenantId: string);
51
+ private supportsTargetType;
47
52
  private normalizePersistedAsset;
48
53
  get(assetIdRaw: string, workspaceIdRaw?: string): WorkspaceAssetEntry | null;
49
54
  getByStorageKey(storageKeyRaw: string, workspaceIdRaw: string): WorkspaceAssetEntry | null;
@@ -98,7 +103,9 @@ export declare class WorkspaceAssetStore {
98
103
  upsertLink(input: {
99
104
  workspaceId: string;
100
105
  assetId: string;
101
- taskId: string;
106
+ taskId?: string;
107
+ targetType?: WorkspaceAssetLinkTargetType;
108
+ targetId?: string;
102
109
  role: WorkspaceAssetLinkRole;
103
110
  displayName?: string | null;
104
111
  sortOrder?: number | null;
@@ -109,13 +116,18 @@ export declare class WorkspaceAssetStore {
109
116
  listLinksForTask(taskIdRaw: string, workspaceIdRaw: string, options?: {
110
117
  includeDeleted?: boolean;
111
118
  }): WorkspaceAssetLinkEntry[];
119
+ listLinksForTarget(targetTypeRaw: WorkspaceAssetLinkTargetType, targetIdRaw: string, workspaceIdRaw: string, options?: {
120
+ includeDeleted?: boolean;
121
+ }): WorkspaceAssetLinkEntry[];
112
122
  listLinksForAsset(assetIdRaw: string, workspaceIdRaw: string, options?: {
113
123
  includeDeleted?: boolean;
114
124
  }): WorkspaceAssetLinkEntry[];
115
125
  deleteLink(input: {
116
126
  workspaceId: string;
117
127
  assetId: string;
118
- taskId: string;
128
+ taskId?: string;
129
+ targetType?: WorkspaceAssetLinkTargetType;
130
+ targetId?: string;
119
131
  role: WorkspaceAssetLinkRole;
120
132
  hardDelete?: boolean;
121
133
  }): boolean;