@taskforcehq/taskforce 0.3.170 → 0.3.300

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 (696) hide show
  1. package/README.md +52 -21
  2. package/dist/Taskforce.module.css +3394 -5981
  3. package/dist/TaskforceCore.CategoryFallback.test.js +5 -2
  4. package/dist/TaskforceCore.filter-persistence.test.js +402 -0
  5. package/dist/TaskforceCore.js +388 -71
  6. package/dist/TaskforceCore.routing.test.js +311 -0
  7. package/dist/TaskforceCore.test.js +3344 -615
  8. package/dist/TaskforceWidget.js +3 -2
  9. package/dist/__tests__/localizationCatalogs.test.js +48 -31
  10. package/dist/__tests__/workflowSimulation.test.js +2 -2
  11. package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.d.ts +60 -0
  12. package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.js +324 -0
  13. package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.test.js +278 -0
  14. package/dist/annotatedAttachments/payload.d.ts +2 -0
  15. package/dist/annotatedAttachments/payload.js +54 -0
  16. package/dist/annotatedAttachments/payload.test.js +67 -0
  17. package/dist/annotatedAttachments/service.d.ts +49 -0
  18. package/dist/annotatedAttachments/service.js +121 -0
  19. package/dist/annotatedAttachments/types.d.ts +86 -0
  20. package/dist/cli.js +74 -25
  21. package/dist/compat/deploymentCompat.d.ts +12 -0
  22. package/dist/compat/deploymentCompat.js +43 -0
  23. package/dist/compat/workspaceSyncCompat.d.ts +6 -0
  24. package/dist/compat/workspaceSyncCompat.js +79 -0
  25. package/dist/compat/workspaceSyncCompat.test.js +87 -0
  26. package/dist/components/features/AgentsModule.d.ts +5 -0
  27. package/dist/components/features/AgentsModule.js +131 -0
  28. package/dist/components/features/AgentsModule.test.js +102 -0
  29. package/dist/components/features/AnnotatedAttachmentWorkspace.d.ts +24 -0
  30. package/dist/components/features/AnnotatedAttachmentWorkspace.js +1942 -0
  31. package/dist/components/features/AnnotatedAttachmentWorkspace.test.js +2831 -0
  32. package/dist/components/features/DocumentGenerateModal.js +8 -16
  33. package/dist/components/features/DocumentIndex.d.ts +3 -4
  34. package/dist/components/features/DocumentIndex.js +22 -10
  35. package/dist/components/features/DocumentViewer.d.ts +6 -2
  36. package/dist/components/features/DocumentViewer.js +1000 -18
  37. package/dist/components/features/DocumentWorkspace.d.ts +40 -2
  38. package/dist/components/features/DocumentWorkspace.js +96 -16
  39. package/dist/components/features/DocumentWorkspace.test.js +1202 -0
  40. package/dist/components/features/InitiativesModule.d.ts +22 -0
  41. package/dist/components/features/InitiativesModule.js +33 -0
  42. package/dist/components/features/TaskSettings.d.ts +41 -32
  43. package/dist/components/features/TaskSettings.js +798 -313
  44. package/dist/components/features/TaskSettings.test.js +1221 -47
  45. package/dist/components/features/WorkflowsModule.d.ts +27 -0
  46. package/dist/components/features/WorkflowsModule.js +21 -0
  47. package/dist/components/features/documentWorkspaceFilters.d.ts +10 -0
  48. package/dist/components/features/documentWorkspaceFilters.js +11 -0
  49. package/dist/components/features/settings/CategoryManager.d.ts +2 -0
  50. package/dist/components/features/settings/CategoryManager.js +15 -8
  51. package/dist/components/features/settings/PriorityManager.d.ts +18 -0
  52. package/dist/components/features/settings/PriorityManager.js +51 -0
  53. package/dist/components/features/settings/TaxonomyEditor.d.ts +2 -1
  54. package/dist/components/features/settings/TaxonomyEditor.js +41 -18
  55. package/dist/components/features/settings/TaxonomyLibraryManager.d.ts +26 -0
  56. package/dist/components/features/settings/TaxonomyLibraryManager.js +301 -0
  57. package/dist/components/features/settings/TaxonomyLibraryManager.test.js +141 -0
  58. package/dist/components/features/settings/TaxonomyManager.d.ts +35 -12
  59. package/dist/components/features/settings/TaxonomyManager.js +59 -27
  60. package/dist/components/features/settings/TypeManager.d.ts +11 -0
  61. package/dist/components/features/settings/TypeManager.js +48 -11
  62. package/dist/components/features/settings/{WorkflowEditorPrototype.d.ts → WorkflowEditor.d.ts} +2 -2
  63. package/dist/components/features/settings/{WorkflowEditorPrototype.js → WorkflowEditor.js} +3 -3
  64. package/dist/components/task/TaskActionHeader.d.ts +12 -2
  65. package/dist/components/task/TaskActionHeader.js +64 -8
  66. package/dist/components/task/TaskActionHeader.test.js +73 -0
  67. package/dist/components/task/TaskCard.d.ts +14 -16
  68. package/dist/components/task/TaskCard.js +144 -174
  69. package/dist/components/task/TaskCard.test.js +416 -64
  70. package/dist/components/task/TaskContextUpload.d.ts +6 -5
  71. package/dist/components/task/TaskContextUpload.js +199 -64
  72. package/dist/components/task/TaskContextUpload.test.js +331 -14
  73. package/dist/components/task/TaskForm.d.ts +23 -29
  74. package/dist/components/task/TaskForm.js +348 -169
  75. package/dist/components/task/TaskForm.test.js +419 -23
  76. package/dist/components/task/TaskKanban.d.ts +20 -21
  77. package/dist/components/task/TaskKanban.js +176 -316
  78. package/dist/components/task/TaskKanban.planning-drop.test.js +93 -0
  79. package/dist/components/task/TaskList.d.ts +22 -11
  80. package/dist/components/task/TaskList.js +98 -12
  81. package/dist/components/task/TaskList.test.js +206 -7
  82. package/dist/components/task/TaskReferenceBadge.d.ts +12 -0
  83. package/dist/components/task/TaskReferenceBadge.js +5 -0
  84. package/dist/components/task/TaskStatusActions.d.ts +12 -0
  85. package/dist/components/task/TaskStatusActions.js +18 -0
  86. package/dist/components/task/TaskStatusActions.test.js +45 -0
  87. package/dist/components/ui/ImageReferenceBadge.d.ts +12 -0
  88. package/dist/components/ui/ImageReferenceBadge.js +5 -0
  89. package/dist/components/ui/LevelSelector.d.ts +2 -1
  90. package/dist/components/ui/LevelSelector.js +2 -2
  91. package/dist/components/ui/Markdown.d.ts +1 -2
  92. package/dist/components/ui/Markdown.js +2 -13
  93. package/dist/components/ui/Modal.d.ts +3 -2
  94. package/dist/components/ui/Modal.js +4 -3
  95. package/dist/components/ui/MultiSelectFilter.d.ts +3 -1
  96. package/dist/components/ui/MultiSelectFilter.js +2 -2
  97. package/dist/components/ui/ReferenceBadgeButton.d.ts +13 -0
  98. package/dist/components/ui/ReferenceBadgeButton.js +6 -0
  99. package/dist/components/ui/TaxonomyDropdown.d.ts +7 -1
  100. package/dist/components/ui/TaxonomyDropdown.js +58 -23
  101. package/dist/components/ui/TopNoticeLayer.d.ts +7 -0
  102. package/dist/components/ui/TopNoticeLayer.js +14 -0
  103. package/dist/components/ui/TopNoticeLayer.test.js +25 -0
  104. package/dist/components/views/AppShellHeader.d.ts +13 -0
  105. package/dist/components/views/AppShellHeader.js +19 -0
  106. package/dist/components/views/AppShellHeader.test.js +21 -0
  107. package/dist/components/views/PlanComparisonPage.d.ts +73 -0
  108. package/dist/components/views/PlanComparisonPage.js +196 -0
  109. package/dist/components/views/PlanComparisonPage.test.js +251 -0
  110. package/dist/components/views/PlansPage.d.ts +14 -0
  111. package/dist/components/views/PlansPage.js +355 -0
  112. package/dist/components/views/StandaloneLayout.d.ts +2 -2
  113. package/dist/components/views/StandaloneLayout.js +2212 -1194
  114. package/dist/components/views/WidgetView.d.ts +2 -2
  115. package/dist/components/views/WidgetView.js +149 -43
  116. package/dist/components/views/chrome/WorkspaceChromeSections.d.ts +57 -0
  117. package/dist/components/views/chrome/WorkspaceChromeSections.js +38 -0
  118. package/dist/components/views/chrome/WorkspaceChromeSections.test.js +54 -0
  119. package/dist/components/views/chrome/workspaceChrome.d.ts +31 -0
  120. package/dist/components/views/chrome/workspaceChrome.js +108 -0
  121. package/dist/components/views/chrome/workspaceChrome.test.js +52 -0
  122. package/dist/components/views/panels/DocumentFilterToolbar.d.ts +10 -0
  123. package/dist/components/views/panels/DocumentFilterToolbar.js +7 -0
  124. package/dist/components/views/panels/DocumentFilterToolbar.test.js +19 -0
  125. package/dist/components/views/panels/FilterToolbar.d.ts +66 -0
  126. package/dist/components/views/panels/FilterToolbar.js +21 -0
  127. package/dist/components/views/panels/FilterToolbar.test.d.ts +1 -0
  128. package/dist/components/views/panels/FilterToolbar.test.js +45 -0
  129. package/dist/components/views/panels/FilterToolbarControls.d.ts +46 -0
  130. package/dist/components/views/panels/FilterToolbarControls.js +61 -0
  131. package/dist/components/views/panels/PlanningDrawer.d.ts +115 -0
  132. package/dist/components/views/panels/PlanningDrawer.js +220 -0
  133. package/dist/components/views/panels/ScheduleSidebar.d.ts +52 -0
  134. package/dist/components/views/panels/ScheduleSidebar.js +127 -0
  135. package/dist/components/views/panels/scheduleUtils.d.ts +14 -0
  136. package/dist/components/views/panels/scheduleUtils.js +79 -0
  137. package/dist/components/views/teamManagementAccess.d.ts +6 -0
  138. package/dist/components/views/teamManagementAccess.js +18 -0
  139. package/dist/components/views/teamManagementAccess.test.d.ts +1 -0
  140. package/dist/components/views/teamManagementAccess.test.js +44 -0
  141. package/dist/config/clientDeployment.d.ts +2 -0
  142. package/dist/config/clientDeployment.js +13 -0
  143. package/dist/config/cloudEnvironment.d.ts +15 -0
  144. package/dist/config/cloudEnvironment.js +60 -0
  145. package/dist/config/deployment.d.ts +20 -0
  146. package/dist/config/deployment.js +67 -0
  147. package/dist/config/deployment.test.d.ts +1 -0
  148. package/dist/config/deployment.test.js +88 -0
  149. package/dist/config/envSchema.js +36 -8
  150. package/dist/config/envSchema.test.js +28 -0
  151. package/dist/core/AiProfileService.d.ts +66 -0
  152. package/dist/core/AiProfileService.js +320 -0
  153. package/dist/core/AiProfileService.test.d.ts +1 -0
  154. package/dist/core/AiProfileService.test.js +164 -0
  155. package/dist/core/AiProfiles.test.d.ts +1 -0
  156. package/dist/core/AiProfiles.test.js +449 -0
  157. package/dist/core/AttachmentLinkService.d.ts +15 -0
  158. package/dist/core/AttachmentLinkService.js +157 -0
  159. package/dist/core/AuthTokenService.d.ts +44 -0
  160. package/dist/core/AuthTokenService.js +207 -0
  161. package/dist/core/CreatedBy.test.js +134 -6
  162. package/dist/core/DeletedTaskLifecycleService.d.ts +33 -0
  163. package/dist/core/DeletedTaskLifecycleService.js +158 -0
  164. package/dist/core/DeletedTaskTrash.test.d.ts +1 -0
  165. package/dist/core/DeletedTaskTrash.test.js +104 -0
  166. package/dist/core/EntitlementsPolicy.test.js +78 -5
  167. package/dist/core/GlobalSettingsService.d.ts +16 -0
  168. package/dist/core/GlobalSettingsService.js +370 -0
  169. package/dist/core/JsonBackupRuntime.test.d.ts +1 -0
  170. package/dist/core/JsonBackupRuntime.test.js +155 -0
  171. package/dist/core/McpTokenService.d.ts +118 -0
  172. package/dist/core/McpTokenService.js +921 -0
  173. package/dist/core/PlanEntitlementService.d.ts +201 -0
  174. package/dist/core/PlanEntitlementService.js +1442 -0
  175. package/dist/core/PlanVersionPolicy.test.d.ts +1 -0
  176. package/dist/core/PlanVersionPolicy.test.js +178 -0
  177. package/dist/core/PlanningEntities.test.d.ts +1 -0
  178. package/dist/core/PlanningEntities.test.js +95 -0
  179. package/dist/core/ScheduleFields.test.js +15 -19
  180. package/dist/core/SignupMonetizationSettings.test.d.ts +1 -0
  181. package/dist/core/SignupMonetizationSettings.test.js +159 -0
  182. package/dist/core/Stats.test.d.ts +1 -0
  183. package/dist/core/Stats.test.js +36 -0
  184. package/dist/core/SyncReconciliationService.d.ts +93 -0
  185. package/dist/core/SyncReconciliationService.js +406 -0
  186. package/dist/core/SystemAdmin.test.js +578 -13
  187. package/dist/core/TaskActivityService.d.ts +21 -0
  188. package/dist/core/TaskActivityService.js +130 -0
  189. package/dist/core/TaskAttachmentsCanonical.test.d.ts +1 -0
  190. package/dist/core/TaskAttachmentsCanonical.test.js +306 -0
  191. package/dist/core/TaskAuditTimeline.test.d.ts +1 -0
  192. package/dist/core/TaskAuditTimeline.test.js +132 -0
  193. package/dist/core/TaskTaxonomyValidation.test.js +338 -15
  194. package/dist/core/Taskforce.d.ts +930 -183
  195. package/dist/core/Taskforce.ids.test.js +252 -0
  196. package/dist/core/Taskforce.js +3848 -2532
  197. package/dist/core/Taskforce.mcpAuth.test.d.ts +1 -0
  198. package/dist/core/Taskforce.mcpAuth.test.js +343 -0
  199. package/dist/core/Taskforce.realtimeMutation.test.js +57 -2
  200. package/dist/core/TaxonomySettingsService.d.ts +18 -0
  201. package/dist/core/TaxonomySettingsService.js +162 -0
  202. package/dist/core/WorkspaceDelete.test.js +32 -13
  203. package/dist/core/WorkspaceLifecycleService.d.ts +11 -0
  204. package/dist/core/WorkspaceLifecycleService.js +88 -0
  205. package/dist/core/WorkspacePermissions.test.js +95 -0
  206. package/dist/core/WorkspacePlanMode.test.js +114 -1
  207. package/dist/core/WorkspacePreferenceService.d.ts +41 -0
  208. package/dist/core/WorkspacePreferenceService.js +246 -0
  209. package/dist/core/WorkspaceSyncSettings.test.d.ts +1 -0
  210. package/dist/core/WorkspaceSyncSettings.test.js +65 -0
  211. package/dist/core/__tests__/TaskAttachmentsCanonical.test.d.ts +1 -0
  212. package/dist/core/__tests__/TaskAttachmentsCanonical.test.js +212 -0
  213. package/dist/core/shared.d.ts +36 -0
  214. package/dist/core/shared.js +128 -0
  215. package/dist/core/types.d.ts +614 -0
  216. package/dist/core/types.js +27 -0
  217. package/dist/documentReviews/DocumentReviewCommentStore.d.ts +56 -0
  218. package/dist/documentReviews/DocumentReviewCommentStore.js +230 -0
  219. package/dist/documentReviews/DocumentReviewSessionStore.d.ts +52 -0
  220. package/dist/documentReviews/DocumentReviewSessionStore.js +193 -0
  221. package/dist/documentReviews/DocumentReviewSessionStore.test.d.ts +1 -0
  222. package/dist/documentReviews/DocumentReviewSessionStore.test.js +127 -0
  223. package/dist/documentReviews/service.d.ts +68 -0
  224. package/dist/documentReviews/service.js +210 -0
  225. package/dist/documentReviews/types.d.ts +58 -0
  226. package/dist/documentReviews/types.js +1 -0
  227. package/dist/hooks/auth/useAuthGuardPolicy.d.ts +2 -0
  228. package/dist/hooks/auth/useAuthGuardPolicy.js +1 -0
  229. package/dist/hooks/tasks/useCurrentTaskRelations.d.ts +15 -0
  230. package/dist/hooks/tasks/useCurrentTaskRelations.js +37 -0
  231. package/dist/hooks/tasks/useTaskActions.d.ts +3 -0
  232. package/dist/hooks/tasks/useTaskActions.js +2 -0
  233. package/dist/hooks/tasks/useTaskEditorNavigation.d.ts +65 -0
  234. package/dist/hooks/tasks/useTaskEditorNavigation.js +235 -0
  235. package/dist/hooks/tasks/useTaskFilters.d.ts +2 -0
  236. package/dist/hooks/tasks/useTaskFilters.js +2 -0
  237. package/dist/hooks/tasks/useTaskFormActions.d.ts +58 -0
  238. package/dist/hooks/tasks/useTaskFormActions.js +365 -0
  239. package/dist/hooks/tasks/useTaskRelationships.d.ts +16 -0
  240. package/dist/hooks/tasks/useTaskRelationships.js +64 -0
  241. package/dist/hooks/ui/useResourceExport.d.ts +19 -0
  242. package/dist/hooks/ui/useResourceExport.js +84 -0
  243. package/dist/hooks/ui/useSettingsModel.d.ts +203 -0
  244. package/dist/hooks/ui/useSettingsModel.js +125 -0
  245. package/dist/hooks/ui/useSettingsPersistence.d.ts +36 -0
  246. package/dist/hooks/ui/useSettingsPersistence.js +254 -0
  247. package/dist/hooks/ui/useSettingsTaxonomyManagement.d.ts +119 -0
  248. package/dist/hooks/ui/useSettingsTaxonomyManagement.js +536 -0
  249. package/dist/hooks/ui/useUiNotice.d.ts +1 -0
  250. package/dist/hooks/ui/useUiNotice.js +1 -0
  251. package/dist/hooks/ui/useWorkflowTemplates.d.ts +37 -0
  252. package/dist/hooks/ui/useWorkflowTemplates.js +111 -0
  253. package/dist/hooks/ui/useZenMode.d.ts +5 -0
  254. package/dist/hooks/ui/useZenMode.js +32 -0
  255. package/dist/hooks/useFilterSort.d.ts +60 -0
  256. package/dist/hooks/useFilterSort.js +362 -0
  257. package/dist/hooks/useFilterSort.test.d.ts +1 -0
  258. package/dist/hooks/useFilterSort.test.js +333 -0
  259. package/dist/hooks/useRealtimeSync.d.ts +1 -0
  260. package/dist/hooks/useRealtimeSync.js +24 -9
  261. package/dist/hooks/useRealtimeSync.test.js +28 -1
  262. package/dist/hooks/useSyncOrchestrator.aiProfiles.test.d.ts +1 -0
  263. package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +34 -0
  264. package/dist/hooks/useSyncOrchestrator.d.ts +65 -103
  265. package/dist/hooks/useSyncOrchestrator.js +1538 -670
  266. package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +700 -174
  267. package/dist/hooks/useTaskData.d.ts +35 -0
  268. package/dist/hooks/useTaskData.js +239 -0
  269. package/dist/hooks/useTaskData.test.d.ts +1 -0
  270. package/dist/hooks/useTaskData.test.js +119 -0
  271. package/dist/hooks/useTaskMutations.d.ts +46 -0
  272. package/dist/hooks/useTaskMutations.js +472 -0
  273. package/dist/hooks/useTaskMutations.test.d.ts +1 -0
  274. package/dist/hooks/useTaskMutations.test.js +80 -0
  275. package/dist/hooks/useTaskforce.contract.test.d.ts +1 -0
  276. package/dist/hooks/useTaskforce.contract.test.js +7 -0
  277. package/dist/hooks/useTaskforce.d.ts +260 -295
  278. package/dist/hooks/useTaskforce.js +1954 -2623
  279. package/dist/hooks/useTaskforce.priority-filters.test.js +6 -11
  280. package/dist/hooks/useTaskforce.sync-behavior.test.d.ts +1 -0
  281. package/dist/hooks/useTaskforce.sync-behavior.test.js +1120 -0
  282. package/dist/hooks/useUiNotice.d.ts +16 -0
  283. package/dist/hooks/useUiNotice.js +49 -0
  284. package/dist/hooks/useWorkspaceSyncController.d.ts +23 -46
  285. package/dist/hooks/useWorkspaceSyncController.js +280 -461
  286. package/dist/hooks/useWorkspaceSyncController.test.js +106 -199
  287. package/dist/hooks/workspace/useTaskforceApiRouting.d.ts +8 -0
  288. package/dist/hooks/workspace/useTaskforceApiRouting.js +91 -0
  289. package/dist/hooks/workspace/useTaskforceApiRouting.test.d.ts +1 -0
  290. package/dist/hooks/workspace/useTaskforceApiRouting.test.js +60 -0
  291. package/dist/hooks/workspace/useWorkspaceSyncController.d.ts +1 -0
  292. package/dist/hooks/workspace/useWorkspaceSyncController.js +1 -0
  293. package/dist/hooks/workspace/workspaceLocalState.d.ts +30 -0
  294. package/dist/hooks/workspace/workspaceLocalState.js +101 -0
  295. package/dist/localization/locales/en-US.d.ts +1 -8
  296. package/dist/localization/locales/en-US.js +4 -11
  297. package/dist/localization/locales/es-419.js +2 -9
  298. package/dist/localization/locales/pt-BR.js +2 -9
  299. package/dist/localization/localizationCatalogs.test.d.ts +1 -0
  300. package/dist/localization/localizationCatalogs.test.js +37 -0
  301. package/dist/main.d.ts +1 -0
  302. package/dist/main.js +9 -15
  303. package/dist/mcp/clientIntegrations.d.ts +33 -0
  304. package/dist/mcp/clientIntegrations.js +199 -0
  305. package/dist/mcp/clientIntegrations.test.d.ts +1 -0
  306. package/dist/mcp/clientIntegrations.test.js +110 -0
  307. package/dist/mcp/index.d.ts +2 -0
  308. package/dist/mcp/index.js +2 -0
  309. package/dist/mcp/optionResolution.test.js +6 -2
  310. package/dist/mcp/runtime.d.ts +120 -0
  311. package/dist/mcp/runtime.js +5668 -0
  312. package/dist/mcp/runtime.test.d.ts +1 -0
  313. package/dist/mcp/runtime.test.js +3293 -0
  314. package/dist/mcp/server.js +2 -1793
  315. package/dist/mcp/structuredCommentValidation.test.d.ts +1 -0
  316. package/dist/{__tests__ → mcp}/structuredCommentValidation.test.js +1 -1
  317. package/dist/mcp/structuredDocValidation.js +1 -2
  318. package/dist/mcp/structuredDocValidation.test.d.ts +1 -0
  319. package/dist/{__tests__ → mcp}/structuredDocValidation.test.js +9 -4
  320. package/dist/mcp/toolRegistry.d.ts +570 -0
  321. package/dist/mcp/toolRegistry.js +90 -0
  322. package/dist/mcp/toolRegistry.test.d.ts +1 -0
  323. package/dist/mcp/toolRegistry.test.js +30 -0
  324. package/dist/migrations/billingSchemaParity.test.js +111 -0
  325. package/dist/migrations/taskSchemaMigrations.d.ts +5 -0
  326. package/dist/migrations/taskSchemaMigrations.js +681 -39
  327. package/dist/migrations/taskSchemaMigrations.test.d.ts +1 -0
  328. package/dist/migrations/taskSchemaMigrations.test.js +210 -0
  329. package/dist/plugins/vite.js +13 -7
  330. package/dist/public/apple-touch-icon.png +0 -0
  331. package/dist/public/archive/phoenix/apple-touch-icon.png +0 -0
  332. package/dist/public/archive/phoenix/favicon.ico +0 -0
  333. package/dist/public/archive/phoenix/site.webmanifest +1 -0
  334. package/dist/public/favicon-96x96.png +0 -0
  335. package/dist/public/favicon.ico +0 -0
  336. package/dist/public/favicon.svg +17 -0
  337. package/dist/public/site.webmanifest +21 -1
  338. package/dist/public/web-app-manifest-192x192.png +0 -0
  339. package/dist/public/web-app-manifest-512x512.png +0 -0
  340. package/dist/releaseVersion.test.d.ts +1 -0
  341. package/dist/{__tests__/releaseVersion.test.js → releaseVersion.test.js} +1 -1
  342. package/dist/resources/templates/WORKFLOW_V2_POLICY.md +1 -1
  343. package/dist/resources/templates/workflow-sources/workflowDocs.mjs +62 -52
  344. package/dist/resources/templates/workflows/collaborate.yaml +11 -5
  345. package/dist/resources/templates/workflows/do.yaml +8 -2
  346. package/dist/resources/templates/workflows/evaluate.yaml +13 -7
  347. package/dist/resources/templates/workflows/execute.yaml +40 -23
  348. package/dist/resources/templates/workflows/plan.yaml +15 -8
  349. package/dist/resources/templates/workflows/review.yaml +14 -8
  350. package/dist/runtime/appGateDefinitions.d.ts +32 -0
  351. package/dist/runtime/appGateDefinitions.js +32 -0
  352. package/dist/runtime/appGates.d.ts +29 -0
  353. package/dist/runtime/appGates.js +53 -0
  354. package/dist/runtime/appGates.test.d.ts +1 -0
  355. package/dist/runtime/appGates.test.js +42 -0
  356. package/dist/runtime/migrationFlags.d.ts +1 -0
  357. package/dist/runtime/migrationFlags.js +1 -0
  358. package/dist/server/annotatedAttachmentsRoutes.test.d.ts +1 -0
  359. package/dist/server/annotatedAttachmentsRoutes.test.js +473 -0
  360. package/dist/server/auth.js +14 -2
  361. package/dist/server/auth.test.js +21 -1
  362. package/dist/server/cors.js +11 -5
  363. package/dist/server/cors.test.js +6 -0
  364. package/dist/server/documentReviewRoutes.test.d.ts +1 -0
  365. package/dist/server/documentReviewRoutes.test.js +157 -0
  366. package/dist/server/index.cookieProxy.test.js +46 -1
  367. package/dist/server/index.d.ts +20 -0
  368. package/dist/server/index.js +168 -41
  369. package/dist/server/index.rateLimit.test.js +6 -0
  370. package/dist/server/index.test.js +133 -2
  371. package/dist/server/mockStripe.d.ts +72 -0
  372. package/dist/server/mockStripe.js +357 -0
  373. package/dist/server/realtimeSyncWs.js +4 -0
  374. package/dist/server/routes/admin.d.ts +114 -0
  375. package/dist/server/routes/admin.js +2226 -0
  376. package/dist/server/routes/annotatedAttachments.d.ts +24 -0
  377. package/dist/server/routes/annotatedAttachments.js +235 -0
  378. package/dist/server/routes/auth.d.ts +61 -0
  379. package/dist/server/routes/auth.js +1296 -0
  380. package/dist/server/{routes.billing.d.ts → routes/billing.d.ts} +3 -2
  381. package/dist/server/routes/billing.js +2001 -0
  382. package/dist/server/routes/billing.test.d.ts +1 -0
  383. package/dist/server/routes/billing.test.js +1631 -0
  384. package/dist/server/routes/documentReviews.d.ts +11 -0
  385. package/dist/server/routes/documentReviews.js +191 -0
  386. package/dist/server/routes/documents.d.ts +118 -0
  387. package/dist/server/routes/documents.js +1113 -0
  388. package/dist/server/routes/resources.d.ts +25 -0
  389. package/dist/server/routes/resources.js +225 -0
  390. package/dist/server/routes/shared.d.ts +35 -0
  391. package/dist/server/routes/shared.js +305 -0
  392. package/dist/server/routes/shared.test.d.ts +1 -0
  393. package/dist/server/routes/shared.test.js +32 -0
  394. package/dist/server/{routes.sync.d.ts → routes/sync.d.ts} +5 -5
  395. package/dist/server/routes/sync.integration.test.d.ts +1 -0
  396. package/dist/server/routes/sync.integration.test.js +2003 -0
  397. package/dist/server/routes/sync.js +3143 -0
  398. package/dist/server/routes/tasks.d.ts +72 -0
  399. package/dist/server/routes/tasks.js +1252 -0
  400. package/dist/server/routes/workspaces.d.ts +32 -0
  401. package/dist/server/routes/workspaces.js +307 -0
  402. package/dist/server/routes.d.ts +8 -9
  403. package/dist/server/routes.js +968 -4092
  404. package/dist/server/routes.test.js +9043 -2415
  405. package/dist/server/runtimeMode.d.ts +1 -1
  406. package/dist/server/runtimeMode.js +3 -18
  407. package/dist/server/runtimeMode.test.js +3 -3
  408. package/dist/server/securityHeaders.d.ts +1 -1
  409. package/dist/server/securityHeaders.js +65 -6
  410. package/dist/server/securityHeaders.test.js +40 -2
  411. package/dist/services/templateEngine.test.d.ts +1 -0
  412. package/dist/{__tests__ → services}/templateEngine.test.js +1 -1
  413. package/dist/services/templates.test.d.ts +1 -0
  414. package/dist/{__tests__ → services}/templates.test.js +1 -1
  415. package/dist/services/workflowDocumentFixtures.test.d.ts +1 -0
  416. package/dist/{__tests__ → services}/workflowDocumentFixtures.test.js +4 -4
  417. package/dist/services/workflowExportMatrix.test.d.ts +1 -0
  418. package/dist/{__tests__ → services}/workflowExportMatrix.test.js +1 -1
  419. package/dist/services/workflowExportSnapshots.test.d.ts +1 -0
  420. package/dist/services/workflowGeneration.test.d.ts +1 -0
  421. package/dist/services/workflowSimulation.test.d.ts +1 -0
  422. package/dist/services/workflowSimulation.test.js +113 -0
  423. package/dist/services/workflowV2Policy.test.d.ts +1 -0
  424. package/dist/{__tests__ → services}/workflowV2Policy.test.js +2 -2
  425. package/dist/shared/aiProfileSurfaceType.d.ts +9 -0
  426. package/dist/shared/aiProfileSurfaceType.js +49 -0
  427. package/dist/shared/customTaxonomyLibrary.d.ts +11 -0
  428. package/dist/shared/customTaxonomyLibrary.js +276 -0
  429. package/dist/shared/customTaxonomyLibrary.test.d.ts +1 -0
  430. package/dist/shared/customTaxonomyLibrary.test.js +20 -0
  431. package/dist/shared/taxonomyCatalog.d.ts +19 -0
  432. package/dist/shared/taxonomyCatalog.js +36 -0
  433. package/dist/shared/taxonomyDefaults.d.ts +29 -0
  434. package/dist/shared/taxonomyDefaults.js +26 -0
  435. package/dist/shared/taxonomyLibrary.d.ts +15 -0
  436. package/dist/shared/taxonomyLibrary.js +98 -0
  437. package/dist/shared/taxonomyLibrary.test.d.ts +1 -0
  438. package/dist/shared/taxonomyLibrary.test.js +26 -0
  439. package/dist/shared/taxonomyState.d.ts +36 -0
  440. package/dist/shared/taxonomyState.js +73 -0
  441. package/dist/shared/taxonomyState.test.d.ts +1 -0
  442. package/dist/shared/taxonomyState.test.js +71 -0
  443. package/dist/shared/workflowDefaults.d.ts +9 -0
  444. package/dist/shared/workflowDefaults.js +11 -0
  445. package/dist/storage/documentIntegrity.d.ts +2 -0
  446. package/dist/storage/documentIntegrity.js +34 -17
  447. package/dist/storage/documentPurge.d.ts +2 -1
  448. package/dist/storage/documentPurge.js +35 -8
  449. package/dist/storage/index.d.ts +4 -0
  450. package/dist/storage/index.js +2 -0
  451. package/dist/storage/objectStorage.d.ts +1 -1
  452. package/dist/storage/objectStorageClient.d.ts +6 -4
  453. package/dist/storage/objectStorageClient.js +77 -29
  454. package/dist/storage/objectStorageClient.test.d.ts +1 -0
  455. package/dist/storage/objectStorageClient.test.js +57 -0
  456. package/dist/storage/objectStorageConfig.js +3 -1
  457. package/dist/storage/objectStorageConfig.test.d.ts +1 -0
  458. package/dist/storage/objectStorageConfig.test.js +38 -0
  459. package/dist/storage/postgresAdapter.d.ts +5 -0
  460. package/dist/storage/postgresAdapter.js +2 -2
  461. package/dist/storage/postgresAdapter.test.d.ts +1 -0
  462. package/dist/storage/postgresAdapter.test.js +29 -0
  463. package/dist/storage/taskAssetStore.d.ts +7 -4
  464. package/dist/storage/taskAssetStore.js +65 -60
  465. package/dist/storage/workspaceAssetStore.d.ts +122 -0
  466. package/dist/storage/workspaceAssetStore.js +496 -0
  467. package/dist/storage/workspaceAssetStore.test.d.ts +1 -0
  468. package/dist/storage/workspaceAssetStore.test.js +501 -0
  469. package/dist/sync/cloudSyncApi.d.ts +33 -2
  470. package/dist/sync/cloudSyncApi.js +37 -15
  471. package/dist/sync/cloudSyncApi.test.js +60 -3
  472. package/dist/sync/index.d.ts +2 -0
  473. package/dist/sync/index.js +3 -0
  474. package/dist/sync/syncService.d.ts +25 -0
  475. package/dist/sync/syncService.js +184 -16
  476. package/dist/sync/syncService.test.js +289 -25
  477. package/dist/sync/workspaceRepair.d.ts +114 -0
  478. package/dist/sync/workspaceRepair.js +566 -0
  479. package/dist/sync/workspaceSyncModel.d.ts +230 -2
  480. package/dist/sync/workspaceSyncModel.js +456 -17
  481. package/dist/sync/workspaceSyncModel.test.js +642 -0
  482. package/dist/sync/workspaceSyncState.d.ts +12 -0
  483. package/dist/sync/workspaceSyncState.js +12 -0
  484. package/dist/sync/workspaceSyncSurface.d.ts +33 -0
  485. package/dist/sync/workspaceSyncSurface.js +74 -0
  486. package/dist/types.d.ts +143 -18
  487. package/dist/types.js +9 -24
  488. package/dist/ui/assets/AgentsModule-TVmCgizS.js +1 -0
  489. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BaS2VwIr.css +1 -0
  490. package/dist/ui/assets/AnnotatedAttachmentWorkspace-CAyhnPeR.js +3 -0
  491. package/dist/ui/assets/DocumentWorkspace-BOCw5e4D.js +250 -0
  492. package/dist/ui/assets/DocumentWorkspace-C_8T8oz-.css +1 -0
  493. package/dist/ui/assets/InitiativesModule-CN0r02Oi.js +1 -0
  494. package/dist/ui/assets/PlansPage-BlVC_lRq.css +1 -0
  495. package/dist/ui/assets/PlansPage-FcQSNLZd.js +1 -0
  496. package/dist/ui/assets/TaskSettings-BwB9NtmJ.css +1 -0
  497. package/dist/ui/assets/TaskSettings-Cw5zYD1L.js +8 -0
  498. package/dist/ui/assets/WorkflowsModule-CY9R2zPB.js +5 -0
  499. package/dist/ui/assets/index-Bzqy5QGm.js +6 -0
  500. package/dist/ui/assets/index-DxRiI3tY.css +1 -0
  501. package/dist/ui/assets/vendor-dnd-DRzYolkg.js +5 -0
  502. package/dist/ui/assets/{vendor-icons-ZFG3SGwo.js → vendor-icons-QZyhEwgT.js} +1 -1
  503. package/dist/ui/assets/{vendor-markdown-CKYkQHfj.js → vendor-markdown-BUxTU7dS.js} +1 -1
  504. package/dist/ui/assets/vendor-react-CKJs5o3c.js +61 -0
  505. package/dist/ui/assets/vendor-router-BbWMxlnO.js +3 -0
  506. package/dist/ui/branding/logos/logo.png +0 -0
  507. package/dist/ui/branding/logos/logo_dark.svg +27 -0
  508. package/dist/ui/branding/logos/logo_favicon.svg +35 -0
  509. package/dist/ui/branding/logos/logo_light.svg +27 -0
  510. package/dist/ui/favicon/apple-touch-icon.png +0 -0
  511. package/dist/ui/favicon/archive/phoenix/apple-touch-icon.png +0 -0
  512. package/dist/ui/favicon/archive/phoenix/favicon.ico +0 -0
  513. package/dist/ui/favicon/archive/phoenix/site.webmanifest +1 -0
  514. package/dist/ui/favicon/favicon-96x96.png +0 -0
  515. package/dist/ui/favicon/favicon.ico +0 -0
  516. package/dist/ui/favicon/favicon.svg +17 -0
  517. package/dist/ui/favicon/site.webmanifest +21 -1
  518. package/dist/ui/favicon/web-app-manifest-192x192.png +0 -0
  519. package/dist/ui/favicon/web-app-manifest-512x512.png +0 -0
  520. package/dist/ui/index.html +10 -7
  521. package/dist/ui/product/screen_01.png +0 -0
  522. package/dist/ui/product/screen_02.png +0 -0
  523. package/dist/ui/product/screen_03.png +0 -0
  524. package/dist/utils/annotatedAttachments.d.ts +20 -0
  525. package/dist/utils/annotatedAttachments.js +74 -0
  526. package/dist/utils/annotatedAttachments.test.d.ts +1 -0
  527. package/dist/utils/annotatedAttachments.test.js +108 -0
  528. package/dist/utils/assignees.d.ts +26 -0
  529. package/dist/utils/assignees.js +132 -0
  530. package/dist/utils/canonicalAssetKind.d.ts +16 -0
  531. package/dist/utils/canonicalAssetKind.js +39 -0
  532. package/dist/utils/canonicalAssetKind.test.d.ts +1 -0
  533. package/dist/utils/canonicalAssetKind.test.js +24 -0
  534. package/dist/utils/coalescedRefresh.d.ts +5 -0
  535. package/dist/utils/coalescedRefresh.js +16 -0
  536. package/dist/utils/coalescedRefresh.test.d.ts +1 -0
  537. package/dist/utils/coalescedRefresh.test.js +30 -0
  538. package/dist/utils/constants.d.ts +16 -3
  539. package/dist/utils/constants.icons.test.js +2 -1
  540. package/dist/utils/constants.js +70 -13
  541. package/dist/utils/contextAssetEvents.d.ts +7 -0
  542. package/dist/utils/contextAssetEvents.js +6 -0
  543. package/dist/utils/contextFiles.d.ts +14 -3
  544. package/dist/utils/contextFiles.js +40 -8
  545. package/dist/utils/documentManagerApi.d.ts +6 -0
  546. package/dist/utils/documentManagerApi.js +19 -0
  547. package/dist/utils/documentNames.d.ts +24 -0
  548. package/dist/utils/documentNames.js +91 -0
  549. package/dist/utils/documentReferences.d.ts +9 -0
  550. package/dist/utils/documentReferences.js +11 -0
  551. package/dist/utils/entityReferences.d.ts +9 -0
  552. package/dist/utils/entityReferences.js +32 -0
  553. package/dist/utils/imageReferences.d.ts +9 -0
  554. package/dist/utils/imageReferences.js +11 -0
  555. package/dist/utils/planParser.d.ts +2 -2
  556. package/dist/utils/planParser.js +11 -11
  557. package/dist/utils/planParser.test.d.ts +1 -0
  558. package/dist/{__tests__ → utils}/planParser.test.js +22 -22
  559. package/dist/utils/planningReferences.d.ts +17 -0
  560. package/dist/utils/planningReferences.js +30 -0
  561. package/dist/utils/planningReferences.test.d.ts +1 -0
  562. package/dist/utils/planningReferences.test.js +17 -0
  563. package/dist/utils/taskActivity.d.ts +9 -0
  564. package/dist/utils/taskActivity.js +147 -0
  565. package/dist/utils/taskActivity.test.d.ts +1 -0
  566. package/dist/utils/taskActivity.test.js +34 -0
  567. package/dist/utils/taskDraftDefaults.d.ts +21 -0
  568. package/dist/utils/taskDraftDefaults.js +40 -0
  569. package/dist/utils/taskDraftDefaults.test.d.ts +1 -0
  570. package/dist/utils/taskDraftDefaults.test.js +34 -0
  571. package/dist/utils/taskNormalization.d.ts +25 -0
  572. package/dist/utils/taskNormalization.js +161 -0
  573. package/dist/utils/taskNormalization.test.d.ts +1 -0
  574. package/dist/utils/taskNormalization.test.js +158 -0
  575. package/dist/utils/taskReferences.d.ts +5 -0
  576. package/dist/utils/taskReferences.js +11 -0
  577. package/dist/utils/taskforceApiClient.d.ts +2 -0
  578. package/dist/utils/taskforceApiClient.js +101 -3
  579. package/dist/utils/taskforceApiClient.test.d.ts +1 -0
  580. package/dist/utils/taskforceApiClient.test.js +44 -0
  581. package/dist/utils/taxonomyFilterOptions.d.ts +2 -0
  582. package/dist/utils/taxonomyFilterOptions.js +17 -0
  583. package/dist/utils/taxonomyFormDefaults.d.ts +3 -0
  584. package/dist/utils/taxonomyFormDefaults.js +28 -0
  585. package/dist/utils/taxonomyFormDefaults.test.d.ts +1 -0
  586. package/dist/utils/taxonomyFormDefaults.test.js +63 -0
  587. package/dist/utils/taxonomyLifecycle.d.ts +3 -0
  588. package/dist/utils/taxonomyLifecycle.js +17 -0
  589. package/dist/utils/taxonomySorting.d.ts +7 -0
  590. package/dist/utils/taxonomySorting.js +74 -0
  591. package/dist/utils/theme.d.ts +15 -0
  592. package/dist/utils/theme.js +23 -0
  593. package/dist/utils/uiNotice.d.ts +7 -0
  594. package/dist/utils/uiNotice.js +6 -0
  595. package/dist/utils/uiNotice.test.d.ts +1 -0
  596. package/dist/utils/uiNotice.test.js +18 -0
  597. package/dist/utils/workspaceIdentity.d.ts +14 -0
  598. package/dist/utils/workspaceIdentity.js +21 -0
  599. package/dist/utils/workspaceIdentity.test.js +30 -1
  600. package/dist/utils/workspaceSyncPresentation.d.ts +20 -0
  601. package/dist/utils/workspaceSyncPresentation.js +21 -0
  602. package/dist/utils/workspaceSyncPresentation.test.d.ts +1 -0
  603. package/dist/utils/workspaceSyncPresentation.test.js +36 -0
  604. package/package.json +28 -23
  605. package/scripts/bootstrap-playwright-auth.mjs +155 -0
  606. package/scripts/check-compat-boundaries.mjs +41 -0
  607. package/scripts/check-env.ts +9 -2
  608. package/scripts/debug-login.mjs +32 -0
  609. package/scripts/migrate-planning-model.ts +233 -0
  610. package/scripts/migrate-task-data-assets.mjs +408 -0
  611. package/scripts/playwright-auth.sh +11 -0
  612. package/scripts/run-dev-proxy.sh +2 -0
  613. package/scripts/update-homebrew-formula.sh +2 -2
  614. package/scripts/with-esbuild.sh +11 -0
  615. package/src/resources/templates/WORKFLOW_V2_POLICY.md +1 -1
  616. package/src/resources/templates/workflow-sources/workflowDocs.mjs +62 -52
  617. package/src/resources/templates/workflows/collaborate.yaml +11 -5
  618. package/src/resources/templates/workflows/do.yaml +8 -2
  619. package/src/resources/templates/workflows/evaluate.yaml +13 -7
  620. package/src/resources/templates/workflows/execute.yaml +40 -23
  621. package/src/resources/templates/workflows/plan.yaml +15 -8
  622. package/src/resources/templates/workflows/review.yaml +14 -8
  623. package/dist/TaskforceScreenshot.d.ts +0 -11
  624. package/dist/TaskforceScreenshot.js +0 -113
  625. package/dist/compat/priorityCompat.d.ts +0 -2
  626. package/dist/compat/priorityCompat.js +0 -24
  627. package/dist/components/features/settings/TaxonomyManager 2.d.ts +0 -52
  628. package/dist/components/features/settings/TaxonomyManager 2.js +0 -75
  629. package/dist/components/task/TaskKanban 2.d.ts +0 -76
  630. package/dist/components/task/TaskKanban 2.js +0 -1004
  631. package/dist/components/task/TaskScreenshotSection.d.ts +0 -15
  632. package/dist/components/task/TaskScreenshotSection.js +0 -22
  633. package/dist/components/views/StandaloneLayout 2.d.ts +0 -8
  634. package/dist/components/views/StandaloneLayout 2.js +0 -1660
  635. package/dist/core/InitiativeTemplates.test.js +0 -50
  636. package/dist/core/ParentLifecycle.test.js +0 -98
  637. package/dist/migrations/clientMigrations.d.ts +0 -9
  638. package/dist/migrations/clientMigrations.js +0 -74
  639. package/dist/migrations/flags.d.ts +0 -6
  640. package/dist/migrations/flags.js +0 -8
  641. package/dist/migrations/taskMigrations.d.ts +0 -71
  642. package/dist/migrations/taskMigrations.js +0 -236
  643. package/dist/migrations/taskMigrations.test.js +0 -34
  644. package/dist/server/routes.billing.js +0 -991
  645. package/dist/server/routes.billing.test.js +0 -387
  646. package/dist/server/routes.sync.integration.test.js +0 -470
  647. package/dist/server/routes.sync.js +0 -1141
  648. package/dist/soak/syncSoakHarness.d.ts +0 -6
  649. package/dist/soak/syncSoakHarness.js +0 -10
  650. package/dist/ui/assets/index-0W5vyCpn.css +0 -1
  651. package/dist/ui/assets/index-MCZuNNfn.js +0 -23
  652. package/dist/ui/assets/logo_white_01-0Vx-iIIv.png +0 -0
  653. package/dist/ui/assets/vendor-dnd-BI1K77C1.js +0 -5
  654. package/dist/ui/assets/vendor-react-DdIDsh7f.js +0 -9
  655. package/dist/ui/assets/vendor-router-BtiNU7Dl.js +0 -3
  656. package/dist/utils/taskHierarchy.d.ts +0 -4
  657. package/dist/utils/taskHierarchy.js +0 -69
  658. package/dist/utils/taskHierarchy.test.js +0 -38
  659. package/dist/utils/taskParenting.d.ts +0 -3
  660. package/dist/utils/taskParenting.js +0 -24
  661. package/dist/utils/taskParenting.test.js +0 -21
  662. package/dist/utils/taskRelations.d.ts +0 -6
  663. package/dist/utils/taskRelations.js +0 -24
  664. package/dist/utils/taskRelations.test.js +0 -34
  665. package/scripts/check-compat-boundaries.js +0 -48
  666. /package/dist/{__tests__/planParser.test.d.ts → TaskforceCore.filter-persistence.test.d.ts} +0 -0
  667. /package/dist/{__tests__/releaseVersion.test.d.ts → TaskforceCore.routing.test.d.ts} +0 -0
  668. /package/dist/{__tests__/structuredCommentValidation.test.d.ts → annotatedAttachments/AnnotatedAttachmentSessionStore.test.d.ts} +0 -0
  669. /package/dist/{__tests__/structuredDocValidation.test.d.ts → annotatedAttachments/payload.test.d.ts} +0 -0
  670. /package/dist/{__tests__/templateEngine.test.d.ts → annotatedAttachments/types.js} +0 -0
  671. /package/dist/{__tests__/templates.test.d.ts → compat/workspaceSyncCompat.test.d.ts} +0 -0
  672. /package/dist/{__tests__/workflowDocumentFixtures.test.d.ts → components/features/AgentsModule.test.d.ts} +0 -0
  673. /package/dist/{__tests__/workflowExportMatrix.test.d.ts → components/features/AnnotatedAttachmentWorkspace.test.d.ts} +0 -0
  674. /package/dist/{__tests__/workflowExportSnapshots.test.d.ts → components/features/DocumentWorkspace.test.d.ts} +0 -0
  675. /package/dist/{__tests__/workflowGeneration.test.d.ts → components/features/settings/TaxonomyLibraryManager.test.d.ts} +0 -0
  676. /package/dist/{__tests__/workflowV2Policy.test.d.ts → components/task/TaskActionHeader.test.d.ts} +0 -0
  677. /package/dist/{core/InitiativeTemplates.test.d.ts → components/task/TaskKanban.planning-drop.test.d.ts} +0 -0
  678. /package/dist/{core/ParentLifecycle.test.d.ts → components/task/TaskStatusActions.test.d.ts} +0 -0
  679. /package/dist/{migrations/taskMigrations.test.d.ts → components/ui/TopNoticeLayer.test.d.ts} +0 -0
  680. /package/dist/{server/routes.billing.test.d.ts → components/views/AppShellHeader.test.d.ts} +0 -0
  681. /package/dist/{server/routes.sync.integration.test.d.ts → components/views/PlanComparisonPage.test.d.ts} +0 -0
  682. /package/dist/{utils/taskHierarchy.test.d.ts → components/views/chrome/WorkspaceChromeSections.test.d.ts} +0 -0
  683. /package/dist/{utils/taskParenting.test.d.ts → components/views/chrome/workspaceChrome.test.d.ts} +0 -0
  684. /package/dist/{utils/taskRelations.test.d.ts → components/views/panels/DocumentFilterToolbar.test.d.ts} +0 -0
  685. /package/dist/public/{android-chrome-192x192.png → archive/phoenix/android-chrome-192x192.png} +0 -0
  686. /package/dist/public/{android-chrome-512x512.png → archive/phoenix/android-chrome-512x512.png} +0 -0
  687. /package/dist/public/{favicon-16x16.png → archive/phoenix/favicon-16x16.png} +0 -0
  688. /package/dist/public/{favicon-32x32.png → archive/phoenix/favicon-32x32.png} +0 -0
  689. /package/dist/public/{favicon.png → archive/phoenix/favicon.png} +0 -0
  690. /package/dist/{__tests__ → services}/workflowExportSnapshots.test.js +0 -0
  691. /package/dist/{__tests__ → services}/workflowGeneration.test.js +0 -0
  692. /package/dist/ui/favicon/{android-chrome-192x192.png → archive/phoenix/android-chrome-192x192.png} +0 -0
  693. /package/dist/ui/favicon/{android-chrome-512x512.png → archive/phoenix/android-chrome-512x512.png} +0 -0
  694. /package/dist/ui/favicon/{favicon-16x16.png → archive/phoenix/favicon-16x16.png} +0 -0
  695. /package/dist/ui/favicon/{favicon-32x32.png → archive/phoenix/favicon-32x32.png} +0 -0
  696. /package/dist/ui/favicon/{favicon.png → archive/phoenix/favicon.png} +0 -0
@@ -0,0 +1,1252 @@
1
+ /**
2
+ * Task route module.
3
+ *
4
+ * Handles all task CRUD, scheduling, bulk operations, initiative templates,
5
+ * taxonomy management (categories/types/priorities/custom taxonomies),
6
+ * workflow option endpoints, configuration, UI state, health, version,
7
+ * and data-version endpoints.
8
+ *
9
+ * Routes registered here (lines from the original routes.ts extraction):
10
+ * GET /api/taskforce/config
11
+ * POST /api/taskforce/config
12
+ * POST /api/taskforce/global-settings
13
+ * POST /api/taskforce/workspace-profile
14
+ * GET /api/taskforce/ui-state
15
+ * POST /api/taskforce/ui-state
16
+ * GET /api/taskforce/tasks
17
+ * GET /api/taskforce/deleted
18
+ * GET /api/taskforce/deleted/:id
19
+ * GET /api/taskforce/schedule
20
+ * GET /api/taskforce/data-version
21
+ * GET /api/taskforce/health
22
+ * GET /api/taskforce/version
23
+ * POST /api/taskforce/task
24
+ * PATCH /api/taskforce/task/:id
25
+ * PATCH /api/taskforce/task/:id/schedule
26
+ * POST /api/taskforce/schedule/reorder
27
+ * GET /api/taskforce/archive
28
+ * POST /api/taskforce/task/:id/complete
29
+ * POST /api/taskforce/task/:id/cancel
30
+ * DELETE /api/taskforce/task/:id
31
+ * POST /api/taskforce/deleted/:id/restore
32
+ * POST /api/taskforce/task/:id/comment
33
+ * POST /api/taskforce/task/:id/unarchive
34
+ * POST /api/taskforce/bulk-create
35
+ * POST /api/taskforce/bulk-archive
36
+ * POST /api/taskforce/bulk-update-fields
37
+ * POST /api/taskforce/bulk-update-fields/preview
38
+ * GET /api/taskforce/initiative-templates
39
+ * POST /api/taskforce/initiative-templates/create
40
+ * GET /api/taskforce/taxonomy-library
41
+ * GET /api/taskforce/categories
42
+ * POST /api/taskforce/categories
43
+ * GET /api/taskforce/types
44
+ * POST /api/taskforce/types
45
+ * GET /api/taskforce/priorities
46
+ * POST /api/taskforce/priorities
47
+ * GET /api/taskforce/approaches
48
+ * POST /api/taskforce/approaches
49
+ * GET /api/taskforce/taxonomies
50
+ * POST /api/taskforce/taxonomies
51
+ */
52
+ import { TaskforceRuleError } from '../../core/Taskforce.js';
53
+ import { toPublicObjectStorageConfig } from '../../storage/objectStorage.js';
54
+ import { getRuntimeCapabilities } from '../../runtime/capabilities.js';
55
+ import { resolveBuildInfo } from '../buildInfo.js';
56
+ import { resolveRealtimeSyncFlag } from '../../sync/realtimeFeature.js';
57
+ import { parseJsonBody } from '../routes.js';
58
+ import { resolveErrorStatusCode, requestHeader, requestRuntimeMode } from './shared.js';
59
+ import { listBuiltInCustomTaxonomyLibraryPacks } from '../../shared/customTaxonomyLibrary.js';
60
+ import { listBuiltInTaxonomyLibraryPacks } from '../../shared/taxonomyLibrary.js';
61
+ // === SECTION: Registration ===
62
+ export function registerTaskRoutes(deps) {
63
+ const { addRoute, core, context, requestWorkspaceId, ensureAppAccess, resolveEffectiveObjectStorageConfig, buildBatchSummary, CLOUD_SAFE_CONFIG_PATHS, } = deps;
64
+ // === SECTION: Config and settings ===
65
+ // GET /api/taskforce/config - Get current configuration
66
+ addRoute('GET', '/api/taskforce/config', async (req, res) => {
67
+ if (!ensureAppAccess(req, res))
68
+ return;
69
+ const workspaceId = requestWorkspaceId(req);
70
+ const requestUserId = String(res.req?.headers?.['x-taskforce-user-id'] || 'anonymous');
71
+ const projectConfig = core.getConfig(workspaceId, requestUserId);
72
+ const paths = core.getPaths();
73
+ const globalSettings = core.getGlobalSettings();
74
+ const effectiveTheme = core.getEffectiveTheme(workspaceId, requestUserId);
75
+ const themeUseGlobalDefault = !core.hasProjectThemeOverride(workspaceId, requestUserId);
76
+ const jsonBackupUseGlobalDefault = !core.hasProjectJsonBackupOverride(workspaceId, requestUserId);
77
+ const mode = res.req?.headers?.['x-taskforce-mode'] || 'standalone';
78
+ const runtimeHeader = String(res.req?.headers?.['x-taskforce-runtime-mode'] || '').toLowerCase();
79
+ const runtimeMode = runtimeHeader === 'cloud' ? 'cloud' : 'local';
80
+ const authRequiredForApi = String(res.req?.headers?.['x-taskforce-auth-required'] || '').toLowerCase() === 'true';
81
+ const requestRole = String(res.req?.headers?.['x-taskforce-role'] || 'member');
82
+ const runtimeCapabilities = getRuntimeCapabilities(runtimeMode);
83
+ const setupState = core.getSetupState(workspaceId, runtimeMode);
84
+ const realtimeSyncFlag = resolveRealtimeSyncFlag(process.env, globalSettings.realtimeSyncEnabled);
85
+ const workspaceDisplayName = String(setupState.workspace?.name || '').trim();
86
+ const resolvedProjectName = workspaceDisplayName
87
+ || (runtimeMode === 'cloud' ? '' : paths.projectName);
88
+ const resolvedPaths = runtimeMode === 'cloud'
89
+ ? CLOUD_SAFE_CONFIG_PATHS
90
+ : paths;
91
+ res.writeHead(200, { 'Content-Type': 'application/json' });
92
+ res.end(JSON.stringify({
93
+ ...projectConfig,
94
+ theme: effectiveTheme,
95
+ shortcut: globalSettings.shortcut,
96
+ schedulePreferences: globalSettings.schedulePreferences,
97
+ globalTheme: globalSettings.theme ?? effectiveTheme,
98
+ themeUseGlobalDefault,
99
+ jsonBackupEnabled: runtimeMode === 'cloud' ? false : core.getJsonBackupEnabled(workspaceId, requestUserId),
100
+ globalJsonBackupEnabled: runtimeMode === 'cloud'
101
+ ? false
102
+ : (typeof globalSettings.jsonBackupEnabled === 'boolean'
103
+ ? globalSettings.jsonBackupEnabled
104
+ : false),
105
+ jsonBackupUseGlobalDefault: runtimeMode === 'cloud' ? false : jsonBackupUseGlobalDefault,
106
+ ...resolvedPaths,
107
+ hostRoot: runtimeMode === 'cloud' ? '' : String(projectConfig?.hostRoot || ''),
108
+ projectName: resolvedProjectName,
109
+ storagePath: runtimeMode === 'cloud' ? '' : paths.basePath,
110
+ mode,
111
+ runtimeMode,
112
+ runtimeCapabilities,
113
+ authRequiredForApi,
114
+ role: requestRole,
115
+ workspaceId,
116
+ userId: requestUserId,
117
+ setupState,
118
+ objectStorage: toPublicObjectStorageConfig(resolveEffectiveObjectStorageConfig()),
119
+ realtimeSyncEnabled: realtimeSyncFlag.enabled,
120
+ realtimeSyncFlagSource: realtimeSyncFlag.source
121
+ }));
122
+ });
123
+ // POST /api/taskforce/global-settings - Update global preferences
124
+ addRoute('POST', '/api/taskforce/global-settings', async (req, res) => {
125
+ if (!ensureAppAccess(req, res))
126
+ return;
127
+ const body = await parseJsonBody(req);
128
+ try {
129
+ core.updateGlobalSettings(body);
130
+ res.writeHead(200, { 'Content-Type': 'application/json' });
131
+ res.end(JSON.stringify({ success: true }));
132
+ }
133
+ catch {
134
+ res.writeHead(500, { 'Content-Type': 'application/json' });
135
+ res.end(JSON.stringify({ success: false }));
136
+ }
137
+ });
138
+ // POST /api/taskforce/workspace-profile - Update workspace name/description
139
+ addRoute('POST', '/api/taskforce/workspace-profile', async (req, res) => {
140
+ if (!ensureAppAccess(req, res))
141
+ return;
142
+ const body = await parseJsonBody(req);
143
+ const name = String(body?.name || '').trim();
144
+ const description = typeof body?.description === 'string' ? body.description : undefined;
145
+ const slug = typeof body?.slug === 'string' ? body.slug : undefined;
146
+ const runtimeHeader = String((req.headers['x-taskforce-runtime-mode'] || '')).toLowerCase();
147
+ const isLocalRuntime = runtimeHeader === 'local';
148
+ const allowCreate = body?.allowCreate === true;
149
+ const explicitWorkspaceId = typeof body?.workspaceId === 'string'
150
+ ? body.workspaceId.trim()
151
+ : '';
152
+ const headerWorkspaceId = requestWorkspaceId(req);
153
+ const incomingWorkspaceId = String(explicitWorkspaceId
154
+ || ((isLocalRuntime && allowCreate && !explicitWorkspaceId) ? '' : headerWorkspaceId)).trim() || 'default';
155
+ try {
156
+ const workspaceExists = Boolean(core.getWorkspaceProfile(incomingWorkspaceId));
157
+ const shouldCreateWorkspace = Boolean(name
158
+ && (incomingWorkspaceId === 'default' || !workspaceExists)
159
+ && (isLocalRuntime || allowCreate));
160
+ const workspace = shouldCreateWorkspace
161
+ ? core.createWorkspace({
162
+ workspaceId: incomingWorkspaceId === 'default' ? undefined : incomingWorkspaceId,
163
+ name,
164
+ description,
165
+ slug
166
+ })
167
+ : core.updateWorkspaceProfile(incomingWorkspaceId, { name, description, slug });
168
+ res.writeHead(200, { 'Content-Type': 'application/json' });
169
+ res.end(JSON.stringify({ success: true, workspace }));
170
+ }
171
+ catch (error) {
172
+ const statusCode = resolveErrorStatusCode(error, 400);
173
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
174
+ res.end(JSON.stringify({ success: false, error: String(error?.message || 'Failed to update workspace profile'), code: error?.code }));
175
+ }
176
+ });
177
+ // GET /api/taskforce/ui-state - Read persisted app UI state
178
+ addRoute('GET', '/api/taskforce/ui-state', async (req, res) => {
179
+ if (!ensureAppAccess(req, res))
180
+ return;
181
+ try {
182
+ const url = new URL(req.url || '/', 'http://localhost');
183
+ const requestedWorkspaceId = String(url.searchParams.get('workspaceId') || '').trim();
184
+ let workspaceId = requestWorkspaceId(req);
185
+ if (requestedWorkspaceId && requestRuntimeMode(req) === 'local') {
186
+ workspaceId = requestedWorkspaceId;
187
+ }
188
+ const userId = requestHeader(req, 'x-taskforce-user-id', 'anonymous');
189
+ const stateKey = String(url.searchParams.get('key') || '').trim() || 'default';
190
+ const state = core.getUiState(workspaceId, userId, stateKey);
191
+ res.writeHead(200, { 'Content-Type': 'application/json' });
192
+ res.end(JSON.stringify({ success: true, state: state || {} }));
193
+ }
194
+ catch (error) {
195
+ const statusCode = resolveErrorStatusCode(error, 400);
196
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
197
+ res.end(JSON.stringify({ success: false, error: String(error?.message || 'Failed to read UI state') }));
198
+ }
199
+ });
200
+ // POST /api/taskforce/ui-state - Merge persisted app UI state
201
+ addRoute('POST', '/api/taskforce/ui-state', async (req, res) => {
202
+ if (!ensureAppAccess(req, res))
203
+ return;
204
+ const body = await parseJsonBody(req);
205
+ try {
206
+ const requestedWorkspaceId = String(body?.workspaceId || '').trim();
207
+ let workspaceId = requestWorkspaceId(req);
208
+ if (requestedWorkspaceId && requestRuntimeMode(req) === 'local') {
209
+ workspaceId = requestedWorkspaceId;
210
+ }
211
+ const userId = requestHeader(req, 'x-taskforce-user-id', 'anonymous');
212
+ const stateKey = String(body?.stateKey || body?.key || '').trim() || 'default';
213
+ const patch = body?.patch && typeof body.patch === 'object'
214
+ ? body.patch
215
+ : body?.state && typeof body.state === 'object'
216
+ ? body.state
217
+ : {};
218
+ core.updateUiState(workspaceId, userId, { stateKey, patch });
219
+ res.writeHead(200, { 'Content-Type': 'application/json' });
220
+ res.end(JSON.stringify({ success: true }));
221
+ }
222
+ catch (error) {
223
+ const statusCode = resolveErrorStatusCode(error, 400);
224
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
225
+ res.end(JSON.stringify({ success: false, error: String(error?.message || 'Failed to merge UI state') }));
226
+ }
227
+ });
228
+ // POST /api/taskforce/config - Update configuration
229
+ addRoute('POST', '/api/taskforce/config', async (req, res) => {
230
+ if (!ensureAppAccess(req, res))
231
+ return;
232
+ const body = await parseJsonBody(req);
233
+ try {
234
+ const workspaceId = requestWorkspaceId(req);
235
+ const userId = requestHeader(req, 'x-taskforce-user-id', 'anonymous');
236
+ core.updateConfig(body, workspaceId, userId);
237
+ res.writeHead(200, { 'Content-Type': 'application/json' });
238
+ res.end(JSON.stringify({ success: true }));
239
+ }
240
+ catch (error) {
241
+ res.writeHead(500, { 'Content-Type': 'application/json' });
242
+ res.end(JSON.stringify({ success: false }));
243
+ }
244
+ });
245
+ // === SECTION: Health and version ===
246
+ // GET /api/taskforce/tasks - List all active tasks
247
+ addRoute('GET', '/api/taskforce/tasks', async (req, res) => {
248
+ if (!ensureAppAccess(req, res))
249
+ return;
250
+ const workspaceId = requestWorkspaceId(req);
251
+ const data = core.listTasks(workspaceId);
252
+ res.writeHead(200, { 'Content-Type': 'application/json' });
253
+ res.end(JSON.stringify(data));
254
+ });
255
+ const handleListDeletedTasks = async (req, res) => {
256
+ if (!ensureAppAccess(req, res))
257
+ return;
258
+ const workspaceId = requestWorkspaceId(req);
259
+ const data = core.listDeletedTasks(workspaceId);
260
+ res.writeHead(200, { 'Content-Type': 'application/json' });
261
+ res.end(JSON.stringify(data));
262
+ };
263
+ // GET /api/taskforce/deleted - List deleted tasks
264
+ addRoute('GET', '/api/taskforce/deleted', handleListDeletedTasks);
265
+ addRoute('GET', '/api/taskforce/trash', handleListDeletedTasks);
266
+ const handleGetDeletedTask = async (req, res, params) => {
267
+ if (!ensureAppAccess(req, res))
268
+ return;
269
+ const workspaceId = requestWorkspaceId(req);
270
+ const deletedTask = core.getDeletedTask(params.id, workspaceId);
271
+ if (!deletedTask) {
272
+ res.writeHead(404, { 'Content-Type': 'application/json' });
273
+ res.end(JSON.stringify({ error: 'Deleted task not found' }));
274
+ return;
275
+ }
276
+ res.writeHead(200, { 'Content-Type': 'application/json' });
277
+ res.end(JSON.stringify(deletedTask));
278
+ };
279
+ // GET /api/taskforce/deleted/:id - Get one deleted task detail
280
+ addRoute('GET', '/api/taskforce/deleted/:id', handleGetDeletedTask);
281
+ addRoute('GET', '/api/taskforce/trash/:id', handleGetDeletedTask);
282
+ // GET /api/taskforce/schedule - Get schedule board for a week
283
+ addRoute('GET', '/api/taskforce/schedule', async (req, res) => {
284
+ if (!ensureAppAccess(req, res))
285
+ return;
286
+ try {
287
+ const requestUrl = new URL(req.url || '', 'http://localhost');
288
+ const week = requestUrl.searchParams.get('week');
289
+ const showWeekendsRaw = requestUrl.searchParams.get('showWeekends');
290
+ const showWeekends = showWeekendsRaw === '1' || showWeekendsRaw === 'true';
291
+ if (!week) {
292
+ const err = new Error('Missing required query parameter: week');
293
+ err.statusCode = 400;
294
+ throw err;
295
+ }
296
+ const workspaceId = requestWorkspaceId(req);
297
+ const board = core.getScheduleBoard(week, showWeekends, workspaceId);
298
+ res.writeHead(200, { 'Content-Type': 'application/json' });
299
+ res.end(JSON.stringify(board));
300
+ }
301
+ catch (error) {
302
+ const statusCode = resolveErrorStatusCode(error, 400);
303
+ const message = error instanceof Error ? error.message : 'Failed to load schedule board';
304
+ const errorCode = error instanceof TaskforceRuleError ? error.code : error?.code;
305
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
306
+ res.end(JSON.stringify({ error: message, code: errorCode }));
307
+ }
308
+ });
309
+ // GET /api/taskforce/data-version - Lightweight DB change signal
310
+ addRoute('GET', '/api/taskforce/data-version', async (req, res) => {
311
+ const dataVersion = core.getDataVersion();
312
+ res.writeHead(200, { 'Content-Type': 'application/json' });
313
+ res.end(JSON.stringify({ dataVersion }));
314
+ });
315
+ // GET /api/taskforce/health - Lightweight readiness signal for API + DB
316
+ addRoute('GET', '/api/taskforce/health', async (req, res) => {
317
+ const healthy = core.isDatabaseHealthy();
318
+ const payload = {
319
+ ok: healthy,
320
+ database: {
321
+ provider: core.getDatabaseProvider(),
322
+ healthy
323
+ }
324
+ };
325
+ res.writeHead(healthy ? 200 : 503, { 'Content-Type': 'application/json' });
326
+ res.end(JSON.stringify(payload));
327
+ });
328
+ // GET /api/taskforce/version - Build/runtime identity for traceability
329
+ addRoute('GET', '/api/taskforce/version', async (_req, res) => {
330
+ const build = resolveBuildInfo();
331
+ res.writeHead(200, { 'Content-Type': 'application/json' });
332
+ res.end(JSON.stringify({ ok: true, build }));
333
+ });
334
+ // === SECTION: Task CRUD ===
335
+ // POST /api/taskforce/task - Create new task
336
+ addRoute('POST', '/api/taskforce/task', async (req, res) => {
337
+ if (!ensureAppAccess(req, res))
338
+ return;
339
+ const body = await parseJsonBody(req);
340
+ const { validate_only = false, ...taskInput } = body || {};
341
+ if (validate_only === true) {
342
+ const workspaceId = requestWorkspaceId(req);
343
+ const result = core.bulkCreateTasks([taskInput], {
344
+ atomic: true,
345
+ validateOnly: true,
346
+ workspaceId
347
+ });
348
+ const hasErrors = result.errors.length > 0;
349
+ const failureStatus = hasErrors
350
+ ? resolveErrorStatusCode({ statusCode: result.errors[0]?.statusCode }, 400)
351
+ : 400;
352
+ const statusCode = hasErrors ? failureStatus : 200;
353
+ const validationSummary = {
354
+ success: !hasErrors,
355
+ ...result,
356
+ needs_confirmation: !!result.errors.find((e) => e?.code === 'TAXONOMY_NEEDS_CONFIRMATION')
357
+ };
358
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
359
+ res.end(JSON.stringify(validationSummary));
360
+ return;
361
+ }
362
+ try {
363
+ const workspaceId = requestWorkspaceId(req);
364
+ const task = core.createTask(taskInput, { workspaceId, actorRef: 'user' });
365
+ res.writeHead(201, { 'Content-Type': 'application/json' });
366
+ res.end(JSON.stringify(task));
367
+ }
368
+ catch (error) {
369
+ const statusCode = resolveErrorStatusCode(error, 400);
370
+ const message = error instanceof Error ? error.message : 'Failed to create task';
371
+ const errorCode = error instanceof TaskforceRuleError ? error.code : error?.code;
372
+ const errorDetails = error instanceof TaskforceRuleError ? error.details : error?.details;
373
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
374
+ res.end(JSON.stringify({
375
+ error: message,
376
+ code: errorCode,
377
+ details: errorDetails,
378
+ needs_confirmation: errorCode === 'TAXONOMY_NEEDS_CONFIRMATION'
379
+ }));
380
+ }
381
+ });
382
+ // PATCH /api/taskforce/task/:id - Update a task
383
+ addRoute('PATCH', '/api/taskforce/task/:id', async (req, res, params) => {
384
+ if (!ensureAppAccess(req, res))
385
+ return;
386
+ const body = await parseJsonBody(req);
387
+ try {
388
+ const workspaceId = requestWorkspaceId(req);
389
+ const updated = core.updateTask(params.id, body, workspaceId, { actorRef: 'user' });
390
+ if (!updated) {
391
+ res.writeHead(404, { 'Content-Type': 'application/json' });
392
+ res.end(JSON.stringify({ error: 'Task not found' }));
393
+ return;
394
+ }
395
+ res.writeHead(200, { 'Content-Type': 'application/json' });
396
+ res.end(JSON.stringify(updated));
397
+ }
398
+ catch (error) {
399
+ const statusCode = resolveErrorStatusCode(error, 400);
400
+ const message = error instanceof Error ? error.message : 'Failed to update task';
401
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
402
+ res.end(JSON.stringify({ error: message }));
403
+ }
404
+ });
405
+ // GET /api/taskforce/task/:id/checklist - Read structured checklist items for one task
406
+ addRoute('GET', '/api/taskforce/task/:id/checklist', async (req, res, params) => {
407
+ if (!ensureAppAccess(req, res))
408
+ return;
409
+ const workspaceId = requestWorkspaceId(req);
410
+ const task = core.getTask(params.id, workspaceId);
411
+ if (!task) {
412
+ res.writeHead(404, { 'Content-Type': 'application/json' });
413
+ res.end(JSON.stringify({ error: 'Task not found' }));
414
+ return;
415
+ }
416
+ const items = core.listChecklistItems(params.id, workspaceId);
417
+ res.writeHead(200, { 'Content-Type': 'application/json' });
418
+ res.end(JSON.stringify(items));
419
+ });
420
+ // PUT /api/taskforce/task/:id/checklist - Replace structured checklist items for one task
421
+ addRoute('PUT', '/api/taskforce/task/:id/checklist', async (req, res, params) => {
422
+ if (!ensureAppAccess(req, res))
423
+ return;
424
+ const body = await parseJsonBody(req);
425
+ const items = Array.isArray(body?.items) ? body.items : [];
426
+ try {
427
+ const workspaceId = requestWorkspaceId(req);
428
+ const task = core.getTask(params.id, workspaceId);
429
+ if (!task) {
430
+ res.writeHead(404, { 'Content-Type': 'application/json' });
431
+ res.end(JSON.stringify({ error: 'Task not found' }));
432
+ return;
433
+ }
434
+ const updated = core.replaceChecklistItems(params.id, items, workspaceId);
435
+ res.writeHead(200, { 'Content-Type': 'application/json' });
436
+ res.end(JSON.stringify(updated));
437
+ }
438
+ catch (error) {
439
+ const statusCode = resolveErrorStatusCode(error, 400);
440
+ const message = error instanceof Error ? error.message : 'Failed to update checklist';
441
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
442
+ res.end(JSON.stringify({ error: message }));
443
+ }
444
+ });
445
+ // GET /api/taskforce/initiatives - List initiatives
446
+ addRoute('GET', '/api/taskforce/initiatives', async (req, res) => {
447
+ if (!ensureAppAccess(req, res))
448
+ return;
449
+ const workspaceId = requestWorkspaceId(req);
450
+ const data = core.listInitiatives(workspaceId);
451
+ res.writeHead(200, { 'Content-Type': 'application/json' });
452
+ res.end(JSON.stringify(data));
453
+ });
454
+ // POST /api/taskforce/initiative - Create initiative
455
+ addRoute('POST', '/api/taskforce/initiative', async (req, res) => {
456
+ if (!ensureAppAccess(req, res))
457
+ return;
458
+ const body = await parseJsonBody(req);
459
+ try {
460
+ const workspaceId = requestWorkspaceId(req);
461
+ const initiative = core.createInitiative(body || {}, workspaceId);
462
+ res.writeHead(201, { 'Content-Type': 'application/json' });
463
+ res.end(JSON.stringify(initiative));
464
+ }
465
+ catch (error) {
466
+ const statusCode = resolveErrorStatusCode(error, 400);
467
+ const message = error instanceof Error ? error.message : 'Failed to create initiative';
468
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
469
+ res.end(JSON.stringify({ error: message }));
470
+ }
471
+ });
472
+ // GET /api/taskforce/initiative/:id - Read one initiative
473
+ addRoute('GET', '/api/taskforce/initiative/:id', async (req, res, params) => {
474
+ if (!ensureAppAccess(req, res))
475
+ return;
476
+ const workspaceId = requestWorkspaceId(req);
477
+ const initiative = core.getInitiative(params.id, workspaceId);
478
+ if (!initiative) {
479
+ res.writeHead(404, { 'Content-Type': 'application/json' });
480
+ res.end(JSON.stringify({ error: 'Initiative not found' }));
481
+ return;
482
+ }
483
+ res.writeHead(200, { 'Content-Type': 'application/json' });
484
+ res.end(JSON.stringify(initiative));
485
+ });
486
+ // PATCH /api/taskforce/initiative/:id - Update initiative
487
+ addRoute('PATCH', '/api/taskforce/initiative/:id', async (req, res, params) => {
488
+ if (!ensureAppAccess(req, res))
489
+ return;
490
+ const body = await parseJsonBody(req);
491
+ try {
492
+ const workspaceId = requestWorkspaceId(req);
493
+ const updated = core.updateInitiative(params.id, body || {}, workspaceId);
494
+ res.writeHead(200, { 'Content-Type': 'application/json' });
495
+ res.end(JSON.stringify(updated));
496
+ }
497
+ catch (error) {
498
+ const statusCode = resolveErrorStatusCode(error, 400);
499
+ const message = error instanceof Error ? error.message : 'Failed to update initiative';
500
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
501
+ res.end(JSON.stringify({ error: message }));
502
+ }
503
+ });
504
+ addRoute('POST', '/api/taskforce/initiative/:id/archive', async (req, res, params) => {
505
+ if (!ensureAppAccess(req, res))
506
+ return;
507
+ try {
508
+ const workspaceId = requestWorkspaceId(req);
509
+ const archived = core.archiveInitiative(params.id, workspaceId);
510
+ res.writeHead(200, { 'Content-Type': 'application/json' });
511
+ res.end(JSON.stringify(archived));
512
+ }
513
+ catch (error) {
514
+ const statusCode = resolveErrorStatusCode(error, 400);
515
+ const message = error instanceof Error ? error.message : 'Failed to archive initiative';
516
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
517
+ res.end(JSON.stringify({ error: message }));
518
+ }
519
+ });
520
+ addRoute('POST', '/api/taskforce/initiative/:id/unarchive', async (req, res, params) => {
521
+ if (!ensureAppAccess(req, res))
522
+ return;
523
+ try {
524
+ const workspaceId = requestWorkspaceId(req);
525
+ const restored = core.unarchiveInitiative(params.id, workspaceId);
526
+ res.writeHead(200, { 'Content-Type': 'application/json' });
527
+ res.end(JSON.stringify(restored));
528
+ }
529
+ catch (error) {
530
+ const statusCode = resolveErrorStatusCode(error, 400);
531
+ const message = error instanceof Error ? error.message : 'Failed to unarchive initiative';
532
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
533
+ res.end(JSON.stringify({ error: message }));
534
+ }
535
+ });
536
+ // GET /api/taskforce/workstreams - List workstreams
537
+ addRoute('GET', '/api/taskforce/workstreams', async (req, res) => {
538
+ if (!ensureAppAccess(req, res))
539
+ return;
540
+ const workspaceId = requestWorkspaceId(req);
541
+ const data = core.listWorkstreams(workspaceId);
542
+ res.writeHead(200, { 'Content-Type': 'application/json' });
543
+ res.end(JSON.stringify(data));
544
+ });
545
+ // POST /api/taskforce/workstream - Create workstream
546
+ addRoute('POST', '/api/taskforce/workstream', async (req, res) => {
547
+ if (!ensureAppAccess(req, res))
548
+ return;
549
+ const body = await parseJsonBody(req);
550
+ try {
551
+ const workspaceId = requestWorkspaceId(req);
552
+ const workstream = core.createWorkstream(body || {}, workspaceId);
553
+ res.writeHead(201, { 'Content-Type': 'application/json' });
554
+ res.end(JSON.stringify(workstream));
555
+ }
556
+ catch (error) {
557
+ const statusCode = resolveErrorStatusCode(error, 400);
558
+ const message = error instanceof Error ? error.message : 'Failed to create workstream';
559
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
560
+ res.end(JSON.stringify({ error: message }));
561
+ }
562
+ });
563
+ // GET /api/taskforce/workstream/:id - Read one workstream
564
+ addRoute('GET', '/api/taskforce/workstream/:id', async (req, res, params) => {
565
+ if (!ensureAppAccess(req, res))
566
+ return;
567
+ const workspaceId = requestWorkspaceId(req);
568
+ const workstream = core.getWorkstream(params.id, workspaceId);
569
+ if (!workstream) {
570
+ res.writeHead(404, { 'Content-Type': 'application/json' });
571
+ res.end(JSON.stringify({ error: 'Workstream not found' }));
572
+ return;
573
+ }
574
+ res.writeHead(200, { 'Content-Type': 'application/json' });
575
+ res.end(JSON.stringify(workstream));
576
+ });
577
+ // PATCH /api/taskforce/workstream/:id - Update workstream
578
+ addRoute('PATCH', '/api/taskforce/workstream/:id', async (req, res, params) => {
579
+ if (!ensureAppAccess(req, res))
580
+ return;
581
+ const body = await parseJsonBody(req);
582
+ try {
583
+ const workspaceId = requestWorkspaceId(req);
584
+ const updated = core.updateWorkstream(params.id, body || {}, workspaceId);
585
+ res.writeHead(200, { 'Content-Type': 'application/json' });
586
+ res.end(JSON.stringify(updated));
587
+ }
588
+ catch (error) {
589
+ const statusCode = resolveErrorStatusCode(error, 400);
590
+ const message = error instanceof Error ? error.message : 'Failed to update workstream';
591
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
592
+ res.end(JSON.stringify({ error: message }));
593
+ }
594
+ });
595
+ addRoute('POST', '/api/taskforce/workstream/:id/archive', async (req, res, params) => {
596
+ if (!ensureAppAccess(req, res))
597
+ return;
598
+ try {
599
+ const workspaceId = requestWorkspaceId(req);
600
+ const archived = core.archiveWorkstream(params.id, workspaceId);
601
+ res.writeHead(200, { 'Content-Type': 'application/json' });
602
+ res.end(JSON.stringify(archived));
603
+ }
604
+ catch (error) {
605
+ const statusCode = resolveErrorStatusCode(error, 400);
606
+ const message = error instanceof Error ? error.message : 'Failed to archive workstream';
607
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
608
+ res.end(JSON.stringify({ error: message }));
609
+ }
610
+ });
611
+ addRoute('POST', '/api/taskforce/workstream/:id/unarchive', async (req, res, params) => {
612
+ if (!ensureAppAccess(req, res))
613
+ return;
614
+ try {
615
+ const workspaceId = requestWorkspaceId(req);
616
+ const restored = core.unarchiveWorkstream(params.id, workspaceId);
617
+ res.writeHead(200, { 'Content-Type': 'application/json' });
618
+ res.end(JSON.stringify(restored));
619
+ }
620
+ catch (error) {
621
+ const statusCode = resolveErrorStatusCode(error, 400);
622
+ const message = error instanceof Error ? error.message : 'Failed to unarchive workstream';
623
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
624
+ res.end(JSON.stringify({ error: message }));
625
+ }
626
+ });
627
+ // PATCH /api/taskforce/task/:id/schedule - Update schedule fields for one task
628
+ addRoute('PATCH', '/api/taskforce/task/:id/schedule', async (req, res, params) => {
629
+ if (!ensureAppAccess(req, res))
630
+ return;
631
+ const body = await parseJsonBody(req);
632
+ try {
633
+ const workspaceId = requestWorkspaceId(req);
634
+ const result = core.updateTaskSchedule(params.id, {
635
+ scheduledDate: body?.scheduledDate ?? null,
636
+ orderInDay: body?.orderInDay
637
+ }, workspaceId);
638
+ if (!result) {
639
+ res.writeHead(404, { 'Content-Type': 'application/json' });
640
+ res.end(JSON.stringify({ error: 'Task not found' }));
641
+ return;
642
+ }
643
+ res.writeHead(200, { 'Content-Type': 'application/json' });
644
+ res.end(JSON.stringify(result));
645
+ }
646
+ catch (error) {
647
+ const statusCode = resolveErrorStatusCode(error, 400);
648
+ const message = error instanceof Error ? error.message : 'Failed to update task schedule';
649
+ const errorCode = error instanceof TaskforceRuleError ? error.code : error?.code;
650
+ const errorDetails = error instanceof TaskforceRuleError ? error.details : error?.details;
651
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
652
+ res.end(JSON.stringify({ error: message, code: errorCode, details: errorDetails }));
653
+ }
654
+ });
655
+ // POST /api/taskforce/schedule/reorder - Reorder/move multiple scheduled tasks
656
+ addRoute('POST', '/api/taskforce/schedule/reorder', async (req, res) => {
657
+ if (!ensureAppAccess(req, res))
658
+ return;
659
+ const body = await parseJsonBody(req);
660
+ try {
661
+ const moves = Array.isArray(body?.moves) ? body.moves : [];
662
+ const workspaceId = requestWorkspaceId(req);
663
+ const result = core.reorderScheduledTasks(moves, workspaceId);
664
+ res.writeHead(200, { 'Content-Type': 'application/json' });
665
+ res.end(JSON.stringify(result));
666
+ }
667
+ catch (error) {
668
+ const statusCode = resolveErrorStatusCode(error, 400);
669
+ const message = error instanceof Error ? error.message : 'Failed to reorder scheduled tasks';
670
+ const errorCode = error instanceof TaskforceRuleError ? error.code : error?.code;
671
+ const errorDetails = error instanceof TaskforceRuleError ? error.details : error?.details;
672
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
673
+ res.end(JSON.stringify({ error: message, code: errorCode, details: errorDetails }));
674
+ }
675
+ });
676
+ // GET /api/taskforce/archive - List all archived tasks
677
+ addRoute('GET', '/api/taskforce/archive', async (req, res) => {
678
+ if (!ensureAppAccess(req, res))
679
+ return;
680
+ const workspaceId = requestWorkspaceId(req);
681
+ const data = core.listArchive(workspaceId);
682
+ res.writeHead(200, { 'Content-Type': 'application/json' });
683
+ res.end(JSON.stringify(data));
684
+ });
685
+ // POST /api/taskforce/task/:id/complete - Archive as complete
686
+ addRoute('POST', '/api/taskforce/task/:id/complete', async (req, res, params) => {
687
+ if (!ensureAppAccess(req, res))
688
+ return;
689
+ try {
690
+ const workspaceId = requestWorkspaceId(req);
691
+ const archived = core.archiveTask(params.id, false, undefined, workspaceId, { actorRef: 'user' });
692
+ if (!archived) {
693
+ res.writeHead(404, { 'Content-Type': 'application/json' });
694
+ res.end(JSON.stringify({ error: 'Task not found' }));
695
+ return;
696
+ }
697
+ res.writeHead(200, { 'Content-Type': 'application/json' });
698
+ res.end(JSON.stringify(archived));
699
+ }
700
+ catch (error) {
701
+ const statusCode = resolveErrorStatusCode(error, 400);
702
+ const message = error instanceof Error ? error.message : 'Failed to archive task';
703
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
704
+ res.end(JSON.stringify({ error: message }));
705
+ }
706
+ });
707
+ // POST /api/taskforce/task/:id/cancel - Archive as cancelled
708
+ addRoute('POST', '/api/taskforce/task/:id/cancel', async (req, res, params) => {
709
+ if (!ensureAppAccess(req, res))
710
+ return;
711
+ const body = await parseJsonBody(req);
712
+ const reason = body.reason || 'Cancelled';
713
+ try {
714
+ const workspaceId = requestWorkspaceId(req);
715
+ const archived = core.archiveTask(params.id, true, reason, workspaceId, { actorRef: 'user' });
716
+ if (!archived) {
717
+ res.writeHead(404, { 'Content-Type': 'application/json' });
718
+ res.end(JSON.stringify({ error: 'Task not found' }));
719
+ return;
720
+ }
721
+ res.writeHead(200, { 'Content-Type': 'application/json' });
722
+ res.end(JSON.stringify(archived));
723
+ }
724
+ catch (error) {
725
+ const statusCode = resolveErrorStatusCode(error, 400);
726
+ const message = error instanceof Error ? error.message : 'Failed to cancel task';
727
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
728
+ res.end(JSON.stringify({ error: message }));
729
+ }
730
+ });
731
+ // DELETE /api/taskforce/task/:id - Delete a task
732
+ addRoute('DELETE', '/api/taskforce/task/:id', async (req, res, params) => {
733
+ if (!ensureAppAccess(req, res))
734
+ return;
735
+ try {
736
+ const workspaceId = requestWorkspaceId(req);
737
+ const deleted = core.softDeleteTask(params.id, workspaceId, { actorRef: 'user', source: 'ui' });
738
+ if (!deleted) {
739
+ res.writeHead(404, { 'Content-Type': 'application/json' });
740
+ res.end(JSON.stringify({ error: 'Task not found' }));
741
+ return;
742
+ }
743
+ res.writeHead(200, { 'Content-Type': 'application/json' });
744
+ res.end(JSON.stringify({ success: true, deleted }));
745
+ }
746
+ catch (error) {
747
+ const statusCode = resolveErrorStatusCode(error, 400);
748
+ const message = error instanceof Error ? error.message : 'Failed to delete task';
749
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
750
+ res.end(JSON.stringify({ error: message }));
751
+ }
752
+ });
753
+ const handleRestoreDeletedTaskRoute = async (req, res, params) => {
754
+ if (!ensureAppAccess(req, res))
755
+ return;
756
+ try {
757
+ const workspaceId = requestWorkspaceId(req);
758
+ const restored = core.restoreDeletedTask(params.id, workspaceId, { actorRef: 'user' });
759
+ if (!restored) {
760
+ res.writeHead(404, { 'Content-Type': 'application/json' });
761
+ res.end(JSON.stringify({ error: 'Deleted task not found' }));
762
+ return;
763
+ }
764
+ res.writeHead(200, { 'Content-Type': 'application/json' });
765
+ res.end(JSON.stringify(restored));
766
+ }
767
+ catch (error) {
768
+ const statusCode = resolveErrorStatusCode(error, 400);
769
+ const message = error instanceof Error ? error.message : 'Failed to restore deleted task';
770
+ const errorCode = error instanceof TaskforceRuleError ? error.code : error?.code;
771
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
772
+ res.end(JSON.stringify({ error: message, code: errorCode }));
773
+ }
774
+ };
775
+ // POST /api/taskforce/deleted/:id/restore - Restore a deleted task
776
+ addRoute('POST', '/api/taskforce/deleted/:id/restore', handleRestoreDeletedTaskRoute);
777
+ addRoute('POST', '/api/taskforce/trash/:id/restore', handleRestoreDeletedTaskRoute);
778
+ const handlePermanentlyDeleteDeletedTaskRoute = async (req, res, params) => {
779
+ if (!ensureAppAccess(req, res))
780
+ return;
781
+ try {
782
+ const workspaceId = requestWorkspaceId(req);
783
+ const deleted = core.permanentlyDeleteDeletedTask(params.id, workspaceId);
784
+ if (!deleted) {
785
+ res.writeHead(404, { 'Content-Type': 'application/json' });
786
+ res.end(JSON.stringify({ error: 'Deleted task not found' }));
787
+ return;
788
+ }
789
+ res.writeHead(200, { 'Content-Type': 'application/json' });
790
+ res.end(JSON.stringify({ success: true }));
791
+ }
792
+ catch (error) {
793
+ const statusCode = resolveErrorStatusCode(error, 400);
794
+ const message = error instanceof Error ? error.message : 'Failed to permanently delete deleted task';
795
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
796
+ res.end(JSON.stringify({ error: message }));
797
+ }
798
+ };
799
+ // DELETE /api/taskforce/deleted/:id - Permanently delete a deleted task
800
+ addRoute('DELETE', '/api/taskforce/deleted/:id', handlePermanentlyDeleteDeletedTaskRoute);
801
+ addRoute('DELETE', '/api/taskforce/trash/:id', handlePermanentlyDeleteDeletedTaskRoute);
802
+ const handleEmptyDeletedTasks = async (req, res) => {
803
+ if (!ensureAppAccess(req, res))
804
+ return;
805
+ try {
806
+ const workspaceId = requestWorkspaceId(req);
807
+ const deleted = core.permanentlyDeleteAllDeletedTasks(workspaceId);
808
+ res.writeHead(200, { 'Content-Type': 'application/json' });
809
+ res.end(JSON.stringify({ success: true, deleted }));
810
+ }
811
+ catch (error) {
812
+ const statusCode = resolveErrorStatusCode(error, 400);
813
+ const message = error instanceof Error ? error.message : 'Failed to permanently delete deleted tasks';
814
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
815
+ res.end(JSON.stringify({ error: message }));
816
+ }
817
+ };
818
+ // POST /api/taskforce/deleted/empty - Permanently delete all deleted tasks in the workspace
819
+ addRoute('POST', '/api/taskforce/deleted/empty', handleEmptyDeletedTasks);
820
+ addRoute('POST', '/api/taskforce/trash/empty', handleEmptyDeletedTasks);
821
+ // POST /api/taskforce/task/:id/comment - Add a comment to a task
822
+ addRoute('POST', '/api/taskforce/task/:id/comment', async (req, res, params) => {
823
+ if (!ensureAppAccess(req, res))
824
+ return;
825
+ const body = await parseJsonBody(req);
826
+ const { text, author = 'user' } = body;
827
+ if (!text) {
828
+ res.writeHead(400, { 'Content-Type': 'application/json' });
829
+ res.end(JSON.stringify({ error: 'Comment text is required' }));
830
+ return;
831
+ }
832
+ const workspaceId = requestWorkspaceId(req);
833
+ const updated = core.addComment(params.id, text, author, workspaceId, { actorRef: author || 'user' });
834
+ if (!updated) {
835
+ res.writeHead(404, { 'Content-Type': 'application/json' });
836
+ res.end(JSON.stringify({ error: 'Task not found' }));
837
+ return;
838
+ }
839
+ res.writeHead(200, { 'Content-Type': 'application/json' });
840
+ res.end(JSON.stringify(updated));
841
+ });
842
+ // POST /api/taskforce/task/:id/unarchive - Restore an archived task
843
+ addRoute('POST', '/api/taskforce/task/:id/unarchive', async (req, res, params) => {
844
+ if (!ensureAppAccess(req, res))
845
+ return;
846
+ const workspaceId = requestWorkspaceId(req);
847
+ const restored = core.unarchiveTask(params.id, workspaceId, { actorRef: 'user' });
848
+ if (!restored) {
849
+ res.writeHead(404, { 'Content-Type': 'application/json' });
850
+ res.end(JSON.stringify({ error: 'Archived task not found' }));
851
+ return;
852
+ }
853
+ res.writeHead(200, { 'Content-Type': 'application/json' });
854
+ res.end(JSON.stringify(restored));
855
+ });
856
+ // === SECTION: Bulk operations ===
857
+ // POST /api/taskforce/bulk-create - Create multiple tasks with optional atomic + validate-only behavior
858
+ addRoute('POST', '/api/taskforce/bulk-create', async (req, res) => {
859
+ if (!ensureAppAccess(req, res))
860
+ return;
861
+ const body = await parseJsonBody(req);
862
+ const { tasks, atomic = true, validate_only = false } = body;
863
+ if (!Array.isArray(tasks) || tasks.length === 0) {
864
+ res.writeHead(400, { 'Content-Type': 'application/json' });
865
+ res.end(JSON.stringify({ error: 'tasks array is required' }));
866
+ return;
867
+ }
868
+ const workspaceId = requestWorkspaceId(req);
869
+ const result = core.bulkCreateTasks(tasks, {
870
+ atomic: atomic !== false,
871
+ validateOnly: validate_only === true,
872
+ workspaceId
873
+ });
874
+ const hasErrors = result.errors.length > 0;
875
+ const succeeded = validate_only ? (hasErrors ? 0 : result.total) : result.created.length;
876
+ const summary = buildBatchSummary({
877
+ operation: 'bulk-create',
878
+ total: result.total,
879
+ succeeded,
880
+ atomic: result.atomic,
881
+ validateOnly: result.validateOnly
882
+ });
883
+ res.writeHead(200, { 'Content-Type': 'application/json' });
884
+ res.end(JSON.stringify({
885
+ success: !hasErrors,
886
+ needs_confirmation: !!result.errors.find((e) => e?.code === 'TAXONOMY_NEEDS_CONFIRMATION'),
887
+ summary,
888
+ results: {
889
+ created: result.created
890
+ },
891
+ errors: result.errors
892
+ }));
893
+ });
894
+ // POST /api/taskforce/bulk-archive - Archive multiple tasks at once
895
+ addRoute('POST', '/api/taskforce/bulk-archive', async (req, res) => {
896
+ if (!ensureAppAccess(req, res))
897
+ return;
898
+ const body = await parseJsonBody(req);
899
+ const { ids, status = 'done' } = body;
900
+ if (!ids || !Array.isArray(ids) || ids.length === 0) {
901
+ res.writeHead(400, { 'Content-Type': 'application/json' });
902
+ res.end(JSON.stringify({ error: 'ids array is required' }));
903
+ return;
904
+ }
905
+ const isCancellation = status === 'cancelled';
906
+ const archived = [];
907
+ const errors = [];
908
+ for (let i = 0; i < ids.length; i++) {
909
+ const taskId = ids[i];
910
+ try {
911
+ const workspaceId = requestWorkspaceId(req);
912
+ const item = core.archiveTask(taskId, isCancellation, undefined, workspaceId);
913
+ if (!item) {
914
+ errors.push({ index: i, id: taskId, message: 'Task not found', statusCode: 404, code: 'TASK_NOT_FOUND' });
915
+ continue;
916
+ }
917
+ archived.push(item);
918
+ }
919
+ catch (error) {
920
+ errors.push({
921
+ index: i,
922
+ id: taskId,
923
+ message: error instanceof Error ? error.message : 'Failed to archive task',
924
+ statusCode: resolveErrorStatusCode(error, 400),
925
+ code: error instanceof TaskforceRuleError ? error.code : error?.code
926
+ });
927
+ }
928
+ }
929
+ const summary = buildBatchSummary({
930
+ operation: 'bulk-archive',
931
+ total: ids.length,
932
+ succeeded: archived.length
933
+ });
934
+ res.writeHead(200, { 'Content-Type': 'application/json' });
935
+ res.end(JSON.stringify({
936
+ success: errors.length === 0,
937
+ summary,
938
+ results: {
939
+ archived
940
+ },
941
+ errors
942
+ }));
943
+ });
944
+ // POST /api/taskforce/bulk-update-fields - Batch update multiple tasks
945
+ addRoute('POST', '/api/taskforce/bulk-update-fields', async (req, res) => {
946
+ if (!ensureAppAccess(req, res))
947
+ return;
948
+ const body = await parseJsonBody(req);
949
+ const { updates } = body;
950
+ if (!updates || !Array.isArray(updates) || updates.length === 0) {
951
+ res.writeHead(400, { 'Content-Type': 'application/json' });
952
+ res.end(JSON.stringify({ error: 'updates array is required' }));
953
+ return;
954
+ }
955
+ const workspaceId = requestWorkspaceId(req);
956
+ const preview = core.bulkUpdateFieldsPreview(updates, workspaceId);
957
+ const results = [];
958
+ const errors = [];
959
+ for (const skipped of preview.skipped) {
960
+ if (skipped.statusCode >= 400) {
961
+ errors.push({
962
+ index: skipped.index,
963
+ id: skipped.id,
964
+ message: skipped.message,
965
+ statusCode: skipped.statusCode,
966
+ code: skipped.code
967
+ });
968
+ }
969
+ }
970
+ for (const item of preview.toApply) {
971
+ const { id, fields } = item;
972
+ try {
973
+ const updated = core.updateTask(id, fields, workspaceId);
974
+ if (updated) {
975
+ results.push(updated);
976
+ }
977
+ else {
978
+ errors.push({ index: item.index, id, message: 'Task not found', statusCode: 404, code: 'TASK_NOT_FOUND' });
979
+ }
980
+ }
981
+ catch (error) {
982
+ errors.push({
983
+ index: item.index,
984
+ id,
985
+ message: error instanceof Error ? error.message : 'Failed to update task',
986
+ statusCode: resolveErrorStatusCode(error, 400),
987
+ code: error instanceof TaskforceRuleError ? error.code : error?.code
988
+ });
989
+ }
990
+ }
991
+ const summary = buildBatchSummary({
992
+ operation: 'bulk-update-fields',
993
+ total: updates.length,
994
+ succeeded: results.length
995
+ });
996
+ res.writeHead(200, { 'Content-Type': 'application/json' });
997
+ res.end(JSON.stringify({
998
+ success: errors.length === 0,
999
+ summary,
1000
+ results: {
1001
+ updated: results,
1002
+ preflight: {
1003
+ deduped: preview.deduped,
1004
+ skipped_noop: preview.skipped.filter((s) => s.code === 'NO_CHANGES' || s.code === 'DUPLICATE_SUPERSEDED').length,
1005
+ by_field: preview.byField,
1006
+ priority_before: preview.priorityBefore,
1007
+ priority_after: preview.priorityAfter
1008
+ }
1009
+ },
1010
+ errors
1011
+ }));
1012
+ });
1013
+ // POST /api/taskforce/bulk-update-fields/preview - Dry-run summary for bulk updates
1014
+ addRoute('POST', '/api/taskforce/bulk-update-fields/preview', async (req, res) => {
1015
+ if (!ensureAppAccess(req, res))
1016
+ return;
1017
+ const body = await parseJsonBody(req);
1018
+ const { updates } = body;
1019
+ if (!updates || !Array.isArray(updates) || updates.length === 0) {
1020
+ res.writeHead(400, { 'Content-Type': 'application/json' });
1021
+ res.end(JSON.stringify({ error: 'updates array is required' }));
1022
+ return;
1023
+ }
1024
+ const workspaceId = requestWorkspaceId(req);
1025
+ const preview = core.bulkUpdateFieldsPreview(updates, workspaceId);
1026
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1027
+ res.end(JSON.stringify({
1028
+ success: true,
1029
+ summary: {
1030
+ operation: 'bulk-update-fields-preview',
1031
+ total: preview.total,
1032
+ deduped: preview.deduped,
1033
+ to_apply: preview.toApply.length,
1034
+ skipped: preview.skipped.length
1035
+ },
1036
+ results: {
1037
+ by_field: preview.byField,
1038
+ priority_before: preview.priorityBefore,
1039
+ priority_after: preview.priorityAfter,
1040
+ to_apply: preview.toApply.map((item) => ({
1041
+ index: item.index,
1042
+ id: item.id,
1043
+ fields: item.changedFields
1044
+ })),
1045
+ skipped: preview.skipped
1046
+ }
1047
+ }));
1048
+ });
1049
+ // === SECTION: Initiative templates ===
1050
+ // GET /api/taskforce/initiative-templates - List built-in initiative templates
1051
+ addRoute('GET', '/api/taskforce/initiative-templates', async (req, res) => {
1052
+ const templates = core.getInitiativeTemplates();
1053
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1054
+ res.end(JSON.stringify({ templates }));
1055
+ });
1056
+ // POST /api/taskforce/initiative-templates/create - Create initiative + milestones from template
1057
+ addRoute('POST', '/api/taskforce/initiative-templates/create', async (req, res) => {
1058
+ const body = await parseJsonBody(req);
1059
+ const { templateId, title } = body || {};
1060
+ if (!templateId || !title) {
1061
+ res.writeHead(400, { 'Content-Type': 'application/json' });
1062
+ res.end(JSON.stringify({ error: 'templateId and title are required' }));
1063
+ return;
1064
+ }
1065
+ try {
1066
+ const workspaceId = requestWorkspaceId(req);
1067
+ const result = core.createInitiativeFromTemplate(body, workspaceId);
1068
+ res.writeHead(201, { 'Content-Type': 'application/json' });
1069
+ res.end(JSON.stringify({
1070
+ success: true,
1071
+ summary: {
1072
+ operation: 'initiative-template-create',
1073
+ total: 1 + result.milestones.length,
1074
+ succeeded: 1 + result.milestones.length,
1075
+ failed: 0,
1076
+ partial: false
1077
+ },
1078
+ results: result,
1079
+ errors: []
1080
+ }));
1081
+ }
1082
+ catch (error) {
1083
+ const statusCode = resolveErrorStatusCode(error, 400);
1084
+ const message = error instanceof Error ? error.message : 'Failed to create initiative from template';
1085
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
1086
+ res.end(JSON.stringify({
1087
+ success: false,
1088
+ error: message,
1089
+ code: error instanceof TaskforceRuleError ? error.code : error?.code,
1090
+ details: error instanceof TaskforceRuleError ? error.details : error?.details
1091
+ }));
1092
+ }
1093
+ });
1094
+ // === SECTION: Taxonomy management ===
1095
+ // GET /api/taskforce/taxonomy-library - List built-in taxonomy library packs
1096
+ addRoute('GET', '/api/taskforce/taxonomy-library', async (req, res) => {
1097
+ if (!ensureAppAccess(req, res))
1098
+ return;
1099
+ const packs = listBuiltInTaxonomyLibraryPacks();
1100
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1101
+ res.end(JSON.stringify({ packs }));
1102
+ });
1103
+ // GET /api/taskforce/custom-taxonomy-library - List built-in custom taxonomy library packs
1104
+ addRoute('GET', '/api/taskforce/custom-taxonomy-library', async (req, res) => {
1105
+ if (!ensureAppAccess(req, res))
1106
+ return;
1107
+ const packs = listBuiltInCustomTaxonomyLibraryPacks();
1108
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1109
+ res.end(JSON.stringify({ packs }));
1110
+ });
1111
+ // GET /api/taskforce/taxonomy-state - Get unified workspace taxonomy state
1112
+ addRoute('GET', '/api/taskforce/taxonomy-state', async (req, res) => {
1113
+ if (!ensureAppAccess(req, res))
1114
+ return;
1115
+ const workspaceId = requestWorkspaceId(req);
1116
+ const taxonomyState = core.getTaxonomyState(workspaceId);
1117
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1118
+ res.end(JSON.stringify(taxonomyState));
1119
+ });
1120
+ addRoute('POST', '/api/taskforce/taxonomy-display-labels', async (req, res) => {
1121
+ if (!ensureAppAccess(req, res))
1122
+ return;
1123
+ const workspaceId = requestWorkspaceId(req);
1124
+ const body = await parseJsonBody(req);
1125
+ const displayLabels = core.updateTaxonomyDisplayLabels(body?.displayLabels || {}, workspaceId);
1126
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1127
+ res.end(JSON.stringify({ success: true, displayLabels }));
1128
+ });
1129
+ // GET /api/taskforce/categories - Get project categories
1130
+ addRoute('GET', '/api/taskforce/categories', async (req, res) => {
1131
+ if (!ensureAppAccess(req, res))
1132
+ return;
1133
+ const workspaceId = requestWorkspaceId(req);
1134
+ const categories = core.getCategories(workspaceId);
1135
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1136
+ res.end(JSON.stringify({ categories }));
1137
+ });
1138
+ // POST /api/taskforce/categories - Update project categories
1139
+ addRoute('POST', '/api/taskforce/categories', async (req, res) => {
1140
+ if (!ensureAppAccess(req, res))
1141
+ return;
1142
+ const workspaceId = requestWorkspaceId(req);
1143
+ const body = await parseJsonBody(req);
1144
+ const { categories } = body;
1145
+ if (!categories || !Array.isArray(categories)) {
1146
+ res.writeHead(400, { 'Content-Type': 'application/json' });
1147
+ res.end(JSON.stringify({ error: 'categories array is required' }));
1148
+ return;
1149
+ }
1150
+ core.updateCategories(categories, workspaceId);
1151
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1152
+ res.end(JSON.stringify({ success: true, categories: core.getCategories(workspaceId) }));
1153
+ });
1154
+ // GET /api/taskforce/types - Get project task types
1155
+ addRoute('GET', '/api/taskforce/types', async (req, res) => {
1156
+ if (!ensureAppAccess(req, res))
1157
+ return;
1158
+ const workspaceId = requestWorkspaceId(req);
1159
+ const types = core.getTypes(workspaceId);
1160
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1161
+ res.end(JSON.stringify({ types }));
1162
+ });
1163
+ // POST /api/taskforce/types - Update project task types
1164
+ addRoute('POST', '/api/taskforce/types', async (req, res) => {
1165
+ if (!ensureAppAccess(req, res))
1166
+ return;
1167
+ const workspaceId = requestWorkspaceId(req);
1168
+ const body = await parseJsonBody(req);
1169
+ const { types } = body;
1170
+ if (!types || !Array.isArray(types)) {
1171
+ res.writeHead(400, { 'Content-Type': 'application/json' });
1172
+ res.end(JSON.stringify({ error: 'types array is required' }));
1173
+ return;
1174
+ }
1175
+ core.updateTypes(types, workspaceId);
1176
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1177
+ res.end(JSON.stringify({ success: true, types: core.getTypes(workspaceId) }));
1178
+ });
1179
+ // GET /api/taskforce/priorities - Get project priority levels
1180
+ addRoute('GET', '/api/taskforce/priorities', async (req, res) => {
1181
+ if (!ensureAppAccess(req, res))
1182
+ return;
1183
+ const workspaceId = requestWorkspaceId(req);
1184
+ const priorities = core.getPriorities(workspaceId);
1185
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1186
+ res.end(JSON.stringify({ priorities }));
1187
+ });
1188
+ // POST /api/taskforce/priorities - Update project priority levels
1189
+ addRoute('POST', '/api/taskforce/priorities', async (req, res) => {
1190
+ if (!ensureAppAccess(req, res))
1191
+ return;
1192
+ const workspaceId = requestWorkspaceId(req);
1193
+ const body = await parseJsonBody(req);
1194
+ const { priorities } = body;
1195
+ if (!priorities || !Array.isArray(priorities)) {
1196
+ res.writeHead(400, { 'Content-Type': 'application/json' });
1197
+ res.end(JSON.stringify({ error: 'priorities array is required' }));
1198
+ return;
1199
+ }
1200
+ core.updatePriorities(priorities, workspaceId);
1201
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1202
+ res.end(JSON.stringify({ success: true, priorities: core.getPriorities(workspaceId) }));
1203
+ });
1204
+ // GET /api/taskforce/approaches - Get project approach options
1205
+ addRoute('GET', '/api/taskforce/approaches', async (req, res) => {
1206
+ if (!ensureAppAccess(req, res))
1207
+ return;
1208
+ const approaches = core.getApproaches();
1209
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1210
+ res.end(JSON.stringify({ approaches }));
1211
+ });
1212
+ // POST /api/taskforce/approaches - Update project approach options
1213
+ addRoute('POST', '/api/taskforce/approaches', async (req, res) => {
1214
+ if (!ensureAppAccess(req, res))
1215
+ return;
1216
+ const body = await parseJsonBody(req);
1217
+ const { approaches } = body;
1218
+ if (!approaches || !Array.isArray(approaches)) {
1219
+ res.writeHead(400, { 'Content-Type': 'application/json' });
1220
+ res.end(JSON.stringify({ error: 'approaches array is required' }));
1221
+ return;
1222
+ }
1223
+ core.updateApproaches(approaches);
1224
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1225
+ res.end(JSON.stringify({ success: true, approaches: core.getApproaches() }));
1226
+ });
1227
+ // GET /api/taskforce/taxonomies - Get project taxonomies
1228
+ addRoute('GET', '/api/taskforce/taxonomies', async (req, res) => {
1229
+ if (!ensureAppAccess(req, res))
1230
+ return;
1231
+ const workspaceId = requestWorkspaceId(req);
1232
+ const taxonomies = core.getTaxonomies(workspaceId);
1233
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1234
+ res.end(JSON.stringify({ taxonomies }));
1235
+ });
1236
+ // POST /api/taskforce/taxonomies - Update project taxonomies
1237
+ addRoute('POST', '/api/taskforce/taxonomies', async (req, res) => {
1238
+ if (!ensureAppAccess(req, res))
1239
+ return;
1240
+ const workspaceId = requestWorkspaceId(req);
1241
+ const body = await parseJsonBody(req);
1242
+ const { taxonomies } = body;
1243
+ if (!taxonomies || !Array.isArray(taxonomies)) {
1244
+ res.writeHead(400, { 'Content-Type': 'application/json' });
1245
+ res.end(JSON.stringify({ error: 'taxonomies array is required' }));
1246
+ return;
1247
+ }
1248
+ core.updateTaxonomies(taxonomies, workspaceId);
1249
+ res.writeHead(200, { 'Content-Type': 'application/json' });
1250
+ res.end(JSON.stringify({ success: true, taxonomies: core.getTaxonomies(workspaceId) }));
1251
+ });
1252
+ }