@taskforcehq/taskforce 0.3.304 → 0.3.306

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (383) hide show
  1. package/README.md +140 -247
  2. package/dist/Taskforce.module.css +295 -89
  3. package/dist/TaskforceCore.js +378 -111
  4. package/dist/TaskforceCore.test.js +1221 -107
  5. package/dist/assets/fonts/CourierPrime-Bold.woff2 +0 -0
  6. package/dist/assets/fonts/CourierPrime-BoldItalic.woff2 +0 -0
  7. package/dist/assets/fonts/CourierPrime-Italic.woff2 +0 -0
  8. package/dist/assets/fonts/CourierPrime-Regular.woff2 +0 -0
  9. package/dist/assets/fonts/Noir_medium.woff2 +0 -0
  10. package/dist/assets/fonts/Noir_regular.woff2 +0 -0
  11. package/dist/assets/fonts/RussoOne-Regular.woff2 +0 -0
  12. package/dist/assets/fonts/SpecialElite-Regular.woff2 +0 -0
  13. package/dist/compat/workspaceSyncCompat.js +52 -2
  14. package/dist/compat/workspaceSyncCompat.test.js +38 -1
  15. package/dist/components/context/ContextAttachmentManager.d.ts +14 -0
  16. package/dist/components/context/ContextAttachmentManager.js +549 -0
  17. package/dist/components/features/AgentsModule.d.ts +10 -1
  18. package/dist/components/features/AgentsModule.js +260 -15
  19. package/dist/components/features/AgentsModule.test.js +255 -5
  20. package/dist/components/features/DocumentIndex.d.ts +1 -1
  21. package/dist/components/features/DocumentIndex.js +1 -1
  22. package/dist/components/features/DocumentViewer.d.ts +6 -2
  23. package/dist/components/features/DocumentViewer.js +90 -10
  24. package/dist/components/features/DocumentWorkspace.d.ts +5 -22
  25. package/dist/components/features/DocumentWorkspace.js +12 -155
  26. package/dist/components/features/DocumentWorkspace.test.js +226 -6
  27. package/dist/components/features/TaskSettings.js +29 -3
  28. package/dist/components/features/TaskSettings.test.js +42 -1
  29. package/dist/components/features/documentWorkspaceModel.d.ts +24 -0
  30. package/dist/components/features/documentWorkspaceModel.js +57 -0
  31. package/dist/components/features/useDocumentWorkspaceController.d.ts +34 -0
  32. package/dist/components/features/useDocumentWorkspaceController.js +113 -0
  33. package/dist/components/task/TaskCard.js +19 -28
  34. package/dist/components/task/TaskCard.test.js +38 -3
  35. package/dist/components/task/TaskContextUpload.js +4 -526
  36. package/dist/components/task/TaskForm.d.ts +8 -8
  37. package/dist/components/task/TaskForm.js +362 -230
  38. package/dist/components/task/TaskForm.test.js +558 -381
  39. package/dist/components/task/TaskKanban.d.ts +2 -1
  40. package/dist/components/task/TaskKanban.js +96 -14
  41. package/dist/components/task/TaskKanban.test.js +36 -0
  42. package/dist/components/ui/EditableAvatarButton.d.ts +18 -0
  43. package/dist/components/ui/EditableAvatarButton.js +18 -0
  44. package/dist/components/views/PlanComparisonPage.d.ts +9 -1
  45. package/dist/components/views/PlanComparisonPage.js +70 -17
  46. package/dist/components/views/PlanComparisonPage.test.js +289 -41
  47. package/dist/components/views/PlansPage.js +239 -106
  48. package/dist/components/views/PlansPage.test.js +593 -42
  49. package/dist/components/views/StandaloneLayout.js +310 -554
  50. package/dist/components/views/panels/FilterToolbar.test.js +6 -4
  51. package/dist/components/views/panels/PlanningDrawer.d.ts +8 -1
  52. package/dist/components/views/panels/PlanningDrawer.js +18 -11
  53. package/dist/components/views/panels/PlanningDrawer.test.d.ts +1 -0
  54. package/dist/components/views/panels/PlanningDrawer.test.js +141 -0
  55. package/dist/components/views/planningScope.d.ts +20 -0
  56. package/dist/components/views/planningScope.js +25 -0
  57. package/dist/components/views/planningScope.test.d.ts +1 -0
  58. package/dist/components/views/planningScope.test.js +60 -0
  59. package/dist/components/views/standalone/modals/AccountHubModal.d.ts +27 -14
  60. package/dist/components/views/standalone/modals/AccountHubModal.js +87 -15
  61. package/dist/components/views/standalone/modals/AccountHubModal.test.js +42 -2
  62. package/dist/components/views/standalone/modals/AvatarImageManagerModal.d.ts +20 -0
  63. package/dist/components/views/standalone/modals/AvatarImageManagerModal.js +127 -0
  64. package/dist/components/views/standalone/modals/EditProfileModal.d.ts +2 -9
  65. package/dist/components/views/standalone/modals/EditProfileModal.js +3 -2
  66. package/dist/components/views/standalone/modals/SyncEnableWarningModal.d.ts +9 -0
  67. package/dist/components/views/standalone/modals/SyncEnableWarningModal.js +6 -0
  68. package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.d.ts +1 -0
  69. package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.js +24 -0
  70. package/dist/components/views/standalone/modals/SyncStatusModal.d.ts +2 -1
  71. package/dist/components/views/standalone/modals/SyncStatusModal.js +2 -2
  72. package/dist/config/envSchema.js +1 -1
  73. package/dist/core/AiProfileService.d.ts +45 -3
  74. package/dist/core/AiProfileService.js +774 -63
  75. package/dist/core/AiProfileService.test.js +22 -2
  76. package/dist/core/AiProfiles.test.js +761 -2
  77. package/dist/core/AttachmentLinkService.js +57 -15
  78. package/dist/core/AuthIdentityService.d.ts +107 -0
  79. package/dist/core/AuthIdentityService.js +284 -0
  80. package/dist/core/AuthTokenService.d.ts +4 -0
  81. package/dist/core/AuthTokenService.js +34 -6
  82. package/dist/core/AuthTokenService.test.d.ts +1 -0
  83. package/dist/core/AuthTokenService.test.js +78 -0
  84. package/dist/core/EntitlementsPolicy.test.js +77 -15
  85. package/dist/core/GlobalSettingsService.js +115 -6
  86. package/dist/core/PlanEntitlementService.d.ts +30 -3
  87. package/dist/core/PlanEntitlementService.js +454 -93
  88. package/dist/core/PlanFeatureCatalog.test.d.ts +1 -0
  89. package/dist/core/PlanFeatureCatalog.test.js +84 -0
  90. package/dist/core/PlanVersionPolicy.test.js +54 -28
  91. package/dist/core/PlanningEntities.test.js +52 -0
  92. package/dist/core/SignupMonetizationSettings.test.js +241 -44
  93. package/dist/core/SyncReconciliationService.js +2 -65
  94. package/dist/core/SystemAdmin.test.js +244 -88
  95. package/dist/core/TaskAttachmentsCanonical.test.js +51 -1
  96. package/dist/core/TaskTaxonomyValidation.test.js +53 -0
  97. package/dist/core/Taskforce.d.ts +228 -14
  98. package/dist/core/Taskforce.js +814 -201
  99. package/dist/core/Taskforce.listTasksSlim.test.d.ts +1 -0
  100. package/dist/core/Taskforce.listTasksSlim.test.js +91 -0
  101. package/dist/core/UserProfileAvatarDrafts.test.js +30 -3
  102. package/dist/core/WorkspaceLifecycleService.js +0 -5
  103. package/dist/core/WorkspacePermissions.test.js +25 -1
  104. package/dist/core/WorkspacePlanMode.test.js +128 -27
  105. package/dist/core/shared.d.ts +3 -1
  106. package/dist/core/shared.js +16 -1
  107. package/dist/core/types.d.ts +68 -2
  108. package/dist/hooks/auth/useTaskforceAuthBootstrap.js +26 -1
  109. package/dist/hooks/sync/auth.js +3 -1
  110. package/dist/hooks/sync/bootstrap.js +2 -0
  111. package/dist/hooks/sync/controlPlane.d.ts +37 -0
  112. package/dist/hooks/sync/controlPlane.js +78 -0
  113. package/dist/hooks/sync/controlPlane.test.d.ts +1 -0
  114. package/dist/hooks/sync/controlPlane.test.js +121 -0
  115. package/dist/hooks/sync/lifecyclePolicy.d.ts +45 -0
  116. package/dist/hooks/sync/lifecyclePolicy.js +93 -0
  117. package/dist/hooks/sync/lifecyclePolicy.test.d.ts +1 -0
  118. package/dist/hooks/sync/lifecyclePolicy.test.js +124 -0
  119. package/dist/hooks/sync/orchestratorShared.d.ts +10 -1
  120. package/dist/hooks/sync/orchestratorShared.js +68 -47
  121. package/dist/hooks/sync/orchestratorShared.test.js +50 -1
  122. package/dist/hooks/sync/pullLifecycle.d.ts +31 -0
  123. package/dist/hooks/sync/pullLifecycle.js +24 -0
  124. package/dist/hooks/sync/pullLifecycle.test.d.ts +1 -0
  125. package/dist/hooks/sync/pullLifecycle.test.js +80 -0
  126. package/dist/hooks/sync/recovery.d.ts +16 -2
  127. package/dist/hooks/sync/recovery.js +171 -53
  128. package/dist/hooks/sync/recovery.test.d.ts +1 -0
  129. package/dist/hooks/sync/recovery.test.js +292 -0
  130. package/dist/hooks/sync/transfers.d.ts +16 -3
  131. package/dist/hooks/sync/transfers.js +186 -65
  132. package/dist/hooks/sync/transfers.test.d.ts +1 -0
  133. package/dist/hooks/sync/transfers.test.js +396 -0
  134. package/dist/hooks/sync/useRecentSyncEvents.d.ts +21 -0
  135. package/dist/hooks/sync/useRecentSyncEvents.js +92 -0
  136. package/dist/hooks/sync/useRecentSyncEvents.test.d.ts +1 -0
  137. package/dist/hooks/sync/useRecentSyncEvents.test.js +124 -0
  138. package/dist/hooks/sync/useSyncStatusActions.d.ts +30 -0
  139. package/dist/hooks/sync/useSyncStatusActions.js +88 -0
  140. package/dist/hooks/sync/useSyncStatusActions.test.d.ts +1 -0
  141. package/dist/hooks/sync/useSyncStatusActions.test.js +133 -0
  142. package/dist/hooks/sync/useSyncStatusControls.d.ts +25 -0
  143. package/dist/hooks/sync/useSyncStatusControls.js +60 -0
  144. package/dist/hooks/sync/useSyncStatusControls.test.d.ts +1 -0
  145. package/dist/hooks/sync/useSyncStatusControls.test.js +88 -0
  146. package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +12 -0
  147. package/dist/hooks/useSyncOrchestrator.d.ts +16 -6
  148. package/dist/hooks/useSyncOrchestrator.js +424 -175
  149. package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +487 -10
  150. package/dist/hooks/useTaskData.js +8 -3
  151. package/dist/hooks/useTaskData.test.js +45 -0
  152. package/dist/hooks/useTaskMutations.d.ts +2 -1
  153. package/dist/hooks/useTaskMutations.js +12 -1
  154. package/dist/hooks/useTaskMutations.test.js +30 -1
  155. package/dist/hooks/useTaskforce.d.ts +65 -4
  156. package/dist/hooks/useTaskforce.js +564 -243
  157. package/dist/hooks/useTaskforce.runtime-routing.test.d.ts +1 -0
  158. package/dist/hooks/useTaskforce.runtime-routing.test.js +152 -0
  159. package/dist/hooks/useTaskforce.sync-behavior.test.js +2454 -208
  160. package/dist/hooks/useWorkspaceSyncController.d.ts +4 -1
  161. package/dist/hooks/useWorkspaceSyncController.js +17 -2
  162. package/dist/hooks/useWorkspaceSyncController.test.js +1 -0
  163. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.d.ts +16 -0
  164. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +316 -35
  165. package/dist/localization/locales/en-US.d.ts +0 -1
  166. package/dist/localization/locales/en-US.js +0 -1
  167. package/dist/localization/locales/es-419.js +0 -1
  168. package/dist/localization/locales/pt-BR.js +0 -1
  169. package/dist/mcp/adminWorkspaceRegistrar.d.ts +2 -0
  170. package/dist/mcp/adminWorkspaceRegistrar.js +154 -0
  171. package/dist/mcp/collaborationRegistrar.d.ts +2 -0
  172. package/dist/mcp/collaborationRegistrar.js +71 -0
  173. package/dist/mcp/documentAssetRegistrar.d.ts +2 -0
  174. package/dist/mcp/documentAssetRegistrar.js +346 -0
  175. package/dist/mcp/runtime.d.ts +2 -0
  176. package/dist/mcp/runtime.js +2433 -3534
  177. package/dist/mcp/runtime.test.js +440 -2
  178. package/dist/mcp/taskPlanningRegistrar.d.ts +2 -0
  179. package/dist/mcp/taskPlanningRegistrar.js +418 -0
  180. package/dist/mcp/toolCatalog.d.ts +35 -0
  181. package/dist/mcp/toolCatalog.js +3 -0
  182. package/dist/migrations/taskSchemaMigrations.d.ts +1 -1
  183. package/dist/migrations/taskSchemaMigrations.js +171 -61
  184. package/dist/migrations/taskSchemaMigrations.test.js +15 -0
  185. package/dist/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
  186. package/dist/resources/templates/workflows/collaborate.yaml +1 -1
  187. package/dist/resources/templates/workflows/evaluate.yaml +2 -2
  188. package/dist/resources/templates/workflows/plan.yaml +1 -1
  189. package/dist/resources/templates/workflows/review.yaml +2 -2
  190. package/dist/server/annotatedAttachmentsRoutes.test.js +3 -3
  191. package/dist/server/auth/providers/apple.d.ts +33 -0
  192. package/dist/server/auth/providers/apple.js +82 -0
  193. package/dist/server/auth/providers/appleClientSecret.d.ts +37 -0
  194. package/dist/server/auth/providers/appleClientSecret.js +65 -0
  195. package/dist/server/auth/providers/github.d.ts +26 -0
  196. package/dist/server/auth/providers/github.js +86 -0
  197. package/dist/server/auth/providers/google.d.ts +21 -0
  198. package/dist/server/auth/providers/google.js +56 -0
  199. package/dist/server/auth/providers/types.d.ts +21 -0
  200. package/dist/server/auth/providers/types.js +1 -0
  201. package/dist/server/auth.d.ts +2 -0
  202. package/dist/server/auth.js +6 -3
  203. package/dist/server/documentReviewRoutes.test.js +36 -3
  204. package/dist/server/index.cookieProxy.test.js +1 -0
  205. package/dist/server/index.d.ts +12 -0
  206. package/dist/server/index.js +120 -9
  207. package/dist/server/index.rateLimit.test.js +3 -0
  208. package/dist/server/index.test.js +106 -3
  209. package/dist/server/routes/admin.d.ts +4 -5
  210. package/dist/server/routes/admin.js +410 -80
  211. package/dist/server/routes/annotatedAttachments.d.ts +1 -1
  212. package/dist/server/routes/annotatedAttachments.js +1 -1
  213. package/dist/server/routes/auth.d.ts +16 -6
  214. package/dist/server/routes/auth.js +1015 -118
  215. package/dist/server/routes/authSupport.d.ts +30 -0
  216. package/dist/server/routes/authSupport.js +81 -0
  217. package/dist/server/routes/billing.d.ts +1 -1
  218. package/dist/server/routes/billing.js +276 -34
  219. package/dist/server/routes/billing.test.js +760 -52
  220. package/dist/server/routes/documentReviews.d.ts +1 -1
  221. package/dist/server/routes/documentReviews.js +1 -1
  222. package/dist/server/routes/documents.d.ts +5 -2
  223. package/dist/server/routes/documents.js +242 -74
  224. package/dist/server/routes/primitives.d.ts +11 -0
  225. package/dist/server/routes/primitives.js +73 -0
  226. package/dist/server/routes/resources.d.ts +1 -1
  227. package/dist/server/routes/resources.js +1 -1
  228. package/dist/server/routes/shared.d.ts +29 -3
  229. package/dist/server/routes/shared.js +69 -4
  230. package/dist/server/routes/sync.d.ts +1 -1
  231. package/dist/server/routes/sync.integration.test.js +437 -39
  232. package/dist/server/routes/sync.js +62 -606
  233. package/dist/server/routes/syncAuxRoutes.d.ts +15 -0
  234. package/dist/server/routes/syncAuxRoutes.js +91 -0
  235. package/dist/server/routes/syncAuxRoutes.test.d.ts +1 -0
  236. package/dist/server/routes/syncAuxRoutes.test.js +158 -0
  237. package/dist/server/routes/syncPullApplyRoutes.d.ts +36 -0
  238. package/dist/server/routes/syncPullApplyRoutes.js +204 -0
  239. package/dist/server/routes/syncPushRoutes.d.ts +24 -0
  240. package/dist/server/routes/syncPushRoutes.js +212 -0
  241. package/dist/server/routes/syncRouteGuards.d.ts +36 -0
  242. package/dist/server/routes/syncRouteGuards.js +67 -0
  243. package/dist/server/routes/syncRouteGuards.test.d.ts +1 -0
  244. package/dist/server/routes/syncRouteGuards.test.js +94 -0
  245. package/dist/server/routes/syncRouteTypes.d.ts +13 -0
  246. package/dist/server/routes/syncRouteTypes.js +1 -0
  247. package/dist/server/routes/syncSnapshotRoutes.d.ts +66 -0
  248. package/dist/server/routes/syncSnapshotRoutes.js +180 -0
  249. package/dist/server/routes/tasks.d.ts +1 -1
  250. package/dist/server/routes/tasks.js +44 -2
  251. package/dist/server/routes/workspaces.d.ts +1 -1
  252. package/dist/server/routes/workspaces.js +37 -6
  253. package/dist/server/routes.d.ts +2 -9
  254. package/dist/server/routes.js +136 -165
  255. package/dist/server/routes.test.js +2457 -162
  256. package/dist/services/workflowExportSnapshots.test.js +2 -0
  257. package/dist/shared/aiProfileSeatScope.d.ts +5 -0
  258. package/dist/shared/aiProfileSeatScope.js +21 -0
  259. package/dist/shared/passwordPolicy.d.ts +13 -0
  260. package/dist/shared/passwordPolicy.js +84 -0
  261. package/dist/shared/passwordPolicy.test.d.ts +1 -0
  262. package/dist/shared/passwordPolicy.test.js +34 -0
  263. package/dist/storage/workspaceAssetStore.d.ts +15 -3
  264. package/dist/storage/workspaceAssetStore.js +132 -44
  265. package/dist/storage/workspaceAssetStore.test.js +93 -6
  266. package/dist/styles/fonts.css +70 -0
  267. package/dist/sync/collaborationSyncPayload.d.ts +6 -1
  268. package/dist/sync/collaborationSyncPayload.js +17 -11
  269. package/dist/sync/collaborationSyncPayload.test.js +13 -1
  270. package/dist/sync/contentSyncState.d.ts +4 -8
  271. package/dist/sync/contentSyncState.js +33 -77
  272. package/dist/sync/syncApplyHandlers.d.ts +7 -0
  273. package/dist/sync/syncApplyHandlers.js +28 -13
  274. package/dist/sync/syncApplyHandlers.test.js +72 -3
  275. package/dist/sync/syncFieldSemantics.d.ts +12 -0
  276. package/dist/sync/syncFieldSemantics.js +55 -0
  277. package/dist/sync/syncResourceAdapters.d.ts +44 -0
  278. package/dist/sync/syncResourceAdapters.js +77 -0
  279. package/dist/sync/syncService.d.ts +6 -0
  280. package/dist/sync/syncService.js +60 -0
  281. package/dist/sync/syncService.test.js +71 -3
  282. package/dist/sync/taskSyncChangeKey.d.ts +2 -0
  283. package/dist/sync/taskSyncChangeKey.js +143 -0
  284. package/dist/sync/taskSyncPayload.js +3 -8
  285. package/dist/sync/workspacePullFeed.js +4 -3
  286. package/dist/sync/workspacePullFeed.test.js +43 -0
  287. package/dist/sync/workspaceRepair.js +5 -2
  288. package/dist/sync/workspaceSyncModel.d.ts +48 -0
  289. package/dist/sync/workspaceSyncModel.js +195 -31
  290. package/dist/sync/workspaceSyncModel.test.js +325 -12
  291. package/dist/sync/workspaceSyncState.d.ts +19 -0
  292. package/dist/sync/workspaceSyncState.js +3 -1
  293. package/dist/sync/workspaceSyncSurface.js +3 -8
  294. package/dist/types.d.ts +17 -0
  295. package/dist/ui/assets/AgentsModule-DrLawwNl.js +1 -0
  296. package/dist/ui/assets/{AnnotatedAttachmentWorkspace-BlS-cqnl.js → AnnotatedAttachmentWorkspace-Z9_whf7F.js} +1 -1
  297. package/dist/ui/assets/CourierPrime-Bold-BuLj_dpw.woff2 +0 -0
  298. package/dist/ui/assets/CourierPrime-BoldItalic-BrK2pUkZ.woff2 +0 -0
  299. package/dist/ui/assets/CourierPrime-Italic-DFUZK5Ey.woff2 +0 -0
  300. package/dist/ui/assets/CourierPrime-Regular-BsKphzVf.woff2 +0 -0
  301. package/dist/ui/assets/DocumentWorkspace-B03MaSkw.js +252 -0
  302. package/dist/ui/assets/DocumentWorkspace-Dhdso07p.css +1 -0
  303. package/dist/ui/assets/{InitiativesModule-BjR6iBf9.js → InitiativesModule-9E6ParrY.js} +1 -1
  304. package/dist/ui/assets/Noir_medium-bxQwKGzB.woff2 +0 -0
  305. package/dist/ui/assets/Noir_regular-ojf2kxlG.woff2 +0 -0
  306. package/dist/ui/assets/PlansPage-CvfnMiWq.css +1 -0
  307. package/dist/ui/assets/PlansPage-DRXscYxH.js +1 -0
  308. package/dist/ui/assets/RussoOne-Regular-Cu_qq_qC.woff2 +0 -0
  309. package/dist/ui/assets/SpecialElite-Regular-Di6gSvAS.woff2 +0 -0
  310. package/dist/ui/assets/TaskSettings-DZX4jk7e.js +9 -0
  311. package/dist/ui/assets/{WorkflowsModule-DnFqdUME.js → WorkflowsModule-BA7jcEpH.js} +1 -1
  312. package/dist/ui/assets/index-9eT8e0Lu.css +1 -0
  313. package/dist/ui/assets/index-C6k75jr8.js +6 -0
  314. package/dist/ui/assets/{vendor-icons-I7ZwG1z_.js → vendor-icons-DuEd_65c.js} +1 -1
  315. package/dist/ui/fonts/CourierPrime-Bold.ttf +0 -0
  316. package/dist/ui/fonts/CourierPrime-Bold.woff2 +0 -0
  317. package/dist/ui/fonts/CourierPrime-BoldItalic.ttf +0 -0
  318. package/dist/ui/fonts/CourierPrime-BoldItalic.woff2 +0 -0
  319. package/dist/ui/fonts/CourierPrime-Italic.ttf +0 -0
  320. package/dist/ui/fonts/CourierPrime-Italic.woff2 +0 -0
  321. package/dist/ui/fonts/CourierPrime-Regular.ttf +0 -0
  322. package/dist/ui/fonts/CourierPrime-Regular.woff2 +0 -0
  323. package/dist/ui/fonts/Noir_medium.otf +0 -0
  324. package/dist/ui/fonts/Noir_medium.woff2 +0 -0
  325. package/dist/ui/fonts/Noir_regular.otf +0 -0
  326. package/dist/ui/fonts/Noir_regular.woff2 +0 -0
  327. package/dist/ui/fonts/RussoOne-Regular.woff2 +0 -0
  328. package/dist/ui/fonts/SpecialElite-Regular.ttf +0 -0
  329. package/dist/ui/fonts/SpecialElite-Regular.woff2 +0 -0
  330. package/dist/ui/index.html +3 -3
  331. package/dist/utils/accountProfileSummaryCache.d.ts +5 -0
  332. package/dist/utils/assignees.d.ts +2 -0
  333. package/dist/utils/assignees.js +2 -0
  334. package/dist/utils/avatarUpload.d.ts +27 -0
  335. package/dist/utils/avatarUpload.js +132 -0
  336. package/dist/utils/avatarUpload.test.d.ts +1 -0
  337. package/dist/utils/avatarUpload.test.js +40 -0
  338. package/dist/utils/bootstrapTrace.d.ts +7 -0
  339. package/dist/utils/bootstrapTrace.js +29 -0
  340. package/dist/utils/commercialLifecyclePresentation.d.ts +19 -0
  341. package/dist/utils/commercialLifecyclePresentation.js +199 -0
  342. package/dist/utils/contextAssetEvents.d.ts +2 -0
  343. package/dist/utils/syncEventDetails.d.ts +3 -0
  344. package/dist/utils/syncEventDetails.js +64 -0
  345. package/dist/utils/syncEventDetails.test.d.ts +1 -0
  346. package/dist/utils/syncEventDetails.test.js +23 -0
  347. package/dist/utils/syncEventPresentation.d.ts +15 -0
  348. package/dist/utils/syncEventPresentation.js +129 -0
  349. package/dist/utils/syncEventPresentation.test.d.ts +1 -0
  350. package/dist/utils/syncEventPresentation.test.js +64 -0
  351. package/dist/utils/syncStatusPresentation.d.ts +72 -0
  352. package/dist/utils/syncStatusPresentation.js +217 -0
  353. package/dist/utils/syncStatusPresentation.test.d.ts +1 -0
  354. package/dist/utils/syncStatusPresentation.test.js +164 -0
  355. package/dist/utils/taskActivity.d.ts +2 -0
  356. package/dist/utils/taskActivity.js +228 -22
  357. package/dist/utils/taskActivity.test.js +119 -8
  358. package/dist/utils/workspaceSyncPresentation.d.ts +4 -0
  359. package/dist/utils/workspaceSyncPresentation.js +68 -2
  360. package/dist/utils/workspaceSyncPresentation.test.js +36 -1
  361. package/package.json +10 -2
  362. package/scripts/check-cloud-mcp.mjs +83 -0
  363. package/scripts/export-sqlite-to-postgres.mjs +7 -9
  364. package/scripts/playwright-auth.sh +5 -1
  365. package/scripts/run-billing-performance-smoke.sh +24 -0
  366. package/scripts/run-e2e-realtime.sh +17 -3
  367. package/scripts/run-smoke.sh +17 -5
  368. package/scripts/run-soak.sh +17 -5
  369. package/src/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
  370. package/src/resources/templates/workflows/collaborate.yaml +1 -1
  371. package/src/resources/templates/workflows/evaluate.yaml +2 -2
  372. package/src/resources/templates/workflows/plan.yaml +1 -1
  373. package/src/resources/templates/workflows/review.yaml +2 -2
  374. package/dist/ui/assets/AgentsModule-BLWVbuKP.js +0 -1
  375. package/dist/ui/assets/DocumentWorkspace-BH_6DF6x.js +0 -250
  376. package/dist/ui/assets/DocumentWorkspace-C_8T8oz-.css +0 -1
  377. package/dist/ui/assets/PlansPage-C2dd2n1X.css +0 -1
  378. package/dist/ui/assets/PlansPage-CSDQ4sLa.js +0 -1
  379. package/dist/ui/assets/RussoOne-Regular-C3BxZIj7.ttf +0 -0
  380. package/dist/ui/assets/TaskSettings-CEDy34Jo.js +0 -9
  381. package/dist/ui/assets/index-DXUdtH1B.js +0 -6
  382. package/dist/ui/assets/index-Ii0B0rTO.css +0 -1
  383. package/scripts/migrate-planning-model.ts +0 -233
@@ -0,0 +1,212 @@
1
+ import { decryptDocument, ENCRYPTION_PREFIX } from '../../sync/encryptionService.js';
2
+ import { serializeTaskForSync } from '../../sync/taskSyncPayload.js';
3
+ import { parseJsonBody } from './primitives.js';
4
+ import { requireAuthenticatedSyncRequest, requireEnabledSyncAuth, resolveAuthorizedSyncWorkspace, } from './syncRouteGuards.js';
5
+ export function registerWorkspacePushSyncRoutes({ addRoute, core, context, auditAuthAction, resolveErrorStatusCode, resolveRequestAccess, readPushIdempotency, writePushIdempotency, dispatchWorkspaceSyncChanges }) {
6
+ // POST /api/taskforce/sync/workspace/push - Incremental workspace deltas from local to cloud
7
+ addRoute('POST', '/api/taskforce/sync/workspace/push', async (req, res) => {
8
+ const auditPushSideEffect = (action, details) => {
9
+ try {
10
+ auditAuthAction(req, action, details);
11
+ }
12
+ catch {
13
+ // success-path diagnostics must never flip a committed push into failure
14
+ }
15
+ };
16
+ const startedAtMs = Date.now();
17
+ const authConfig = context.authConfig;
18
+ if (!requireEnabledSyncAuth(res, authConfig)) {
19
+ return;
20
+ }
21
+ const access = requireAuthenticatedSyncRequest({
22
+ req,
23
+ res,
24
+ authConfig,
25
+ resolveRequestAccess,
26
+ auditAuthAction,
27
+ unauthorizedAuditAction: 'sync-workspace-push-unauthorized'
28
+ });
29
+ if (!access) {
30
+ return;
31
+ }
32
+ const body = await parseJsonBody(req, 50 * 1024 * 1024);
33
+ const targetWorkspaceId = resolveAuthorizedSyncWorkspace({
34
+ req,
35
+ res,
36
+ core,
37
+ access,
38
+ requestedWorkspaceId: String(body?.workspaceId || '').trim(),
39
+ auditAuthAction,
40
+ missingWorkspaceAuditAction: 'sync-workspace-push-missing-workspace',
41
+ forbiddenWorkspaceAuditAction: 'sync-workspace-push-forbidden',
42
+ missingWorkspaceResponseExtras: {
43
+ durationMs: Date.now() - startedAtMs
44
+ }
45
+ });
46
+ if (!targetWorkspaceId) {
47
+ return;
48
+ }
49
+ const idempotencyKey = String(body?.idempotencyKey || '').trim();
50
+ if (idempotencyKey) {
51
+ const replay = readPushIdempotency(targetWorkspaceId, idempotencyKey);
52
+ if (replay) {
53
+ auditAuthAction(req, 'sync-workspace-push-idempotent-replay', {
54
+ workspaceId: targetWorkspaceId,
55
+ idempotencyKey
56
+ });
57
+ res.writeHead(200, { 'Content-Type': 'application/json' });
58
+ res.end(replay);
59
+ return;
60
+ }
61
+ }
62
+ let incomingChanges = Array.isArray(body?.changes) ? body.changes : [];
63
+ const incomingTaskUpsertIds = incomingChanges
64
+ .filter((change) => change?.op === 'upsert')
65
+ .map((change) => String(change.task?.id || '').trim())
66
+ .filter((taskId) => taskId.length > 0);
67
+ const allowReferenceNumberReassignment = body?.repair === true;
68
+ if (typeof process !== 'undefined' && process.env?.TASKFORCE_SYNC_KEY) {
69
+ const syncKey = process.env.TASKFORCE_SYNC_KEY;
70
+ const decryptedChanges = [];
71
+ for (const change of incomingChanges) {
72
+ if (change.op === 'asset-upsert' && typeof change.contentBase64 === 'string' && change.contentBase64.startsWith(ENCRYPTION_PREFIX)) {
73
+ try {
74
+ decryptedChanges.push({ ...change, contentBase64: await decryptDocument(change.contentBase64, syncKey) });
75
+ }
76
+ catch {
77
+ decryptedChanges.push(change);
78
+ }
79
+ }
80
+ else if (change.op === 'document-upsert' && typeof change.content === 'string' && change.content.startsWith(ENCRYPTION_PREFIX)) {
81
+ try {
82
+ decryptedChanges.push({ ...change, content: await decryptDocument(change.content, syncKey) });
83
+ }
84
+ catch {
85
+ decryptedChanges.push(change);
86
+ }
87
+ }
88
+ else {
89
+ decryptedChanges.push(change);
90
+ }
91
+ }
92
+ incomingChanges = decryptedChanges;
93
+ }
94
+ const receivedAtBaseMs = Date.now();
95
+ incomingChanges = incomingChanges.map((change, index) => {
96
+ if (change.op !== 'upsert')
97
+ return change;
98
+ const task = change.task;
99
+ const rawReferenceNumber = task.referenceNumber;
100
+ const incomingReferenceNumber = rawReferenceNumber === undefined || rawReferenceNumber === null
101
+ ? null
102
+ : (Number.isFinite(Number(rawReferenceNumber))
103
+ ? Math.max(1, Math.floor(Number(rawReferenceNumber)))
104
+ : null);
105
+ if (incomingReferenceNumber)
106
+ return change;
107
+ return {
108
+ ...change,
109
+ task: {
110
+ ...task,
111
+ updatedAt: new Date(receivedAtBaseMs + index).toISOString()
112
+ }
113
+ };
114
+ });
115
+ try {
116
+ const { result, deleteCount, emittedEventIds } = await dispatchWorkspaceSyncChanges(targetWorkspaceId, incomingChanges, {
117
+ allowReferenceNumberReassignment
118
+ });
119
+ let appliedTaskUpserts = [];
120
+ try {
121
+ appliedTaskUpserts = incomingTaskUpsertIds
122
+ .map((taskId) => core.getTask(taskId, targetWorkspaceId))
123
+ .filter((task) => Boolean(task))
124
+ .map((task) => ({
125
+ archived: Boolean(task.isArchived),
126
+ task: serializeTaskForSync(task)
127
+ }));
128
+ }
129
+ catch (error) {
130
+ auditPushSideEffect('sync-workspace-push-upsert-echo-failed', {
131
+ workspaceId: targetWorkspaceId,
132
+ taskCount: incomingTaskUpsertIds.length,
133
+ error: String(error?.message || 'Failed to read back applied task upserts')
134
+ });
135
+ }
136
+ const durationMs = Date.now() - startedAtMs;
137
+ const payload = JSON.stringify({
138
+ success: true,
139
+ workspaceId: targetWorkspaceId,
140
+ idempotencyKey: idempotencyKey || null,
141
+ emittedEventIds,
142
+ appliedTaskUpserts,
143
+ result,
144
+ durationMs
145
+ });
146
+ if (idempotencyKey) {
147
+ try {
148
+ writePushIdempotency(targetWorkspaceId, idempotencyKey, payload);
149
+ }
150
+ catch (error) {
151
+ auditPushSideEffect('sync-workspace-push-idempotency-write-failed', {
152
+ workspaceId: targetWorkspaceId,
153
+ idempotencyKey,
154
+ error: String(error?.message || 'Failed to persist push idempotency replay payload')
155
+ });
156
+ }
157
+ }
158
+ res.writeHead(200, { 'Content-Type': 'application/json' });
159
+ res.end(payload);
160
+ try {
161
+ core.recordSyncEvent(targetWorkspaceId, {
162
+ eventType: 'push',
163
+ status: 'success',
164
+ changeCount: incomingChanges.length,
165
+ requestMs: durationMs
166
+ });
167
+ }
168
+ catch {
169
+ // success-path diagnostics must never flip a committed push into failure
170
+ }
171
+ auditPushSideEffect('sync-workspace-push-success', {
172
+ workspaceId: targetWorkspaceId,
173
+ idempotencyKey: idempotencyKey || null,
174
+ changeCount: incomingChanges.length,
175
+ deleteCount,
176
+ durationMs
177
+ });
178
+ }
179
+ catch (error) {
180
+ const statusCode = resolveErrorStatusCode(error, 400);
181
+ const durationMs = Date.now() - startedAtMs;
182
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
183
+ res.end(JSON.stringify({
184
+ success: false,
185
+ error: String(error?.message || 'Failed to apply workspace deltas'),
186
+ code: error?.code,
187
+ details: error?.details || undefined,
188
+ durationMs
189
+ }));
190
+ try {
191
+ core.recordSyncEvent(targetWorkspaceId, {
192
+ eventType: 'push',
193
+ status: 'error',
194
+ statusCode,
195
+ errorMessage: String(error?.message || 'Failed to apply workspace deltas'),
196
+ changeCount: incomingChanges.length,
197
+ requestMs: durationMs
198
+ });
199
+ }
200
+ catch {
201
+ // error-path diagnostics must never suppress a committed error response
202
+ }
203
+ auditPushSideEffect('sync-workspace-push-failed', {
204
+ workspaceId: targetWorkspaceId,
205
+ code: error?.code || null,
206
+ statusCode,
207
+ details: error?.details || null,
208
+ durationMs
209
+ });
210
+ }
211
+ });
212
+ }
@@ -0,0 +1,36 @@
1
+ import type { IncomingMessage, ServerResponse } from 'http';
2
+ import type { SyncResolveRequestAccess, SyncResolvedAccess, SyncRouteAuthConfig } from './syncRouteTypes.js';
3
+ interface SyncWorkspaceAccessCoreLike {
4
+ listUserWorkspaces(userId: string): Array<{
5
+ id: string;
6
+ }>;
7
+ }
8
+ interface RequireAuthenticatedSyncRequestArgs<TAuthConfig extends NonNullable<SyncRouteAuthConfig>> {
9
+ req: IncomingMessage;
10
+ res: ServerResponse;
11
+ authConfig: TAuthConfig | null | undefined;
12
+ resolveRequestAccess: SyncResolveRequestAccess;
13
+ auditAuthAction?: (req: IncomingMessage, action: string, details: Record<string, unknown>) => void;
14
+ unauthorizedAuditAction?: string;
15
+ }
16
+ interface ResolveAuthorizedSyncWorkspaceArgs {
17
+ req: IncomingMessage;
18
+ res: ServerResponse;
19
+ core: SyncWorkspaceAccessCoreLike;
20
+ access: SyncResolvedAccess;
21
+ requestedWorkspaceId: string;
22
+ auditAuthAction?: (req: IncomingMessage, action: string, details: Record<string, unknown>) => void;
23
+ missingWorkspaceAuditAction?: string;
24
+ forbiddenWorkspaceAuditAction?: string;
25
+ missingWorkspaceResponseExtras?: Record<string, unknown>;
26
+ forbiddenWorkspaceResponseExtras?: Record<string, unknown>;
27
+ }
28
+ export declare function requireEnabledSyncAuth(res: ServerResponse, authConfig: SyncRouteAuthConfig | null | undefined): boolean;
29
+ export declare function requireAuthenticatedSyncRequest<TAuthConfig extends NonNullable<SyncRouteAuthConfig>>({ req, res, authConfig, resolveRequestAccess, auditAuthAction, unauthorizedAuditAction }: Omit<RequireAuthenticatedSyncRequestArgs<TAuthConfig>, 'authConfig'> & {
30
+ authConfig: TAuthConfig | null | undefined;
31
+ }): SyncResolvedAccess | null;
32
+ export declare function requireCloudRuntimeSnapshotAccess<TAuthConfig extends NonNullable<SyncRouteAuthConfig>>(args: Omit<RequireAuthenticatedSyncRequestArgs<TAuthConfig>, 'authConfig'> & {
33
+ authConfig: TAuthConfig | null | undefined;
34
+ }): SyncResolvedAccess | null;
35
+ export declare function resolveAuthorizedSyncWorkspace({ req, res, core, access, requestedWorkspaceId, auditAuthAction, missingWorkspaceAuditAction, forbiddenWorkspaceAuditAction, missingWorkspaceResponseExtras, forbiddenWorkspaceResponseExtras }: ResolveAuthorizedSyncWorkspaceArgs): string | null;
36
+ export {};
@@ -0,0 +1,67 @@
1
+ function writeJson(res, statusCode, payload) {
2
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
3
+ res.end(JSON.stringify(payload));
4
+ }
5
+ export function requireEnabledSyncAuth(res, authConfig) {
6
+ if (authConfig?.enabled)
7
+ return true;
8
+ writeJson(res, 400, {
9
+ success: false,
10
+ error: 'Sync is unavailable when auth is disabled.'
11
+ });
12
+ return false;
13
+ }
14
+ export function requireAuthenticatedSyncRequest({ req, res, authConfig, resolveRequestAccess, auditAuthAction, unauthorizedAuditAction }) {
15
+ if (!authConfig?.enabled)
16
+ return null;
17
+ const access = resolveRequestAccess(req, authConfig);
18
+ if (access.authenticated && access.userId && access.userId !== 'anonymous') {
19
+ return access;
20
+ }
21
+ if (auditAuthAction && unauthorizedAuditAction) {
22
+ auditAuthAction(req, unauthorizedAuditAction, {});
23
+ }
24
+ writeJson(res, 401, {
25
+ success: false,
26
+ error: 'Authentication required.'
27
+ });
28
+ return null;
29
+ }
30
+ export function requireCloudRuntimeSnapshotAccess(args) {
31
+ if (args.authConfig?.runtimeMode !== 'cloud') {
32
+ return { authenticated: true, userId: null, workspaceId: null };
33
+ }
34
+ return requireAuthenticatedSyncRequest(args);
35
+ }
36
+ export function resolveAuthorizedSyncWorkspace({ req, res, core, access, requestedWorkspaceId, auditAuthAction, missingWorkspaceAuditAction, forbiddenWorkspaceAuditAction, missingWorkspaceResponseExtras, forbiddenWorkspaceResponseExtras }) {
37
+ const normalizedWorkspaceId = String(requestedWorkspaceId || '').trim();
38
+ if (!normalizedWorkspaceId) {
39
+ if (auditAuthAction && missingWorkspaceAuditAction) {
40
+ auditAuthAction(req, missingWorkspaceAuditAction, { code: 'WORKSPACE_ID_REQUIRED' });
41
+ }
42
+ writeJson(res, 400, {
43
+ success: false,
44
+ error: 'workspaceId is required.',
45
+ code: 'WORKSPACE_ID_REQUIRED',
46
+ workspaceId: null,
47
+ ...missingWorkspaceResponseExtras
48
+ });
49
+ return null;
50
+ }
51
+ const allowed = core.listUserWorkspaces(String(access.userId || '')).find((workspace) => workspace.id === normalizedWorkspaceId);
52
+ if (allowed)
53
+ return normalizedWorkspaceId;
54
+ if (auditAuthAction && forbiddenWorkspaceAuditAction) {
55
+ auditAuthAction(req, forbiddenWorkspaceAuditAction, {
56
+ requestedWorkspaceId: normalizedWorkspaceId
57
+ });
58
+ }
59
+ writeJson(res, 403, {
60
+ success: false,
61
+ error: 'You do not have access to this workspace.',
62
+ code: 'WORKSPACE_ACCESS_DENIED',
63
+ workspaceId: normalizedWorkspaceId,
64
+ ...forbiddenWorkspaceResponseExtras
65
+ });
66
+ return null;
67
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,94 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { requireAuthenticatedSyncRequest, requireCloudRuntimeSnapshotAccess, requireEnabledSyncAuth, resolveAuthorizedSyncWorkspace, } from './syncRouteGuards';
3
+ function createMockRes() {
4
+ return {
5
+ writeHead: vi.fn(),
6
+ end: vi.fn()
7
+ };
8
+ }
9
+ describe('syncRouteGuards', () => {
10
+ it('rejects sync routes when auth is disabled', () => {
11
+ const res = createMockRes();
12
+ expect(requireEnabledSyncAuth(res, { enabled: false })).toBe(false);
13
+ expect(res.writeHead).toHaveBeenCalledWith(400, { 'Content-Type': 'application/json' });
14
+ expect(res.end).toHaveBeenCalledWith(expect.stringContaining('Sync is unavailable when auth is disabled.'));
15
+ });
16
+ it('requires authentication for enabled sync routes', () => {
17
+ const req = {};
18
+ const res = createMockRes();
19
+ const auditAuthAction = vi.fn();
20
+ expect(requireAuthenticatedSyncRequest({
21
+ req,
22
+ res,
23
+ authConfig: { enabled: true },
24
+ resolveRequestAccess: () => ({ authenticated: false, userId: null }),
25
+ auditAuthAction,
26
+ unauthorizedAuditAction: 'sync-workspace-pull-unauthorized'
27
+ })).toBeNull();
28
+ expect(auditAuthAction).toHaveBeenCalledWith(req, 'sync-workspace-pull-unauthorized', {});
29
+ expect(res.writeHead).toHaveBeenCalledWith(401, { 'Content-Type': 'application/json' });
30
+ });
31
+ it('skips snapshot auth in local runtime but enforces it in cloud runtime', () => {
32
+ const req = {};
33
+ const localRes = createMockRes();
34
+ expect(requireCloudRuntimeSnapshotAccess({
35
+ req,
36
+ res: localRes,
37
+ authConfig: { enabled: true, runtimeMode: 'local' },
38
+ resolveRequestAccess: () => ({ authenticated: false, userId: null })
39
+ })).toEqual({ authenticated: true, userId: null, workspaceId: null });
40
+ expect(localRes.writeHead).not.toHaveBeenCalled();
41
+ const cloudRes = createMockRes();
42
+ expect(requireCloudRuntimeSnapshotAccess({
43
+ req,
44
+ res: cloudRes,
45
+ authConfig: { enabled: true, runtimeMode: 'cloud' },
46
+ resolveRequestAccess: () => ({ authenticated: false, userId: null })
47
+ })).toBeNull();
48
+ expect(cloudRes.writeHead).toHaveBeenCalledWith(401, { 'Content-Type': 'application/json' });
49
+ });
50
+ it('rejects missing and unauthorized workspace access consistently', () => {
51
+ const req = {};
52
+ const res = createMockRes();
53
+ const auditAuthAction = vi.fn();
54
+ const access = { authenticated: true, userId: 'user-1' };
55
+ const core = {
56
+ listUserWorkspaces: vi.fn(() => [{ id: 'workspace-2' }])
57
+ };
58
+ expect(resolveAuthorizedSyncWorkspace({
59
+ req,
60
+ res,
61
+ core,
62
+ access,
63
+ requestedWorkspaceId: '',
64
+ auditAuthAction,
65
+ missingWorkspaceAuditAction: 'sync-workspace-pull-missing-workspace',
66
+ forbiddenWorkspaceAuditAction: 'sync-workspace-pull-forbidden'
67
+ })).toBeNull();
68
+ expect(auditAuthAction).toHaveBeenCalledWith(req, 'sync-workspace-pull-missing-workspace', { code: 'WORKSPACE_ID_REQUIRED' });
69
+ vi.clearAllMocks();
70
+ expect(resolveAuthorizedSyncWorkspace({
71
+ req,
72
+ res,
73
+ core,
74
+ access,
75
+ requestedWorkspaceId: 'workspace-1',
76
+ auditAuthAction,
77
+ missingWorkspaceAuditAction: 'sync-workspace-pull-missing-workspace',
78
+ forbiddenWorkspaceAuditAction: 'sync-workspace-pull-forbidden'
79
+ })).toBeNull();
80
+ expect(auditAuthAction).toHaveBeenCalledWith(req, 'sync-workspace-pull-forbidden', { requestedWorkspaceId: 'workspace-1' });
81
+ expect(res.end).toHaveBeenCalledWith(expect.stringContaining('WORKSPACE_ACCESS_DENIED'));
82
+ });
83
+ it('returns an authorized workspace id for allowed users', () => {
84
+ expect(resolveAuthorizedSyncWorkspace({
85
+ req: {},
86
+ res: createMockRes(),
87
+ core: {
88
+ listUserWorkspaces: () => [{ id: 'workspace-1' }]
89
+ },
90
+ access: { authenticated: true, userId: 'user-1' },
91
+ requestedWorkspaceId: 'workspace-1'
92
+ })).toBe('workspace-1');
93
+ });
94
+ });
@@ -0,0 +1,13 @@
1
+ import type { IncomingMessage, ServerResponse } from 'http';
2
+ import type { TaskforceCore, TaskforceSyncCapable } from '../../core/Taskforce.js';
3
+ import type { RouteContext } from './primitives.js';
4
+ export interface SyncResolvedAccess {
5
+ authenticated: boolean;
6
+ userId?: string | null;
7
+ workspaceId?: string | null;
8
+ }
9
+ export type SyncRouteAuthConfig = RouteContext['authConfig'];
10
+ export type SyncRouteCore = TaskforceCore & TaskforceSyncCapable;
11
+ export type SyncRouteHandler = (req: IncomingMessage, res: ServerResponse) => Promise<void>;
12
+ export type SyncAddRoute = (method: string, path: string, handler: SyncRouteHandler) => void;
13
+ export type SyncResolveRequestAccess = (req: IncomingMessage, config: NonNullable<SyncRouteAuthConfig>) => SyncResolvedAccess;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,66 @@
1
+ import type { IncomingMessage } from 'http';
2
+ import type { SyncAddRoute, SyncResolveRequestAccess, SyncRouteAuthConfig, SyncRouteCore } from './syncRouteTypes.js';
3
+ interface WorkspaceSyncDocumentSnapshotState {
4
+ listWorkspaceSyncDocumentIndex(basePath: string, workspaceId: string): Promise<Array<{
5
+ path: string;
6
+ }>>;
7
+ listWorkspaceSyncDocumentsSnapshot(basePath: string, workspaceId: string): Promise<Array<{
8
+ path: string;
9
+ updatedAt: string;
10
+ content: string;
11
+ assetId?: string | null;
12
+ documentId?: string | null;
13
+ version?: number | null;
14
+ taskId?: string | null;
15
+ linkRole?: string | null;
16
+ }>>;
17
+ listWorkspaceSyncBinaryAssetIndex(workspaceId: string): Promise<Array<{
18
+ path: string;
19
+ }>>;
20
+ listWorkspaceSyncBinaryAssetsSnapshot(basePath: string, workspaceId: string): Promise<Array<{
21
+ path: string;
22
+ updatedAt: string;
23
+ contentBase64: string;
24
+ assetId?: string | null;
25
+ kind: string;
26
+ mimeType: string;
27
+ taskId?: string | null;
28
+ originalFilename?: string | null;
29
+ linkRole?: string | null;
30
+ }>>;
31
+ }
32
+ interface WorkspaceSyncCollaborationSnapshotState {
33
+ listWorkspaceSyncDocumentReviewSessionsSnapshot(workspaceId: string): Array<{
34
+ id: string;
35
+ updatedAt: string;
36
+ status: string;
37
+ comments: unknown[];
38
+ }>;
39
+ listWorkspaceSyncDocumentReviewCommentsSnapshot(workspaceId: string): Array<{
40
+ id: string;
41
+ sessionId: string;
42
+ updatedAt: string;
43
+ deletedAt?: string | null;
44
+ }>;
45
+ listWorkspaceSyncAnnotatedAttachmentSessionsSnapshot(workspaceId: string): Array<{
46
+ id: string;
47
+ updatedAt: string;
48
+ taskId: string;
49
+ baseImageAssetId: string;
50
+ annotations: unknown[];
51
+ deletedAt?: string | null;
52
+ }>;
53
+ }
54
+ interface RegisterWorkspaceSnapshotSyncRoutesArgs {
55
+ addRoute: SyncAddRoute;
56
+ core: SyncRouteCore;
57
+ context: {
58
+ authConfig?: SyncRouteAuthConfig | null;
59
+ };
60
+ resolveRequestAccess: SyncResolveRequestAccess;
61
+ requestWorkspaceId: (req: IncomingMessage) => string | null | undefined;
62
+ contentSyncState: WorkspaceSyncDocumentSnapshotState;
63
+ collaborationSyncState: WorkspaceSyncCollaborationSnapshotState;
64
+ }
65
+ export declare function registerWorkspaceSnapshotSyncRoutes({ addRoute, core, context, resolveRequestAccess, requestWorkspaceId, contentSyncState, collaborationSyncState }: RegisterWorkspaceSnapshotSyncRoutesArgs): void;
66
+ export {};
@@ -0,0 +1,180 @@
1
+ import { requireCloudRuntimeSnapshotAccess } from './syncRouteGuards.js';
2
+ export function registerWorkspaceSnapshotSyncRoutes({ addRoute, core, context, resolveRequestAccess, requestWorkspaceId, contentSyncState, collaborationSyncState }) {
3
+ // GET /api/taskforce/sync/workspace/documents - Snapshot markdown documents only.
4
+ // Binary image/file assets travel through the sibling /assets snapshot and asset-* sync ops.
5
+ addRoute('GET', '/api/taskforce/sync/workspace/documents', async (req, res) => {
6
+ const snapshotAccess = requireCloudRuntimeSnapshotAccess({
7
+ req,
8
+ res,
9
+ authConfig: context.authConfig,
10
+ resolveRequestAccess
11
+ });
12
+ if (!snapshotAccess)
13
+ return;
14
+ const workspaceId = requestWorkspaceId(req) || 'default';
15
+ const basePath = core.getPaths().basePath;
16
+ const documentIndex = await contentSyncState.listWorkspaceSyncDocumentIndex(basePath, workspaceId);
17
+ const documents = await contentSyncState.listWorkspaceSyncDocumentsSnapshot(basePath, workspaceId);
18
+ const knownPaths = documentIndex
19
+ .map((doc) => String(doc?.path || '').trim())
20
+ .filter((docPath) => docPath.length > 0);
21
+ const fingerprint = JSON.stringify([
22
+ ...knownPaths.map((docPath) => `known:${docPath}`),
23
+ ...documents.map((doc) => [
24
+ doc.path,
25
+ doc.updatedAt,
26
+ doc.content.length,
27
+ doc.assetId || '',
28
+ doc.documentId || '',
29
+ String(doc.version ?? ''),
30
+ doc.taskId || '',
31
+ doc.linkRole || ''
32
+ ].join(':'))
33
+ ]);
34
+ res.writeHead(200, { 'Content-Type': 'application/json' });
35
+ res.end(JSON.stringify({
36
+ success: true,
37
+ documents,
38
+ knownPaths,
39
+ fingerprint
40
+ }));
41
+ });
42
+ // GET /api/taskforce/sync/workspace/ai-profiles - Snapshot workspace AI profiles for local->cloud sync.
43
+ addRoute('GET', '/api/taskforce/sync/workspace/ai-profiles', async (req, res) => {
44
+ const snapshotAccess = requireCloudRuntimeSnapshotAccess({
45
+ req,
46
+ res,
47
+ authConfig: context.authConfig,
48
+ resolveRequestAccess
49
+ });
50
+ if (!snapshotAccess)
51
+ return;
52
+ const workspaceId = requestWorkspaceId(req) || 'default';
53
+ const aiProfiles = core.listAiProfiles(workspaceId, { includeArchived: true });
54
+ const fingerprint = JSON.stringify(aiProfiles.map((profile) => [
55
+ profile.id,
56
+ profile.updatedAt,
57
+ profile.name,
58
+ profile.username,
59
+ profile.profileToken,
60
+ profile.avatarUrl ?? '',
61
+ profile.avatarSourceUrl ?? '',
62
+ profile.surfaceType ?? '',
63
+ profile.seatScope ?? '',
64
+ profile.archivedAt ?? '',
65
+ profile.archivedReason ?? '',
66
+ profile.mergedIntoProfileId ?? '',
67
+ profile.rosterStateUpdatedAt ?? ''
68
+ ].join(':')));
69
+ res.writeHead(200, { 'Content-Type': 'application/json' });
70
+ res.end(JSON.stringify({
71
+ success: true,
72
+ aiProfiles,
73
+ fingerprint
74
+ }));
75
+ });
76
+ // GET /api/taskforce/sync/workspace/document-reviews - Snapshot document review sessions for local->cloud sync.
77
+ addRoute('GET', '/api/taskforce/sync/workspace/document-reviews', async (req, res) => {
78
+ const snapshotAccess = requireCloudRuntimeSnapshotAccess({
79
+ req,
80
+ res,
81
+ authConfig: context.authConfig,
82
+ resolveRequestAccess
83
+ });
84
+ if (!snapshotAccess)
85
+ return;
86
+ const workspaceId = requestWorkspaceId(req) || 'default';
87
+ const sessions = collaborationSyncState.listWorkspaceSyncDocumentReviewSessionsSnapshot(workspaceId);
88
+ const comments = collaborationSyncState.listWorkspaceSyncDocumentReviewCommentsSnapshot(workspaceId);
89
+ const fingerprint = JSON.stringify([
90
+ ...sessions.map((session) => [
91
+ 'session',
92
+ session.id,
93
+ session.updatedAt,
94
+ session.status,
95
+ session.comments.length
96
+ ].join(':')),
97
+ ...comments.map((comment) => [
98
+ 'comment',
99
+ comment.id,
100
+ comment.sessionId,
101
+ comment.updatedAt,
102
+ comment.deletedAt || ''
103
+ ].join(':'))
104
+ ]);
105
+ res.writeHead(200, { 'Content-Type': 'application/json' });
106
+ res.end(JSON.stringify({
107
+ success: true,
108
+ sessions,
109
+ comments,
110
+ fingerprint
111
+ }));
112
+ });
113
+ // GET /api/taskforce/sync/workspace/annotated-attachments - Snapshot Image Notes sessions for local->cloud sync.
114
+ addRoute('GET', '/api/taskforce/sync/workspace/annotated-attachments', async (req, res) => {
115
+ const snapshotAccess = requireCloudRuntimeSnapshotAccess({
116
+ req,
117
+ res,
118
+ authConfig: context.authConfig,
119
+ resolveRequestAccess
120
+ });
121
+ if (!snapshotAccess)
122
+ return;
123
+ const workspaceId = requestWorkspaceId(req) || 'default';
124
+ const sessions = collaborationSyncState.listWorkspaceSyncAnnotatedAttachmentSessionsSnapshot(workspaceId);
125
+ const fingerprint = JSON.stringify(sessions.map((session) => [
126
+ session.id,
127
+ session.updatedAt,
128
+ session.taskId,
129
+ session.baseImageAssetId,
130
+ session.annotations.length,
131
+ session.deletedAt || ''
132
+ ].join(':')));
133
+ res.writeHead(200, { 'Content-Type': 'application/json' });
134
+ res.end(JSON.stringify({
135
+ success: true,
136
+ sessions,
137
+ fingerprint
138
+ }));
139
+ });
140
+ // GET /api/taskforce/sync/workspace/assets - Snapshot non-markdown local assets.
141
+ // Markdown remains on the /documents snapshot so document encryption/version semantics stay isolated.
142
+ addRoute('GET', '/api/taskforce/sync/workspace/assets', async (req, res) => {
143
+ const snapshotAccess = requireCloudRuntimeSnapshotAccess({
144
+ req,
145
+ res,
146
+ authConfig: context.authConfig,
147
+ resolveRequestAccess
148
+ });
149
+ if (!snapshotAccess)
150
+ return;
151
+ const workspaceId = requestWorkspaceId(req) || 'default';
152
+ const basePath = core.getPaths().basePath;
153
+ const assetIndex = await contentSyncState.listWorkspaceSyncBinaryAssetIndex(workspaceId);
154
+ const assets = await contentSyncState.listWorkspaceSyncBinaryAssetsSnapshot(basePath, workspaceId);
155
+ const knownPaths = assetIndex
156
+ .map((asset) => String(asset?.path || '').trim())
157
+ .filter((assetPath) => assetPath.length > 0);
158
+ const fingerprint = JSON.stringify([
159
+ ...knownPaths.map((assetPath) => `known:${assetPath}`),
160
+ ...assets.map((asset) => [
161
+ asset.path,
162
+ asset.updatedAt,
163
+ asset.contentBase64.length,
164
+ asset.assetId || '',
165
+ asset.kind,
166
+ asset.mimeType,
167
+ asset.taskId || '',
168
+ asset.originalFilename || '',
169
+ asset.linkRole || ''
170
+ ].join(':'))
171
+ ]);
172
+ res.writeHead(200, { 'Content-Type': 'application/json' });
173
+ res.end(JSON.stringify({
174
+ success: true,
175
+ assets,
176
+ knownPaths,
177
+ fingerprint
178
+ }));
179
+ });
180
+ }