@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
@@ -56,10 +56,12 @@ import { resolveBuildInfo } from '../buildInfo.js';
56
56
  import { resolveRealtimeSyncFlag } from '../../sync/realtimeFeature.js';
57
57
  import { parseJsonBody } from './primitives.js';
58
58
  import { resolveRequestAccess } from '../auth.js';
59
- import { resolveErrorStatusCode, requestHeader, requestRuntimeMode } from './shared.js';
59
+ import { getRouteTimingNow, logSlowBootstrapRoute, requestBootstrapTraceId, requestHeader, requestRuntimeMode, resolveErrorStatusCode, serializeJsonWithTiming, setServerTimingHeader } from './shared.js';
60
60
  import { listBuiltInCustomTaxonomyLibraryPacks } from '../../shared/customTaxonomyLibrary.js';
61
61
  import { listBuiltInTaxonomyLibraryPacks } from '../../shared/taxonomyLibrary.js';
62
62
  import { shouldUseProvisionalTaskReferences } from '../../utils/taskReferences.js';
63
+ // === SECTION: Module dependency interface ===
64
+ const UI_STATE_MAX_JSON_BODY_BYTES = 50 * 1024 * 1024;
63
65
  function createUiStateRequestId() {
64
66
  return `ui-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
65
67
  }
@@ -237,8 +239,9 @@ export function registerTaskRoutes(deps) {
237
239
  const requestId = createUiStateRequestId();
238
240
  const startedAt = Date.now();
239
241
  attachUiStateDebugHeaders(res, requestId);
240
- const body = await parseJsonBody(req);
242
+ let body = {};
241
243
  try {
244
+ body = await parseJsonBody(req, UI_STATE_MAX_JSON_BODY_BYTES);
242
245
  const requestedWorkspaceId = String(body?.workspaceId || '').trim();
243
246
  let workspaceId = requestWorkspaceId(req);
244
247
  if (requestedWorkspaceId && requestRuntimeMode(req) === 'local') {
@@ -506,6 +509,48 @@ export function registerTaskRoutes(deps) {
506
509
  res.writeHead(200, { 'Content-Type': 'application/json' });
507
510
  res.end(JSON.stringify(data));
508
511
  });
512
+ // GET /api/taskforce/planning/bootstrap - List planning entities plus lightweight task summaries
513
+ addRoute('GET', '/api/taskforce/planning/bootstrap', async (req, res) => {
514
+ if (!ensureAppAccess(req, res))
515
+ return;
516
+ const startedAt = getRouteTimingNow();
517
+ const workspaceId = requestWorkspaceId(req);
518
+ const traceId = requestBootstrapTraceId(req);
519
+ const diagnostics = {};
520
+ const data = core.listPlanningBootstrap(workspaceId, diagnostics);
521
+ const serializeStartedAt = getRouteTimingNow();
522
+ const serialized = serializeJsonWithTiming(data, serializeStartedAt);
523
+ const totalDurationMs = Math.max(0, getRouteTimingNow() - startedAt);
524
+ const details = diagnostics;
525
+ setServerTimingHeader(res, [
526
+ { name: 'planning-bootstrap', durationMs: totalDurationMs },
527
+ { name: 'planning-bootstrap-initiatives', durationMs: details.initiativeLoadMs ?? 0 },
528
+ { name: 'planning-bootstrap-workstreams', durationMs: details.workstreamLoadMs ?? 0 },
529
+ { name: 'planning-bootstrap-tasks', durationMs: details.taskSummaryQueryMs ?? 0 },
530
+ { name: 'planning-bootstrap-build', durationMs: details.taskSummaryBuildMs ?? 0 },
531
+ { name: 'planning-bootstrap-json', durationMs: serialized.durationMs },
532
+ ]);
533
+ logSlowBootstrapRoute({
534
+ route: '/api/taskforce/planning/bootstrap',
535
+ workspaceId,
536
+ traceId,
537
+ durationMs: totalDurationMs,
538
+ details: {
539
+ initiativeCount: details.initiativeCount ?? 0,
540
+ workstreamCount: details.workstreamCount ?? 0,
541
+ workstreamLinkedTaskCount: details.workstreamLinkedTaskCount ?? 0,
542
+ workstreamTaskSummaryCount: details.workstreamTaskSummaryCount ?? 0,
543
+ responseBytes: serialized.byteLength,
544
+ initiativeLoadMs: details.initiativeLoadMs ?? 0,
545
+ workstreamLoadMs: details.workstreamLoadMs ?? 0,
546
+ taskSummaryQueryMs: details.taskSummaryQueryMs ?? 0,
547
+ taskSummaryBuildMs: details.taskSummaryBuildMs ?? 0,
548
+ jsonSerializeMs: serialized.durationMs,
549
+ },
550
+ });
551
+ res.writeHead(200, { 'Content-Type': 'application/json' });
552
+ res.end(serialized.body);
553
+ });
509
554
  // POST /api/taskforce/initiative - Create initiative
510
555
  addRoute('POST', '/api/taskforce/initiative', async (req, res) => {
511
556
  if (!ensureAppAccess(req, res))
@@ -513,7 +558,7 @@ export function registerTaskRoutes(deps) {
513
558
  const body = await parseJsonBody(req);
514
559
  try {
515
560
  const workspaceId = requestWorkspaceId(req);
516
- const initiative = core.createInitiative(body || {}, workspaceId);
561
+ const initiative = core.createInitiative(body || {}, workspaceId, { actorRef: 'user' });
517
562
  res.writeHead(201, { 'Content-Type': 'application/json' });
518
563
  res.end(JSON.stringify(initiative));
519
564
  }
@@ -545,7 +590,7 @@ export function registerTaskRoutes(deps) {
545
590
  const body = await parseJsonBody(req);
546
591
  try {
547
592
  const workspaceId = requestWorkspaceId(req);
548
- const updated = core.updateInitiative(params.id, body || {}, workspaceId);
593
+ const updated = core.updateInitiative(params.id, body || {}, workspaceId, { actorRef: 'user' });
549
594
  res.writeHead(200, { 'Content-Type': 'application/json' });
550
595
  res.end(JSON.stringify(updated));
551
596
  }
@@ -561,7 +606,7 @@ export function registerTaskRoutes(deps) {
561
606
  return;
562
607
  try {
563
608
  const workspaceId = requestWorkspaceId(req);
564
- const archived = core.archiveInitiative(params.id, workspaceId);
609
+ const archived = core.archiveInitiative(params.id, workspaceId, { actorRef: 'user' });
565
610
  res.writeHead(200, { 'Content-Type': 'application/json' });
566
611
  res.end(JSON.stringify(archived));
567
612
  }
@@ -577,7 +622,7 @@ export function registerTaskRoutes(deps) {
577
622
  return;
578
623
  try {
579
624
  const workspaceId = requestWorkspaceId(req);
580
- const restored = core.unarchiveInitiative(params.id, workspaceId);
625
+ const restored = core.unarchiveInitiative(params.id, workspaceId, { actorRef: 'user' });
581
626
  res.writeHead(200, { 'Content-Type': 'application/json' });
582
627
  res.end(JSON.stringify(restored));
583
628
  }
@@ -604,7 +649,7 @@ export function registerTaskRoutes(deps) {
604
649
  const body = await parseJsonBody(req);
605
650
  try {
606
651
  const workspaceId = requestWorkspaceId(req);
607
- const workstream = core.createWorkstream(body || {}, workspaceId);
652
+ const workstream = core.createWorkstream(body || {}, workspaceId, { actorRef: 'user' });
608
653
  res.writeHead(201, { 'Content-Type': 'application/json' });
609
654
  res.end(JSON.stringify(workstream));
610
655
  }
@@ -636,7 +681,7 @@ export function registerTaskRoutes(deps) {
636
681
  const body = await parseJsonBody(req);
637
682
  try {
638
683
  const workspaceId = requestWorkspaceId(req);
639
- const updated = core.updateWorkstream(params.id, body || {}, workspaceId);
684
+ const updated = core.updateWorkstream(params.id, body || {}, workspaceId, { actorRef: 'user' });
640
685
  res.writeHead(200, { 'Content-Type': 'application/json' });
641
686
  res.end(JSON.stringify(updated));
642
687
  }
@@ -652,7 +697,7 @@ export function registerTaskRoutes(deps) {
652
697
  return;
653
698
  try {
654
699
  const workspaceId = requestWorkspaceId(req);
655
- const archived = core.archiveWorkstream(params.id, workspaceId);
700
+ const archived = core.archiveWorkstream(params.id, workspaceId, { actorRef: 'user' });
656
701
  res.writeHead(200, { 'Content-Type': 'application/json' });
657
702
  res.end(JSON.stringify(archived));
658
703
  }
@@ -668,7 +713,7 @@ export function registerTaskRoutes(deps) {
668
713
  return;
669
714
  try {
670
715
  const workspaceId = requestWorkspaceId(req);
671
- const restored = core.unarchiveWorkstream(params.id, workspaceId);
716
+ const restored = core.unarchiveWorkstream(params.id, workspaceId, { actorRef: 'user' });
672
717
  res.writeHead(200, { 'Content-Type': 'application/json' });
673
718
  res.end(JSON.stringify(restored));
674
719
  }
@@ -16,7 +16,7 @@ import * as path from 'path';
16
16
  import { parseJsonBody } from './primitives.js';
17
17
  import { resolveRequestAccess, createSessionTokenCookie, resolveSessionCookieAttributesForRequest, } from '../auth.js';
18
18
  import { isWorkspaceSwitchingEnabledForRuntime } from '../../shared/runtimeContract.js';
19
- import { resolveErrorStatusCode } from './shared.js';
19
+ import { getRouteTimingNow, logSlowBootstrapRoute, requestBootstrapTraceId, resolveErrorStatusCode, serializeJsonWithTiming, setServerTimingHeader } from './shared.js';
20
20
  // === SECTION: Registration ===
21
21
  export function registerWorkspaceRoutes(deps) {
22
22
  const { addRoute, core, context, ensureAppAccess, auditAuthAction, getObjectStorageClient, ensureWithinDir, sanitizeStorageSegment, sanitizeTaskIdForPath, normalizeDocumentPathInput, } = deps;
@@ -94,6 +94,8 @@ export function registerWorkspaceRoutes(deps) {
94
94
  // === SECTION: Workspace CRUD routes ===
95
95
  // GET /api/taskforce/workspaces - List authenticated user's accessible workspaces
96
96
  addRoute('GET', '/api/taskforce/workspaces', async (req, res) => {
97
+ const routeStartedAt = getRouteTimingNow();
98
+ const traceId = requestBootstrapTraceId(req);
97
99
  const authConfig = context.authConfig;
98
100
  if (!isWorkspaceSwitchingEnabledForRuntime(authConfig?.runtimeMode)) {
99
101
  res.writeHead(501, { 'Content-Type': 'application/json' });
@@ -106,6 +108,7 @@ export function registerWorkspaceRoutes(deps) {
106
108
  return;
107
109
  }
108
110
  const access = resolveRequestAccess(req, authConfig);
111
+ const authResolvedAt = getRouteTimingNow();
109
112
  if (!access.authenticated || !access.userId || access.userId === 'anonymous') {
110
113
  res.writeHead(401, { 'Content-Type': 'application/json' });
111
114
  res.end(JSON.stringify({ success: false, error: 'Authentication required.' }));
@@ -113,17 +116,45 @@ export function registerWorkspaceRoutes(deps) {
113
116
  }
114
117
  if (!ensureAppAccess(req, res))
115
118
  return;
119
+ const appAccessCheckedAt = getRouteTimingNow();
116
120
  const workspaces = core.listUserWorkspaces(access.userId);
121
+ const workspacesLoadedAt = getRouteTimingNow();
117
122
  const requestedCurrentWorkspaceId = String(access.workspaceId || '').trim();
118
123
  const currentWorkspaceId = workspaces.some((workspace) => workspace.id === requestedCurrentWorkspaceId)
119
124
  ? requestedCurrentWorkspaceId
120
125
  : (workspaces[0]?.id || 'default');
121
- res.writeHead(200, { 'Content-Type': 'application/json' });
122
- res.end(JSON.stringify({
126
+ const currentWorkspaceResolvedAt = getRouteTimingNow();
127
+ const serialized = serializeJsonWithTiming({
123
128
  success: true,
124
129
  workspaces,
125
130
  currentWorkspaceId: currentWorkspaceId || access.workspaceId
126
- }));
131
+ }, currentWorkspaceResolvedAt);
132
+ const totalDurationMs = getRouteTimingNow() - routeStartedAt;
133
+ setServerTimingHeader(res, [
134
+ { name: 'workspaces', durationMs: totalDurationMs },
135
+ { name: 'workspaces-auth', durationMs: authResolvedAt - routeStartedAt },
136
+ { name: 'workspaces-app-access', durationMs: appAccessCheckedAt - authResolvedAt },
137
+ { name: 'workspaces-list', durationMs: workspacesLoadedAt - appAccessCheckedAt },
138
+ { name: 'workspaces-current', durationMs: currentWorkspaceResolvedAt - workspacesLoadedAt },
139
+ { name: 'workspaces-json', durationMs: serialized.durationMs },
140
+ ]);
141
+ logSlowBootstrapRoute({
142
+ route: '/api/taskforce/workspaces',
143
+ workspaceId: currentWorkspaceId || access.workspaceId || 'default',
144
+ traceId,
145
+ durationMs: totalDurationMs,
146
+ details: {
147
+ workspaceCount: workspaces.length,
148
+ payloadBytes: serialized.byteLength,
149
+ authMs: authResolvedAt - routeStartedAt,
150
+ appAccessMs: appAccessCheckedAt - authResolvedAt,
151
+ listWorkspacesMs: workspacesLoadedAt - appAccessCheckedAt,
152
+ currentWorkspaceMs: currentWorkspaceResolvedAt - workspacesLoadedAt,
153
+ serializeMs: serialized.durationMs,
154
+ }
155
+ });
156
+ res.writeHead(200, { 'Content-Type': 'application/json' });
157
+ res.end(serialized.body);
127
158
  });
128
159
  // POST /api/taskforce/workspaces - Create workspace for current authenticated user
129
160
  addRoute('POST', '/api/taskforce/workspaces', async (req, res) => {
@@ -281,7 +312,7 @@ export function registerWorkspaceRoutes(deps) {
281
312
  return;
282
313
  }
283
314
  const resolved = core.resolveUserAccess(access.userId, workspaceId, access.role);
284
- if (!resolved || resolved.role === 'read-only') {
315
+ if (!resolved || resolved.disabled) {
285
316
  res.writeHead(403, { 'Content-Type': 'application/json' });
286
317
  res.end(JSON.stringify({ success: false, error: 'Workspace access is not active for this user.' }));
287
318
  return;
@@ -36,12 +36,33 @@ import { registerDocumentReviewRoutes } from './routes/documentReviews.js';
36
36
  import { registerAnnotatedAttachmentRoutes } from './routes/annotatedAttachments.js';
37
37
  import { escapeHtml, parseJsonBody } from './routes/primitives.js';
38
38
  import { getRouteEmailConfig, resolvePublicAuthBaseUrl, resolveRuntimeConfigBaseUrl } from './routes/authSupport.js';
39
- import { buildCloudMcpRuntimeAuth, requestHeader, requestRole, requestRuntimeMode, requestUserId, makeAuditAdminAction, makeAuditAuthAction, makeEnsureAdminRole, makeEnsureAppAccess, makeEnsureAuthenticatedUser, makeEnsureCloudPlanData, makeRequestWorkspaceId, makeRequireCloudRuntime, makeResolveAdminRequestActor, makeResolveAuthenticatedUserId, makeResolveAuthenticatedMutationUserId, ensureWorkspaceAdminRole, } from './routes/shared.js';
39
+ import { buildCloudMcpRuntimeAuth, requestHeader, requestRole, requestRuntimeMode, requestUserId, makeAuditAdminAction, makeAuditAuthAction, makeEnsureAdminRole, makeEnsureAppAccess, makeEnsureAuthenticatedUser, makeEnsureCloudPlanData, makeRequestWorkspaceId, makeRequireCloudRuntime, makeResolveAdminRequestActor, makeResolveAuthenticatedUserId, makeResolveAuthenticatedMutationUserId, } from './routes/shared.js';
40
40
  import { resolveDeploymentConfig } from '../config/deployment.js';
41
41
  import { getTaskforceCloudEnvironmentConfig, resolveTaskforceCloudEnvironmentFromBaseUrl } from '../config/cloudEnvironment.js';
42
42
  import { getCanonicalDocumentName } from '../utils/documentNames.js';
43
43
  import { MCP_CLOUD_TOOL_SCOPE_REQUIREMENTS } from '../mcp/toolRegistry.js';
44
44
  export { parseJsonBody } from './routes/primitives.js';
45
+ function pathMatchesRouteAuthExclusion(pathname, excludedPaths) {
46
+ if (!Array.isArray(excludedPaths))
47
+ return false;
48
+ return excludedPaths.some((path) => pathname === path || pathname.startsWith(`${path}/`));
49
+ }
50
+ function shouldRequireAuthenticatedCloudApiRoute(pathname, context) {
51
+ const authConfig = context.authConfig;
52
+ if (!authConfig?.enabled)
53
+ return false;
54
+ if (!pathname.startsWith('/api/taskforce/'))
55
+ return false;
56
+ if (pathname.startsWith('/api/taskforce/sync/'))
57
+ return false;
58
+ if (pathMatchesRouteAuthExclusion(pathname, authConfig.excludedPaths))
59
+ return false;
60
+ return true;
61
+ }
62
+ function writeRouteAuthenticationRequired(res) {
63
+ res.writeHead(401, { 'Content-Type': 'application/json' });
64
+ res.end(JSON.stringify({ error: 'Authentication required.' }));
65
+ }
45
66
  const DEFAULT_DOCUMENT_RETENTION_DAYS = 7;
46
67
  const STORAGE_INTEGRITY_HISTORY_LIMIT = 50;
47
68
  const MCP_TOKEN_SCOPE_VALUES = new Set(['tasks:read', 'tasks:write', 'workspace:read']);
@@ -90,13 +111,14 @@ function resolveErrorStatusCode(error, fallback = 400) {
90
111
  }
91
112
  return fallback;
92
113
  }
93
- function writeMcpHttpError(res, statusCode, message) {
114
+ function writeMcpHttpError(res, statusCode, message, data) {
94
115
  res.writeHead(statusCode, { 'Content-Type': 'application/json' });
95
116
  res.end(JSON.stringify({
96
117
  jsonrpc: '2.0',
97
118
  error: {
98
119
  code: -32000,
99
120
  message,
121
+ ...(data ? { data } : {}),
100
122
  },
101
123
  id: null,
102
124
  }));
@@ -175,8 +197,24 @@ export function createRoutes(core, context = {}) {
175
197
  const routes = [];
176
198
  const uiStateCache = new Map();
177
199
  const addRoute = (method, path, handler) => {
200
+ const wrappedHandler = async (req, res, params) => {
201
+ const runtimeHeader = requestHeader(req, 'x-taskforce-runtime-mode', '').trim().toLowerCase();
202
+ const runtimeMode = runtimeHeader === 'cloud'
203
+ ? 'cloud'
204
+ : runtimeHeader === 'local'
205
+ ? 'local'
206
+ : (context.authConfig?.runtimeMode || requestRuntimeMode(req));
207
+ if (runtimeMode === 'cloud' && shouldRequireAuthenticatedCloudApiRoute(path, context)) {
208
+ const access = resolveRequestAccess(req, context.authConfig);
209
+ if (!access.authenticated || !access.userId || access.userId === 'anonymous') {
210
+ writeRouteAuthenticationRequired(res);
211
+ return;
212
+ }
213
+ }
214
+ await handler(req, res, params);
215
+ };
178
216
  const { pattern, keys } = createRoutePattern(`${method}:${path}`);
179
- routes.push({ pattern, keys, handler });
217
+ routes.push({ pattern, keys, handler: wrappedHandler });
180
218
  };
181
219
  const buildUiStateCacheKey = (workspaceId, userId, stateKey) => `${workspaceId}::${userId}::${stateKey}`;
182
220
  const readCachedUiState = (workspaceId, userId, stateKey) => {
@@ -485,7 +523,10 @@ export function createRoutes(core, context = {}) {
485
523
  const primaryLink = canonicalAsset?.assetId
486
524
  ? workspaceAssetStore?.listLinksForAsset(canonicalAsset.assetId, inferWorkspaceIdFromStoragePath(normalizedStorageKey)).find((entry) => !entry.deletedAt && (!opts?.taskId || entry.taskId === opts.taskId))
487
525
  : null;
526
+ const isExplicitTaskAttachment = typeof opts?.taskId === 'string' && opts.taskId.trim().length > 0;
488
527
  const timestamp = String(opts?.timestamp
528
+ || primaryLink?.updatedAt
529
+ || (isExplicitTaskAttachment ? new Date().toISOString() : null)
489
530
  || canonicalAsset?.updatedAt
490
531
  || canonicalAsset?.createdAt
491
532
  || new Date().toISOString()).trim() || new Date().toISOString();
@@ -530,6 +571,45 @@ export function createRoutes(core, context = {}) {
530
571
  taskId
531
572
  };
532
573
  };
574
+ const taskHasAttachmentForAsset = (task, asset) => {
575
+ if (!task || !Array.isArray(task.attachments))
576
+ return false;
577
+ const canonicalDocumentPath = `/api/taskforce/documents/${encodeURIComponent(asset.assetId)}/content`;
578
+ const contextPath = `/api/taskforce/context/${encodeURIComponent(asset.storageKey)}`;
579
+ return task.attachments.some((attachment) => {
580
+ if (typeof attachment === 'string') {
581
+ return attachment === canonicalDocumentPath
582
+ || attachment === contextPath
583
+ || attachment === asset.storageKey;
584
+ }
585
+ if (!attachment || typeof attachment !== 'object')
586
+ return false;
587
+ return attachment.assetId === asset.assetId
588
+ || attachment.fsPath === asset.storageKey
589
+ || attachment.path === canonicalDocumentPath
590
+ || attachment.path === contextPath;
591
+ });
592
+ };
593
+ const recordTaskAttachmentActivity = (input) => {
594
+ const afterTask = core.getTask(input.taskId, input.workspaceId);
595
+ if (!taskHasAttachmentForAsset(afterTask, input.asset))
596
+ return;
597
+ core.recordTaskEvent({
598
+ taskId: input.taskId,
599
+ workspaceId: input.workspaceId,
600
+ action: 'task-attachments-changed',
601
+ actor: 'user',
602
+ createdAt: input.createdAt || new Date().toISOString(),
603
+ details: {
604
+ changes: {
605
+ attachments: {
606
+ from: input.beforeTask.attachments || [],
607
+ to: afterTask?.attachments || [],
608
+ },
609
+ },
610
+ },
611
+ });
612
+ };
533
613
  const sanitizeDownloadFilename = (nameRaw, fallback = 'download') => {
534
614
  const normalized = String(nameRaw || '').trim()
535
615
  .replace(/[\\/:*?"<>|]/g, '-')
@@ -623,6 +703,8 @@ export function createRoutes(core, context = {}) {
623
703
  purgeAfter: null
624
704
  });
625
705
  const taskId = String(params.taskId || inferTaskIdFromStoragePath(params.relativeToStorage) || '').trim();
706
+ const taskBeforeLink = taskId ? core.getTask(taskId, workspaceId) : null;
707
+ const wasAttachedBefore = taskHasAttachmentForAsset(taskBeforeLink, asset);
626
708
  if (taskId) {
627
709
  workspaceAssetStore.upsertLink({
628
710
  workspaceId,
@@ -632,6 +714,15 @@ export function createRoutes(core, context = {}) {
632
714
  displayName: null,
633
715
  deletedAt: null
634
716
  });
717
+ if (taskBeforeLink && !wasAttachedBefore) {
718
+ recordTaskAttachmentActivity({
719
+ taskId,
720
+ workspaceId,
721
+ asset,
722
+ beforeTask: taskBeforeLink,
723
+ createdAt: asset.updatedAt,
724
+ });
725
+ }
635
726
  }
636
727
  core.notifyDocumentMetadataMutation(workspaceId, [params.relativeToStorage], 'upsert');
637
728
  }
@@ -1109,6 +1200,8 @@ export function createRoutes(core, context = {}) {
1109
1200
  authenticatedViaOAuth: oauthAuth || null,
1110
1201
  userId: null,
1111
1202
  ...bootstrap,
1203
+ aiProfileToken: bootstrap.aiProfileToken || oauthAuth?.aiProfileToken || null,
1204
+ aiProfileName: bootstrap.aiProfileName || oauthAuth?.aiProfileName || null,
1112
1205
  };
1113
1206
  }
1114
1207
  core.addMcpAuditLog({
@@ -1348,6 +1441,7 @@ export function createRoutes(core, context = {}) {
1348
1441
  return;
1349
1442
  }
1350
1443
  const authScopes = auth.authenticatedViaToken?.scopes || auth.authenticatedViaOAuth?.scopes || [];
1444
+ const requestId = String(req.headers['x-request-id'] || req.headers['x-railway-request-id'] || '').trim() || randomUUID();
1351
1445
  const deniedToolName = findDeniedCloudMcpToolName(body, authScopes);
1352
1446
  if (deniedToolName) {
1353
1447
  core.addMcpAuditLog({
@@ -1357,7 +1451,7 @@ export function createRoutes(core, context = {}) {
1357
1451
  tokenId: auth.authenticatedViaToken?.tokenId || auth.authenticatedViaOAuth?.grantId || null,
1358
1452
  toolName: deniedToolName,
1359
1453
  details: {
1360
- requestId: String(req.headers['x-request-id'] || req.headers['x-railway-request-id'] || '').trim() || randomUUID(),
1454
+ requestId,
1361
1455
  ip: req.socket?.remoteAddress || null,
1362
1456
  userAgent: requestHeader(req, 'user-agent', '') || null,
1363
1457
  outcome: 'deny',
@@ -1371,11 +1465,13 @@ export function createRoutes(core, context = {}) {
1371
1465
  if (!applyCloudMcpWriteRateLimit(req, res, auth, body)) {
1372
1466
  return;
1373
1467
  }
1468
+ let runtime = null;
1374
1469
  try {
1375
- const runtime = createTaskforceMcpServer({
1470
+ runtime = createTaskforceMcpServer({
1376
1471
  projectRoot: core.getPaths().projectRoot,
1377
1472
  tenantId: core.getTenantId(),
1378
1473
  workspaceId: auth.workspaceId,
1474
+ core: core,
1379
1475
  serverName: 'taskforce-cloud',
1380
1476
  logStartup: false,
1381
1477
  runtimeMode: 'cloud',
@@ -1383,7 +1479,7 @@ export function createRoutes(core, context = {}) {
1383
1479
  req,
1384
1480
  auth,
1385
1481
  requestHeader,
1386
- requestId: String(req.headers['x-request-id'] || req.headers['x-railway-request-id'] || '').trim() || randomUUID(),
1482
+ requestId,
1387
1483
  authScopes,
1388
1484
  }),
1389
1485
  });
@@ -1398,13 +1494,29 @@ export function createRoutes(core, context = {}) {
1398
1494
  }
1399
1495
  await transport.handleRequest(req, res, body);
1400
1496
  recordCloudMcpCredentialUsage(req, auth.authenticatedViaToken, auth.authenticatedViaOAuth);
1401
- await transport.close().catch(() => undefined);
1402
- await runtime.server.close().catch(() => undefined);
1403
1497
  }
1404
1498
  catch (error) {
1405
- console.error('[Taskforce MCP] Cloud transport request failed:', error);
1499
+ console.error('[Taskforce MCP] Cloud transport request failed:', {
1500
+ requestId,
1501
+ kind: 'tool_transport_failure',
1502
+ message: error instanceof Error ? error.message : String(error),
1503
+ });
1406
1504
  if (!res.headersSent) {
1407
- writeMcpHttpError(res, 500, 'Internal server error');
1505
+ writeMcpHttpError(res, 500, 'MCP transport failure.', {
1506
+ kind: 'tool_transport_failure',
1507
+ retryable: true,
1508
+ requestId,
1509
+ });
1510
+ }
1511
+ }
1512
+ finally {
1513
+ if (runtime) {
1514
+ try {
1515
+ await runtime.server.close();
1516
+ }
1517
+ catch (closeError) {
1518
+ console.warn('[Taskforce MCP] Cloud transport cleanup failed:', closeError);
1519
+ }
1408
1520
  }
1409
1521
  }
1410
1522
  };
@@ -1412,7 +1524,26 @@ export function createRoutes(core, context = {}) {
1412
1524
  const auditAdminAction = makeAuditAdminAction(core, context);
1413
1525
  const auditAuthAction = makeAuditAuthAction(core, requestWorkspaceId, context);
1414
1526
  const ensureAdminRole = makeEnsureAdminRole(core, context);
1415
- const ensureAuthenticatedUser = makeEnsureAuthenticatedUser();
1527
+ const ensureAuthenticatedUser = makeEnsureAuthenticatedUser(context.authConfig);
1528
+ const ensureWorkspaceAdminRole = (req, workspaceIdOverride) => {
1529
+ const hasWorkspaceOverride = typeof workspaceIdOverride === 'string' && workspaceIdOverride.trim().length > 0;
1530
+ const workspaceId = String(hasWorkspaceOverride ? workspaceIdOverride : requestWorkspaceId(req) || '').trim() || 'default';
1531
+ const userId = String(resolveAuthenticatedUserId(req) || '').trim();
1532
+ if (userId && userId !== 'anonymous') {
1533
+ const membership = core.listWorkspaceUsers(workspaceId).find((user) => String(user.userId || '').trim() === userId);
1534
+ if (membership) {
1535
+ const role = String(membership.role || '').trim().toLowerCase();
1536
+ const status = String(membership.status || '').trim().toLowerCase();
1537
+ return membership.disabled !== true
1538
+ && status === 'active'
1539
+ && (role === 'owner' || role === 'admin');
1540
+ }
1541
+ if (hasWorkspaceOverride)
1542
+ return false;
1543
+ }
1544
+ const fallbackRole = String(requestRole(req) || '').trim().toLowerCase();
1545
+ return fallbackRole === 'owner' || fallbackRole === 'admin';
1546
+ };
1416
1547
  const isCollaborationPolicyEnabled = () => {
1417
1548
  const rawDefault = String(process.env.TASKFORCE_COLLAB_POLICY_V1 || 'true').trim().toLowerCase();
1418
1549
  const envDefaultEnabled = !(rawDefault === '0' || rawDefault === 'false' || rawDefault === 'off' || rawDefault === 'no');
@@ -1464,6 +1595,7 @@ export function createRoutes(core, context = {}) {
1464
1595
  context,
1465
1596
  requestWorkspaceId,
1466
1597
  requestUserId,
1598
+ resolveAuthenticatedUserId,
1467
1599
  requestRole,
1468
1600
  ensureAppAccess,
1469
1601
  ensureAuthenticatedUser,
@@ -1474,6 +1606,10 @@ export function createRoutes(core, context = {}) {
1474
1606
  resolveAdminRequestActor,
1475
1607
  resolveEffectiveObjectStorageConfig,
1476
1608
  getObjectStorageClient,
1609
+ workspaceAssetStore,
1610
+ ensureWithinDir,
1611
+ markAssetDeleted,
1612
+ appendStorageTelemetry,
1477
1613
  });
1478
1614
  registerWorkspaceRoutes({
1479
1615
  addRoute,