@taskforcehq/taskforce 0.3.305 → 0.3.307

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (440) hide show
  1. package/README.md +0 -2
  2. package/dist/Taskforce.module.css +603 -107
  3. package/dist/TaskforceCore.js +216 -43
  4. package/dist/TaskforceCore.test.js +611 -28
  5. package/dist/assets/fonts/CourierPrime-Bold.woff2 +0 -0
  6. package/dist/assets/fonts/CourierPrime-BoldItalic.woff2 +0 -0
  7. package/dist/assets/fonts/CourierPrime-Italic.woff2 +0 -0
  8. package/dist/assets/fonts/CourierPrime-Regular.woff2 +0 -0
  9. package/dist/assets/fonts/Noir_medium.woff2 +0 -0
  10. package/dist/assets/fonts/Noir_regular.woff2 +0 -0
  11. package/dist/assets/fonts/RussoOne-Regular.woff2 +0 -0
  12. package/dist/assets/fonts/SpecialElite-Regular.woff2 +0 -0
  13. package/dist/compat/workspaceSyncCompat.js +46 -2
  14. package/dist/compat/workspaceSyncCompat.test.js +38 -1
  15. package/dist/components/activity/EntityActivityTimeline.d.ts +34 -0
  16. package/dist/components/activity/EntityActivityTimeline.js +81 -0
  17. package/dist/components/context/ContextAttachmentManager.d.ts +14 -0
  18. package/dist/components/context/ContextAttachmentManager.js +561 -0
  19. package/dist/components/features/AgentsModule.d.ts +14 -1
  20. package/dist/components/features/AgentsModule.js +366 -18
  21. package/dist/components/features/AgentsModule.test.js +507 -8
  22. package/dist/components/features/AnnotatedAttachmentWorkspace.d.ts +3 -1
  23. package/dist/components/features/AnnotatedAttachmentWorkspace.js +118 -4
  24. package/dist/components/features/AnnotatedAttachmentWorkspace.test.js +52 -0
  25. package/dist/components/features/DocumentIndex.d.ts +2 -2
  26. package/dist/components/features/DocumentIndex.js +3 -4
  27. package/dist/components/features/DocumentViewer.d.ts +7 -1
  28. package/dist/components/features/DocumentViewer.js +62 -4
  29. package/dist/components/features/DocumentWorkspace.d.ts +10 -2
  30. package/dist/components/features/DocumentWorkspace.js +15 -4
  31. package/dist/components/features/DocumentWorkspace.test.js +51 -1
  32. package/dist/components/features/TaskSettings.d.ts +2 -0
  33. package/dist/components/features/TaskSettings.js +83 -78
  34. package/dist/components/features/TaskSettings.test.js +171 -82
  35. package/dist/components/features/documentWorkspaceModel.d.ts +1 -1
  36. package/dist/components/task/TaskActionHeader.js +11 -5
  37. package/dist/components/task/TaskActionHeader.test.js +10 -0
  38. package/dist/components/task/TaskCard.js +24 -29
  39. package/dist/components/task/TaskCard.test.js +38 -3
  40. package/dist/components/task/TaskContextUpload.js +4 -526
  41. package/dist/components/task/TaskContextUpload.test.js +3 -3
  42. package/dist/components/task/TaskForm.js +61 -116
  43. package/dist/components/task/TaskForm.test.js +110 -8
  44. package/dist/components/task/TaskKanban.d.ts +2 -1
  45. package/dist/components/task/TaskKanban.js +94 -21
  46. package/dist/components/task/TaskKanban.test.js +36 -0
  47. package/dist/components/task/TaskList.js +5 -1
  48. package/dist/components/task/TaskList.test.js +4 -0
  49. package/dist/components/ui/EditableAvatarButton.d.ts +18 -0
  50. package/dist/components/ui/EditableAvatarButton.js +18 -0
  51. package/dist/components/ui/HierarchyActionBadge.d.ts +10 -0
  52. package/dist/components/ui/HierarchyActionBadge.js +5 -0
  53. package/dist/components/views/AppShellHeader.d.ts +3 -1
  54. package/dist/components/views/AppShellHeader.js +27 -11
  55. package/dist/components/views/AppShellHeader.test.js +18 -1
  56. package/dist/components/views/PlanComparisonPage.d.ts +9 -1
  57. package/dist/components/views/PlanComparisonPage.js +78 -14
  58. package/dist/components/views/PlanComparisonPage.test.js +257 -0
  59. package/dist/components/views/PlansPage.js +127 -36
  60. package/dist/components/views/PlansPage.test.js +294 -12
  61. package/dist/components/views/StandaloneLayout.js +529 -592
  62. package/dist/components/views/WidgetView.js +10 -8
  63. package/dist/components/views/panels/PlanningDrawer.d.ts +25 -5
  64. package/dist/components/views/panels/PlanningDrawer.js +270 -55
  65. package/dist/components/views/panels/PlanningDrawer.test.d.ts +1 -0
  66. package/dist/components/views/panels/PlanningDrawer.test.js +529 -0
  67. package/dist/components/views/planningScope.d.ts +20 -0
  68. package/dist/components/views/planningScope.js +25 -0
  69. package/dist/components/views/planningScope.test.d.ts +1 -0
  70. package/dist/components/views/planningScope.test.js +60 -0
  71. package/dist/components/views/standalone/modals/AccountHubModal.d.ts +26 -1
  72. package/dist/components/views/standalone/modals/AccountHubModal.js +76 -2
  73. package/dist/components/views/standalone/modals/AccountHubModal.test.js +20 -3
  74. package/dist/components/views/standalone/modals/AvatarImageManagerModal.d.ts +20 -0
  75. package/dist/components/views/standalone/modals/AvatarImageManagerModal.js +127 -0
  76. package/dist/components/views/standalone/modals/EditProfileModal.d.ts +2 -9
  77. package/dist/components/views/standalone/modals/EditProfileModal.js +3 -2
  78. package/dist/components/views/standalone/modals/SyncEnableWarningModal.d.ts +9 -0
  79. package/dist/components/views/standalone/modals/SyncEnableWarningModal.js +6 -0
  80. package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.d.ts +1 -0
  81. package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.js +24 -0
  82. package/dist/components/views/standalone/modals/SyncStatusModal.d.ts +2 -1
  83. package/dist/components/views/standalone/modals/SyncStatusModal.js +2 -2
  84. package/dist/config/envSchema.js +1 -0
  85. package/dist/core/AiProfileService.d.ts +46 -2
  86. package/dist/core/AiProfileService.js +1073 -82
  87. package/dist/core/AiProfileService.test.js +19 -1
  88. package/dist/core/AiProfiles.test.js +1249 -44
  89. package/dist/core/AttachmentLinkService.d.ts +3 -0
  90. package/dist/core/AttachmentLinkService.js +110 -23
  91. package/dist/core/AuthIdentityService.d.ts +107 -0
  92. package/dist/core/AuthIdentityService.js +284 -0
  93. package/dist/core/AuthTokenService.d.ts +4 -0
  94. package/dist/core/AuthTokenService.js +34 -6
  95. package/dist/core/AuthTokenService.test.js +3 -3
  96. package/dist/core/EntitlementsPolicy.test.js +2 -2
  97. package/dist/core/GlobalSettingsService.js +127 -6
  98. package/dist/core/McpTokenService.d.ts +12 -0
  99. package/dist/core/McpTokenService.js +44 -1
  100. package/dist/core/PlanEntitlementService.d.ts +23 -2
  101. package/dist/core/PlanEntitlementService.js +343 -57
  102. package/dist/core/PlanFeatureCatalog.test.d.ts +1 -0
  103. package/dist/core/PlanFeatureCatalog.test.js +84 -0
  104. package/dist/core/PlanVersionPolicy.test.js +35 -2
  105. package/dist/core/PlanningEntities.test.js +418 -4
  106. package/dist/core/SignupMonetizationSettings.test.js +199 -27
  107. package/dist/core/SyncReconciliationService.js +2 -65
  108. package/dist/core/SystemAdmin.test.js +42 -42
  109. package/dist/core/TaskActivityService.d.ts +28 -1
  110. package/dist/core/TaskActivityService.js +227 -46
  111. package/dist/core/TaskActivitySync.test.d.ts +1 -0
  112. package/dist/core/TaskActivitySync.test.js +90 -0
  113. package/dist/core/TaskAttachmentsCanonical.test.js +51 -1
  114. package/dist/core/TaskAuditTimeline.test.js +96 -0
  115. package/dist/core/Taskforce.d.ts +415 -40
  116. package/dist/core/Taskforce.ids.test.js +58 -0
  117. package/dist/core/Taskforce.js +1543 -266
  118. package/dist/core/Taskforce.listTasksSlim.test.d.ts +1 -0
  119. package/dist/core/Taskforce.listTasksSlim.test.js +91 -0
  120. package/dist/core/Taskforce.mcpAuth.test.js +109 -0
  121. package/dist/core/UserProfileAvatarDrafts.test.js +30 -3
  122. package/dist/core/WorkspaceLifecycleService.js +0 -5
  123. package/dist/core/WorkspacePermissions.test.js +25 -1
  124. package/dist/core/WorkspacePlanMode.test.js +117 -16
  125. package/dist/core/shared.d.ts +1 -1
  126. package/dist/core/shared.js +5 -1
  127. package/dist/core/types.d.ts +75 -2
  128. package/dist/hooks/auth/useTaskforceAuthBootstrap.js +28 -2
  129. package/dist/hooks/bootstrapTimeouts.d.ts +4 -0
  130. package/dist/hooks/bootstrapTimeouts.js +8 -0
  131. package/dist/hooks/bootstrapTimeouts.test.d.ts +1 -0
  132. package/dist/hooks/bootstrapTimeouts.test.js +12 -0
  133. package/dist/hooks/sync/bootstrap.js +2 -0
  134. package/dist/hooks/sync/controlPlane.d.ts +37 -0
  135. package/dist/hooks/sync/controlPlane.js +78 -0
  136. package/dist/hooks/sync/controlPlane.test.d.ts +1 -0
  137. package/dist/hooks/sync/controlPlane.test.js +121 -0
  138. package/dist/hooks/sync/lifecyclePolicy.d.ts +45 -0
  139. package/dist/hooks/sync/lifecyclePolicy.js +93 -0
  140. package/dist/hooks/sync/lifecyclePolicy.test.d.ts +1 -0
  141. package/dist/hooks/sync/lifecyclePolicy.test.js +124 -0
  142. package/dist/hooks/sync/orchestratorShared.d.ts +13 -4
  143. package/dist/hooks/sync/orchestratorShared.js +129 -48
  144. package/dist/hooks/sync/orchestratorShared.test.js +50 -1
  145. package/dist/hooks/sync/pullLifecycle.d.ts +31 -0
  146. package/dist/hooks/sync/pullLifecycle.js +24 -0
  147. package/dist/hooks/sync/pullLifecycle.test.d.ts +1 -0
  148. package/dist/hooks/sync/pullLifecycle.test.js +80 -0
  149. package/dist/hooks/sync/recovery.d.ts +16 -2
  150. package/dist/hooks/sync/recovery.js +179 -53
  151. package/dist/hooks/sync/recovery.test.d.ts +1 -0
  152. package/dist/hooks/sync/recovery.test.js +292 -0
  153. package/dist/hooks/sync/transfers.d.ts +16 -3
  154. package/dist/hooks/sync/transfers.js +210 -66
  155. package/dist/hooks/sync/transfers.test.d.ts +1 -0
  156. package/dist/hooks/sync/transfers.test.js +928 -0
  157. package/dist/hooks/sync/useRecentSyncEvents.d.ts +21 -0
  158. package/dist/hooks/sync/useRecentSyncEvents.js +92 -0
  159. package/dist/hooks/sync/useRecentSyncEvents.test.d.ts +1 -0
  160. package/dist/hooks/sync/useRecentSyncEvents.test.js +124 -0
  161. package/dist/hooks/sync/useSyncStatusActions.d.ts +30 -0
  162. package/dist/hooks/sync/useSyncStatusActions.js +88 -0
  163. package/dist/hooks/sync/useSyncStatusActions.test.d.ts +1 -0
  164. package/dist/hooks/sync/useSyncStatusActions.test.js +133 -0
  165. package/dist/hooks/sync/useSyncStatusControls.d.ts +25 -0
  166. package/dist/hooks/sync/useSyncStatusControls.js +60 -0
  167. package/dist/hooks/sync/useSyncStatusControls.test.d.ts +1 -0
  168. package/dist/hooks/sync/useSyncStatusControls.test.js +88 -0
  169. package/dist/hooks/useFilterSort.js +13 -13
  170. package/dist/hooks/useFilterSort.test.js +87 -1
  171. package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +12 -0
  172. package/dist/hooks/useSyncOrchestrator.d.ts +9 -2
  173. package/dist/hooks/useSyncOrchestrator.js +409 -183
  174. package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +407 -0
  175. package/dist/hooks/useTaskData.js +8 -3
  176. package/dist/hooks/useTaskData.test.js +45 -0
  177. package/dist/hooks/useTaskforce.d.ts +145 -52
  178. package/dist/hooks/useTaskforce.js +592 -253
  179. package/dist/hooks/useTaskforce.runtime-routing.test.d.ts +1 -0
  180. package/dist/hooks/useTaskforce.runtime-routing.test.js +246 -0
  181. package/dist/hooks/useTaskforce.sync-behavior.test.js +2468 -201
  182. package/dist/hooks/useWorkspaceSyncController.d.ts +1 -0
  183. package/dist/hooks/useWorkspaceSyncController.js +13 -2
  184. package/dist/hooks/useWorkspaceSyncController.test.js +48 -0
  185. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.d.ts +16 -0
  186. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +328 -40
  187. package/dist/localization/locales/en-US.d.ts +0 -1
  188. package/dist/localization/locales/en-US.js +0 -1
  189. package/dist/localization/locales/es-419.js +0 -1
  190. package/dist/localization/locales/pt-BR.js +0 -1
  191. package/dist/mcp/canonicalAssetHelpers.d.ts +16 -4
  192. package/dist/mcp/canonicalAssetHelpers.js +18 -10
  193. package/dist/mcp/canonicalAssetHelpers.test.d.ts +1 -0
  194. package/dist/mcp/canonicalAssetHelpers.test.js +67 -0
  195. package/dist/mcp/clientIntegrations.d.ts +1 -0
  196. package/dist/mcp/clientIntegrations.js +25 -0
  197. package/dist/mcp/clientIntegrations.test.js +14 -3
  198. package/dist/mcp/clientProfileDefaults.js +3 -3
  199. package/dist/mcp/collaborationRegistrar.js +7 -7
  200. package/dist/mcp/documentAssetRegistrar.js +116 -10
  201. package/dist/mcp/runtime.d.ts +3 -0
  202. package/dist/mcp/runtime.js +1099 -185
  203. package/dist/mcp/runtime.test.js +1491 -140
  204. package/dist/mcp/taskAttachmentTypes.d.ts +1 -1
  205. package/dist/mcp/taskPlanningRegistrar.js +48 -0
  206. package/dist/mcp/toolRegistry.d.ts +56 -0
  207. package/dist/mcp/toolRegistry.js +8 -0
  208. package/dist/mcp/toolRegistry.test.js +4 -0
  209. package/dist/migrations/taskSchemaMigrations.d.ts +1 -1
  210. package/dist/migrations/taskSchemaMigrations.js +192 -61
  211. package/dist/migrations/taskSchemaMigrations.test.js +15 -0
  212. package/dist/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
  213. package/dist/resources/templates/workflows/collaborate.yaml +1 -1
  214. package/dist/resources/templates/workflows/evaluate.yaml +2 -2
  215. package/dist/resources/templates/workflows/plan.yaml +1 -1
  216. package/dist/resources/templates/workflows/review.yaml +2 -2
  217. package/dist/server/aiProfileAvatarAssets.d.ts +49 -0
  218. package/dist/server/aiProfileAvatarAssets.js +319 -0
  219. package/dist/server/aiProfileAvatarAssets.test.d.ts +1 -0
  220. package/dist/server/aiProfileAvatarAssets.test.js +213 -0
  221. package/dist/server/annotatedAttachmentsRoutes.test.js +69 -10
  222. package/dist/server/auth/providers/apple.d.ts +33 -0
  223. package/dist/server/auth/providers/apple.js +82 -0
  224. package/dist/server/auth/providers/appleClientSecret.d.ts +37 -0
  225. package/dist/server/auth/providers/appleClientSecret.js +65 -0
  226. package/dist/server/auth/providers/github.d.ts +26 -0
  227. package/dist/server/auth/providers/github.js +86 -0
  228. package/dist/server/auth/providers/google.d.ts +21 -0
  229. package/dist/server/auth/providers/google.js +56 -0
  230. package/dist/server/auth/providers/types.d.ts +21 -0
  231. package/dist/server/auth/providers/types.js +1 -0
  232. package/dist/server/auth.d.ts +2 -0
  233. package/dist/server/auth.js +6 -3
  234. package/dist/server/documentReviewRoutes.test.js +36 -3
  235. package/dist/server/index.cookieProxy.test.js +1 -0
  236. package/dist/server/index.d.ts +12 -0
  237. package/dist/server/index.js +124 -9
  238. package/dist/server/index.rateLimit.test.js +3 -0
  239. package/dist/server/index.test.js +111 -3
  240. package/dist/server/routes/admin.d.ts +3 -0
  241. package/dist/server/routes/admin.js +459 -28
  242. package/dist/server/routes/annotatedAttachments.js +51 -0
  243. package/dist/server/routes/auth.d.ts +26 -2
  244. package/dist/server/routes/auth.js +1170 -71
  245. package/dist/server/routes/authSupport.d.ts +5 -1
  246. package/dist/server/routes/authSupport.js +13 -2
  247. package/dist/server/routes/billing.js +372 -35
  248. package/dist/server/routes/billing.test.js +595 -12
  249. package/dist/server/routes/documents.d.ts +1 -0
  250. package/dist/server/routes/documents.js +182 -70
  251. package/dist/server/routes/shared.d.ts +28 -2
  252. package/dist/server/routes/shared.js +69 -14
  253. package/dist/server/routes/sync.integration.test.js +658 -39
  254. package/dist/server/routes/sync.js +74 -608
  255. package/dist/server/routes/syncAuxRoutes.d.ts +15 -0
  256. package/dist/server/routes/syncAuxRoutes.js +91 -0
  257. package/dist/server/routes/syncAuxRoutes.test.d.ts +1 -0
  258. package/dist/server/routes/syncAuxRoutes.test.js +158 -0
  259. package/dist/server/routes/syncPullApplyRoutes.d.ts +36 -0
  260. package/dist/server/routes/syncPullApplyRoutes.js +204 -0
  261. package/dist/server/routes/syncPushRoutes.d.ts +24 -0
  262. package/dist/server/routes/syncPushRoutes.js +212 -0
  263. package/dist/server/routes/syncRouteGuards.d.ts +36 -0
  264. package/dist/server/routes/syncRouteGuards.js +67 -0
  265. package/dist/server/routes/syncRouteGuards.test.d.ts +1 -0
  266. package/dist/server/routes/syncRouteGuards.test.js +94 -0
  267. package/dist/server/routes/syncRouteTypes.d.ts +13 -0
  268. package/dist/server/routes/syncRouteTypes.js +1 -0
  269. package/dist/server/routes/syncSnapshotRoutes.d.ts +66 -0
  270. package/dist/server/routes/syncSnapshotRoutes.js +182 -0
  271. package/dist/server/routes/tasks.js +55 -10
  272. package/dist/server/routes/workspaces.js +36 -5
  273. package/dist/server/routes.js +147 -11
  274. package/dist/server/routes.test.js +2704 -183
  275. package/dist/services/workflowExportSnapshots.test.js +2 -0
  276. package/dist/shared/aiProfileSeatScope.d.ts +5 -0
  277. package/dist/shared/aiProfileSeatScope.js +21 -0
  278. package/dist/shared/aiProfileSurfaceType.d.ts +1 -1
  279. package/dist/shared/aiProfileSurfaceType.js +10 -8
  280. package/dist/shared/passwordPolicy.d.ts +13 -0
  281. package/dist/shared/passwordPolicy.js +84 -0
  282. package/dist/shared/passwordPolicy.test.d.ts +1 -0
  283. package/dist/shared/passwordPolicy.test.js +34 -0
  284. package/dist/storage/objectStorage.d.ts +1 -0
  285. package/dist/storage/objectStorage.js +2 -1
  286. package/dist/storage/objectStorageClient.d.ts +1 -0
  287. package/dist/storage/objectStorageClient.js +41 -8
  288. package/dist/storage/objectStorageClient.test.js +26 -1
  289. package/dist/storage/objectStorageConfig.js +3 -1
  290. package/dist/storage/objectStorageConfig.test.js +13 -1
  291. package/dist/storage/workspaceAssetStore.d.ts +15 -3
  292. package/dist/storage/workspaceAssetStore.js +132 -44
  293. package/dist/storage/workspaceAssetStore.test.js +93 -6
  294. package/dist/styles/fonts.css +70 -0
  295. package/dist/sync/collaborationSyncPayload.d.ts +6 -1
  296. package/dist/sync/collaborationSyncPayload.js +19 -11
  297. package/dist/sync/collaborationSyncPayload.test.js +14 -1
  298. package/dist/sync/collaborationSyncState.d.ts +3 -3
  299. package/dist/sync/collaborationSyncState.js +19 -12
  300. package/dist/sync/contentSyncPayload.d.ts +5 -1
  301. package/dist/sync/contentSyncPayload.js +9 -0
  302. package/dist/sync/contentSyncPayload.test.js +39 -0
  303. package/dist/sync/contentSyncState.d.ts +9 -9
  304. package/dist/sync/contentSyncState.js +248 -107
  305. package/dist/sync/planningSyncPayload.js +5 -0
  306. package/dist/sync/planningSyncPayload.test.js +24 -0
  307. package/dist/sync/syncApplyHandlers.d.ts +11 -4
  308. package/dist/sync/syncApplyHandlers.js +115 -42
  309. package/dist/sync/syncApplyHandlers.test.js +251 -4
  310. package/dist/sync/syncFieldSemantics.d.ts +12 -0
  311. package/dist/sync/syncFieldSemantics.js +55 -0
  312. package/dist/sync/syncResourceAdapters.d.ts +46 -0
  313. package/dist/sync/syncResourceAdapters.js +79 -0
  314. package/dist/sync/syncService.d.ts +6 -0
  315. package/dist/sync/syncService.js +65 -1
  316. package/dist/sync/syncService.test.js +96 -3
  317. package/dist/sync/taskSyncChangeKey.d.ts +2 -0
  318. package/dist/sync/taskSyncChangeKey.js +143 -0
  319. package/dist/sync/taskSyncPayload.js +3 -8
  320. package/dist/sync/workspacePullFeed.d.ts +4 -0
  321. package/dist/sync/workspacePullFeed.js +132 -72
  322. package/dist/sync/workspacePullFeed.test.js +92 -0
  323. package/dist/sync/workspaceRepair.js +5 -2
  324. package/dist/sync/workspaceSyncModel.d.ts +73 -6
  325. package/dist/sync/workspaceSyncModel.js +342 -73
  326. package/dist/sync/workspaceSyncModel.test.js +559 -14
  327. package/dist/sync/workspaceSyncState.d.ts +17 -0
  328. package/dist/sync/workspaceSyncState.js +2 -1
  329. package/dist/sync/workspaceSyncSurface.js +3 -8
  330. package/dist/types.d.ts +50 -2
  331. package/dist/ui/assets/AgentsModule-2y82_3DO.js +1 -0
  332. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BTLZZCiQ.js +3 -0
  333. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BVKew-mH.css +1 -0
  334. package/dist/ui/assets/ContextAttachmentManager-D2epuNnG.js +3 -0
  335. package/dist/ui/assets/CourierPrime-Bold-BuLj_dpw.woff2 +0 -0
  336. package/dist/ui/assets/CourierPrime-BoldItalic-BrK2pUkZ.woff2 +0 -0
  337. package/dist/ui/assets/CourierPrime-Italic-DFUZK5Ey.woff2 +0 -0
  338. package/dist/ui/assets/CourierPrime-Regular-BsKphzVf.woff2 +0 -0
  339. package/dist/ui/assets/DocumentWorkspace-D4rJKXzd.css +1 -0
  340. package/dist/ui/assets/DocumentWorkspace-sVa-3Do6.js +252 -0
  341. package/dist/ui/assets/EntityActivityTimeline-DyqvvhuF.css +1 -0
  342. package/dist/ui/assets/EntityActivityTimeline-Zods27y_.js +1 -0
  343. package/dist/ui/assets/{InitiativesModule-Dhm7M8e7.js → InitiativesModule-D4XseTwW.js} +1 -1
  344. package/dist/ui/assets/Noir_medium-bxQwKGzB.woff2 +0 -0
  345. package/dist/ui/assets/Noir_regular-ojf2kxlG.woff2 +0 -0
  346. package/dist/ui/assets/PlansPage-D5AcbO0L.js +1 -0
  347. package/dist/ui/assets/PlansPage-Dvqsz5zc.css +1 -0
  348. package/dist/ui/assets/RussoOne-Regular-Cu_qq_qC.woff2 +0 -0
  349. package/dist/ui/assets/SpecialElite-Regular-Di6gSvAS.woff2 +0 -0
  350. package/dist/ui/assets/TaskContextUpload-uC5qx4Bv.js +1 -0
  351. package/dist/ui/assets/TaskSettings-CqvPAsTv.js +9 -0
  352. package/dist/ui/assets/{WorkflowsModule-BcS4afRn.js → WorkflowsModule-oOA9bcdK.js} +4 -4
  353. package/dist/ui/assets/documentReferences-DPZuTgHh.js +1 -0
  354. package/dist/ui/assets/index-607WPo_X.js +4 -0
  355. package/dist/ui/assets/index-CYyodXsg.css +1 -0
  356. package/dist/ui/assets/{vendor-icons-BSUaRwF8.js → vendor-icons-B32hGuF2.js} +1 -1
  357. package/dist/ui/fonts/CourierPrime-Bold.ttf +0 -0
  358. package/dist/ui/fonts/CourierPrime-Bold.woff2 +0 -0
  359. package/dist/ui/fonts/CourierPrime-BoldItalic.ttf +0 -0
  360. package/dist/ui/fonts/CourierPrime-BoldItalic.woff2 +0 -0
  361. package/dist/ui/fonts/CourierPrime-Italic.ttf +0 -0
  362. package/dist/ui/fonts/CourierPrime-Italic.woff2 +0 -0
  363. package/dist/ui/fonts/CourierPrime-Regular.ttf +0 -0
  364. package/dist/ui/fonts/CourierPrime-Regular.woff2 +0 -0
  365. package/dist/ui/fonts/Noir_medium.otf +0 -0
  366. package/dist/ui/fonts/Noir_medium.woff2 +0 -0
  367. package/dist/ui/fonts/Noir_regular.otf +0 -0
  368. package/dist/ui/fonts/Noir_regular.woff2 +0 -0
  369. package/dist/ui/fonts/RussoOne-Regular.woff2 +0 -0
  370. package/dist/ui/fonts/SpecialElite-Regular.ttf +0 -0
  371. package/dist/ui/fonts/SpecialElite-Regular.woff2 +0 -0
  372. package/dist/ui/index.html +3 -3
  373. package/dist/ui/product/agent manager.png +0 -0
  374. package/dist/ui/product/agent_manager_02.png +0 -0
  375. package/dist/utils/accountProfileSummaryCache.d.ts +5 -0
  376. package/dist/utils/aiProfileEvents.d.ts +7 -0
  377. package/dist/utils/aiProfileEvents.js +6 -0
  378. package/dist/utils/assignees.d.ts +8 -0
  379. package/dist/utils/assignees.js +10 -1
  380. package/dist/utils/assignees.test.d.ts +1 -0
  381. package/dist/utils/assignees.test.js +25 -0
  382. package/dist/utils/avatarDisplay.d.ts +1 -0
  383. package/dist/utils/avatarDisplay.js +15 -0
  384. package/dist/utils/avatarUpload.d.ts +27 -0
  385. package/dist/utils/avatarUpload.js +132 -0
  386. package/dist/utils/avatarUpload.test.d.ts +1 -0
  387. package/dist/utils/avatarUpload.test.js +40 -0
  388. package/dist/utils/bootstrapTrace.d.ts +7 -0
  389. package/dist/utils/bootstrapTrace.js +29 -0
  390. package/dist/utils/commercialLifecyclePresentation.js +3 -0
  391. package/dist/utils/contextAssetEvents.d.ts +2 -0
  392. package/dist/utils/contextFiles.d.ts +3 -1
  393. package/dist/utils/contextFiles.js +2 -1
  394. package/dist/utils/syncEventDetails.d.ts +3 -0
  395. package/dist/utils/syncEventDetails.js +64 -0
  396. package/dist/utils/syncEventDetails.test.d.ts +1 -0
  397. package/dist/utils/syncEventDetails.test.js +23 -0
  398. package/dist/utils/syncEventPresentation.d.ts +15 -0
  399. package/dist/utils/syncEventPresentation.js +129 -0
  400. package/dist/utils/syncEventPresentation.test.d.ts +1 -0
  401. package/dist/utils/syncEventPresentation.test.js +64 -0
  402. package/dist/utils/syncStatusPresentation.d.ts +72 -0
  403. package/dist/utils/syncStatusPresentation.js +217 -0
  404. package/dist/utils/syncStatusPresentation.test.d.ts +1 -0
  405. package/dist/utils/syncStatusPresentation.test.js +164 -0
  406. package/dist/utils/taskActivity.d.ts +9 -1
  407. package/dist/utils/taskActivity.js +290 -22
  408. package/dist/utils/taskActivity.test.js +141 -8
  409. package/dist/utils/taskSearch.d.ts +22 -0
  410. package/dist/utils/taskSearch.js +87 -0
  411. package/dist/utils/taskSearch.test.d.ts +1 -0
  412. package/dist/utils/taskSearch.test.js +69 -0
  413. package/dist/utils/taskUtils.js +10 -3
  414. package/dist/utils/taskUtils.test.d.ts +1 -0
  415. package/dist/utils/taskUtils.test.js +19 -0
  416. package/dist/utils/workspaceSyncPresentation.d.ts +4 -0
  417. package/dist/utils/workspaceSyncPresentation.js +68 -2
  418. package/dist/utils/workspaceSyncPresentation.test.js +36 -1
  419. package/package.json +3 -2
  420. package/scripts/export-sqlite-to-postgres.mjs +7 -9
  421. package/scripts/run-e2e-realtime.sh +17 -3
  422. package/scripts/run-smoke.sh +17 -5
  423. package/scripts/run-soak.sh +17 -5
  424. package/src/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
  425. package/src/resources/templates/workflows/collaborate.yaml +1 -1
  426. package/src/resources/templates/workflows/evaluate.yaml +2 -2
  427. package/src/resources/templates/workflows/plan.yaml +1 -1
  428. package/src/resources/templates/workflows/review.yaml +2 -2
  429. package/dist/ui/assets/AgentsModule-N2MnQBZk.js +0 -1
  430. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BG6P_GVW.js +0 -3
  431. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BaS2VwIr.css +0 -1
  432. package/dist/ui/assets/DocumentWorkspace-B3nV_Gc5.css +0 -1
  433. package/dist/ui/assets/DocumentWorkspace-DRbDMwh8.js +0 -252
  434. package/dist/ui/assets/PlansPage-C2dd2n1X.css +0 -1
  435. package/dist/ui/assets/PlansPage-Cq0zXj3I.js +0 -1
  436. package/dist/ui/assets/RussoOne-Regular-C3BxZIj7.ttf +0 -0
  437. package/dist/ui/assets/TaskSettings-ln0aF7xc.js +0 -9
  438. package/dist/ui/assets/index-C2-OXZV7.css +0 -1
  439. package/dist/ui/assets/index-DcSI5F86.js +0 -6
  440. package/scripts/migrate-planning-model.ts +0 -233
@@ -7,6 +7,7 @@
7
7
  *
8
8
  * Routes registered here:
9
9
  * GET/POST /api/platform/plans
10
+ * GET /api/platform/onboarding-plan-options
10
11
  * GET/POST /api/platform/plans/:planId/versions
11
12
  * GET /api/platform/features
12
13
  * GET/PATCH /api/platform/plans/:planId/versions/:versionId/features
@@ -23,6 +24,8 @@
23
24
  * GET/POST /api/taskforce/admin/email-settings
24
25
  * GET /api/taskforce/admin/email-settings/health
25
26
  * POST /api/taskforce/admin/email-settings/test
27
+ * GET/POST /api/taskforce/admin/auth-provider-settings
28
+ * GET /api/taskforce/admin/auth-provider-settings/health
26
29
  * GET/POST /api/taskforce/admin/system-settings
27
30
  * GET/POST /api/taskforce/admin/object-storage-settings
28
31
  * GET /api/taskforce/admin/object-storage-telemetry
@@ -68,6 +71,7 @@ import { getTaskforceCloudEnvironmentConfig, resolveTaskforceCloudEnvironmentFro
68
71
  import { buildCloudMcpRuntimeAuth, resolveErrorStatusCode } from './shared.js';
69
72
  import { buildAuthBehavior, buildSiteBehavior, getRouteEmailConfig, resolvePublicAuthBaseUrl, resolveRuntimeConfigBaseUrl, } from './authSupport.js';
70
73
  import { applyWorkspaceRepair, scanWorkspaceRepair } from '../../sync/workspaceRepair.js';
74
+ import { testMintAppleClientSecret } from '../auth/providers/appleClientSecret.js';
71
75
  // === SECTION: Registration ===
72
76
  export function registerAdminRoutes(deps) {
73
77
  const { addRoute, core, context, requestWorkspaceId, requestUserId, requestRole, requestHeader, requestRuntimeMode, ensureAppAccess, ensureAdminRole, ensureCloudPlanData, requireCloudRuntime, resolveAuthenticatedUserId, resolveAdminRequestActor, auditAdminAction, resolveEffectiveObjectStorageConfig, getObjectStorageClient, taskAssetStore, normalizeDocumentPathInput, ensureWithinDir, getAssetMetadata, markAssetDeleted, clearAssetDeleted, removeAssetMetadata, getStorageTelemetry, appendStorageTelemetry, getStorageIntegrityHistory, appendStorageIntegrityHistory, getDocumentPurgeHistory, appendDocumentPurgeHistory, getCollaborationTelemetry, isCollaborationPolicyEnabled, normalizeMcpOauthScopeString, MCP_TOKEN_SCOPE_VALUES, MCP_CLOUD_TOOL_SCOPE_REQUIREMENTS, MCP_WRITE_RATE_LIMIT_ENABLED, MCP_WRITE_RATE_LIMIT_ACTOR_MAX_REQUESTS, MCP_WRITE_RATE_LIMIT_WORKSPACE_MAX_REQUESTS, MCP_WRITE_RATE_LIMIT_WINDOW_MS, } = deps;
@@ -75,6 +79,26 @@ export function registerAdminRoutes(deps) {
75
79
  const workspaceAssetStore = typeof core.getDatabaseAdapter === 'function' && typeof core.getTenantId === 'function'
76
80
  ? new WorkspaceAssetStore(core.getDatabaseAdapter(), core.getTenantId())
77
81
  : null;
82
+ const isAiProfileAvatarStorageKey = (storageKey, workspaceId) => {
83
+ const normalized = String(storageKey || '').replace(/\\/g, '/');
84
+ return normalized.startsWith(`workspaces/${workspaceId}/assets/images/ai-profiles/`)
85
+ && normalized.includes('/avatar/');
86
+ };
87
+ const listReferencedAiProfileAvatarStorageKeys = (workspaceId) => {
88
+ const referenced = new Set();
89
+ const profiles = typeof core.listAiProfiles === 'function'
90
+ ? core.listAiProfiles(workspaceId, { includeArchived: true })
91
+ : [];
92
+ for (const profile of Array.isArray(profiles) ? profiles : []) {
93
+ for (const value of [profile?.avatarUrl, profile?.avatarSourceUrl]) {
94
+ const storageKey = normalizeDocumentPathInput(value);
95
+ if (!storageKey || !isAiProfileAvatarStorageKey(storageKey, workspaceId))
96
+ continue;
97
+ referenced.add(storageKey);
98
+ }
99
+ }
100
+ return referenced;
101
+ };
78
102
  // === SECTION: Email helpers ===
79
103
  const resolveEffectiveVirusScanSettings = () => {
80
104
  const settings = core.getGlobalSettings().objectStorage || {};
@@ -91,11 +115,15 @@ export function registerAdminRoutes(deps) {
91
115
  };
92
116
  // === SECTION: MCP helpers ===
93
117
  const MCP_CONNECTION_TEST_TIMEOUT_MS = 5000;
94
- const writeMcpHttpError = (res, statusCode, message) => {
118
+ const writeMcpHttpError = (res, statusCode, message, data) => {
95
119
  res.writeHead(statusCode, { 'Content-Type': 'application/json' });
96
120
  res.end(JSON.stringify({
97
121
  jsonrpc: '2.0',
98
- error: { code: -32000, message },
122
+ error: {
123
+ code: -32000,
124
+ message,
125
+ ...(data ? { data } : {}),
126
+ },
99
127
  id: null,
100
128
  }));
101
129
  };
@@ -390,6 +418,8 @@ export function registerAdminRoutes(deps) {
390
418
  authenticatedViaOAuth: oauthAuth || null,
391
419
  userId: null,
392
420
  ...bootstrap,
421
+ aiProfileToken: bootstrap.aiProfileToken || oauthAuth?.aiProfileToken || null,
422
+ aiProfileName: bootstrap.aiProfileName || oauthAuth?.aiProfileName || null,
393
423
  };
394
424
  }
395
425
  core.addMcpAuditLog({
@@ -502,6 +532,7 @@ export function registerAdminRoutes(deps) {
502
532
  return;
503
533
  }
504
534
  const authScopes = auth.authenticatedViaToken?.scopes || auth.authenticatedViaOAuth?.scopes || [];
535
+ const requestId = String(req.headers['x-request-id'] || req.headers['x-railway-request-id'] || '').trim() || randomUUID();
505
536
  const deniedToolName = findDeniedCloudMcpToolName(body, authScopes);
506
537
  if (deniedToolName) {
507
538
  core.addMcpAuditLog({
@@ -511,7 +542,7 @@ export function registerAdminRoutes(deps) {
511
542
  tokenId: auth.authenticatedViaToken?.tokenId || auth.authenticatedViaOAuth?.grantId || null,
512
543
  toolName: deniedToolName,
513
544
  details: {
514
- requestId: String(req.headers['x-request-id'] || req.headers['x-railway-request-id'] || '').trim() || randomUUID(),
545
+ requestId,
515
546
  ip: req.socket?.remoteAddress || null,
516
547
  userAgent: requestHeader(req, 'user-agent', '') || null,
517
548
  outcome: 'deny',
@@ -524,11 +555,13 @@ export function registerAdminRoutes(deps) {
524
555
  }
525
556
  if (!applyCloudMcpWriteRateLimit(req, res, auth, body))
526
557
  return;
558
+ let runtime = null;
527
559
  try {
528
- const runtime = createTaskforceMcpServer({
560
+ runtime = createTaskforceMcpServer({
529
561
  projectRoot: core.getPaths().projectRoot,
530
562
  tenantId: core.getTenantId(),
531
563
  workspaceId: auth.workspaceId,
564
+ core,
532
565
  serverName: 'taskforce-cloud',
533
566
  logStartup: false,
534
567
  runtimeMode: 'cloud',
@@ -536,7 +569,7 @@ export function registerAdminRoutes(deps) {
536
569
  req,
537
570
  auth,
538
571
  requestHeader,
539
- requestId: String(req.headers['x-request-id'] || req.headers['x-railway-request-id'] || '').trim() || randomUUID(),
572
+ requestId,
540
573
  authScopes,
541
574
  }),
542
575
  });
@@ -553,8 +586,27 @@ export function registerAdminRoutes(deps) {
553
586
  recordCloudMcpCredentialUsage(req, auth.authenticatedViaToken, auth.authenticatedViaOAuth);
554
587
  }
555
588
  catch (error) {
589
+ console.error('[Taskforce MCP] Cloud transport request failed:', {
590
+ requestId,
591
+ kind: 'tool_transport_failure',
592
+ message: error instanceof Error ? error.message : String(error),
593
+ });
556
594
  if (!res.headersSent) {
557
- writeMcpHttpError(res, 500, 'Internal server error.');
595
+ writeMcpHttpError(res, 500, 'MCP transport failure.', {
596
+ kind: 'tool_transport_failure',
597
+ retryable: true,
598
+ requestId,
599
+ });
600
+ }
601
+ }
602
+ finally {
603
+ if (runtime) {
604
+ try {
605
+ await runtime.server.close();
606
+ }
607
+ catch (closeError) {
608
+ console.warn('[Taskforce MCP] Cloud transport cleanup failed:', closeError);
609
+ }
558
610
  }
559
611
  }
560
612
  };
@@ -571,6 +623,18 @@ export function registerAdminRoutes(deps) {
571
623
  res.writeHead(200, { 'Content-Type': 'application/json' });
572
624
  res.end(JSON.stringify({ success: true, plans }));
573
625
  });
626
+ addRoute('GET', '/api/platform/onboarding-plan-options', async (req, res) => {
627
+ if (!ensureCloudPlanData(req, res))
628
+ return;
629
+ if (!ensureAdminRole(req)) {
630
+ res.writeHead(403, { 'Content-Type': 'application/json' });
631
+ res.end(JSON.stringify({ error: 'Forbidden: system admin role required.' }));
632
+ return;
633
+ }
634
+ const options = core.listOnboardingPlanOptions();
635
+ res.writeHead(200, { 'Content-Type': 'application/json' });
636
+ res.end(JSON.stringify({ success: true, options }));
637
+ });
574
638
  addRoute('POST', '/api/platform/plans', async (req, res) => {
575
639
  if (!ensureCloudPlanData(req, res))
576
640
  return;
@@ -580,10 +644,19 @@ export function registerAdminRoutes(deps) {
580
644
  return;
581
645
  }
582
646
  const body = await parseJsonBody(req);
647
+ const description = body?.description === undefined || body?.description === null
648
+ ? body?.description
649
+ : String(body.description);
650
+ if (typeof description === 'string' && description.trim().length > 240) {
651
+ res.writeHead(400, { 'Content-Type': 'application/json' });
652
+ res.end(JSON.stringify({ success: false, error: 'Plan description must be 240 characters or fewer.', code: 'PLAN_DESCRIPTION_TOO_LONG' }));
653
+ return;
654
+ }
583
655
  try {
584
656
  const plan = core.upsertPlanCatalog({
585
657
  planId: body?.planId,
586
658
  displayName: body?.displayName,
659
+ description,
587
660
  status: body?.status,
588
661
  initialMode: body?.initialMode,
589
662
  initialTrialDays: body?.initialTrialDays === undefined ? undefined : Number(body?.initialTrialDays),
@@ -639,6 +712,62 @@ export function registerAdminRoutes(deps) {
639
712
  res.end(JSON.stringify({ success: false, error: String(error?.message || 'Unable to list feature catalog'), code: error?.code }));
640
713
  }
641
714
  });
715
+ addRoute('PATCH', '/api/platform/features/:featureKey', async (req, res, params) => {
716
+ if (!ensureCloudPlanData(req, res))
717
+ return;
718
+ if (!ensureAdminRole(req)) {
719
+ res.writeHead(403, { 'Content-Type': 'application/json' });
720
+ res.end(JSON.stringify({ error: 'Forbidden: system admin role required.' }));
721
+ return;
722
+ }
723
+ const body = await parseJsonBody(req);
724
+ const featureKey = String(params.featureKey || '').trim();
725
+ const publicLabel = body?.publicLabel === undefined || body?.publicLabel === null
726
+ ? body?.publicLabel
727
+ : String(body.publicLabel);
728
+ const publicDescription = body?.publicDescription === undefined || body?.publicDescription === null
729
+ ? body?.publicDescription
730
+ : String(body.publicDescription);
731
+ const publicDisplayOrder = body?.publicDisplayOrder === undefined || body?.publicDisplayOrder === null || body?.publicDisplayOrder === ''
732
+ ? null
733
+ : Math.max(0, Math.floor(Number(body.publicDisplayOrder)));
734
+ if (typeof publicLabel === 'string' && publicLabel.trim().length > 120) {
735
+ res.writeHead(400, { 'Content-Type': 'application/json' });
736
+ res.end(JSON.stringify({ success: false, error: 'Public label must be 120 characters or fewer.', code: 'PLAN_FEATURE_PUBLIC_LABEL_TOO_LONG' }));
737
+ return;
738
+ }
739
+ if (typeof publicDescription === 'string' && publicDescription.trim().length > 280) {
740
+ res.writeHead(400, { 'Content-Type': 'application/json' });
741
+ res.end(JSON.stringify({ success: false, error: 'Public description must be 280 characters or fewer.', code: 'PLAN_FEATURE_PUBLIC_DESCRIPTION_TOO_LONG' }));
742
+ return;
743
+ }
744
+ if (publicDisplayOrder !== null && !Number.isFinite(publicDisplayOrder)) {
745
+ res.writeHead(400, { 'Content-Type': 'application/json' });
746
+ res.end(JSON.stringify({ success: false, error: 'Public display order must be a non-negative number.', code: 'PLAN_FEATURE_PUBLIC_DISPLAY_ORDER_INVALID' }));
747
+ return;
748
+ }
749
+ try {
750
+ const feature = core.updatePlanFeatureCatalogMarketingCopy({
751
+ featureKey,
752
+ publicLabel,
753
+ publicDescription,
754
+ publicDisplayOrder
755
+ });
756
+ auditAdminAction(req, 'platform-plan-feature-catalog-updated', {
757
+ featureKey,
758
+ publicLabel: feature.publicLabel ?? null,
759
+ publicDescription: feature.publicDescription ?? null,
760
+ publicDisplayOrder: feature.publicDisplayOrder ?? null
761
+ });
762
+ res.writeHead(200, { 'Content-Type': 'application/json' });
763
+ res.end(JSON.stringify({ success: true, feature }));
764
+ }
765
+ catch (error) {
766
+ const statusCode = resolveErrorStatusCode(error, 400);
767
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
768
+ res.end(JSON.stringify({ success: false, error: String(error?.message || 'Unable to update feature catalog entry'), code: error?.code }));
769
+ }
770
+ });
642
771
  addRoute('POST', '/api/platform/plans/:planId/versions', async (req, res, params) => {
643
772
  if (!ensureCloudPlanData(req, res))
644
773
  return;
@@ -855,9 +984,23 @@ export function registerAdminRoutes(deps) {
855
984
  res.end(JSON.stringify({ error: 'Forbidden: system admin role required.' }));
856
985
  return;
857
986
  }
858
- const users = core.listSystemUsers();
987
+ const reqUrl = new URL(req.url || '/api/taskforce/admin/system-users', 'http://localhost');
988
+ const query = String(reqUrl.searchParams.get('q') || '').trim();
989
+ const sort = reqUrl.searchParams.get('sort') === 'oldest' ? 'oldest' : 'newest';
990
+ const limitRaw = Number(reqUrl.searchParams.get('limit') || '50');
991
+ const offsetRaw = Number(reqUrl.searchParams.get('offset') || '0');
992
+ const limit = Number.isFinite(limitRaw) ? Math.max(1, Math.min(200, Math.floor(limitRaw))) : 50;
993
+ const offset = Number.isFinite(offsetRaw) ? Math.max(0, Math.floor(offsetRaw)) : 0;
994
+ const total = core.countSystemUsers({ query });
995
+ const users = core.listSystemUsers({ query, sort, limit, offset });
859
996
  res.writeHead(200, { 'Content-Type': 'application/json' });
860
- res.end(JSON.stringify({ users }));
997
+ res.end(JSON.stringify({
998
+ users,
999
+ total,
1000
+ limit,
1001
+ offset,
1002
+ hasMore: offset + users.length < total
1003
+ }));
861
1004
  });
862
1005
  // GET /api/taskforce/admin/audit-logs - Read recent admin audit events
863
1006
  addRoute('GET', '/api/taskforce/admin/audit-logs', async (req, res) => {
@@ -1136,8 +1279,10 @@ export function registerAdminRoutes(deps) {
1136
1279
  }
1137
1280
  const globalSettings = core.getGlobalSettings();
1138
1281
  const authSettings = globalSettings.auth || {};
1139
- const billingSettings = globalSettings.billing || {};
1282
+ const siteSettings = globalSettings.site || {};
1283
+ const onboardingPolicy = core.getOnboardingPolicy();
1140
1284
  const effective = buildAuthBehavior(core);
1285
+ const effectiveSite = buildSiteBehavior(core);
1141
1286
  res.writeHead(200, { 'Content-Type': 'application/json' });
1142
1287
  res.end(JSON.stringify({
1143
1288
  settings: {
@@ -1147,14 +1292,14 @@ export function registerAdminRoutes(deps) {
1147
1292
  ...(typeof authSettings.authRateLimitEnabled === 'boolean' ? { authRateLimitEnabled: authSettings.authRateLimitEnabled } : {}),
1148
1293
  ...(typeof authSettings.authRateLimitMaxRequests === 'number' ? { authRateLimitMaxRequests: authSettings.authRateLimitMaxRequests } : {}),
1149
1294
  ...(typeof authSettings.authRateLimitWindowMs === 'number' ? { authRateLimitWindowMs: authSettings.authRateLimitWindowMs } : {}),
1150
- ...((billingSettings.onboardingPolicy?.mode === 'require_plan_selection'
1151
- || billingSettings.onboardingPolicy?.mode === 'auto_grant_free'
1152
- || billingSettings.onboardingPolicy?.mode === 'auto_start_trial')
1153
- ? { onboardingPolicyMode: billingSettings.onboardingPolicy.mode }
1154
- : {}),
1155
- ...(typeof billingSettings.onboardingPolicy?.planVersionId === 'string' || billingSettings.onboardingPolicy?.planVersionId === null
1156
- ? { onboardingPlanVersionId: billingSettings.onboardingPolicy?.planVersionId ?? null }
1157
- : {})
1295
+ ...(typeof siteSettings.showRunTaskforceLocally === 'boolean' ? { showRunTaskforceLocally: siteSettings.showRunTaskforceLocally } : {}),
1296
+ ...(typeof siteSettings.pricingPageEnabled === 'boolean' ? { pricingPageEnabled: siteSettings.pricingPageEnabled } : {}),
1297
+ ...(typeof siteSettings.animatedBackgroundEnabled === 'boolean' ? { animatedBackgroundEnabled: siteSettings.animatedBackgroundEnabled } : {}),
1298
+ ...(siteSettings.siteTheme === 'light' || siteSettings.siteTheme === 'dark' ? { siteTheme: siteSettings.siteTheme } : {}),
1299
+ ...(typeof siteSettings.pricingPageTitle === 'string' ? { pricingPageTitle: siteSettings.pricingPageTitle } : {}),
1300
+ ...(typeof siteSettings.pricingPageDescription === 'string' ? { pricingPageDescription: siteSettings.pricingPageDescription } : {}),
1301
+ onboardingPolicyMode: onboardingPolicy.mode,
1302
+ onboardingPlanId: onboardingPolicy.planId
1158
1303
  },
1159
1304
  status: {
1160
1305
  allowSelfRegistration: effective.allowSelfRegistration,
@@ -1163,8 +1308,14 @@ export function registerAdminRoutes(deps) {
1163
1308
  authRateLimitEnabled: effective.authRateLimitEnabled,
1164
1309
  authRateLimitMaxRequests: effective.authRateLimitMaxRequests,
1165
1310
  authRateLimitWindowMs: effective.authRateLimitWindowMs,
1311
+ showRunTaskforceLocally: effectiveSite.showRunTaskforceLocally,
1312
+ pricingPageEnabled: effectiveSite.pricingPageEnabled,
1313
+ animatedBackgroundEnabled: effectiveSite.animatedBackgroundEnabled,
1314
+ siteTheme: effectiveSite.siteTheme,
1315
+ pricingPageTitle: effectiveSite.pricingPageTitle,
1316
+ pricingPageDescription: effectiveSite.pricingPageDescription,
1166
1317
  onboardingPolicyMode: effective.onboardingPolicyMode,
1167
- onboardingPlanVersionId: effective.onboardingPlanVersionId
1318
+ onboardingPlanId: effective.onboardingPlanId
1168
1319
  }
1169
1320
  }));
1170
1321
  });
@@ -1184,11 +1335,27 @@ export function registerAdminRoutes(deps) {
1184
1335
  : {}),
1185
1336
  ...(typeof siteSettings.pricingPageEnabled === 'boolean'
1186
1337
  ? { pricingPageEnabled: siteSettings.pricingPageEnabled }
1338
+ : {}),
1339
+ ...(typeof siteSettings.animatedBackgroundEnabled === 'boolean'
1340
+ ? { animatedBackgroundEnabled: siteSettings.animatedBackgroundEnabled }
1341
+ : {}),
1342
+ ...(siteSettings.siteTheme === 'light' || siteSettings.siteTheme === 'dark'
1343
+ ? { siteTheme: siteSettings.siteTheme }
1344
+ : {}),
1345
+ ...(typeof siteSettings.pricingPageTitle === 'string'
1346
+ ? { pricingPageTitle: siteSettings.pricingPageTitle }
1347
+ : {}),
1348
+ ...(typeof siteSettings.pricingPageDescription === 'string'
1349
+ ? { pricingPageDescription: siteSettings.pricingPageDescription }
1187
1350
  : {})
1188
1351
  },
1189
1352
  status: {
1190
1353
  showRunTaskforceLocally: siteBehavior.showRunTaskforceLocally,
1191
- pricingPageEnabled: siteBehavior.pricingPageEnabled
1354
+ pricingPageEnabled: siteBehavior.pricingPageEnabled,
1355
+ animatedBackgroundEnabled: siteBehavior.animatedBackgroundEnabled,
1356
+ siteTheme: siteBehavior.siteTheme,
1357
+ pricingPageTitle: siteBehavior.pricingPageTitle,
1358
+ pricingPageDescription: siteBehavior.pricingPageDescription
1192
1359
  }
1193
1360
  }));
1194
1361
  };
@@ -1359,9 +1526,11 @@ export function registerAdminRoutes(deps) {
1359
1526
  }
1360
1527
  const reqUrl = new URL(req.url || '/api/taskforce/admin/orphaned-assets', 'http://localhost');
1361
1528
  const workspaceId = String(reqUrl.searchParams.get('workspaceId') || requestWorkspaceId(req) || '').trim();
1529
+ const aiProfileAvatarStorageKeys = listReferencedAiProfileAvatarStorageKeys(workspaceId);
1362
1530
  const assets = workspaceAssetStore.listAllByWorkspace(workspaceId, {
1363
1531
  includeDeleted: false
1364
- }).filter((asset) => workspaceAssetStore.listLinksForAsset(asset.assetId, workspaceId).every((link) => !!link.deletedAt))
1532
+ }).filter((asset) => (!aiProfileAvatarStorageKeys.has(asset.storageKey)
1533
+ && workspaceAssetStore.listLinksForAsset(asset.assetId, workspaceId).every((link) => !!link.deletedAt)))
1365
1534
  .map((asset) => ({
1366
1535
  assetId: asset.assetId,
1367
1536
  workspaceId: asset.workspaceId,
@@ -1440,6 +1609,11 @@ export function registerAdminRoutes(deps) {
1440
1609
  res.end(JSON.stringify({ error: 'Asset not found.' }));
1441
1610
  return;
1442
1611
  }
1612
+ if (listReferencedAiProfileAvatarStorageKeys(workspaceId).has(asset.storageKey)) {
1613
+ res.writeHead(409, { 'Content-Type': 'application/json' });
1614
+ res.end(JSON.stringify({ error: 'Asset is still referenced by an AI profile avatar.' }));
1615
+ return;
1616
+ }
1443
1617
  const objectStorageClient = getObjectStorageClient();
1444
1618
  const { basePath } = core.getPaths();
1445
1619
  try {
@@ -1471,7 +1645,8 @@ export function registerAdminRoutes(deps) {
1471
1645
  workspaceAssetStore.deleteLink({
1472
1646
  workspaceId,
1473
1647
  assetId,
1474
- taskId: link.taskId,
1648
+ targetType: link.targetType,
1649
+ targetId: link.targetId,
1475
1650
  role: link.role
1476
1651
  });
1477
1652
  }
@@ -1796,20 +1971,59 @@ export function registerAdminRoutes(deps) {
1796
1971
  : body?.onboardingPolicyMode === 'require_plan_selection'
1797
1972
  ? 'require_plan_selection'
1798
1973
  : currentOnboardingPolicy.mode;
1799
- const onboardingPlanVersionId = typeof body?.onboardingPlanVersionId === 'string'
1800
- ? body.onboardingPlanVersionId.trim() || null
1801
- : body?.onboardingPlanVersionId === null
1974
+ const onboardingPlanId = typeof body?.onboardingPlanId === 'string'
1975
+ ? body.onboardingPlanId.trim().toLowerCase() || null
1976
+ : body?.onboardingPlanId === null
1802
1977
  ? null
1803
- : currentOnboardingPolicy.planVersionId;
1978
+ : currentOnboardingPolicy.planId;
1979
+ const pricingPageTitle = typeof body?.pricingPageTitle === 'string'
1980
+ ? body.pricingPageTitle.trim()
1981
+ : undefined;
1982
+ const pricingPageDescription = typeof body?.pricingPageDescription === 'string'
1983
+ ? body.pricingPageDescription.trim()
1984
+ : undefined;
1985
+ const siteTheme = body?.siteTheme === 'light' || body?.siteTheme === 'dark'
1986
+ ? body.siteTheme
1987
+ : undefined;
1988
+ if (pricingPageTitle !== undefined && pricingPageTitle.length > 120) {
1989
+ res.writeHead(400, { 'Content-Type': 'application/json' });
1990
+ res.end(JSON.stringify({ error: 'Pricing page title must be 120 characters or fewer.', code: 'PRICING_PAGE_TITLE_TOO_LONG' }));
1991
+ return;
1992
+ }
1993
+ if (pricingPageDescription !== undefined && pricingPageDescription.length > 280) {
1994
+ res.writeHead(400, { 'Content-Type': 'application/json' });
1995
+ res.end(JSON.stringify({ error: 'Pricing page description must be 280 characters or fewer.', code: 'PRICING_PAGE_DESCRIPTION_TOO_LONG' }));
1996
+ return;
1997
+ }
1804
1998
  const validation = core.validateOnboardingPolicy({
1805
1999
  mode: onboardingPolicyMode,
1806
- planVersionId: onboardingPlanVersionId
2000
+ planId: onboardingPlanId
1807
2001
  });
1808
2002
  if (!validation.valid) {
1809
2003
  res.writeHead(400, { 'Content-Type': 'application/json' });
1810
2004
  res.end(JSON.stringify({ error: validation.message || 'Invalid onboarding policy.', code: validation.code, details: validation.details }));
1811
2005
  return;
1812
2006
  }
2007
+ const siteSettingsUpdate = {
2008
+ ...(typeof body?.showRunTaskforceLocally === 'boolean'
2009
+ ? { showRunTaskforceLocally: body.showRunTaskforceLocally }
2010
+ : {}),
2011
+ ...(typeof body?.pricingPageEnabled === 'boolean'
2012
+ ? { pricingPageEnabled: body.pricingPageEnabled }
2013
+ : {}),
2014
+ ...(typeof body?.animatedBackgroundEnabled === 'boolean'
2015
+ ? { animatedBackgroundEnabled: body.animatedBackgroundEnabled }
2016
+ : {}),
2017
+ ...(siteTheme !== undefined
2018
+ ? { siteTheme }
2019
+ : {}),
2020
+ ...(pricingPageTitle !== undefined
2021
+ ? { pricingPageTitle }
2022
+ : {}),
2023
+ ...(pricingPageDescription !== undefined
2024
+ ? { pricingPageDescription }
2025
+ : {})
2026
+ };
1813
2027
  core.updateGlobalSettings({
1814
2028
  auth: {
1815
2029
  ...(typeof body?.allowSelfRegistration === 'boolean' ? { allowSelfRegistration: body.allowSelfRegistration } : {}),
@@ -1824,9 +2038,12 @@ export function registerAdminRoutes(deps) {
1824
2038
  billing: {
1825
2039
  onboardingPolicy: {
1826
2040
  mode: onboardingPolicyMode,
1827
- planVersionId: onboardingPlanVersionId ?? null
2041
+ planId: onboardingPlanId ?? null
1828
2042
  }
1829
- }
2043
+ },
2044
+ ...(Object.keys(siteSettingsUpdate).length > 0
2045
+ ? { site: siteSettingsUpdate }
2046
+ : {})
1830
2047
  });
1831
2048
  res.writeHead(200, { 'Content-Type': 'application/json' });
1832
2049
  res.end(JSON.stringify({ success: true }));
@@ -1838,6 +2055,25 @@ export function registerAdminRoutes(deps) {
1838
2055
  return;
1839
2056
  }
1840
2057
  const body = await parseJsonBody(req);
2058
+ const pricingPageTitle = typeof body?.pricingPageTitle === 'string'
2059
+ ? body.pricingPageTitle.trim()
2060
+ : undefined;
2061
+ const pricingPageDescription = typeof body?.pricingPageDescription === 'string'
2062
+ ? body.pricingPageDescription.trim()
2063
+ : undefined;
2064
+ const siteTheme = body?.siteTheme === 'light' || body?.siteTheme === 'dark'
2065
+ ? body.siteTheme
2066
+ : undefined;
2067
+ if (pricingPageTitle !== undefined && pricingPageTitle.length > 120) {
2068
+ res.writeHead(400, { 'Content-Type': 'application/json' });
2069
+ res.end(JSON.stringify({ error: 'Pricing page title must be 120 characters or fewer.', code: 'PRICING_PAGE_TITLE_TOO_LONG' }));
2070
+ return;
2071
+ }
2072
+ if (pricingPageDescription !== undefined && pricingPageDescription.length > 280) {
2073
+ res.writeHead(400, { 'Content-Type': 'application/json' });
2074
+ res.end(JSON.stringify({ error: 'Pricing page description must be 280 characters or fewer.', code: 'PRICING_PAGE_DESCRIPTION_TOO_LONG' }));
2075
+ return;
2076
+ }
1841
2077
  core.updateGlobalSettings({
1842
2078
  site: {
1843
2079
  ...(typeof body?.showRunTaskforceLocally === 'boolean'
@@ -1845,6 +2081,18 @@ export function registerAdminRoutes(deps) {
1845
2081
  : {}),
1846
2082
  ...(typeof body?.pricingPageEnabled === 'boolean'
1847
2083
  ? { pricingPageEnabled: body.pricingPageEnabled }
2084
+ : {}),
2085
+ ...(typeof body?.animatedBackgroundEnabled === 'boolean'
2086
+ ? { animatedBackgroundEnabled: body.animatedBackgroundEnabled }
2087
+ : {}),
2088
+ ...(siteTheme !== undefined
2089
+ ? { siteTheme }
2090
+ : {}),
2091
+ ...(pricingPageTitle !== undefined
2092
+ ? { pricingPageTitle }
2093
+ : {}),
2094
+ ...(pricingPageDescription !== undefined
2095
+ ? { pricingPageDescription }
1848
2096
  : {})
1849
2097
  }
1850
2098
  });
@@ -1914,6 +2162,169 @@ export function registerAdminRoutes(deps) {
1914
2162
  res.writeHead(200, { 'Content-Type': 'application/json' });
1915
2163
  res.end(JSON.stringify({ success: true, provider: result.provider, messageId: result.messageId || null }));
1916
2164
  });
2165
+ // === SECTION: Admin auth provider settings ===
2166
+ // GET /api/taskforce/admin/auth-provider-settings - Read OAuth provider config (secrets masked)
2167
+ addRoute('GET', '/api/taskforce/admin/auth-provider-settings', async (req, res) => {
2168
+ if (!ensureAdminRole(req)) {
2169
+ res.writeHead(403, { 'Content-Type': 'application/json' });
2170
+ res.end(JSON.stringify({ error: 'Forbidden: admin role required.' }));
2171
+ return;
2172
+ }
2173
+ if (context.authConfig?.runtimeMode !== 'cloud') {
2174
+ res.writeHead(200, { 'Content-Type': 'application/json' });
2175
+ res.end(JSON.stringify({
2176
+ status: {
2177
+ google: { enabled: false, clientId: '', hasClientSecret: false, ready: false },
2178
+ github: { enabled: false, clientId: '', hasClientSecret: false, ready: false },
2179
+ apple: { enabled: false, servicesId: '', teamId: '', keyId: '', hasPrivateKeyPem: false, ready: false }
2180
+ }
2181
+ }));
2182
+ return;
2183
+ }
2184
+ const providers = core.getGlobalSettings().oauthProviders || {};
2185
+ const g = providers.google || {};
2186
+ const gh = providers.github || {};
2187
+ const ap = providers.apple || {};
2188
+ res.writeHead(200, { 'Content-Type': 'application/json' });
2189
+ res.end(JSON.stringify({
2190
+ status: {
2191
+ google: {
2192
+ enabled: g.enabled === true,
2193
+ clientId: String(g.clientId || ''),
2194
+ hasClientSecret: typeof g.clientSecret === 'string' && g.clientSecret.trim().length > 0,
2195
+ ready: g.enabled === true && Boolean(g.clientId) && typeof g.clientSecret === 'string' && g.clientSecret.trim().length > 0
2196
+ },
2197
+ github: {
2198
+ enabled: gh.enabled === true,
2199
+ clientId: String(gh.clientId || ''),
2200
+ hasClientSecret: typeof gh.clientSecret === 'string' && gh.clientSecret.trim().length > 0,
2201
+ ready: gh.enabled === true && Boolean(gh.clientId) && typeof gh.clientSecret === 'string' && gh.clientSecret.trim().length > 0
2202
+ },
2203
+ apple: {
2204
+ enabled: ap.enabled === true,
2205
+ servicesId: String(ap.servicesId || ''),
2206
+ teamId: String(ap.teamId || ''),
2207
+ keyId: String(ap.keyId || ''),
2208
+ hasPrivateKeyPem: typeof ap.privateKeyPem === 'string' && ap.privateKeyPem.trim().length > 0,
2209
+ ready: ap.enabled === true && Boolean(ap.servicesId) && Boolean(ap.teamId) && Boolean(ap.keyId)
2210
+ && typeof ap.privateKeyPem === 'string' && ap.privateKeyPem.trim().length > 0
2211
+ }
2212
+ }
2213
+ }));
2214
+ });
2215
+ // GET /api/taskforce/admin/auth-provider-settings/health - Per-provider readiness check
2216
+ addRoute('GET', '/api/taskforce/admin/auth-provider-settings/health', async (req, res) => {
2217
+ if (!ensureAdminRole(req)) {
2218
+ res.writeHead(403, { 'Content-Type': 'application/json' });
2219
+ res.end(JSON.stringify({ error: 'Forbidden: admin role required.' }));
2220
+ return;
2221
+ }
2222
+ const providers = core.getGlobalSettings().oauthProviders || {};
2223
+ const g = providers.google || {};
2224
+ const gh = providers.github || {};
2225
+ const ap = providers.apple || {};
2226
+ const googleReady = g.enabled === true && Boolean(g.clientId) && typeof g.clientSecret === 'string' && g.clientSecret.trim().length > 0;
2227
+ const googleReason = !g.enabled
2228
+ ? 'Provider disabled.'
2229
+ : !g.clientId ? 'Missing Client ID.'
2230
+ : !googleReady ? 'Missing Client Secret.'
2231
+ : null;
2232
+ const githubReady = gh.enabled === true && Boolean(gh.clientId) && typeof gh.clientSecret === 'string' && gh.clientSecret.trim().length > 0;
2233
+ const githubReason = !gh.enabled
2234
+ ? 'Provider disabled.'
2235
+ : !gh.clientId ? 'Missing Client ID.'
2236
+ : !githubReady ? 'Missing Client Secret.'
2237
+ : null;
2238
+ const appleBaseReady = ap.enabled === true && Boolean(ap.servicesId) && Boolean(ap.teamId) && Boolean(ap.keyId)
2239
+ && typeof ap.privateKeyPem === 'string' && ap.privateKeyPem.trim().length > 0;
2240
+ let appleSecretMintOk;
2241
+ let appleReason = null;
2242
+ if (!ap.enabled) {
2243
+ appleReason = 'Provider disabled.';
2244
+ }
2245
+ else if (!ap.servicesId || !ap.teamId || !ap.keyId) {
2246
+ appleReason = 'Missing Services ID, Team ID, or Key ID.';
2247
+ }
2248
+ else if (!appleBaseReady) {
2249
+ appleReason = 'Missing private key PEM.';
2250
+ }
2251
+ else {
2252
+ // Attempt a test-mint to verify the key is valid
2253
+ const mintResult = testMintAppleClientSecret({
2254
+ teamId: ap.teamId,
2255
+ servicesId: ap.servicesId,
2256
+ keyId: ap.keyId,
2257
+ privateKeyPem: ap.privateKeyPem
2258
+ });
2259
+ appleSecretMintOk = mintResult.ok;
2260
+ if (!mintResult.ok) {
2261
+ appleReason = `Client-secret JWT mint failed: ${mintResult.error}`;
2262
+ }
2263
+ }
2264
+ res.writeHead(200, { 'Content-Type': 'application/json' });
2265
+ res.end(JSON.stringify({
2266
+ success: true,
2267
+ health: {
2268
+ google: { enabled: g.enabled === true, ready: googleReady, reason: googleReason },
2269
+ github: { enabled: gh.enabled === true, ready: githubReady, reason: githubReason },
2270
+ apple: {
2271
+ enabled: ap.enabled === true,
2272
+ ready: appleBaseReady && appleSecretMintOk !== false,
2273
+ reason: appleReason,
2274
+ ...(typeof appleSecretMintOk === 'boolean' ? { secretMintOk: appleSecretMintOk } : {})
2275
+ }
2276
+ }
2277
+ }));
2278
+ });
2279
+ // POST /api/taskforce/admin/auth-provider-settings - Save OAuth provider config (including secrets)
2280
+ addRoute('POST', '/api/taskforce/admin/auth-provider-settings', async (req, res) => {
2281
+ if (!ensureAdminRole(req)) {
2282
+ res.writeHead(403, { 'Content-Type': 'application/json' });
2283
+ res.end(JSON.stringify({ error: 'Forbidden: admin role required.' }));
2284
+ return;
2285
+ }
2286
+ if (!requireCloudRuntime(res, 'Auth provider settings'))
2287
+ return;
2288
+ const body = await parseJsonBody(req);
2289
+ const update = {};
2290
+ if (body?.google && typeof body.google === 'object') {
2291
+ const g = body.google;
2292
+ update.google = {
2293
+ ...(typeof g.enabled === 'boolean' ? { enabled: g.enabled } : {}),
2294
+ ...(typeof g.clientId === 'string' ? { clientId: g.clientId } : {}),
2295
+ ...(typeof g.clientSecret === 'string' ? { clientSecret: g.clientSecret } : {})
2296
+ };
2297
+ }
2298
+ if (body?.github && typeof body.github === 'object') {
2299
+ const gh = body.github;
2300
+ update.github = {
2301
+ ...(typeof gh.enabled === 'boolean' ? { enabled: gh.enabled } : {}),
2302
+ ...(typeof gh.clientId === 'string' ? { clientId: gh.clientId } : {}),
2303
+ ...(typeof gh.clientSecret === 'string' ? { clientSecret: gh.clientSecret } : {})
2304
+ };
2305
+ }
2306
+ if (body?.apple && typeof body.apple === 'object') {
2307
+ const ap = body.apple;
2308
+ update.apple = {
2309
+ ...(typeof ap.enabled === 'boolean' ? { enabled: ap.enabled } : {}),
2310
+ ...(typeof ap.servicesId === 'string' ? { servicesId: ap.servicesId } : {}),
2311
+ ...(typeof ap.teamId === 'string' ? { teamId: ap.teamId } : {}),
2312
+ ...(typeof ap.keyId === 'string' ? { keyId: ap.keyId } : {}),
2313
+ ...(typeof ap.privateKeyPem === 'string' ? { privateKeyPem: ap.privateKeyPem } : {})
2314
+ };
2315
+ }
2316
+ if (Object.keys(update).length === 0) {
2317
+ res.writeHead(400, { 'Content-Type': 'application/json' });
2318
+ res.end(JSON.stringify({ error: 'No provider settings provided.' }));
2319
+ return;
2320
+ }
2321
+ core.updateGlobalSettings({ oauthProviders: update });
2322
+ auditAdminAction(req, 'auth-provider-settings.update', {
2323
+ providers: Object.keys(update)
2324
+ });
2325
+ res.writeHead(200, { 'Content-Type': 'application/json' });
2326
+ res.end(JSON.stringify({ success: true }));
2327
+ });
1917
2328
  // === SECTION: Cloud MCP HTTP transport ===
1918
2329
  addRoute('POST', '/mcp', async (req, res) => { await handleCloudMcpRequest(req, res); });
1919
2330
  addRoute('POST', '/mcp/', async (req, res) => { await handleCloudMcpRequest(req, res); });
@@ -2256,6 +2667,26 @@ export function registerAdminRoutes(deps) {
2256
2667
  res.end(JSON.stringify({ success: false, error: error.message, code: error?.code || 'MCP_TOKEN_REVOKE_FAILED' }));
2257
2668
  }
2258
2669
  });
2670
+ addRoute('DELETE', '/api/taskforce/settings/mcp/tokens/:id', async (req, res, params) => {
2671
+ if (!ensureAppAccess(req, res))
2672
+ return;
2673
+ const userId = resolveAuthenticatedUserId(req);
2674
+ if (!userId || userId === 'anonymous') {
2675
+ res.writeHead(401, { 'Content-Type': 'application/json' });
2676
+ res.end(JSON.stringify({ success: false, error: 'Authentication required.' }));
2677
+ return;
2678
+ }
2679
+ try {
2680
+ const deleted = core.deleteMcpAccessToken({ actorUserId: userId, workspaceId: requestWorkspaceId(req), tokenId: params.id });
2681
+ res.writeHead(200, { 'Content-Type': 'application/json' });
2682
+ res.end(JSON.stringify({ success: true, deleted }));
2683
+ }
2684
+ catch (error) {
2685
+ const statusCode = resolveErrorStatusCode(error);
2686
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
2687
+ res.end(JSON.stringify({ success: false, error: error.message, code: error?.code || 'MCP_TOKEN_DELETE_FAILED' }));
2688
+ }
2689
+ });
2259
2690
  addRoute('POST', '/api/taskforce/settings/mcp/tokens/:id/regenerate', async (req, res, params) => {
2260
2691
  if (!ensureAppAccess(req, res))
2261
2692
  return;