@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
@@ -11,6 +11,13 @@ export interface StandaloneServerOptions {
11
11
  projectRoot: string;
12
12
  port: number;
13
13
  }
14
+ export type HttpServerTimeoutSettings = {
15
+ keepAliveTimeoutMs: number;
16
+ headersTimeoutMs: number;
17
+ requestTimeoutMs: number;
18
+ };
19
+ export declare function resolveHttpServerTimeoutSettings(env?: NodeJS.ProcessEnv): HttpServerTimeoutSettings;
20
+ export declare function configureHttpServerTimeouts(server: Pick<http.Server, 'keepAliveTimeout' | 'headersTimeout' | 'requestTimeout'>, env?: NodeJS.ProcessEnv): HttpServerTimeoutSettings;
14
21
  export declare const TASKFORCE_PROXY_ORIGIN_HOST_HEADER = "x-taskforce-origin-host";
15
22
  export declare const TASKFORCE_PROXY_ORIGIN_PROTO_HEADER = "x-taskforce-origin-proto";
16
23
  export declare const TASKFORCE_PROXY_ORIGIN_BASE_URL_HEADER = "x-taskforce-origin-base-url";
@@ -18,10 +25,15 @@ export declare const TASKFORCE_PROXY_ORIGIN_RUNTIME_HEADER = "x-taskforce-origin
18
25
  export declare const TASKFORCE_PROXY_CLOUD_ENVIRONMENT_HEADER = "x-taskforce-cloud-environment";
19
26
  interface AuthorizedRequestAccess extends RequestAccessContext {
20
27
  disabled?: boolean;
28
+ accountDisabled?: boolean;
29
+ workspaceDisabled?: boolean;
21
30
  }
31
+ export declare function isWorkspaceAccessRecoveryRoute(pathname: string): boolean;
32
+ export declare function resolveDisabledAccessError(access: Pick<AuthorizedRequestAccess, 'disabled' | 'accountDisabled' | 'workspaceDisabled'>, pathname: string): string | null;
22
33
  export declare function shouldProxyCloudPath(pathname: string): boolean;
23
34
  export declare function resolveCloudProxyUpstreamBaseUrl(req: http.IncomingMessage, fallbackBaseUrl: string): string;
24
35
  export declare function resolveAuthorizedWorkspaceAccess(core: Pick<TaskforceCore, 'resolveUserAccess' | 'getSystemRole'>, access: AuthorizedRequestAccess, requestedWorkspaceId: string): AuthorizedRequestAccess;
36
+ export declare function shouldApplyReadOnlyMutationGuard(methodRaw: string | undefined, pathname: string): boolean;
25
37
  export declare function resolveEffectiveRequestUserId(accessUserId: string, explicitUserId: string): string;
26
38
  export declare function resolveMaxPayloadBytesForPath(pathname: string, defaultMaxBytes: number): number;
27
39
  export declare function shouldRewriteSetCookieForLocalDevHost(hostHeader: string | undefined): boolean;
@@ -84,11 +84,85 @@ const CORS_RESPONSE_HEADERS = new Set([
84
84
  'access-control-max-age',
85
85
  'vary'
86
86
  ]);
87
+ const REFRESH_DIAGNOSTIC_PATH_PREFIXES = [
88
+ '/api/taskforce/auth/session',
89
+ '/api/taskforce/config',
90
+ '/api/taskforce/tasks',
91
+ '/api/taskforce/archive',
92
+ '/api/taskforce/workspaces',
93
+ '/api/taskforce/workspace/assignee-options',
94
+ '/api/taskforce/auth/workspace-members',
95
+ '/api/taskforce/taxonomy-state',
96
+ '/api/taskforce/categories',
97
+ '/api/taskforce/types',
98
+ '/api/taskforce/priorities',
99
+ '/api/taskforce/taxonomies',
100
+ '/api/taskforce/initiative-templates',
101
+ '/api/taskforce/workflow-templates',
102
+ '/api/taskforce/workflow-editor/overrides',
103
+ '/api/taskforce/environments',
104
+ '/api/taskforce/sync/'
105
+ ];
106
+ const REFRESH_DIAGNOSTIC_DURATION_MS = 100;
107
+ const DEFAULT_HTTP_KEEP_ALIVE_TIMEOUT_MS = 65_000;
108
+ const DEFAULT_HTTP_HEADERS_TIMEOUT_MS = 70_000;
109
+ const DEFAULT_HTTP_REQUEST_TIMEOUT_MS = 120_000;
110
+ export function resolveHttpServerTimeoutSettings(env = process.env) {
111
+ const keepAliveTimeoutMs = readPositiveInteger(env.TASKFORCE_HTTP_KEEP_ALIVE_TIMEOUT_MS, DEFAULT_HTTP_KEEP_ALIVE_TIMEOUT_MS);
112
+ const configuredHeadersTimeoutMs = readPositiveInteger(env.TASKFORCE_HTTP_HEADERS_TIMEOUT_MS, DEFAULT_HTTP_HEADERS_TIMEOUT_MS);
113
+ const headersTimeoutMs = Math.max(configuredHeadersTimeoutMs, keepAliveTimeoutMs + 5_000);
114
+ const requestTimeoutMs = readPositiveInteger(env.TASKFORCE_HTTP_REQUEST_TIMEOUT_MS, DEFAULT_HTTP_REQUEST_TIMEOUT_MS);
115
+ return {
116
+ keepAliveTimeoutMs,
117
+ headersTimeoutMs,
118
+ requestTimeoutMs
119
+ };
120
+ }
121
+ export function configureHttpServerTimeouts(server, env = process.env) {
122
+ const settings = resolveHttpServerTimeoutSettings(env);
123
+ server.keepAliveTimeout = settings.keepAliveTimeoutMs;
124
+ server.headersTimeout = settings.headersTimeoutMs;
125
+ server.requestTimeout = settings.requestTimeoutMs;
126
+ return settings;
127
+ }
87
128
  export const TASKFORCE_PROXY_ORIGIN_HOST_HEADER = 'x-taskforce-origin-host';
88
129
  export const TASKFORCE_PROXY_ORIGIN_PROTO_HEADER = 'x-taskforce-origin-proto';
89
130
  export const TASKFORCE_PROXY_ORIGIN_BASE_URL_HEADER = 'x-taskforce-origin-base-url';
90
131
  export const TASKFORCE_PROXY_ORIGIN_RUNTIME_HEADER = 'x-taskforce-origin-runtime';
91
132
  export const TASKFORCE_PROXY_CLOUD_ENVIRONMENT_HEADER = 'x-taskforce-cloud-environment';
133
+ export function isWorkspaceAccessRecoveryRoute(pathname) {
134
+ return pathname === '/api/taskforce/workspaces'
135
+ || pathname === '/api/taskforce/session/workspace';
136
+ }
137
+ export function resolveDisabledAccessError(access, pathname) {
138
+ if (pathname.startsWith('/api/taskforce/auth/'))
139
+ return null;
140
+ if (access.accountDisabled ?? access.disabled) {
141
+ return 'Forbidden: user account is disabled.';
142
+ }
143
+ if (access.workspaceDisabled && !isWorkspaceAccessRecoveryRoute(pathname)) {
144
+ return 'Forbidden: workspace access is not active for this user.';
145
+ }
146
+ return null;
147
+ }
148
+ function shouldLogRefreshDiagnostic(pathname) {
149
+ return REFRESH_DIAGNOSTIC_PATH_PREFIXES.some((prefix) => pathname === prefix || pathname.startsWith(prefix));
150
+ }
151
+ function getRequestTimingNow() {
152
+ return Date.now();
153
+ }
154
+ function isCloudOwnedUserAvatarContextPath(pathname) {
155
+ const prefix = '/api/taskforce/context/';
156
+ if (!pathname.startsWith(prefix))
157
+ return false;
158
+ try {
159
+ const decodedPath = decodeURIComponent(pathname.slice(prefix.length)).replace(/\\/g, '/');
160
+ return /^users\/[^/]+\/profile\/avatar\/[^/]+$/i.test(decodedPath);
161
+ }
162
+ catch {
163
+ return false;
164
+ }
165
+ }
92
166
  export function shouldProxyCloudPath(pathname) {
93
167
  if (!pathname)
94
168
  return false;
@@ -114,6 +188,7 @@ export function shouldProxyCloudPath(pathname) {
114
188
  || pathname.startsWith('/api/taskforce/admin/')
115
189
  || pathname.startsWith('/api/taskforce/billing/')
116
190
  || pathname.startsWith('/api/taskforce/auth/')
191
+ || isCloudOwnedUserAvatarContextPath(pathname)
117
192
  || pathname.startsWith('/api/taskforce/settings/mcp/')
118
193
  || pathname.startsWith('/api/platform/')
119
194
  || pathname.startsWith('/api/taskforce/sync/');
@@ -142,11 +217,27 @@ export function resolveAuthorizedWorkspaceAccess(core, access, requestedWorkspac
142
217
  workspaceId: resolved.workspaceId,
143
218
  userId: resolved.userId,
144
219
  systemRole: core.getSystemRole(resolved.userId),
145
- disabled: resolved.disabled
220
+ disabled: resolved.disabled,
221
+ accountDisabled: resolved.accountDisabled ?? resolved.disabled,
222
+ workspaceDisabled: resolved.workspaceDisabled ?? false
146
223
  };
147
224
  }
148
225
  return access;
149
226
  }
227
+ export function shouldApplyReadOnlyMutationGuard(methodRaw, pathname) {
228
+ const method = String(methodRaw || 'GET').toUpperCase();
229
+ if (method !== 'POST' && method !== 'PATCH' && method !== 'DELETE')
230
+ return false;
231
+ if (!pathname.startsWith('/api/taskforce/'))
232
+ return false;
233
+ if (pathname.startsWith('/api/taskforce/auth/'))
234
+ return false;
235
+ if (pathname === '/api/taskforce/health')
236
+ return false;
237
+ if (method === 'POST' && pathname === '/api/taskforce/session/workspace')
238
+ return false;
239
+ return true;
240
+ }
150
241
  export function resolveEffectiveRequestUserId(accessUserId, explicitUserId) {
151
242
  const normalizedAccessUserId = String(accessUserId || '').trim();
152
243
  if (normalizedAccessUserId && normalizedAccessUserId !== 'anonymous') {
@@ -163,6 +254,10 @@ export function resolveMaxPayloadBytesForPath(pathname, defaultMaxBytes) {
163
254
  // Sync routes (especially applying local changes) often include large binary attachments
164
255
  return Math.max(defaultMaxBytes, 50 * 1024 * 1024);
165
256
  }
257
+ if (pathname === '/api/taskforce/ui-state') {
258
+ // Workspace-sync UI state can carry large baselines; keep the global guard aligned with its route parser.
259
+ return Math.max(defaultMaxBytes, 50 * 1024 * 1024);
260
+ }
166
261
  return defaultMaxBytes;
167
262
  }
168
263
  export function shouldRewriteSetCookieForLocalDevHost(hostHeader) {
@@ -259,6 +354,7 @@ export function shouldApplyAuthRateLimitForPath(pathname) {
259
354
  const normalizedPath = String(pathname || '').trim();
260
355
  return normalizedPath.startsWith('/api/taskforce/auth/')
261
356
  && normalizedPath !== '/api/taskforce/auth/session'
357
+ && normalizedPath !== '/api/taskforce/auth/providers'
262
358
  && normalizedPath !== '/api/taskforce/auth/runtime-config'
263
359
  && normalizedPath !== '/api/taskforce/auth/admin-session';
264
360
  }
@@ -458,6 +554,17 @@ export function createStandaloneServer(options) {
458
554
  statusCode
459
555
  }, counterKeys);
460
556
  };
557
+ const logRefreshDiagnostic = (input) => {
558
+ const { pathname, method, statusCode, durationMs, req } = input;
559
+ if (!shouldLogRefreshDiagnostic(pathname))
560
+ return;
561
+ if (durationMs < REFRESH_DIAGNOSTIC_DURATION_MS && statusCode < 400)
562
+ return;
563
+ const requestId = String(req.headers['x-request-id'] || req.headers['x-railway-request-id'] || '').trim() || '-';
564
+ const workspaceId = String(req.headers['x-taskforce-workspace-id'] || '').trim() || '-';
565
+ const userId = String(req.headers['x-taskforce-user-id'] || '').trim() || '-';
566
+ console.info(`[Taskforce RefreshDiag] method=${method} path=${pathname} status=${statusCode} durationMs=${durationMs} requestId=${requestId} workspaceId=${workspaceId} userId=${userId}`);
567
+ };
461
568
  // Resolve static files directory at runtime
462
569
  // Standalone UI source now lives in apps/app and builds to dist/ui.
463
570
  // When built: dist/server/index.js -> dist/ui/
@@ -514,6 +621,7 @@ export function createStandaloneServer(options) {
514
621
  const integritySchedulePollMinutes = readPositiveInteger(process.env.TASKFORCE_STORAGE_INTEGRITY_SCHEDULE_POLL_MINUTES, 1);
515
622
  console.log(`[Taskforce] Storage integrity scheduler poll: every ${integritySchedulePollMinutes} minute(s)`);
516
623
  const server = http.createServer(async (req, res) => {
624
+ const requestStartedAt = getRequestTimingNow();
517
625
  if (!distUiPath) {
518
626
  uiResolution = resolveStaticUiPath();
519
627
  distUiPath = uiResolution.uiPath;
@@ -568,11 +676,12 @@ export function createStandaloneServer(options) {
568
676
  const hasBody = method !== 'GET' && method !== 'HEAD';
569
677
  const requestMaxPayload = resolveMaxPayloadBytesForPath(url.pathname, maxPayloadBytes);
570
678
  const body = hasBody ? await readRequestBody(req, requestMaxPayload) : undefined;
679
+ const shouldStreamCloudAvatar = method === 'GET' && isCloudOwnedUserAvatarContextPath(url.pathname);
571
680
  const upstream = await fetch(upstreamUrl, {
572
681
  method,
573
682
  headers,
574
683
  body: body && body.length > 0 ? new Uint8Array(body) : undefined,
575
- redirect: 'manual'
684
+ redirect: shouldStreamCloudAvatar ? 'follow' : 'manual'
576
685
  });
577
686
  const outgoingHeaders = {};
578
687
  for (const [key, value] of upstream.headers.entries()) {
@@ -714,19 +823,16 @@ export function createStandaloneServer(options) {
714
823
  return;
715
824
  }
716
825
  const pathname = url.pathname;
717
- const isMutation = (req.method === 'POST' || req.method === 'PATCH' || req.method === 'DELETE')
718
- && pathname.startsWith('/api/taskforce/')
719
- && !pathname.startsWith('/api/taskforce/auth/')
720
- && pathname !== '/api/taskforce/health';
826
+ const isMutation = shouldApplyReadOnlyMutationGuard(req.method, pathname);
721
827
  let access = accessForRateLimit;
722
- const isAuthRoute = pathname.startsWith('/api/taskforce/auth/');
723
828
  if (access.authenticated) {
724
829
  access = resolveAuthorizedWorkspaceAccess(core, access, Array.isArray(req.headers['x-taskforce-workspace-id'])
725
830
  ? String(req.headers['x-taskforce-workspace-id'][0] || '')
726
831
  : String(req.headers['x-taskforce-workspace-id'] || ''));
727
- if (access.disabled && !isAuthRoute) {
832
+ const disabledAccessError = resolveDisabledAccessError(access, pathname);
833
+ if (disabledAccessError) {
728
834
  res.writeHead(403, { 'Content-Type': 'application/json' });
729
- res.end(JSON.stringify({ error: 'Forbidden: user account is disabled.' }));
835
+ res.end(JSON.stringify({ error: disabledAccessError }));
730
836
  return;
731
837
  }
732
838
  }
@@ -756,6 +862,13 @@ export function createStandaloneServer(options) {
756
862
  res.writeHead = originalWriteHead;
757
863
  const finalStatus = Number.isFinite(Number(observedStatusCode)) ? Number(observedStatusCode) : 200;
758
864
  recordCollaborationRouteTelemetry(url.pathname, req.method || 'GET', finalStatus);
865
+ logRefreshDiagnostic({
866
+ pathname: url.pathname,
867
+ method: String(req.method || 'GET').toUpperCase(),
868
+ statusCode: finalStatus,
869
+ durationMs: Math.max(0, Math.round(getRequestTimingNow() - requestStartedAt)),
870
+ req
871
+ });
759
872
  }
760
873
  return;
761
874
  }
@@ -789,6 +902,8 @@ export function createStandaloneServer(options) {
789
902
  res.writeHead(404);
790
903
  res.end('Not Found');
791
904
  });
905
+ const timeoutSettings = configureHttpServerTimeouts(server);
906
+ console.log(`[Taskforce] HTTP timeouts: keepAlive=${timeoutSettings.keepAliveTimeoutMs}ms headers=${timeoutSettings.headersTimeoutMs}ms request=${timeoutSettings.requestTimeoutMs}ms`);
792
907
  // WebSocket server at /Taskforce-ws path
793
908
  const wss = new WebSocketServer({ server, path: '/taskforce-ws' });
794
909
  const realtimeWsManager = createRealtimeSyncWsManager(core, authConfig);
@@ -7,6 +7,9 @@ describe('shouldApplyAuthRateLimitForPath', () => {
7
7
  it('excludes auth session endpoint', () => {
8
8
  expect(shouldApplyAuthRateLimitForPath('/api/taskforce/auth/session')).toBe(false);
9
9
  });
10
+ it('excludes auth providers metadata endpoint', () => {
11
+ expect(shouldApplyAuthRateLimitForPath('/api/taskforce/auth/providers')).toBe(false);
12
+ });
10
13
  it('excludes runtime config bootstrap endpoint', () => {
11
14
  expect(shouldApplyAuthRateLimitForPath('/api/taskforce/auth/runtime-config')).toBe(false);
12
15
  });
@@ -1,6 +1,42 @@
1
1
  import { describe, expect, it, vi } from 'vitest';
2
- import { ensureBillingWebhookAuthExclusion, ensurePublicSiteConfigAuthExclusion, isBillingWebhookPath, rewriteProxySetCookieForLocalHost, resolveEffectiveRequestUserId, resolveAuthorizedWorkspaceAccess, shouldRewriteProxySetCookieDomain, shouldApplyAuthRateLimitForPath, shouldProxyCloudPath, writeJsonErrorIfPossible } from './index.js';
2
+ import { ensureBillingWebhookAuthExclusion, ensurePublicSiteConfigAuthExclusion, configureHttpServerTimeouts, isBillingWebhookPath, rewriteProxySetCookieForLocalHost, resolveHttpServerTimeoutSettings, resolveEffectiveRequestUserId, resolveAuthorizedWorkspaceAccess, resolveDisabledAccessError, resolveMaxPayloadBytesForPath, shouldApplyReadOnlyMutationGuard, shouldRewriteProxySetCookieDomain, shouldApplyAuthRateLimitForPath, shouldProxyCloudPath, writeJsonErrorIfPossible } from './index.js';
3
3
  describe('server index helper policies', () => {
4
+ it('uses proxy-friendly HTTP server timeouts by default', () => {
5
+ const settings = resolveHttpServerTimeoutSettings({});
6
+ expect(settings.keepAliveTimeoutMs).toBe(65_000);
7
+ expect(settings.headersTimeoutMs).toBe(70_000);
8
+ expect(settings.requestTimeoutMs).toBe(120_000);
9
+ });
10
+ it('keeps headers timeout above keep-alive timeout for reverse proxies', () => {
11
+ const settings = resolveHttpServerTimeoutSettings({
12
+ TASKFORCE_HTTP_KEEP_ALIVE_TIMEOUT_MS: '80000',
13
+ TASKFORCE_HTTP_HEADERS_TIMEOUT_MS: '1000',
14
+ TASKFORCE_HTTP_REQUEST_TIMEOUT_MS: '150000'
15
+ });
16
+ expect(settings.keepAliveTimeoutMs).toBe(80_000);
17
+ expect(settings.headersTimeoutMs).toBe(85_000);
18
+ expect(settings.requestTimeoutMs).toBe(150_000);
19
+ });
20
+ it('applies resolved HTTP server timeouts to the Node server', () => {
21
+ const server = {
22
+ keepAliveTimeout: 0,
23
+ headersTimeout: 0,
24
+ requestTimeout: 0
25
+ };
26
+ const settings = configureHttpServerTimeouts(server, {
27
+ TASKFORCE_HTTP_KEEP_ALIVE_TIMEOUT_MS: '61000',
28
+ TASKFORCE_HTTP_HEADERS_TIMEOUT_MS: '66000',
29
+ TASKFORCE_HTTP_REQUEST_TIMEOUT_MS: '90000'
30
+ });
31
+ expect(settings).toEqual({
32
+ keepAliveTimeoutMs: 61_000,
33
+ headersTimeoutMs: 66_000,
34
+ requestTimeoutMs: 90_000
35
+ });
36
+ expect(server.keepAliveTimeout).toBe(61_000);
37
+ expect(server.headersTimeout).toBe(66_000);
38
+ expect(server.requestTimeout).toBe(90_000);
39
+ });
4
40
  it('adds webhook path to auth exclusions without duplicates', () => {
5
41
  const base = ['/api/taskforce/health', '/api/taskforce/auth'];
6
42
  const next = ensureBillingWebhookAuthExclusion(base);
@@ -24,6 +60,11 @@ describe('server index helper policies', () => {
24
60
  expect(shouldApplyAuthRateLimitForPath('/api/taskforce/auth/session')).toBe(false);
25
61
  expect(shouldApplyAuthRateLimitForPath('/api/taskforce/billing/webhook')).toBe(false);
26
62
  });
63
+ it('allows workspace sync-sized ui-state payloads through the global guard', () => {
64
+ expect(resolveMaxPayloadBytesForPath('/api/taskforce/ui-state', 1_048_576)).toBe(50 * 1024 * 1024);
65
+ expect(resolveMaxPayloadBytesForPath('/api/taskforce/sync/workspace/push', 1_048_576)).toBe(50 * 1024 * 1024);
66
+ expect(resolveMaxPayloadBytesForPath('/api/taskforce/task', 1_048_576)).toBe(1_048_576);
67
+ });
27
68
  it('writes a json error when headers are still available', () => {
28
69
  let headersSent = false;
29
70
  let writableEnded = false;
@@ -82,6 +123,12 @@ describe('shouldProxyCloudPath', () => {
82
123
  expect(shouldProxyCloudPath('/api/taskforce/sync/workspace/pull')).toBe(true);
83
124
  expect(shouldProxyCloudPath('/api/taskforce/sync/workspace/push')).toBe(true);
84
125
  });
126
+ it('proxies cloud-owned user avatar context paths only', () => {
127
+ expect(shouldProxyCloudPath('/api/taskforce/context/users%2Fuser-1%2Fprofile%2Favatar%2Favatar.webp')).toBe(true);
128
+ expect(shouldProxyCloudPath('/api/taskforce/context/users/user-1/profile/avatar/avatar.webp')).toBe(true);
129
+ expect(shouldProxyCloudPath('/api/taskforce/context/workspaces%2Fworkspace-1%2Fassets%2Fimages%2Fasset.png')).toBe(false);
130
+ expect(shouldProxyCloudPath('/api/taskforce/context/users%2Fuser-1%2Fexports%2Favatar.webp')).toBe(false);
131
+ });
85
132
  it('proxies admin, billing, and auth routes', () => {
86
133
  expect(shouldProxyCloudPath('/api/taskforce/admin/users')).toBe(true);
87
134
  expect(shouldProxyCloudPath('/api/taskforce/billing/plans')).toBe(true);
@@ -91,6 +138,11 @@ describe('shouldProxyCloudPath', () => {
91
138
  expect(shouldProxyCloudPath('/api/taskforce/public/site-config')).toBe(true);
92
139
  expect(shouldProxyCloudPath('/api/taskforce/public/site-config-script')).toBe(true);
93
140
  });
141
+ it('keeps AI profile workspace mutations local so workspace sync owns replication', () => {
142
+ expect(shouldProxyCloudPath('/api/taskforce/workspace/ai-profiles/avatar')).toBe(false);
143
+ expect(shouldProxyCloudPath('/api/taskforce/workspace/ai-profiles/archive')).toBe(false);
144
+ expect(shouldProxyCloudPath('/api/taskforce/workspace/ai-profiles/merge')).toBe(false);
145
+ });
94
146
  });
95
147
  describe('proxy cookie helpers', () => {
96
148
  it('rewrites mismatched cookie domains for non-loopback local hosts', () => {
@@ -126,7 +178,8 @@ describe('resolveAuthorizedWorkspaceAccess', () => {
126
178
  userId: 'user-1',
127
179
  workspaceId: 'workspace-personal',
128
180
  role: 'member',
129
- systemRole: 'user'
181
+ systemRole: 'user',
182
+ identityId: null
130
183
  }, 'workspace-team');
131
184
  expect(core.resolveUserAccess).toHaveBeenCalledWith('user-1', 'workspace-team', 'member');
132
185
  expect(next.workspaceId).toBe('workspace-team');
@@ -154,12 +207,67 @@ describe('resolveAuthorizedWorkspaceAccess', () => {
154
207
  userId: 'user-1',
155
208
  workspaceId: 'workspace-personal',
156
209
  role: 'member',
157
- systemRole: 'user'
210
+ systemRole: 'user',
211
+ identityId: null
158
212
  }, 'workspace-team');
159
213
  expect(core.resolveUserAccess).toHaveBeenNthCalledWith(1, 'user-1', 'workspace-team', 'member');
160
214
  expect(core.resolveUserAccess).toHaveBeenNthCalledWith(2, 'user-1', 'workspace-personal', 'member');
161
215
  expect(next.workspaceId).toBe('workspace-personal');
162
216
  });
217
+ it('preserves account and workspace disabled scopes separately', () => {
218
+ const core = {
219
+ resolveUserAccess: vi.fn((userId, workspaceId, role) => ({
220
+ userId,
221
+ workspaceId,
222
+ role,
223
+ permissionMode: 'read-write',
224
+ disabled: true,
225
+ accountDisabled: false,
226
+ workspaceDisabled: true,
227
+ betaAccess: true
228
+ })),
229
+ getSystemRole: vi.fn(() => 'user')
230
+ };
231
+ const next = resolveAuthorizedWorkspaceAccess(core, {
232
+ authenticated: true,
233
+ sessionId: 'session-1',
234
+ userId: 'user-1',
235
+ workspaceId: 'workspace-shared',
236
+ role: 'member',
237
+ systemRole: 'user',
238
+ identityId: null
239
+ }, 'workspace-shared');
240
+ expect(next.disabled).toBe(true);
241
+ expect(next.accountDisabled).toBe(false);
242
+ expect(next.workspaceDisabled).toBe(true);
243
+ });
244
+ });
245
+ describe('resolveDisabledAccessError', () => {
246
+ it('blocks globally disabled accounts outside auth routes', () => {
247
+ expect(resolveDisabledAccessError({ disabled: true, accountDisabled: true }, '/api/taskforce/workspaces')).toBe('Forbidden: user account is disabled.');
248
+ expect(resolveDisabledAccessError({ disabled: true, accountDisabled: true }, '/api/taskforce/auth/session')).toBeNull();
249
+ });
250
+ it('allows workspace-disabled sessions to reach recovery routes only', () => {
251
+ const access = { disabled: true, accountDisabled: false, workspaceDisabled: true };
252
+ expect(resolveDisabledAccessError(access, '/api/taskforce/workspaces')).toBeNull();
253
+ expect(resolveDisabledAccessError(access, '/api/taskforce/session/workspace')).toBeNull();
254
+ expect(resolveDisabledAccessError(access, '/api/taskforce/tasks')).toBe('Forbidden: workspace access is not active for this user.');
255
+ });
256
+ });
257
+ describe('shouldApplyReadOnlyMutationGuard', () => {
258
+ it('guards ordinary Taskforce mutations', () => {
259
+ expect(shouldApplyReadOnlyMutationGuard('POST', '/api/taskforce/tasks')).toBe(true);
260
+ expect(shouldApplyReadOnlyMutationGuard('PATCH', '/api/taskforce/task/task-1')).toBe(true);
261
+ expect(shouldApplyReadOnlyMutationGuard('DELETE', '/api/taskforce/task/task-1')).toBe(true);
262
+ });
263
+ it('allows session workspace switching through route-level access validation', () => {
264
+ expect(shouldApplyReadOnlyMutationGuard('POST', '/api/taskforce/session/workspace')).toBe(false);
265
+ });
266
+ it('does not guard non-mutations, auth routes, or health checks', () => {
267
+ expect(shouldApplyReadOnlyMutationGuard('GET', '/api/taskforce/tasks')).toBe(false);
268
+ expect(shouldApplyReadOnlyMutationGuard('POST', '/api/taskforce/auth/login')).toBe(false);
269
+ expect(shouldApplyReadOnlyMutationGuard('POST', '/api/taskforce/health')).toBe(false);
270
+ });
163
271
  });
164
272
  describe('resolveEffectiveRequestUserId', () => {
165
273
  it('prefers the authenticated access user when present', () => {
@@ -7,6 +7,7 @@
7
7
  *
8
8
  * Routes registered here:
9
9
  * GET/POST /api/platform/plans
10
+ * GET /api/platform/onboarding-plan-options
10
11
  * GET/POST /api/platform/plans/:planId/versions
11
12
  * GET /api/platform/features
12
13
  * GET/PATCH /api/platform/plans/:planId/versions/:versionId/features
@@ -23,6 +24,8 @@
23
24
  * GET/POST /api/taskforce/admin/email-settings
24
25
  * GET /api/taskforce/admin/email-settings/health
25
26
  * POST /api/taskforce/admin/email-settings/test
27
+ * GET/POST /api/taskforce/admin/auth-provider-settings
28
+ * GET /api/taskforce/admin/auth-provider-settings/health
26
29
  * GET/POST /api/taskforce/admin/system-settings
27
30
  * GET/POST /api/taskforce/admin/object-storage-settings
28
31
  * GET /api/taskforce/admin/object-storage-telemetry