@taskforcehq/taskforce 0.3.170 → 0.3.301

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 (698) hide show
  1. package/README.md +71 -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 +2227 -1188
  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 +68 -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 +47 -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 +243 -0
  269. package/dist/hooks/useTaskData.test.d.ts +1 -0
  270. package/dist/hooks/useTaskData.test.js +180 -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 +3299 -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-Bdq3T1Ts.js +1 -0
  489. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BaS2VwIr.css +1 -0
  490. package/dist/ui/assets/AnnotatedAttachmentWorkspace-jKUVo-PJ.js +3 -0
  491. package/dist/ui/assets/DocumentWorkspace-C_8T8oz-.css +1 -0
  492. package/dist/ui/assets/DocumentWorkspace-DuQa-uIC.js +250 -0
  493. package/dist/ui/assets/InitiativesModule-C8Pi2VTk.js +1 -0
  494. package/dist/ui/assets/PlansPage-B6BDECSi.js +1 -0
  495. package/dist/ui/assets/PlansPage-BlVC_lRq.css +1 -0
  496. package/dist/ui/assets/TaskSettings-BwB9NtmJ.css +1 -0
  497. package/dist/ui/assets/TaskSettings-DUJgRTPU.js +8 -0
  498. package/dist/ui/assets/WorkflowsModule-b6TLuHwJ.js +5 -0
  499. package/dist/ui/assets/index-BiiF1cLQ.css +1 -0
  500. package/dist/ui/assets/index-xBWLPOEb.js +6 -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 +30 -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/deploy-prod.sh +41 -0
  610. package/scripts/deploy-staging.sh +23 -0
  611. package/scripts/migrate-planning-model.ts +233 -0
  612. package/scripts/migrate-task-data-assets.mjs +408 -0
  613. package/scripts/playwright-auth.sh +11 -0
  614. package/scripts/run-dev-proxy.sh +2 -0
  615. package/scripts/update-homebrew-formula.sh +2 -2
  616. package/scripts/with-esbuild.sh +11 -0
  617. package/src/resources/templates/WORKFLOW_V2_POLICY.md +1 -1
  618. package/src/resources/templates/workflow-sources/workflowDocs.mjs +62 -52
  619. package/src/resources/templates/workflows/collaborate.yaml +11 -5
  620. package/src/resources/templates/workflows/do.yaml +8 -2
  621. package/src/resources/templates/workflows/evaluate.yaml +13 -7
  622. package/src/resources/templates/workflows/execute.yaml +40 -23
  623. package/src/resources/templates/workflows/plan.yaml +15 -8
  624. package/src/resources/templates/workflows/review.yaml +14 -8
  625. package/dist/TaskforceScreenshot.d.ts +0 -11
  626. package/dist/TaskforceScreenshot.js +0 -113
  627. package/dist/compat/priorityCompat.d.ts +0 -2
  628. package/dist/compat/priorityCompat.js +0 -24
  629. package/dist/components/features/settings/TaxonomyManager 2.d.ts +0 -52
  630. package/dist/components/features/settings/TaxonomyManager 2.js +0 -75
  631. package/dist/components/task/TaskKanban 2.d.ts +0 -76
  632. package/dist/components/task/TaskKanban 2.js +0 -1004
  633. package/dist/components/task/TaskScreenshotSection.d.ts +0 -15
  634. package/dist/components/task/TaskScreenshotSection.js +0 -22
  635. package/dist/components/views/StandaloneLayout 2.d.ts +0 -8
  636. package/dist/components/views/StandaloneLayout 2.js +0 -1660
  637. package/dist/core/InitiativeTemplates.test.js +0 -50
  638. package/dist/core/ParentLifecycle.test.js +0 -98
  639. package/dist/migrations/clientMigrations.d.ts +0 -9
  640. package/dist/migrations/clientMigrations.js +0 -74
  641. package/dist/migrations/flags.d.ts +0 -6
  642. package/dist/migrations/flags.js +0 -8
  643. package/dist/migrations/taskMigrations.d.ts +0 -71
  644. package/dist/migrations/taskMigrations.js +0 -236
  645. package/dist/migrations/taskMigrations.test.js +0 -34
  646. package/dist/server/routes.billing.js +0 -991
  647. package/dist/server/routes.billing.test.js +0 -387
  648. package/dist/server/routes.sync.integration.test.js +0 -470
  649. package/dist/server/routes.sync.js +0 -1141
  650. package/dist/soak/syncSoakHarness.d.ts +0 -6
  651. package/dist/soak/syncSoakHarness.js +0 -10
  652. package/dist/ui/assets/index-0W5vyCpn.css +0 -1
  653. package/dist/ui/assets/index-MCZuNNfn.js +0 -23
  654. package/dist/ui/assets/logo_white_01-0Vx-iIIv.png +0 -0
  655. package/dist/ui/assets/vendor-dnd-BI1K77C1.js +0 -5
  656. package/dist/ui/assets/vendor-react-DdIDsh7f.js +0 -9
  657. package/dist/ui/assets/vendor-router-BtiNU7Dl.js +0 -3
  658. package/dist/utils/taskHierarchy.d.ts +0 -4
  659. package/dist/utils/taskHierarchy.js +0 -69
  660. package/dist/utils/taskHierarchy.test.js +0 -38
  661. package/dist/utils/taskParenting.d.ts +0 -3
  662. package/dist/utils/taskParenting.js +0 -24
  663. package/dist/utils/taskParenting.test.js +0 -21
  664. package/dist/utils/taskRelations.d.ts +0 -6
  665. package/dist/utils/taskRelations.js +0 -24
  666. package/dist/utils/taskRelations.test.js +0 -34
  667. package/scripts/check-compat-boundaries.js +0 -48
  668. /package/dist/{__tests__/planParser.test.d.ts → TaskforceCore.filter-persistence.test.d.ts} +0 -0
  669. /package/dist/{__tests__/releaseVersion.test.d.ts → TaskforceCore.routing.test.d.ts} +0 -0
  670. /package/dist/{__tests__/structuredCommentValidation.test.d.ts → annotatedAttachments/AnnotatedAttachmentSessionStore.test.d.ts} +0 -0
  671. /package/dist/{__tests__/structuredDocValidation.test.d.ts → annotatedAttachments/payload.test.d.ts} +0 -0
  672. /package/dist/{__tests__/templateEngine.test.d.ts → annotatedAttachments/types.js} +0 -0
  673. /package/dist/{__tests__/templates.test.d.ts → compat/workspaceSyncCompat.test.d.ts} +0 -0
  674. /package/dist/{__tests__/workflowDocumentFixtures.test.d.ts → components/features/AgentsModule.test.d.ts} +0 -0
  675. /package/dist/{__tests__/workflowExportMatrix.test.d.ts → components/features/AnnotatedAttachmentWorkspace.test.d.ts} +0 -0
  676. /package/dist/{__tests__/workflowExportSnapshots.test.d.ts → components/features/DocumentWorkspace.test.d.ts} +0 -0
  677. /package/dist/{__tests__/workflowGeneration.test.d.ts → components/features/settings/TaxonomyLibraryManager.test.d.ts} +0 -0
  678. /package/dist/{__tests__/workflowV2Policy.test.d.ts → components/task/TaskActionHeader.test.d.ts} +0 -0
  679. /package/dist/{core/InitiativeTemplates.test.d.ts → components/task/TaskKanban.planning-drop.test.d.ts} +0 -0
  680. /package/dist/{core/ParentLifecycle.test.d.ts → components/task/TaskStatusActions.test.d.ts} +0 -0
  681. /package/dist/{migrations/taskMigrations.test.d.ts → components/ui/TopNoticeLayer.test.d.ts} +0 -0
  682. /package/dist/{server/routes.billing.test.d.ts → components/views/AppShellHeader.test.d.ts} +0 -0
  683. /package/dist/{server/routes.sync.integration.test.d.ts → components/views/PlanComparisonPage.test.d.ts} +0 -0
  684. /package/dist/{utils/taskHierarchy.test.d.ts → components/views/chrome/WorkspaceChromeSections.test.d.ts} +0 -0
  685. /package/dist/{utils/taskParenting.test.d.ts → components/views/chrome/workspaceChrome.test.d.ts} +0 -0
  686. /package/dist/{utils/taskRelations.test.d.ts → components/views/panels/DocumentFilterToolbar.test.d.ts} +0 -0
  687. /package/dist/public/{android-chrome-192x192.png → archive/phoenix/android-chrome-192x192.png} +0 -0
  688. /package/dist/public/{android-chrome-512x512.png → archive/phoenix/android-chrome-512x512.png} +0 -0
  689. /package/dist/public/{favicon-16x16.png → archive/phoenix/favicon-16x16.png} +0 -0
  690. /package/dist/public/{favicon-32x32.png → archive/phoenix/favicon-32x32.png} +0 -0
  691. /package/dist/public/{favicon.png → archive/phoenix/favicon.png} +0 -0
  692. /package/dist/{__tests__ → services}/workflowExportSnapshots.test.js +0 -0
  693. /package/dist/{__tests__ → services}/workflowGeneration.test.js +0 -0
  694. /package/dist/ui/favicon/{android-chrome-192x192.png → archive/phoenix/android-chrome-192x192.png} +0 -0
  695. /package/dist/ui/favicon/{android-chrome-512x512.png → archive/phoenix/android-chrome-512x512.png} +0 -0
  696. /package/dist/ui/favicon/{favicon-16x16.png → archive/phoenix/favicon-16x16.png} +0 -0
  697. /package/dist/ui/favicon/{favicon-32x32.png → archive/phoenix/favicon-32x32.png} +0 -0
  698. /package/dist/ui/favicon/{favicon.png → archive/phoenix/favicon.png} +0 -0
@@ -1,12 +1,21 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useEffect, useState } from 'react';
3
- import { Sun, Moon, Sparkles, FolderOpen, Keyboard, FileText, Users, Check, AlertTriangle, Loader2, Settings, Layers, Box, Copy, Trash2, Terminal, Bot, Codepen, Command, Wind, Github, Zap } from 'lucide-react';
2
+ import React, { useEffect, useMemo, useState } from 'react';
3
+ import { Sun, Moon, Sparkles, Keyboard, FileText, Check, AlertTriangle, Loader2, Settings, Layers, Box, Copy, Trash2, Terminal, Bot, Codepen, Command, Wind, Github, Zap, ChevronDown, ChevronRight, Plug } from 'lucide-react';
4
4
  import styles from '../../Taskforce.module.css';
5
+ import { TASKFORCE_THEME_OPTIONS } from '../../utils/theme';
6
+ import { MCP_CLIENT_OPTIONS, buildCloudMcpClientIntegration, buildCloudMcpServerId, sanitizeMcpId } from '../../mcp/clientIntegrations';
7
+ import { resolveTaskforceMcpBaseUrlFromBaseUrl } from '../../config/cloudEnvironment';
5
8
  import { TaxonomyManager } from './settings/TaxonomyManager';
6
- import { WorkflowEditorPrototype } from './settings/WorkflowEditorPrototype';
9
+ const THEME_ICON_MAP = {
10
+ sun: Sun,
11
+ wind: Wind,
12
+ moon: Moon,
13
+ sparkles: Sparkles,
14
+ };
7
15
  export function TaskSettings(props) {
8
16
  const { settingsModel, onSectionChange } = props;
9
- const { currentTheme, globalTheme, themeUseGlobalDefault, keyShortcut, jsonBackupEnabled, globalJsonBackupEnabled, globalWeekStartsOn, locale = 'en-US', supportedLocales = ['en-US', 'es-419', 'pt-BR'], jsonBackupUseGlobalDefault, manualComplexityEnabled, checklistDropdownEnabled = false, assigneeFilterEnabled = false, exportWorkflowsPath, exportSpecialistsPath, exportingResource, exportResult, initialSection, onThemeChange, onSaveTheme, onSaveGlobalTheme, onResetProjectToGlobal, onKeyShortcutChange, onJsonBackupEnabledChange, onSaveGlobalJsonBackupEnabled, onSaveGlobalWeekStartsOn, onSaveLocale, onManualComplexityEnabledChange, onChecklistDropdownEnabledChange, onAssigneeFilterEnabledChange, onSaveSettings, onExportWorkflowsPathChange, onExportSpecialistsPathChange, onExportResources, onShowFolderBrowserChange, onBrowserTargetChange, onFetchFolders, categories, pathValidation, onUpdateCategory, onRemoveCategory, onSaveCategory, onAddPath, onRemovePath, onUpdateCategoryIcon, onUpdateCategoryColor, types, onSaveType, onRemoveType, taxonomies, onUpdateTaxonomies, priorities, onUpdatePriorities, approaches, onUpdateApproaches, projectRoot, projectName, mcpHostRoot, serverHostRoot, mcpScriptPath, tenantId, workspaceId, runtimeMode = 'local', workspaceSwitchingEnabled = false, currentWorkspaceRole = 'member', currentWorkspaceName = '', onDeleteWorkspace, onMcpHostRootChange, isAuthenticated = false, exportEnvironment, setupState = null, buildInfo = null, onExportEnvironmentChange, onSaveSetupMode, onSaveWorkspaceProfile, availableWorkflows = [], onExportWorkflows, initiativeTemplates = [], onRefreshInitiativeTemplates, onCreateInitiativeFromTemplate, onCloneChecklistBlocksToChildren, onRefreshWorkflows, onFetchWorkflowTemplate, onFetchWorkflowOverrideNames, onSaveWorkflowTemplateDraft, onResetWorkflowTemplateDraft } = settingsModel;
17
+ const { currentTheme, globalTheme, themeUseGlobalDefault, keyShortcut, jsonBackupEnabled, globalJsonBackupEnabled, globalWeekStartsOn, locale = 'en-US', supportedLocales = ['en-US', 'es-419', 'pt-BR'], jsonBackupUseGlobalDefault, manualComplexityEnabled, checklistDropdownEnabled = true, showTaskCardStatusLabel = true, exportWorkflowsPath, exportingResource, exportResult, initialSection, onThemeChange, onSaveTheme, onSaveGlobalTheme, onResetProjectToGlobal, onKeyShortcutChange, onJsonBackupEnabledChange, onSaveGlobalJsonBackupEnabled, onSaveGlobalWeekStartsOn, onSaveLocale, onManualComplexityEnabledChange, onChecklistDropdownEnabledChange, onShowTaskCardStatusLabelChange, onSaveSettings, onExportWorkflowsPathChange, onShowFolderBrowserChange, onBrowserTargetChange, onFetchFolders, categories, pathValidation, taxonomyDisplayLabels, onUpdateCategory, onRemoveCategory, onSaveCategory, onAddPath, onRemovePath, onUpdateCategoryIcon, onUpdateCategoryColor, types, onSaveType, onRemoveType, onUpdateType, taxonomies, onUpdateTaxonomies, priorities, onUpdatePriorities, onAnalyzeSystemTaxonomyPack, onApplySystemTaxonomyPack, onUpdateTaxonomyDisplayLabels, projectRoot, projectName, mcpHostRoot, serverHostRoot, mcpScriptPath, tenantId, workspaceId, runtimeMode = 'local', cloudAuthBaseUrl = '', cloudMcpBaseUrl = '', fetchCloudAuthApi, workspaceSwitchingEnabled = false, currentWorkspaceRole = 'member', currentWorkspaceName = '', onDeleteWorkspace, onMcpHostRootChange, isAuthenticated = false, exportEnvironment, setupState = null, buildInfo = null, onExportEnvironmentChange, onSaveSetupMode, onSaveWorkspaceProfile, availableWorkflows = [], onExportWorkflows, initiativeTemplates = [], onRefreshInitiativeTemplates, onCreateInitiativeFromTemplate, onRefreshWorkflows } = settingsModel;
18
+ const showJsonBackupSettings = runtimeMode !== 'cloud';
10
19
  // Workflow Selection State
11
20
  const [selectedWorkflows, setSelectedWorkflows] = useState([]);
12
21
  // Initialize selection when availableWorkflows changes
@@ -26,23 +35,85 @@ export function TaskSettings(props) {
26
35
  const [setupMode, setSetupMode] = useState(() => setupState?.mode === 'operations' ? 'operations' : 'core');
27
36
  const [workspaceDisplayName, setWorkspaceDisplayName] = useState(() => String(setupState?.workspace?.name || '').trim());
28
37
  const [workspaceDescription, setWorkspaceDescription] = useState(() => String(setupState?.workspace?.description || ''));
29
- const [workspacePlanMode, setWorkspacePlanMode] = useState('personal');
30
- const [workspacePlanModeLoading, setWorkspacePlanModeLoading] = useState(false);
31
- const [workspacePlanModeError, setWorkspacePlanModeError] = useState(null);
32
38
  const [selectedInitiativeTemplateId, setSelectedInitiativeTemplateId] = useState('');
33
39
  const [initiativeTitle, setInitiativeTitle] = useState('');
34
- const [initiativeParentTaskId, setInitiativeParentTaskId] = useState('');
35
- const [cloneChecklistParentTaskId, setCloneChecklistParentTaskId] = useState('');
36
- const [cloneChecklistDodText, setCloneChecklistDodText] = useState('');
37
- const [cloneChecklistRollbackText, setCloneChecklistRollbackText] = useState('');
38
40
  const [isCreatingInitiative, setIsCreatingInitiative] = useState(false);
39
- const [isCloningChecklists, setIsCloningChecklists] = useState(false);
40
- const [documentsConfigLoading, setDocumentsConfigLoading] = useState(false);
41
- const [documentsStorageProvider, setDocumentsStorageProvider] = useState('unknown');
42
41
  const [activeTab, setActiveTab] = useState('general');
42
+ const [appearanceExpanded, setAppearanceExpanded] = useState(true);
43
43
  const [generalScopeTab, setGeneralScopeTab] = useState(() => {
44
44
  return 'project';
45
45
  });
46
+ const [aiProfiles, setAiProfiles] = useState([]);
47
+ const [aiProfilesLoading, setAiProfilesLoading] = useState(false);
48
+ const [aiProfileMergeState, setAiProfileMergeState] = useState(null);
49
+ const [aiProfileMergeStatus, setAiProfileMergeStatus] = useState(null);
50
+ const loadAiProfiles = React.useCallback(async () => {
51
+ if (!workspaceId)
52
+ return;
53
+ setAiProfilesLoading(true);
54
+ try {
55
+ const assigneeOptionsUrl = typeof window !== 'undefined'
56
+ ? new URL(`/api/taskforce/workspace/assignee-options?workspaceId=${encodeURIComponent(workspaceId)}`, window.location.origin).toString()
57
+ : `/api/taskforce/workspace/assignee-options?workspaceId=${encodeURIComponent(workspaceId)}`;
58
+ const res = await fetch(assigneeOptionsUrl, { credentials: 'include' });
59
+ if (!res.ok)
60
+ return;
61
+ const data = await res.json().catch(() => ({}));
62
+ const agents = Array.isArray(data?.assignees)
63
+ ? data.assignees.filter((a) => a.kind === 'agent').map((a) => ({
64
+ id: String(a.value || ''),
65
+ name: String(a.label || ''),
66
+ profileToken: typeof a.profileToken === 'string' ? a.profileToken : null,
67
+ username: String(a.username || a.value || ''),
68
+ icon: String(a.icon || 'Bot'),
69
+ color: String(a.color || '#6B7280'),
70
+ kind: 'agent',
71
+ description: typeof a.description === 'string' ? a.description : null,
72
+ role: typeof a.role === 'string' ? a.role : null,
73
+ provider: typeof a.provider === 'string' ? a.provider : null,
74
+ model: typeof a.model === 'string' ? a.model : null,
75
+ surfaceType: typeof a.surfaceType === 'string' ? a.surfaceType : null,
76
+ }))
77
+ : [];
78
+ setAiProfiles(agents);
79
+ }
80
+ catch {
81
+ setAiProfiles([]);
82
+ }
83
+ finally {
84
+ setAiProfilesLoading(false);
85
+ }
86
+ }, [workspaceId]);
87
+ const doMergeAiProfiles = React.useCallback(async (keepId, mergeId) => {
88
+ if (!workspaceId)
89
+ return;
90
+ setAiProfileMergeStatus(null);
91
+ try {
92
+ const res = await fetch('/api/taskforce/workspace/ai-profiles/merge', {
93
+ method: 'POST',
94
+ credentials: 'include',
95
+ headers: { 'Content-Type': 'application/json' },
96
+ body: JSON.stringify({ workspaceId, keepId, mergeId }),
97
+ });
98
+ const data = await res.json().catch(() => ({}));
99
+ if (!res.ok) {
100
+ setAiProfileMergeStatus({ type: 'error', message: data?.error || 'Merge failed.' });
101
+ }
102
+ else {
103
+ setAiProfileMergeStatus({ type: 'success', message: `Profiles merged successfully.` });
104
+ setAiProfileMergeState(null);
105
+ await loadAiProfiles();
106
+ }
107
+ }
108
+ catch {
109
+ setAiProfileMergeStatus({ type: 'error', message: 'Network error during merge.' });
110
+ }
111
+ }, [workspaceId, loadAiProfiles]);
112
+ useEffect(() => {
113
+ if (activeTab === 'agents' || activeTab === 'mcp') {
114
+ loadAiProfiles();
115
+ }
116
+ }, [activeTab, loadAiProfiles]);
46
117
  useEffect(() => {
47
118
  if (initiativeTemplates.length > 0 && !selectedInitiativeTemplateId) {
48
119
  setSelectedInitiativeTemplateId(initiativeTemplates[0].id);
@@ -61,41 +132,6 @@ export function TaskSettings(props) {
61
132
  setWorkspaceDisplayName(String(setupState?.workspace?.name || '').trim());
62
133
  setWorkspaceDescription(String(setupState?.workspace?.description || ''));
63
134
  }, [setupState?.workspace?.name, setupState?.workspace?.description]);
64
- useEffect(() => {
65
- if (activeTab !== 'general' || generalScopeTab !== 'project' || !isAuthenticated)
66
- return;
67
- let cancelled = false;
68
- (async () => {
69
- setWorkspacePlanModeLoading(true);
70
- setWorkspacePlanModeError(null);
71
- try {
72
- const res = await fetch('/api/taskforce/account/entitlements', {
73
- method: 'GET',
74
- credentials: 'include'
75
- });
76
- const payload = await res.json().catch(() => ({}));
77
- if (cancelled)
78
- return;
79
- if (!res.ok) {
80
- setWorkspacePlanModeError(String(payload?.error || 'Failed to load account entitlements.'));
81
- return;
82
- }
83
- const planId = String(payload?.planId || '').trim().toLowerCase();
84
- setWorkspacePlanMode(planId === 'team' ? 'team' : 'personal');
85
- }
86
- catch {
87
- if (!cancelled)
88
- setWorkspacePlanModeError('Failed to load account entitlements.');
89
- }
90
- finally {
91
- if (!cancelled)
92
- setWorkspacePlanModeLoading(false);
93
- }
94
- })();
95
- return () => {
96
- cancelled = true;
97
- };
98
- }, [activeTab, generalScopeTab, isAuthenticated]);
99
135
  const handleThemeChange = async (theme) => {
100
136
  onThemeChange(theme);
101
137
  const success = await onSaveTheme(theme);
@@ -104,16 +140,235 @@ export function TaskSettings(props) {
104
140
  message: success ? 'Project theme saved.' : 'Failed to save project theme.'
105
141
  });
106
142
  };
143
+ const renderThemeButton = (themeOption, activeTheme, onSelect) => {
144
+ const Icon = THEME_ICON_MAP[themeOption.icon];
145
+ return (_jsxs("button", { className: `${styles.themeBtn} tf-button-tile ${activeTheme === themeOption.id ? styles.activeTheme : ''}`, onClick: () => { void onSelect(themeOption.id); }, children: [_jsx(Icon, { size: 20 }), " ", themeOption.label] }, themeOption.id));
146
+ };
147
+ const cloudMcpAvailable = runtimeMode === 'cloud' || isAuthenticated;
148
+ const defaultMcpMode = runtimeMode === 'cloud'
149
+ ? 'cloud'
150
+ : (isAuthenticated ? 'cloud' : 'local');
151
+ const [selectedMcpMode, setSelectedMcpMode] = useState(defaultMcpMode);
107
152
  const [copiedConfig, setCopiedConfig] = useState(false);
108
153
  const [useGlobalMcp, setUseGlobalMcp] = useState(true);
109
154
  const [showAdvancedMcp, setShowAdvancedMcp] = useState(false);
110
- const sanitizeMcpId = (value, fallback) => {
111
- const normalized = String(value || '')
112
- .toLowerCase()
113
- .replace(/[^a-zA-Z0-9_-]+/g, '-')
114
- .replace(/-+/g, '-')
115
- .replace(/^[-_]+|[-_]+$/g, '');
116
- return normalized || fallback.toLowerCase();
155
+ const [showMcpConnectionTest, setShowMcpConnectionTest] = useState(false);
156
+ const [showMcpTokensList, setShowMcpTokensList] = useState(true);
157
+ const [mcpTokens, setMcpTokens] = useState([]);
158
+ const [mcpTokensLoading, setMcpTokensLoading] = useState(false);
159
+ const [mcpTokensError, setMcpTokensError] = useState(null);
160
+ const [mcpActionBusyId, setMcpActionBusyId] = useState(null);
161
+ const defaultTokenName = useMemo(() => {
162
+ const label = String(currentWorkspaceName
163
+ || setupState?.workspace?.name
164
+ || projectName
165
+ || workspaceId
166
+ || 'Taskforce Workspace').trim();
167
+ return `${label} MCP`;
168
+ }, [currentWorkspaceName, setupState?.workspace?.name, projectName, workspaceId]);
169
+ const [newTokenName, setNewTokenName] = useState(defaultTokenName);
170
+ const [newTokenScopes, setNewTokenScopes] = useState(['tasks:read', 'tasks:write', 'workspace:read']);
171
+ const [newTokenExpiresAt, setNewTokenExpiresAt] = useState('');
172
+ const [mcpTokenNotice, setMcpTokenNotice] = useState(null);
173
+ const [generatedTokenValue, setGeneratedTokenValue] = useState(null);
174
+ const [selectedMcpClient, setSelectedMcpClient] = useState('cursor');
175
+ const [automationAiName, setAutomationAiName] = useState('');
176
+ const [automationAiProfileToken, setAutomationAiProfileToken] = useState('');
177
+ const [mcpConnectionToken, setMcpConnectionToken] = useState('');
178
+ const [mcpConnectionBusy, setMcpConnectionBusy] = useState(false);
179
+ const [mcpConnectionResult, setMcpConnectionResult] = useState(null);
180
+ const [mcpConnectorGrants, setMcpConnectorGrants] = useState([]);
181
+ const [mcpConnectorsLoading, setMcpConnectorsLoading] = useState(false);
182
+ const [mcpConnectorsError, setMcpConnectorsError] = useState(null);
183
+ const [mcpConnectorBusyId, setMcpConnectorBusyId] = useState(null);
184
+ useEffect(() => {
185
+ setSelectedMcpMode(defaultMcpMode);
186
+ }, [defaultMcpMode]);
187
+ useEffect(() => {
188
+ setNewTokenName((current) => current.trim().length > 0 ? current : defaultTokenName);
189
+ }, [defaultTokenName]);
190
+ useEffect(() => {
191
+ if (!mcpTokenNotice)
192
+ return;
193
+ const timer = setTimeout(() => setMcpTokenNotice(null), 3500);
194
+ return () => clearTimeout(timer);
195
+ }, [mcpTokenNotice]);
196
+ useEffect(() => {
197
+ if (!generatedTokenValue)
198
+ return;
199
+ setMcpConnectionToken(generatedTokenValue);
200
+ setMcpConnectionResult(null);
201
+ }, [generatedTokenValue]);
202
+ const cloudMcpEndpoint = useMemo(() => {
203
+ const inferredMcpBase = resolveTaskforceMcpBaseUrlFromBaseUrl(cloudMcpBaseUrl || cloudAuthBaseUrl || '');
204
+ const configuredBase = String(inferredMcpBase || cloudMcpBaseUrl || cloudAuthBaseUrl || '').trim().replace(/\/+$/, '');
205
+ if (configuredBase)
206
+ return `${configuredBase}/mcp`;
207
+ if (typeof window === 'undefined')
208
+ return '/mcp';
209
+ return `${window.location.origin.replace(/\/+$/, '')}/mcp`;
210
+ }, [cloudMcpBaseUrl, cloudAuthBaseUrl]);
211
+ const localMcpEnabled = runtimeMode !== 'cloud';
212
+ const showMcpModeToggle = localMcpEnabled && cloudMcpAvailable;
213
+ const showCloudMcp = runtimeMode === 'cloud' || selectedMcpMode === 'cloud';
214
+ const showLocalMcp = runtimeMode !== 'cloud' && (!cloudMcpAvailable || selectedMcpMode === 'local');
215
+ const sortedMcpTokens = useMemo(() => {
216
+ const statusRank = {
217
+ active: 0,
218
+ expired: 1,
219
+ revoked: 2,
220
+ };
221
+ return [...mcpTokens].sort((a, b) => {
222
+ const rankDiff = (statusRank[a.status] ?? 99) - (statusRank[b.status] ?? 99);
223
+ if (rankDiff !== 0)
224
+ return rankDiff;
225
+ return String(b.createdAt || '').localeCompare(String(a.createdAt || ''));
226
+ });
227
+ }, [mcpTokens]);
228
+ const cloudMcpServerId = useMemo(() => buildCloudMcpServerId(currentWorkspaceName || null, projectName || null), [currentWorkspaceName, projectName]);
229
+ const cloudMcpTokenValue = generatedTokenValue || '<<GENERATE_TOKEN>>';
230
+ const selectedAutomationProfileId = useMemo(() => {
231
+ if (automationAiProfileToken) {
232
+ const byToken = aiProfiles.find((profile) => String(profile.profileToken || '').trim() === automationAiProfileToken.trim());
233
+ if (byToken)
234
+ return byToken.id;
235
+ }
236
+ if (automationAiName) {
237
+ const byName = aiProfiles.find((profile) => profile.name === automationAiName.trim());
238
+ if (byName)
239
+ return byName.id;
240
+ }
241
+ return '';
242
+ }, [aiProfiles, automationAiName, automationAiProfileToken]);
243
+ const selectedAutomationProfile = useMemo(() => aiProfiles.find((profile) => profile.id === selectedAutomationProfileId) || null, [aiProfiles, selectedAutomationProfileId]);
244
+ const inferredAutomationProfileMetadata = useMemo(() => {
245
+ switch (selectedMcpClient) {
246
+ case 'codex':
247
+ return { description: 'OpenAI Codex coding agent connected through MCP.', role: 'Coding Agent', provider: 'OpenAI', model: 'Codex', surfaceType: 'coding_tool' };
248
+ case 'chatgpt-desktop':
249
+ return { description: 'ChatGPT desktop app connected through the Taskforce MCP connector.', role: 'AI Assistant', provider: 'OpenAI', model: 'ChatGPT', surfaceType: 'chat_app' };
250
+ case 'claude-code':
251
+ return { description: 'Claude Code coding agent connected through MCP.', role: 'Coding Agent', provider: 'Anthropic', model: 'Claude Code', surfaceType: 'coding_tool' };
252
+ case 'claude-desktop':
253
+ return { description: 'Claude Desktop connected through the Taskforce MCP connector.', role: 'AI Assistant', provider: 'Anthropic', model: 'Claude', surfaceType: 'chat_app' };
254
+ case 'gemini-cli':
255
+ return { description: 'Gemini CLI coding agent connected through MCP.', role: 'Coding Agent', provider: 'Google', model: 'Gemini', surfaceType: 'coding_tool' };
256
+ case 'vscode':
257
+ return { description: 'VS Code MCP-connected coding agent.', role: 'Coding Agent', provider: null, model: null, surfaceType: 'ide' };
258
+ case 'cline':
259
+ case 'windsurf':
260
+ case 'antigravity':
261
+ case 'openclaw':
262
+ return {
263
+ description: `${MCP_CLIENT_OPTIONS.find((option) => option.id === selectedMcpClient)?.label || 'MCP'} coding agent connected through MCP.`,
264
+ role: 'Coding Agent',
265
+ provider: null,
266
+ model: null,
267
+ surfaceType: 'coding_tool'
268
+ };
269
+ default:
270
+ return { description: null, role: null, provider: null, model: null, surfaceType: null };
271
+ }
272
+ }, [selectedMcpClient]);
273
+ const cloudClientIntegration = useMemo(() => buildCloudMcpClientIntegration({
274
+ clientId: selectedMcpClient,
275
+ endpoint: cloudMcpEndpoint,
276
+ tokenValue: cloudMcpTokenValue,
277
+ serverId: cloudMcpServerId,
278
+ aiProfileName: automationAiName,
279
+ aiProfileToken: automationAiProfileToken,
280
+ aiProfileDescription: selectedAutomationProfile?.description ?? inferredAutomationProfileMetadata.description,
281
+ aiProfileRole: selectedAutomationProfile?.role ?? inferredAutomationProfileMetadata.role,
282
+ aiProfileProvider: selectedAutomationProfile?.provider ?? inferredAutomationProfileMetadata.provider,
283
+ aiProfileModel: selectedAutomationProfile?.model ?? inferredAutomationProfileMetadata.model,
284
+ aiProfileSurfaceType: selectedAutomationProfile?.surfaceType ?? inferredAutomationProfileMetadata.surfaceType,
285
+ }), [
286
+ automationAiName,
287
+ automationAiProfileToken,
288
+ cloudMcpEndpoint,
289
+ cloudMcpServerId,
290
+ cloudMcpTokenValue,
291
+ inferredAutomationProfileMetadata.description,
292
+ inferredAutomationProfileMetadata.model,
293
+ inferredAutomationProfileMetadata.provider,
294
+ inferredAutomationProfileMetadata.role,
295
+ inferredAutomationProfileMetadata.surfaceType,
296
+ selectedAutomationProfile?.description,
297
+ selectedAutomationProfile?.model,
298
+ selectedAutomationProfile?.provider,
299
+ selectedAutomationProfile?.role,
300
+ selectedAutomationProfile?.surfaceType,
301
+ selectedMcpClient
302
+ ]);
303
+ const cloudMcpServerConfig = cloudClientIntegration.kind === 'json'
304
+ ? cloudClientIntegration.serverConfig ?? null
305
+ : null;
306
+ const selectedMcpClientUsesOAuth = selectedMcpClient === 'chatgpt-desktop' || selectedMcpClient === 'claude-desktop';
307
+ const activeChatGptConnector = useMemo(() => mcpConnectorGrants.find((grant) => grant.provider === 'chatgpt' && grant.status === 'active') || null, [mcpConnectorGrants]);
308
+ const activeClaudeConnector = useMemo(() => mcpConnectorGrants.find((grant) => grant.provider === 'claude' && grant.status === 'active') || null, [mcpConnectorGrants]);
309
+ const selectedConnectorGrant = selectedMcpClient === 'chatgpt-desktop'
310
+ ? activeChatGptConnector
311
+ : (selectedMcpClient === 'claude-desktop' ? activeClaudeConnector : null);
312
+ const cloudMcpFullConfig = useMemo(() => {
313
+ if (cloudClientIntegration.kind === 'text') {
314
+ return cloudClientIntegration.renderedText || '';
315
+ }
316
+ let payload = {
317
+ [cloudClientIntegration.rootKey || 'mcpServers']: {
318
+ [cloudMcpServerId]: cloudClientIntegration.serverConfig
319
+ }
320
+ };
321
+ for (const key of [...(cloudClientIntegration.wrapperKeys || [])].reverse()) {
322
+ payload = { [key]: payload };
323
+ }
324
+ return JSON.stringify(payload, null, 2);
325
+ }, [cloudClientIntegration, cloudMcpServerId]);
326
+ const renderMcpConfigBlock = (serverId, serverConfig, rootKey = 'mcpServers', wrapperKeys = []) => {
327
+ const dimmed = { color: 'var(--text-helper)' };
328
+ const highlighted = { color: 'var(--brand-primary-strong)', fontWeight: 'bold' };
329
+ const bracketColor = { color: 'var(--text-secondary)' };
330
+ const normalText = { color: 'var(--text-primary, #fff)' };
331
+ const tokenText = cloudMcpTokenValue;
332
+ const containerKeys = [...wrapperKeys, rootKey];
333
+ const serverIndent = ' '.repeat(containerKeys.length + 1);
334
+ const configText = JSON.stringify(serverConfig, null, 2)
335
+ .split('\n')
336
+ .map((line, i) => i === 0 ? line : `${serverIndent}${line}`)
337
+ .join('\n');
338
+ const configSegments = configText.split(tokenText);
339
+ return (_jsxs(_Fragment, { children: [_jsx("span", { style: bracketColor, children: "{" }), "\n", containerKeys.map((key, index) => (_jsxs(React.Fragment, { children: [`${' '.repeat(index + 1)}`, _jsx("span", { style: dimmed, children: `"${key}"` }), _jsx("span", { style: dimmed, children: ":" }), " ", _jsx("span", { style: bracketColor, children: "{" }), "\n"] }, `mcp-container-open-${key}-${index}`))), serverIndent, _jsxs("span", { style: normalText, children: [`"${serverId}"`, ": ", configSegments.map((segment, index) => (_jsxs(React.Fragment, { children: [segment, index < configSegments.length - 1 && _jsx("span", { style: highlighted, children: tokenText })] }, `config-segment-${index}`)))] }), "\n", [...containerKeys].reverse().map((key, index) => (_jsxs(React.Fragment, { children: [`${' '.repeat(containerKeys.length - index)}`, _jsx("span", { style: bracketColor, children: "}" }), "\n"] }, `mcp-container-close-${key}-${index}`))), _jsx("span", { style: bracketColor, children: "}" })] }));
340
+ };
341
+ const renderTextConfigBlock = (text) => {
342
+ const normalText = { color: 'var(--text-primary, #fff)' };
343
+ const highlighted = { color: 'var(--brand-primary-strong)', fontWeight: 'bold' };
344
+ const tokenText = cloudMcpTokenValue;
345
+ const segments = String(text || '').split(tokenText);
346
+ return segments.map((segment, index) => (_jsxs(React.Fragment, { children: [_jsx("span", { style: normalText, children: segment }), index < segments.length - 1 && _jsx("span", { style: highlighted, children: tokenText })] }, `text-config-${index}`)));
347
+ };
348
+ const toggleTokenScope = (scope) => {
349
+ setNewTokenScopes((current) => {
350
+ if (current.includes(scope)) {
351
+ if (current.length === 1)
352
+ return current;
353
+ return current.filter((item) => item !== scope);
354
+ }
355
+ return [...current, scope];
356
+ });
357
+ };
358
+ const copyToClipboard = (value, mode) => {
359
+ navigator.clipboard.writeText(value);
360
+ setCopiedConfig(mode);
361
+ setTimeout(() => setCopiedConfig(false), 2000);
362
+ };
363
+ const handleCopyCloudMcpConfig = () => {
364
+ if (!selectedMcpClientUsesOAuth && !generatedTokenValue) {
365
+ setMcpTokenNotice({
366
+ type: 'error',
367
+ message: 'Generate a token before copying the Cloud MCP configuration.'
368
+ });
369
+ return;
370
+ }
371
+ copyToClipboard(cloudMcpFullConfig, 'full');
117
372
  };
118
373
  const buildMcpServerConfig = () => {
119
374
  let finalPath = mcpScriptPath || "";
@@ -166,55 +421,234 @@ export function TaskSettings(props) {
166
421
  const toCopy = mode === 'full'
167
422
  ? JSON.stringify({ mcpServers: { [serverId]: serverConfig } }, null, 2)
168
423
  : `"${serverId}": ${JSON.stringify(serverConfig, null, 2)}`;
169
- navigator.clipboard.writeText(toCopy);
170
- setCopiedConfig(mode);
171
- setTimeout(() => setCopiedConfig(false), 2000);
424
+ copyToClipboard(toCopy, mode);
172
425
  };
173
- useEffect(() => {
174
- if (activeTab === 'initiatives' && initiativeTemplates.length === 0) {
175
- onRefreshInitiativeTemplates?.();
426
+ const loadMcpTokens = async () => {
427
+ if (!cloudMcpAvailable)
428
+ return;
429
+ setMcpTokensLoading(true);
430
+ setMcpTokensError(null);
431
+ try {
432
+ const res = await fetchCloudAuthApi('/api/taskforce/settings/mcp/tokens', {
433
+ method: 'GET',
434
+ credentials: 'include'
435
+ });
436
+ const payload = await res.json().catch(() => ({}));
437
+ if (!res.ok) {
438
+ setMcpTokensError(String(payload?.error || 'Failed to load MCP tokens.'));
439
+ return;
440
+ }
441
+ setMcpTokens(Array.isArray(payload?.items) ? payload.items : []);
176
442
  }
177
- }, [activeTab, initiativeTemplates.length, onRefreshInitiativeTemplates]);
178
- useEffect(() => {
179
- if (activeTab !== 'documents')
443
+ catch {
444
+ setMcpTokensError('Failed to load MCP tokens.');
445
+ }
446
+ finally {
447
+ setMcpTokensLoading(false);
448
+ }
449
+ };
450
+ const loadMcpConnectors = async () => {
451
+ if (!cloudMcpAvailable)
180
452
  return;
181
- let cancelled = false;
182
- (async () => {
183
- setDocumentsConfigLoading(true);
184
- try {
185
- const res = await fetch('/api/taskforce/config', { credentials: 'include' });
186
- const payload = await res.json().catch(() => ({}));
187
- if (cancelled)
188
- return;
189
- const provider = payload?.objectStorage?.provider === 'r2' ? 'r2' : 'local';
190
- setDocumentsStorageProvider(provider);
453
+ setMcpConnectorsLoading(true);
454
+ setMcpConnectorsError(null);
455
+ try {
456
+ const res = await fetchCloudAuthApi('/api/taskforce/settings/mcp/connectors', {
457
+ method: 'GET',
458
+ credentials: 'include'
459
+ });
460
+ const payload = await res.json().catch(() => ({}));
461
+ if (!res.ok) {
462
+ setMcpConnectorsError(String(payload?.error || 'Failed to load MCP connectors.'));
463
+ return;
191
464
  }
192
- catch {
193
- if (!cancelled)
194
- setDocumentsStorageProvider('unknown');
465
+ setMcpConnectorGrants(Array.isArray(payload?.items) ? payload.items : []);
466
+ }
467
+ catch {
468
+ setMcpConnectorsError('Failed to load MCP connectors.');
469
+ }
470
+ finally {
471
+ setMcpConnectorsLoading(false);
472
+ }
473
+ };
474
+ const handleCreateMcpToken = async () => {
475
+ const trimmedName = newTokenName.trim();
476
+ if (!trimmedName) {
477
+ setMcpTokenNotice({ type: 'error', message: 'Token name is required.' });
478
+ return;
479
+ }
480
+ setMcpActionBusyId('create');
481
+ setMcpTokenNotice(null);
482
+ try {
483
+ const res = await fetchCloudAuthApi('/api/taskforce/settings/mcp/tokens', {
484
+ method: 'POST',
485
+ credentials: 'include',
486
+ headers: { 'Content-Type': 'application/json' },
487
+ body: JSON.stringify({
488
+ name: trimmedName,
489
+ scopes: newTokenScopes,
490
+ expiresAt: newTokenExpiresAt ? new Date(`${newTokenExpiresAt}T00:00:00`).toISOString() : null
491
+ })
492
+ });
493
+ const payload = await res.json().catch(() => ({}));
494
+ if (!res.ok) {
495
+ setMcpTokenNotice({ type: 'error', message: String(payload?.error || 'Failed to create token.') });
496
+ return;
195
497
  }
196
- finally {
197
- if (!cancelled)
198
- setDocumentsConfigLoading(false);
498
+ setGeneratedTokenValue(String(payload?.token || ''));
499
+ setNewTokenName(defaultTokenName);
500
+ setNewTokenExpiresAt('');
501
+ setMcpTokens((current) => {
502
+ const next = payload?.record ? [payload.record, ...current.filter((item) => item.id !== payload.record.id)] : current;
503
+ return next;
504
+ });
505
+ }
506
+ catch {
507
+ setMcpTokenNotice({ type: 'error', message: 'Failed to create token.' });
508
+ }
509
+ finally {
510
+ setMcpActionBusyId(null);
511
+ }
512
+ };
513
+ const handleMcpTokenAction = async (tokenId, action) => {
514
+ setMcpActionBusyId(`${action}:${tokenId}`);
515
+ setMcpTokenNotice(null);
516
+ try {
517
+ const res = await fetchCloudAuthApi(`/api/taskforce/settings/mcp/tokens/${encodeURIComponent(tokenId)}/${action}`, {
518
+ method: 'POST',
519
+ credentials: 'include'
520
+ });
521
+ const payload = await res.json().catch(() => ({}));
522
+ if (!res.ok) {
523
+ setMcpTokenNotice({ type: 'error', message: String(payload?.error || `Failed to ${action} token.`) });
524
+ return;
199
525
  }
200
- })();
201
- return () => {
202
- cancelled = true;
203
- };
204
- }, [activeTab]);
205
- const resolveAdminConsoleUrl = () => {
206
- const envUrlRaw = String(import.meta?.env?.VITE_TASKFORCE_ADMIN_APP_URL || '').trim();
207
- if (envUrlRaw)
208
- return envUrlRaw.replace(/\/+$/, '');
209
- if (typeof window === 'undefined')
210
- return 'https://admin.taskforcehq.ai';
211
- const { protocol, hostname } = window.location;
212
- if (hostname === 'localhost' || hostname === '127.0.0.1')
213
- return 'http://localhost:5181';
214
- if (hostname.startsWith('app.'))
215
- return `${protocol}//admin.${hostname.slice(4)}`;
216
- return `${protocol}//admin.${hostname}`;
526
+ if (action === 'regenerate') {
527
+ setGeneratedTokenValue(String(payload?.token || ''));
528
+ setMcpTokenNotice({ type: 'success', message: 'Token regenerated. Copy the new value now.' });
529
+ }
530
+ else {
531
+ setMcpTokenNotice({ type: 'success', message: 'Token revoked.' });
532
+ }
533
+ const nextRecord = payload?.record || null;
534
+ if (nextRecord?.id) {
535
+ setMcpTokens((current) => current.map((item) => item.id === nextRecord.id ? nextRecord : item));
536
+ }
537
+ else {
538
+ await loadMcpTokens();
539
+ }
540
+ }
541
+ catch {
542
+ setMcpTokenNotice({ type: 'error', message: `Failed to ${action} token.` });
543
+ }
544
+ finally {
545
+ setMcpActionBusyId(null);
546
+ }
547
+ };
548
+ const handleTestMcpConnection = async () => {
549
+ const trimmedToken = mcpConnectionToken.trim();
550
+ if (!trimmedToken) {
551
+ setMcpConnectionResult({
552
+ type: 'error',
553
+ message: 'Paste a token to test the MCP connection.'
554
+ });
555
+ return;
556
+ }
557
+ setMcpConnectionBusy(true);
558
+ setMcpConnectionResult(null);
559
+ try {
560
+ const res = await fetchCloudAuthApi('/api/taskforce/settings/mcp/test-connection', {
561
+ method: 'POST',
562
+ credentials: 'include',
563
+ headers: { 'Content-Type': 'application/json' },
564
+ body: JSON.stringify({
565
+ token: trimmedToken,
566
+ requiredScopes: newTokenScopes
567
+ })
568
+ });
569
+ const payload = await res.json().catch(() => ({}));
570
+ if (!res.ok) {
571
+ const details = payload?.details && typeof payload.details === 'object' ? payload.details : {};
572
+ const missingScopes = Array.isArray(details?.missingScopes)
573
+ ? details.missingScopes.map((scope) => String(scope))
574
+ : [];
575
+ const workspaceName = typeof details?.tokenWorkspaceId === 'string'
576
+ ? String(details.tokenWorkspaceId)
577
+ : undefined;
578
+ const message = payload?.code === 'MCP_TOKEN_MISSING_SCOPES' && missingScopes.length > 0
579
+ ? `Token is missing required scopes: ${missingScopes.join(', ')}.`
580
+ : String(payload?.error || 'Failed to test MCP connection.');
581
+ setMcpConnectionResult({
582
+ type: 'error',
583
+ message,
584
+ workspaceName,
585
+ });
586
+ return;
587
+ }
588
+ const result = payload?.result && typeof payload.result === 'object' ? payload.result : {};
589
+ setMcpConnectionResult({
590
+ type: 'success',
591
+ message: 'Connection looks good for this workspace.',
592
+ scopes: Array.isArray(result?.scopes) ? result.scopes.map((scope) => String(scope)) : [],
593
+ workspaceName: typeof result?.workspaceName === 'string' ? String(result.workspaceName) : '',
594
+ workspaceId: typeof result?.workspaceId === 'string' ? String(result.workspaceId) : '',
595
+ });
596
+ }
597
+ catch {
598
+ setMcpConnectionResult({
599
+ type: 'error',
600
+ message: 'Failed to test MCP connection.'
601
+ });
602
+ }
603
+ finally {
604
+ setMcpConnectionBusy(false);
605
+ }
217
606
  };
607
+ const handleDisconnectConnector = async (grantId) => {
608
+ setMcpConnectorBusyId(grantId);
609
+ setMcpConnectorsError(null);
610
+ try {
611
+ const res = await fetchCloudAuthApi(`/api/taskforce/settings/mcp/connectors/${encodeURIComponent(grantId)}/disconnect`, {
612
+ method: 'POST',
613
+ credentials: 'include'
614
+ });
615
+ const payload = await res.json().catch(() => ({}));
616
+ if (!res.ok) {
617
+ setMcpConnectorsError(String(payload?.error || 'Failed to disconnect connector.'));
618
+ return;
619
+ }
620
+ const nextRecord = payload?.record || null;
621
+ if (nextRecord?.id) {
622
+ setMcpConnectorGrants((current) => current.map((grant) => grant.id === nextRecord.id ? nextRecord : grant));
623
+ }
624
+ else {
625
+ await loadMcpConnectors();
626
+ }
627
+ }
628
+ catch {
629
+ setMcpConnectorsError('Failed to disconnect connector.');
630
+ }
631
+ finally {
632
+ setMcpConnectorBusyId(null);
633
+ }
634
+ };
635
+ useEffect(() => {
636
+ if (!cloudMcpAvailable)
637
+ return;
638
+ if (activeTab === 'mcp' && showCloudMcp) {
639
+ void loadMcpTokens();
640
+ void loadMcpConnectors();
641
+ return;
642
+ }
643
+ if (activeTab === 'integrations') {
644
+ void loadMcpConnectors();
645
+ }
646
+ }, [activeTab, showCloudMcp, cloudMcpAvailable]);
647
+ useEffect(() => {
648
+ if (activeTab === 'initiatives' && initiativeTemplates.length === 0) {
649
+ onRefreshInitiativeTemplates?.();
650
+ }
651
+ }, [activeTab, initiativeTemplates.length, onRefreshInitiativeTemplates]);
218
652
  const availableEnvironments = settingsModel.availableEnvironments || [];
219
653
  const getIconComponent = (iconName) => {
220
654
  switch (iconName) {
@@ -235,10 +669,19 @@ export function TaskSettings(props) {
235
669
  setActiveTab('taxonomy');
236
670
  }
237
671
  else if (initialSection === 'documents') {
238
- setActiveTab('documents');
672
+ setActiveTab('general');
673
+ }
674
+ else if (initialSection === 'appearance-application') {
675
+ setAppearanceExpanded(true);
676
+ setActiveTab('appearanceApplication');
239
677
  }
240
- else if (initialSection === 'workflow-editor') {
241
- setActiveTab('workflowEditor');
678
+ else if (initialSection === 'appearance-task-cards') {
679
+ setAppearanceExpanded(true);
680
+ setActiveTab('appearanceTaskCards');
681
+ }
682
+ else if (initialSection === 'appearance-task-forms') {
683
+ setAppearanceExpanded(true);
684
+ setActiveTab('appearanceTaskForms');
242
685
  }
243
686
  else if (initialSection === 'resources' || initialSection === 'commands') {
244
687
  setActiveTab('commands');
@@ -249,11 +692,19 @@ export function TaskSettings(props) {
249
692
  else if (initialSection === 'agents') {
250
693
  setActiveTab('agents');
251
694
  }
695
+ else if (initialSection === 'integrations') {
696
+ setActiveTab('integrations');
697
+ }
252
698
  else {
253
699
  setActiveTab(initialSection);
254
700
  }
255
701
  }
256
702
  }, [initialSection]);
703
+ useEffect(() => {
704
+ if (activeTab === 'appearanceApplication' || activeTab === 'appearanceTaskCards' || activeTab === 'appearanceTaskForms') {
705
+ setAppearanceExpanded(true);
706
+ }
707
+ }, [activeTab]);
257
708
  const handleBrowseFolders = (catValue) => {
258
709
  onBrowserTargetChange({ type: 'category', value: catValue });
259
710
  onFetchFolders('');
@@ -269,232 +720,266 @@ export function TaskSettings(props) {
269
720
  }
270
721
  return fullPath;
271
722
  };
272
- return (_jsxs("div", { className: styles.settingsTab, children: [_jsxs("div", { className: styles.settingsTabs, children: [_jsxs("button", { className: `${styles.settingsTabBtn} ${activeTab === 'general' ? styles.settingsTabBtnActive : ''}`, onClick: () => {
273
- setActiveTab('general');
274
- onSectionChange?.('general');
275
- }, children: [_jsx(Settings, { size: 14 }), " General"] }), _jsxs("button", { className: `${styles.settingsTabBtn} ${activeTab === 'documents' ? styles.settingsTabBtnActive : ''}`, onClick: () => {
276
- setActiveTab('documents');
277
- onSectionChange?.('documents');
278
- }, children: [_jsx(FolderOpen, { size: 14 }), " Documents"] }), _jsxs("button", { className: `${styles.settingsTabBtn} ${activeTab === 'commands' ? styles.settingsTabBtnActive : ''}`, onClick: () => {
279
- setActiveTab('commands');
280
- onSectionChange?.('commands');
281
- }, children: [_jsx(Terminal, { size: 14 }), " Commands"] }), _jsxs("button", { className: `${styles.settingsTabBtn} ${activeTab === 'initiatives' ? styles.settingsTabBtnActive : ''}`, onClick: () => {
282
- setActiveTab('initiatives');
283
- onSectionChange?.('initiatives');
284
- }, children: [_jsx(Zap, { size: 14 }), " Initiatives"] }), _jsxs("button", { className: `${styles.settingsTabBtn} ${activeTab === 'workflowEditor' ? styles.settingsTabBtnActive : ''}`, onClick: () => {
285
- setActiveTab('workflowEditor');
286
- onSectionChange?.('workflow-editor');
287
- }, children: [_jsx(FileText, { size: 14 }), " Workflows"] }), _jsxs("button", { className: `${styles.settingsTabBtn} ${activeTab === 'agents' ? styles.settingsTabBtnActive : ''}`, onClick: () => {
288
- setActiveTab('agents');
289
- onSectionChange?.('agents');
290
- }, children: [_jsx(Bot, { size: 14 }), " Agents"] }), _jsxs("button", { className: `${styles.settingsTabBtn} ${activeTab === 'taxonomy' ? styles.settingsTabBtnActive : ''}`, onClick: () => {
291
- setActiveTab('taxonomy');
292
- onSectionChange?.('taxonomy');
293
- }, children: [_jsx(Layers, { size: 14 }), " Taxonomies"] }), _jsxs("button", { className: `${styles.settingsTabBtn} ${activeTab === 'mcp' ? styles.settingsTabBtnActive : ''}`, onClick: () => {
294
- setActiveTab('mcp');
295
- onSectionChange?.('mcp');
296
- }, children: [_jsx(Box, { size: 14 }), " MCP"] })] }), _jsxs("div", { className: styles.settingsContent, children: [settingsFeedback && (_jsxs("div", { className: `${styles.settingsToast} ${settingsFeedback.type === 'success' ? styles.settingsToastSuccess : styles.settingsToastError}`, children: [settingsFeedback.type === 'success' ? _jsx(Check, { size: 14 }) : _jsx(AlertTriangle, { size: 14 }), _jsx("span", { children: settingsFeedback.message })] })), activeTab === 'general' && (_jsxs(_Fragment, { children: [_jsx("div", { className: styles.settingGroup, children: _jsxs("div", { className: styles.settingTitleRow, children: [_jsx("h3", { className: styles.settingTitle, children: generalScopeTab === 'project' ? 'Project Settings' : 'Global Settings' }), _jsxs("div", { className: styles.settingsTabs, children: [_jsx("button", { className: `${styles.settingsTabBtn} ${generalScopeTab === 'project' ? styles.settingsTabBtnActive : ''}`, onClick: () => setGeneralScopeTab('project'), children: "Project" }), _jsx("button", { className: `${styles.settingsTabBtn} ${generalScopeTab === 'global' ? styles.settingsTabBtnActive : ''}`, onClick: () => setGeneralScopeTab('global'), children: "Global" })] }), generalScopeTab === 'project' && (_jsx("button", { onClick: async () => {
297
- const confirmed = window.confirm('Reset project Theme and Backups to global defaults?');
298
- if (!confirmed)
299
- return;
300
- const success = await onResetProjectToGlobal();
301
- setSettingsFeedback({
302
- type: success ? 'success' : 'error',
303
- message: success ? 'Project settings reset to global.' : 'Failed to reset project settings.'
304
- });
305
- }, className: styles.copyBtn, children: "Reset to Global" }))] }) }), generalScopeTab === 'project' && (_jsxs("div", { className: styles.settingGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Workspace Profile" }), _jsxs("div", { className: styles.pathInputGroup, children: [_jsxs("label", { className: styles.label, style: { minWidth: '110px' }, children: [setupMode === 'operations' ? 'Mission' : 'Project', " name:"] }), _jsx("input", { className: styles.input, type: "text", value: workspaceDisplayName, onChange: (event) => setWorkspaceDisplayName(event.target.value), placeholder: setupMode === 'operations' ? 'Mission name' : 'Project name', style: { maxWidth: '360px' } })] }), _jsxs("div", { className: styles.pathInputGroup, children: [_jsx("label", { className: styles.label, style: { minWidth: '110px' }, children: "Description:" }), _jsx("textarea", { className: styles.textarea, value: workspaceDescription, onChange: (event) => setWorkspaceDescription(event.target.value), placeholder: setupMode === 'operations' ? 'Mission description (optional)' : 'Project description (optional)', rows: 3, style: { maxWidth: '360px' } })] }), _jsx("div", { className: styles.pathInputGroup, children: _jsx("button", { onClick: async () => {
306
- if (!onSaveWorkspaceProfile)
307
- return;
308
- const result = await onSaveWorkspaceProfile({
309
- workspaceId: setupState?.workspaceId,
310
- name: workspaceDisplayName,
311
- description: workspaceDescription
312
- });
313
- setSettingsFeedback({
314
- type: result.success ? 'success' : 'error',
315
- message: result.success
316
- ? `${setupMode === 'operations' ? 'Mission' : 'Project'} profile saved.`
317
- : (result.error || 'Failed to save workspace profile.')
318
- });
319
- }, className: `${styles.saveSettingsBtn} ${styles.saveSettingsBtnWrapper}`, disabled: !onSaveWorkspaceProfile, children: "Save Profile" }) })] })), generalScopeTab === 'project' && isAuthenticated && (_jsxs("div", { className: styles.settingGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Account Plan" }), _jsx("p", { className: styles.settingHelper, children: "Effective plan state is managed by platform admin and surfaced here as read-only." }), _jsxs("div", { className: styles.pathInputGroup, children: [_jsx("label", { className: styles.label, style: { minWidth: '110px' }, children: "Plan mode:" }), _jsxs("select", { className: styles.input, value: workspacePlanMode, style: { maxWidth: '220px' }, disabled: true, children: [_jsx("option", { value: "personal", children: "Personal" }), _jsx("option", { value: "team", children: "Team" })] })] }), workspacePlanModeLoading && (_jsx("p", { className: styles.settingHelper, children: "Loading current account entitlements..." })), workspacePlanModeError && (_jsx("p", { className: styles.settingHelper, style: { color: '#fda4af' }, children: workspacePlanModeError }))] })), generalScopeTab === 'project' && (_jsxs("div", { className: styles.settingGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Theme" }), _jsxs("div", { className: styles.buttonGrid, children: [_jsxs("button", { className: `${styles.themeBtn} ${currentTheme === 'light' ? styles.activeTheme : ''}`, onClick: () => { void handleThemeChange('light'); }, children: [_jsx(Sun, { size: 20 }), " Light"] }), _jsxs("button", { className: `${styles.themeBtn} ${currentTheme === 'dark' ? styles.activeTheme : ''}`, onClick: () => { void handleThemeChange('dark'); }, children: [_jsx(Moon, { size: 20 }), " Dark"] }), _jsxs("button", { className: `${styles.themeBtn} ${currentTheme === 'midnight' ? styles.activeTheme : ''}`, onClick: () => { void handleThemeChange('midnight'); }, children: [_jsx(Sparkles, { size: 20 }), " Midnight"] })] }), _jsx("h3", { className: styles.settingTitle, children: "Backup" }), _jsxs("label", { className: styles.archiveToggle, children: [_jsx("input", { type: "checkbox", checked: jsonBackupEnabled, onChange: async (e) => {
320
- const success = await onJsonBackupEnabledChange(e.target.checked);
321
- setSettingsFeedback({
322
- type: success ? 'success' : 'error',
323
- message: success ? 'Project backup setting saved.' : 'Failed to save project backup setting.'
324
- });
325
- } }), _jsx("span", { children: "Enable automatic JSON backup (`.taskforce/tasks.json`)" })] }), _jsx("h3", { className: styles.settingTitle, children: "Task Form" }), _jsxs("label", { className: styles.archiveToggle, children: [_jsx("input", { type: "checkbox", checked: checklistDropdownEnabled, onChange: async (e) => {
326
- if (!onChecklistDropdownEnabledChange)
723
+ const settingsNavItems = [
724
+ { key: 'general', label: 'General', icon: _jsx(Settings, { size: 14 }), section: 'general' },
725
+ { key: 'taxonomy', label: 'Taxonomy', icon: _jsx(Layers, { size: 14 }), section: 'taxonomy' },
726
+ { key: 'integrations', label: 'Integrations', icon: _jsx(Plug, { size: 14 }), section: 'integrations' },
727
+ { key: 'mcp', label: 'MCP', icon: _jsx(Box, { size: 14 }), section: 'mcp' }
728
+ ];
729
+ const appearanceNavItems = [
730
+ { key: 'appearanceApplication', label: 'Application', section: 'appearance-application' },
731
+ { key: 'appearanceTaskCards', label: 'Task cards', section: 'appearance-task-cards' },
732
+ { key: 'appearanceTaskForms', label: 'Task forms', section: 'appearance-task-forms' }
733
+ ];
734
+ const selectTab = (tab, section) => {
735
+ setActiveTab(tab);
736
+ onSectionChange?.(section);
737
+ };
738
+ const renderProjectThemeControls = () => (_jsxs("div", { className: styles.settingGroup, children: [_jsx("h3", { className: `${styles.settingTitle} tf-heading-section`, children: "Theme" }), _jsx("div", { className: styles.buttonGrid, children: TASKFORCE_THEME_OPTIONS.map((themeOption) => renderThemeButton(themeOption, currentTheme, handleThemeChange)) })] }));
739
+ const renderGlobalThemeControls = () => (_jsxs("div", { className: styles.settingGroup, children: [_jsx("h3", { className: `${styles.settingTitle} tf-heading-section`, children: "Theme Defaults" }), _jsx("div", { className: styles.buttonGrid, children: TASKFORCE_THEME_OPTIONS.map((themeOption) => renderThemeButton(themeOption, globalTheme, async (theme) => {
740
+ const success = await onSaveGlobalTheme(theme);
741
+ setSettingsFeedback({
742
+ type: success ? 'success' : 'error',
743
+ message: success ? 'Global theme saved.' : 'Failed to save global theme.'
744
+ });
745
+ })) })] }));
746
+ const renderTaskFormsControls = () => (_jsxs("div", { className: styles.settingGroup, children: [_jsx("h3", { className: `${styles.settingTitle} tf-heading-section`, children: "Task Form" }), _jsxs("label", { className: styles.archiveToggle, children: [_jsx("input", { type: "checkbox", checked: checklistDropdownEnabled, onChange: async (e) => {
747
+ if (!onChecklistDropdownEnabledChange)
748
+ return;
749
+ const success = await onChecklistDropdownEnabledChange(e.target.checked);
750
+ setSettingsFeedback({
751
+ type: success ? 'success' : 'error',
752
+ message: success ? 'Checklist dropdown setting saved.' : 'Failed to save checklist dropdown setting.'
753
+ });
754
+ }, disabled: !onChecklistDropdownEnabledChange }), _jsx("span", { children: "Enable checklist dropdown in task form" })] })] }));
755
+ return (_jsx("div", { className: styles.settingsTab, children: _jsxs("div", { className: styles.settingsLayout, children: [_jsxs("aside", { className: styles.settingsSidebar, children: [_jsx("div", { className: styles.settingsSidebarHeader, children: "Sections" }), _jsxs("div", { className: `${styles.settingsSidebarNav} tf-scrollbar tf-scrollbar--track-transparent tf-scrollbar--compact`, children: [settingsNavItems.filter((item) => item.key === 'general').map((item) => (_jsxs("button", { className: `${styles.settingsSidebarBtn} ${activeTab === item.key ? styles.settingsSidebarBtnActive : ''}`, onClick: () => selectTab(item.key, item.section), children: [item.icon, _jsx("span", { children: item.label })] }, item.key))), _jsxs("div", { className: styles.settingsSidebarGroup, children: [_jsxs("button", { className: `${styles.settingsSidebarBtn} ${styles.settingsSidebarGroupBtn} ${(activeTab === 'appearanceApplication' || activeTab === 'appearanceTaskCards' || activeTab === 'appearanceTaskForms') ? styles.settingsSidebarBtnActive : ''}`, onClick: () => setAppearanceExpanded((current) => !current), "aria-expanded": appearanceExpanded, "aria-controls": "settings-appearance-nav", children: [_jsx(Sparkles, { size: 14 }), _jsx("span", { className: styles.settingsSidebarGroupLabel, children: "Appearance" }), _jsx("span", { className: styles.settingsSidebarGroupChevron, children: appearanceExpanded ? _jsx(ChevronDown, { size: 14 }) : _jsx(ChevronRight, { size: 14 }) })] }), appearanceExpanded && (_jsx("div", { id: "settings-appearance-nav", className: styles.settingsSidebarSubnav, children: appearanceNavItems.map((item) => (_jsx("button", { className: `${styles.settingsSidebarSubBtn} ${activeTab === item.key ? styles.settingsSidebarBtnActive : ''}`, onClick: () => selectTab(item.key, item.section), children: _jsx("span", { children: item.label }) }, item.key))) }))] }), settingsNavItems.filter((item) => item.key !== 'general').map((item) => (_jsxs("button", { className: `${styles.settingsSidebarBtn} ${activeTab === item.key ? styles.settingsSidebarBtnActive : ''}`, onClick: () => selectTab(item.key, item.section), children: [item.icon, _jsx("span", { children: item.label })] }, item.key)))] })] }), _jsxs("div", { className: styles.settingsContent, children: [settingsFeedback && (_jsxs("div", { className: `${styles.settingsToast} ${settingsFeedback.type === 'success' ? styles.settingsToastSuccess : styles.settingsToastError}`, children: [settingsFeedback.type === 'success' ? _jsx(Check, { size: 14 }) : _jsx(AlertTriangle, { size: 14 }), _jsx("span", { children: settingsFeedback.message })] })), activeTab === 'general' && (_jsxs(_Fragment, { children: [_jsxs("div", { className: styles.settingGroup, children: [_jsxs("div", { className: `${styles.settingsTabs} tf-scrollbar tf-scrollbar--track-transparent tf-scrollbar--compact`, children: [_jsx("button", { className: `${styles.settingsTabBtn} ${generalScopeTab === 'project' ? styles.settingsTabBtnActive : ''}`, onClick: () => setGeneralScopeTab('project'), children: "Project" }), _jsx("button", { className: `${styles.settingsTabBtn} ${generalScopeTab === 'global' ? styles.settingsTabBtnActive : ''}`, onClick: () => setGeneralScopeTab('global'), children: "Global" })] }), generalScopeTab === 'project' && (_jsx("div", { className: styles.pathInputGroup, style: { justifyContent: 'flex-end' }, children: _jsx("button", { onClick: async () => {
756
+ const confirmed = window.confirm('Reset project Theme and Backups to global defaults?');
757
+ if (!confirmed)
327
758
  return;
328
- const success = await onChecklistDropdownEnabledChange(e.target.checked);
759
+ const success = await onResetProjectToGlobal();
329
760
  setSettingsFeedback({
330
761
  type: success ? 'success' : 'error',
331
- message: success ? 'Checklist dropdown setting saved.' : 'Failed to save checklist dropdown setting.'
762
+ message: success ? 'Project settings reset to global.' : 'Failed to reset project settings.'
332
763
  });
333
- }, disabled: !onChecklistDropdownEnabledChange }), _jsx("span", { children: "Enable checklist dropdown in task form" })] }), _jsxs("label", { className: styles.archiveToggle, children: [_jsx("input", { type: "checkbox", checked: assigneeFilterEnabled, onChange: async (e) => {
334
- if (!onAssigneeFilterEnabledChange)
764
+ }, className: styles.copyBtn, children: "Reset to Global" }) }))] }), generalScopeTab === 'project' && (_jsxs("div", { className: styles.settingGroup, children: [_jsxs("div", { className: styles.pathInputGroup, children: [_jsxs("label", { className: styles.label, style: { minWidth: '110px' }, children: [setupMode === 'operations' ? 'Mission' : 'Project', " name:"] }), _jsx("input", { className: styles.input, type: "text", value: workspaceDisplayName, onChange: (event) => setWorkspaceDisplayName(event.target.value), placeholder: setupMode === 'operations' ? 'Mission name' : 'Project name' })] }), _jsxs("div", { className: styles.pathInputGroup, children: [_jsx("label", { className: styles.label, style: { minWidth: '110px' }, children: "Description:" }), _jsx("textarea", { className: styles.textarea, value: workspaceDescription, onChange: (event) => setWorkspaceDescription(event.target.value), placeholder: setupMode === 'operations' ? 'Mission description (optional)' : 'Project description (optional)', rows: 3 })] }), _jsx("div", { className: styles.pathInputGroup, style: { justifyContent: 'flex-end' }, children: _jsx("button", { onClick: async () => {
765
+ if (!onSaveWorkspaceProfile)
335
766
  return;
336
- const success = await onAssigneeFilterEnabledChange(e.target.checked);
767
+ const result = await onSaveWorkspaceProfile({
768
+ workspaceId: setupState?.workspaceId,
769
+ name: workspaceDisplayName,
770
+ description: workspaceDescription
771
+ });
337
772
  setSettingsFeedback({
338
- type: success ? 'success' : 'error',
339
- message: success ? 'Assignee filter setting saved.' : 'Failed to save assignee filter setting.'
773
+ type: result.success ? 'success' : 'error',
774
+ message: result.success
775
+ ? `${setupMode === 'operations' ? 'Mission' : 'Project'} profile saved.`
776
+ : (result.error || 'Failed to save workspace profile.')
340
777
  });
341
- }, disabled: !onAssigneeFilterEnabledChange }), _jsx("span", { children: "Enable assignee filter in task views" })] })] })), generalScopeTab === 'global' && (_jsxs(_Fragment, { children: [_jsxs("div", { className: styles.settingGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Operating Mode" }), _jsxs("div", { className: styles.pathInputGroup, children: [_jsx("label", { className: styles.label, style: { minWidth: '110px' }, children: "Mode:" }), _jsxs("select", { className: styles.input, value: setupMode, onChange: (e) => setSetupMode(e.target.value === 'operations' ? 'operations' : 'core'), style: { maxWidth: '220px' }, children: [_jsx("option", { value: "core", children: "Core (Project)" }), _jsx("option", { value: "operations", children: "Operations (Mission)" })] }), _jsx("button", { onClick: async () => {
342
- if (!onSaveSetupMode)
343
- return;
344
- const success = await onSaveSetupMode(setupMode);
778
+ }, className: styles.copyBtn, disabled: !onSaveWorkspaceProfile, children: "Save" }) })] })), generalScopeTab === 'project' && (_jsx("div", { className: styles.settingGroup, children: showJsonBackupSettings && (_jsxs(_Fragment, { children: [_jsx("h3", { className: styles.settingTitle, children: "Backup" }), _jsxs("label", { className: styles.archiveToggle, children: [_jsx("input", { type: "checkbox", checked: jsonBackupEnabled, onChange: async (e) => {
779
+ const success = await onJsonBackupEnabledChange(e.target.checked);
345
780
  setSettingsFeedback({
346
781
  type: success ? 'success' : 'error',
347
- message: success ? 'Operating mode saved.' : 'Failed to save operating mode.'
782
+ message: success ? 'Project backup setting saved.' : 'Failed to save project backup setting.'
348
783
  });
349
- }, className: `${styles.saveSettingsBtn} ${styles.saveSettingsBtnWrapper}`, disabled: !onSaveSetupMode, children: "Save" })] })] }), _jsxs("div", { className: styles.settingGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Theme" }), _jsxs("div", { className: styles.buttonGrid, children: [_jsxs("button", { className: `${styles.themeBtn} ${globalTheme === 'light' ? styles.activeTheme : ''}`, onClick: async () => {
350
- const success = await onSaveGlobalTheme('light');
351
- setSettingsFeedback({
352
- type: success ? 'success' : 'error',
353
- message: success ? 'Global theme saved.' : 'Failed to save global theme.'
354
- });
355
- }, children: [_jsx(Sun, { size: 20 }), " Light"] }), _jsxs("button", { className: `${styles.themeBtn} ${globalTheme === 'dark' ? styles.activeTheme : ''}`, onClick: async () => {
356
- const success = await onSaveGlobalTheme('dark');
357
- setSettingsFeedback({
358
- type: success ? 'success' : 'error',
359
- message: success ? 'Global theme saved.' : 'Failed to save global theme.'
360
- });
361
- }, children: [_jsx(Moon, { size: 20 }), " Dark"] }), _jsxs("button", { className: `${styles.themeBtn} ${globalTheme === 'midnight' ? styles.activeTheme : ''}`, onClick: async () => {
362
- const success = await onSaveGlobalTheme('midnight');
363
- setSettingsFeedback({
364
- type: success ? 'success' : 'error',
365
- message: success ? 'Global theme saved.' : 'Failed to save global theme.'
366
- });
367
- }, children: [_jsx(Sparkles, { size: 20 }), " Midnight"] })] }), _jsx("h3", { className: styles.settingTitle, children: "Backup" }), _jsxs("label", { className: styles.archiveToggle, children: [_jsx("input", { type: "checkbox", checked: globalJsonBackupEnabled, onChange: async (e) => {
368
- const success = await onSaveGlobalJsonBackupEnabled(e.target.checked);
369
- setSettingsFeedback({
370
- type: success ? 'success' : 'error',
371
- message: success ? 'Global backup default saved.' : 'Failed to save global backup default.'
372
- });
373
- } }), _jsx("span", { children: "Enable global JSON backup default" })] })] }), _jsxs("div", { className: styles.settingGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Regional" }), _jsxs("div", { className: styles.pathInputGroup, children: [_jsx("label", { className: styles.label, style: { minWidth: '110px' }, children: "Calendar start:" }), _jsxs("select", { className: styles.input, value: globalWeekStartsOn, onChange: async (e) => {
374
- const value = e.target.value;
375
- const success = await onSaveGlobalWeekStartsOn(value);
376
- setSettingsFeedback({
377
- type: success ? 'success' : 'error',
378
- message: success
379
- ? `Week start saved (${value === 'sunday' ? 'Sunday' : 'Monday'}).`
380
- : 'Failed to save week start.'
381
- });
382
- }, style: { maxWidth: '220px' }, children: [_jsx("option", { value: "sunday", children: "Sunday" }), _jsx("option", { value: "monday", children: "Monday" })] })] }), _jsxs("div", { className: styles.pathInputGroup, children: [_jsx("label", { className: styles.label, style: { minWidth: '110px' }, children: "Language:" }), _jsx("select", { className: styles.input, value: locale, onChange: async (e) => {
383
- const value = e.target.value;
384
- if (!onSaveLocale)
385
- return;
386
- const success = await onSaveLocale(value);
387
- setSettingsFeedback({
388
- type: success ? 'success' : 'error',
389
- message: success ? `Language saved (${value}).` : 'Failed to save language.'
390
- });
391
- }, style: { maxWidth: '220px' }, disabled: !onSaveLocale, children: supportedLocales.map((value) => (_jsx("option", { value: value, children: value }, value))) })] })] }), _jsxs("div", { className: styles.settingGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Keyboard Shortcut" }), _jsxs("div", { className: styles.pathInputGroup, children: [_jsxs("div", { className: styles.shortcutInputWrapper, children: [_jsx(Keyboard, { size: 16, className: styles.inputIcon }), _jsx("input", { type: "text", value: keyShortcut, onChange: (e) => onKeyShortcutChange(e.target.value), placeholder: "e.g. Alt+T, Ctrl+Shift+K", className: `${styles.input} ${styles.shortcutInput}` })] }), _jsx("button", { onClick: async () => {
392
- const success = await onSaveSettings();
393
- setSettingsFeedback({
394
- type: success ? 'success' : 'error',
395
- message: success ? 'Global shortcut saved.' : 'Failed to save global shortcut.'
396
- });
397
- }, className: `${styles.saveSettingsBtn} ${styles.saveSettingsBtnWrapper}`, children: "Save" })] }), _jsxs("p", { className: styles.settingHelper, children: ["Supported modifiers: Alt, Option, Ctrl, Shift, Meta (Cmd). Example: ", _jsx("code", { children: "Alt+T" }), " or ", _jsx("code", { children: "Ctrl+Shift+L" }), "."] })] })] })), generalScopeTab === 'project' && (_jsxs("div", { className: styles.settingGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Danger Zone" }), runtimeMode !== 'cloud' || !workspaceSwitchingEnabled ? (_jsx("p", { className: styles.settingHelper, children: "Workspace deletion is available in cloud runtime only." })) : !isAuthenticated ? (_jsx("p", { className: styles.settingHelper, children: "Sign in to manage workspace deletion." })) : currentWorkspaceRole !== 'owner' ? (_jsx("p", { className: styles.settingHelper, children: "Only workspace owners can delete a workspace." })) : (_jsx("div", { className: styles.pathInputGroup, children: _jsxs("button", { className: styles.destructiveBtn, onClick: async () => {
398
- if (!onDeleteWorkspace)
399
- return;
400
- const normalizedWorkspaceId = String(workspaceId || '').trim();
401
- if (!normalizedWorkspaceId || normalizedWorkspaceId === 'default') {
402
- setSettingsFeedback({
403
- type: 'error',
404
- message: 'A non-default workspace is required for deletion.'
405
- });
406
- return;
407
- }
408
- const expectedName = String(currentWorkspaceName || '').trim();
409
- const confirmation = window.prompt(`Type "${expectedName}" to permanently delete this workspace.`);
410
- if (confirmation === null)
411
- return;
412
- if (confirmation.trim() !== expectedName) {
413
- setSettingsFeedback({
414
- type: 'error',
415
- message: 'Workspace name confirmation did not match.'
416
- });
417
- return;
418
- }
419
- const result = await onDeleteWorkspace(normalizedWorkspaceId);
420
- if (!result.success) {
784
+ } }), _jsx("span", { children: "Enable automatic JSON backup (`.taskforce/tasks.json`)" })] })] })) })), generalScopeTab === 'global' && (_jsxs(_Fragment, { children: [_jsx("div", { className: styles.settingGroup, children: showJsonBackupSettings && (_jsxs(_Fragment, { children: [_jsx("h3", { className: styles.settingTitle, children: "Backup" }), _jsxs("label", { className: styles.archiveToggle, children: [_jsx("input", { type: "checkbox", checked: globalJsonBackupEnabled, onChange: async (e) => {
785
+ const success = await onSaveGlobalJsonBackupEnabled(e.target.checked);
786
+ setSettingsFeedback({
787
+ type: success ? 'success' : 'error',
788
+ message: success ? 'Global backup default saved.' : 'Failed to save global backup default.'
789
+ });
790
+ } }), _jsx("span", { children: "Enable global JSON backup default" })] })] })) }), _jsxs("div", { className: styles.settingGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Regional" }), _jsxs("div", { className: styles.pathInputGroup, children: [_jsx("label", { className: styles.label, style: { minWidth: '110px' }, children: "Calendar start:" }), _jsxs("select", { className: styles.input, value: globalWeekStartsOn, onChange: async (e) => {
791
+ const value = e.target.value;
792
+ const success = await onSaveGlobalWeekStartsOn(value);
793
+ setSettingsFeedback({
794
+ type: success ? 'success' : 'error',
795
+ message: success
796
+ ? `Week start saved (${value === 'sunday' ? 'Sunday' : 'Monday'}).`
797
+ : 'Failed to save week start.'
798
+ });
799
+ }, style: { maxWidth: '220px' }, children: [_jsx("option", { value: "sunday", children: "Sunday" }), _jsx("option", { value: "monday", children: "Monday" })] })] }), _jsxs("div", { className: styles.pathInputGroup, children: [_jsx("label", { className: styles.label, style: { minWidth: '110px' }, children: "Language:" }), _jsx("select", { className: styles.input, value: locale, onChange: async (e) => {
800
+ const value = e.target.value;
801
+ if (!onSaveLocale)
802
+ return;
803
+ const success = await onSaveLocale(value);
804
+ setSettingsFeedback({
805
+ type: success ? 'success' : 'error',
806
+ message: success ? `Language saved (${value}).` : 'Failed to save language.'
807
+ });
808
+ }, style: { maxWidth: '220px' }, disabled: !onSaveLocale, children: supportedLocales.map((value) => (_jsx("option", { value: value, children: value }, value))) })] })] }), _jsxs("div", { className: styles.settingGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Keyboard Shortcut" }), _jsxs("div", { className: styles.pathInputGroup, children: [_jsxs("div", { className: styles.shortcutInputWrapper, children: [_jsx(Keyboard, { size: 16, className: styles.inputIcon }), _jsx("input", { type: "text", value: keyShortcut, onChange: (e) => onKeyShortcutChange(e.target.value), placeholder: "e.g. Alt+T, Ctrl+Shift+K", className: `${styles.input} ${styles.shortcutInput}` })] }), _jsx("button", { onClick: async () => {
809
+ const success = await onSaveSettings();
810
+ setSettingsFeedback({
811
+ type: success ? 'success' : 'error',
812
+ message: success ? 'Global shortcut saved.' : 'Failed to save global shortcut.'
813
+ });
814
+ }, className: `${styles.saveSettingsBtn} ${styles.saveSettingsBtnWrapper}`, children: "Save" })] }), _jsxs("p", { className: styles.settingHelper, children: ["Supported modifiers: Alt, Option, Ctrl, Shift, Meta (Cmd). Example: ", _jsx("code", { children: "Alt+T" }), " or ", _jsx("code", { children: "Ctrl+Shift+L" }), "."] })] })] })), generalScopeTab === 'project' && runtimeMode === 'cloud' && (_jsxs("div", { className: styles.settingGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Danger Zone" }), !workspaceSwitchingEnabled ? (_jsx("p", { className: styles.settingHelper, children: "Workspace deletion is available in cloud runtime only." })) : !isAuthenticated ? (_jsx("p", { className: styles.settingHelper, children: "Sign in to manage workspace deletion." })) : currentWorkspaceRole !== 'owner' ? (_jsx("p", { className: styles.settingHelper, children: "Only workspace owners can delete a workspace." })) : (_jsx("div", { className: styles.pathInputGroup, children: _jsxs("button", { className: styles.destructiveBtn, onClick: async () => {
815
+ if (!onDeleteWorkspace)
816
+ return;
817
+ const normalizedWorkspaceId = String(workspaceId || '').trim();
818
+ if (!normalizedWorkspaceId || normalizedWorkspaceId === 'default') {
819
+ setSettingsFeedback({
820
+ type: 'error',
821
+ message: 'A non-default workspace is required for deletion.'
822
+ });
823
+ return;
824
+ }
825
+ const expectedName = String(currentWorkspaceName || '').trim();
826
+ const confirmation = window.prompt(`Type "${expectedName}" to permanently delete this workspace.`);
827
+ if (confirmation === null)
828
+ return;
829
+ if (confirmation.trim() !== expectedName) {
830
+ setSettingsFeedback({
831
+ type: 'error',
832
+ message: 'Workspace name confirmation did not match.'
833
+ });
834
+ return;
835
+ }
836
+ const result = await onDeleteWorkspace(normalizedWorkspaceId);
837
+ if (!result.success) {
838
+ setSettingsFeedback({
839
+ type: 'error',
840
+ message: result.error || 'Failed to delete workspace.'
841
+ });
842
+ return;
843
+ }
844
+ const warningCount = Array.isArray(result.cleanupWarnings) ? result.cleanupWarnings.length : 0;
421
845
  setSettingsFeedback({
422
- type: 'error',
423
- message: result.error || 'Failed to delete workspace.'
846
+ type: warningCount > 0 ? 'error' : 'success',
847
+ message: warningCount > 0
848
+ ? `Workspace deleted with ${warningCount} cleanup warning(s).`
849
+ : 'Workspace deleted.'
424
850
  });
851
+ }, disabled: !onDeleteWorkspace, children: [_jsx(Trash2, { size: 14, style: { marginRight: 8 } }), "Delete Workspace"] }) }))] }))] })), activeTab === 'appearanceApplication' && (_jsxs(_Fragment, { children: [_jsx("div", { className: styles.settingGroup, children: _jsxs("div", { className: `${styles.settingsTabs} tf-scrollbar tf-scrollbar--track-transparent tf-scrollbar--compact`, children: [_jsx("button", { className: `${styles.settingsTabBtn} ${generalScopeTab === 'project' ? styles.settingsTabBtnActive : ''}`, onClick: () => setGeneralScopeTab('project'), children: "Project" }), _jsx("button", { className: `${styles.settingsTabBtn} ${generalScopeTab === 'global' ? styles.settingsTabBtnActive : ''}`, onClick: () => setGeneralScopeTab('global'), children: "Global" })] }) }), generalScopeTab === 'project' ? renderProjectThemeControls() : renderGlobalThemeControls()] })), activeTab === 'appearanceTaskCards' && (_jsxs("div", { className: styles.settingGroup, children: [_jsx("h3", { className: `${styles.settingTitle} tf-heading-section`, children: "Task Cards" }), _jsxs("label", { className: styles.archiveToggle, children: [_jsx("input", { type: "checkbox", checked: showTaskCardStatusLabel, onChange: async (e) => {
852
+ if (!onShowTaskCardStatusLabelChange)
425
853
  return;
426
- }
427
- const warningCount = Array.isArray(result.cleanupWarnings) ? result.cleanupWarnings.length : 0;
854
+ const success = await onShowTaskCardStatusLabelChange(e.target.checked);
428
855
  setSettingsFeedback({
429
- type: warningCount > 0 ? 'error' : 'success',
430
- message: warningCount > 0
431
- ? `Workspace deleted with ${warningCount} cleanup warning(s).`
432
- : 'Workspace deleted.'
856
+ type: success ? 'success' : 'error',
857
+ message: success ? 'Task card status label setting saved.' : 'Failed to save task card status label setting.'
433
858
  });
434
- }, disabled: !onDeleteWorkspace, children: [_jsx(Trash2, { size: 14, style: { marginRight: 8 } }), "Delete Workspace"] }) }))] }))] })), activeTab === 'documents' && (_jsxs(_Fragment, { children: [_jsxs("div", { className: styles.settingGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Local Documents" }), _jsx("p", { className: styles.settingHelper, children: "Local document behavior is available to all users and does not require admin permissions." }), _jsxs("div", { className: `${styles.pathInputGroup} ${styles.marginTop12}`, children: [_jsx("label", { className: styles.label, style: { minWidth: '110px' }, children: "Storage mode:" }), _jsx("input", { className: styles.input, value: documentsConfigLoading
435
- ? 'Loading...'
436
- : (documentsStorageProvider === 'r2' ? 'Cloud (R2)' : documentsStorageProvider === 'local' ? 'Local filesystem' : 'Unavailable'), disabled: true, style: { maxWidth: '260px' } })] }), _jsx("p", { className: styles.settingHelper, children: "Per-user editor preferences are configured directly from the document editor screen." }), documentsStorageProvider === 'local' && (_jsx("p", { className: styles.settingHelper, children: "Local documents are stored in `.taskforce/docs` and `.taskforce/task-data/.../attachments`." }))] }), _jsxs("div", { className: `${styles.settingGroup} ${styles.marginTop16}`, children: [_jsx("h3", { className: styles.settingTitle, children: "Cloud Document Storage" }), isAuthenticated && documentsStorageProvider === 'r2' ? (_jsxs(_Fragment, { children: [_jsx("p", { className: styles.settingHelper, children: "System-level cloud storage and integrity controls are managed in App Admin." }), _jsx("div", { className: `${styles.pathInputGroup} ${styles.marginTop12}`, style: { flexWrap: 'wrap', alignItems: 'center' }, children: _jsx("button", { className: styles.copyBtn, onClick: () => {
437
- window.open(resolveAdminConsoleUrl(), '_blank', 'noopener,noreferrer');
438
- }, children: "Open App Admin" }) })] })) : isAuthenticated && documentsStorageProvider === 'local' ? (_jsx("p", { className: styles.settingHelper, children: "Cloud storage is not active in this environment. No cloud document settings are currently applied." })) : (_jsx("p", { className: styles.settingHelper, children: "Sign in to access cloud document storage controls in App Admin." }))] })] })), activeTab === 'commands' && (_jsx(_Fragment, { children: _jsxs("div", { className: styles.settingGroup, children: [_jsxs("div", { className: styles.settingTitleRow, children: [_jsx("h3", { className: styles.settingTitle, children: "Command Workflows" }), _jsx("button", { onClick: () => {
439
- setActiveTab('workflowEditor');
440
- onSectionChange?.('workflow-editor');
441
- }, className: styles.copyBtn, children: "Open Workflows" })] }), _jsx("p", { className: `${styles.settingsHint} ${styles.marginBottom12}`, children: "Export standard workflows to your project to verify and commit them." }), _jsxs("div", { className: `${styles.exportRow} ${styles.exportRowGrid}`, children: [_jsxs("div", { className: styles.settingGroup, children: [_jsx("h4", { className: `${styles.settingSubtitle} ${styles.settingSubtitleCustom}`, children: "Target Environment" }), _jsx("div", { className: styles.buttonGrid, children: availableEnvironments.map(env => (_jsxs("button", { onClick: () => onExportEnvironmentChange(env.id), className: `${styles.themeBtn} ${exportEnvironment === env.id ? styles.activeTheme : ''} ${styles.capitalize}`, children: [getIconComponent(env.icon), env.name] }, env.id))) })] }), _jsxs("div", { className: styles.exportItem, children: [_jsxs("div", { className: styles.labelGroupFlex, children: [_jsx("label", { className: styles.label, children: "Workflows" }), _jsxs("span", { className: styles.settingDescription, children: ["Destination: ", _jsx("code", { className: styles.code, children: exportWorkflowsPath })] })] }), _jsxs("div", { className: styles.workflowList, children: [_jsxs("div", { className: styles.workflowActions, children: [_jsx("button", { onClick: handleSelectAllWorkflows, className: styles.textBtn, children: "All" }), _jsx("button", { onClick: handleDeselectAllWorkflows, className: styles.textBtn, children: "None" })] }), _jsx("div", { className: styles.workflowGrid, children: availableWorkflows.length === 0 ? (_jsxs("div", { className: styles.emptyState, children: ["No workflow templates found.", _jsx("button", { onClick: () => onRefreshWorkflows?.(true), className: styles.secondaryBtn, style: { marginTop: '8px' }, children: "Retry Fetch" })] })) : availableWorkflows.map(wf => (_jsxs("label", { className: styles.checkboxLabel, children: [_jsx("input", { type: "checkbox", checked: selectedWorkflows.includes(wf), onChange: () => handleToggleWorkflow(wf) }), wf] }, wf))) })] }), _jsxs("button", { className: `${styles.secondaryHeaderBtn} ${styles.marginTop12}`, onClick: () => onExportWorkflows?.(exportEnvironment, selectedWorkflows), disabled: exportingResource === 'workflows' || selectedWorkflows.length === 0, children: [exportingResource === 'workflows' ? _jsx(Loader2, { size: 14, className: styles.spinner }) : _jsx(FileText, { size: 14 }), "Export Selected (", selectedWorkflows.length, ")"] })] })] }), exportResult && (_jsxs("div", { className: `${exportResult.type === 'success' ? styles.successMessage : styles.errorMessage} ${styles.marginTop12}`, children: [exportResult.type === 'success' ? _jsx(Check, { size: 14 }) : _jsx(AlertTriangle, { size: 14 }), exportResult.message] }))] }) })), activeTab === 'initiatives' && (_jsxs("div", { className: styles.settingGroup, children: [_jsxs("div", { className: styles.settingTitleRow, children: [_jsx("h3", { className: styles.settingTitle, children: "Initiative Templates" }), _jsx("button", { className: styles.copyBtn, onClick: () => { void onRefreshInitiativeTemplates?.(); }, children: "Refresh" })] }), _jsx("p", { className: `${styles.settingsHint} ${styles.marginBottom12}`, children: "Create launch, migration, or incident initiatives with checklist-ready child milestones." }), _jsxs("div", { className: styles.exportItem, children: [_jsx("label", { className: styles.label, children: "Template" }), _jsx("select", { className: styles.input, value: selectedInitiativeTemplateId, onChange: (e) => {
442
- const nextId = e.target.value;
443
- setSelectedInitiativeTemplateId(nextId);
444
- const selected = initiativeTemplates.find(t => t.id === nextId);
445
- if (selected) {
446
- setCloneChecklistDodText((selected.checklistBlocks?.definitionOfDone || []).join('\n'));
447
- setCloneChecklistRollbackText((selected.checklistBlocks?.rollbackPlan || []).join('\n'));
448
- }
449
- }, children: initiativeTemplates.map(template => (_jsx("option", { value: template.id, children: template.name }, template.id))) })] }), _jsxs("div", { className: `${styles.exportItem} ${styles.marginTop12}`, children: [_jsx("label", { className: styles.label, children: "Initiative Title" }), _jsx("input", { className: styles.input, placeholder: "e.g. Taskforce Private Beta Launch", value: initiativeTitle, onChange: (e) => setInitiativeTitle(e.target.value) })] }), _jsxs("div", { className: `${styles.exportItem} ${styles.marginTop12}`, children: [_jsx("label", { className: styles.label, children: "Parent Task ID (optional)" }), _jsx("input", { className: styles.input, placeholder: "task-...", value: initiativeParentTaskId, onChange: (e) => setInitiativeParentTaskId(e.target.value) })] }), _jsxs("button", { className: `${styles.secondaryHeaderBtn} ${styles.marginTop12}`, disabled: isCreatingInitiative || !selectedInitiativeTemplateId || !initiativeTitle.trim() || !onCreateInitiativeFromTemplate, onClick: async () => {
450
- if (!onCreateInitiativeFromTemplate)
451
- return;
452
- setIsCreatingInitiative(true);
453
- const result = await onCreateInitiativeFromTemplate({
454
- templateId: selectedInitiativeTemplateId,
455
- title: initiativeTitle.trim(),
456
- parentTaskId: initiativeParentTaskId.trim() || null
457
- });
458
- setIsCreatingInitiative(false);
459
- setSettingsFeedback({
460
- type: result.success ? 'success' : 'error',
461
- message: result.success
462
- ? 'Initiative created from template.'
463
- : (result.error || 'Failed to create initiative.')
464
- });
465
- }, children: [isCreatingInitiative ? _jsx(Loader2, { size: 14, className: styles.spinner }) : _jsx(Zap, { size: 14 }), "Create Initiative"] }), _jsxs("div", { className: `${styles.exportItem} ${styles.marginTop12}`, children: [_jsx("label", { className: styles.label, children: "Clone Checklists to Children" }), _jsx("input", { className: styles.input, placeholder: "Parent task ID to update children (task-...)", value: cloneChecklistParentTaskId, onChange: (e) => setCloneChecklistParentTaskId(e.target.value) }), _jsx("textarea", { className: `${styles.input} ${styles.marginTop12}`, rows: 4, placeholder: "Definition of Done items, one per line", value: cloneChecklistDodText, onChange: (e) => setCloneChecklistDodText(e.target.value) }), _jsx("textarea", { className: `${styles.input} ${styles.marginTop12}`, rows: 4, placeholder: "Rollback Plan items, one per line", value: cloneChecklistRollbackText, onChange: (e) => setCloneChecklistRollbackText(e.target.value) })] }), _jsxs("button", { className: `${styles.secondaryHeaderBtn} ${styles.marginTop12}`, disabled: isCloningChecklists || !cloneChecklistParentTaskId.trim() || !onCloneChecklistBlocksToChildren, onClick: async () => {
466
- if (!onCloneChecklistBlocksToChildren)
467
- return;
468
- setIsCloningChecklists(true);
469
- const result = await onCloneChecklistBlocksToChildren({
470
- parentTaskId: cloneChecklistParentTaskId.trim(),
471
- checklistBlocks: {
472
- definitionOfDone: cloneChecklistDodText.split('\n').map(s => s.trim()).filter(Boolean),
473
- rollbackPlan: cloneChecklistRollbackText.split('\n').map(s => s.trim()).filter(Boolean)
859
+ }, disabled: !onShowTaskCardStatusLabelChange }), _jsx("span", { children: "Show status label" })] })] })), activeTab === 'appearanceTaskForms' && renderTaskFormsControls(), activeTab === 'commands' && (_jsx(_Fragment, { children: _jsxs("div", { className: styles.settingGroup, children: [_jsx("div", { className: styles.settingTitleRow, children: _jsx("h3", { className: styles.settingTitle, children: "Command Workflows" }) }), _jsx("p", { className: `${styles.settingsHint} ${styles.marginBottom12}`, children: "Export standard workflows to your project to verify and commit them." }), _jsxs("div", { className: `${styles.exportRow} ${styles.exportRowGrid}`, children: [_jsxs("div", { className: styles.settingGroup, children: [_jsx("h4", { className: `${styles.settingSubtitle} ${styles.settingSubtitleCustom}`, children: "Target Environment" }), _jsx("div", { className: styles.buttonGrid, children: availableEnvironments.map(env => (_jsxs("button", { onClick: () => onExportEnvironmentChange(env.id), className: `${styles.themeBtn} ${exportEnvironment === env.id ? styles.activeTheme : ''} ${styles.capitalize}`, children: [getIconComponent(env.icon), env.name] }, env.id))) })] }), _jsxs("div", { className: styles.exportItem, children: [_jsxs("div", { className: styles.labelGroupFlex, children: [_jsx("label", { className: styles.label, children: "Workflows" }), _jsxs("span", { className: styles.settingDescription, children: ["Destination: ", _jsx("code", { className: styles.code, children: exportWorkflowsPath })] })] }), _jsxs("div", { className: styles.workflowList, children: [_jsxs("div", { className: styles.workflowActions, children: [_jsx("button", { onClick: handleSelectAllWorkflows, className: styles.textBtn, children: "All" }), _jsx("button", { onClick: handleDeselectAllWorkflows, className: styles.textBtn, children: "None" })] }), _jsx("div", { className: styles.workflowGrid, children: availableWorkflows.length === 0 ? (_jsxs("div", { className: styles.emptyState, children: ["No workflow templates found.", _jsx("button", { onClick: () => onRefreshWorkflows?.(true), className: styles.secondaryBtn, style: { marginTop: '8px' }, children: "Retry Fetch" })] })) : availableWorkflows.map(wf => (_jsxs("label", { className: styles.checkboxLabel, children: [_jsx("input", { type: "checkbox", checked: selectedWorkflows.includes(wf), onChange: () => handleToggleWorkflow(wf) }), wf] }, wf))) })] }), _jsxs("button", { className: `${styles.secondaryHeaderBtn} ${styles.marginTop12}`, onClick: () => onExportWorkflows?.(exportEnvironment, selectedWorkflows), disabled: exportingResource === 'workflows' || selectedWorkflows.length === 0, children: [exportingResource === 'workflows' ? _jsx(Loader2, { size: 14, className: styles.spinner }) : _jsx(FileText, { size: 14 }), "Export Selected (", selectedWorkflows.length, ")"] })] })] }), exportResult && (_jsxs("div", { className: `${exportResult.type === 'success' ? styles.successMessage : styles.errorMessage} ${styles.marginTop12}`, children: [exportResult.type === 'success' ? _jsx(Check, { size: 14 }) : _jsx(AlertTriangle, { size: 14 }), exportResult.message] }))] }) })), activeTab === 'initiatives' && (_jsxs("div", { className: styles.settingGroup, children: [_jsxs("div", { className: styles.settingTitleRow, children: [_jsx("h3", { className: styles.settingTitle, children: "Initiative Templates" }), _jsx("button", { className: styles.copyBtn, onClick: () => { void onRefreshInitiativeTemplates?.(); }, children: "Refresh" })] }), _jsx("p", { className: `${styles.settingsHint} ${styles.marginBottom12}`, children: "Create launch, migration, or incident initiatives from reusable templates." }), _jsxs("div", { className: styles.exportItem, children: [_jsx("label", { className: styles.label, children: "Template" }), _jsx("select", { className: styles.input, value: selectedInitiativeTemplateId, onChange: (e) => {
860
+ const nextId = e.target.value;
861
+ setSelectedInitiativeTemplateId(nextId);
862
+ }, children: initiativeTemplates.map(template => (_jsx("option", { value: template.id, children: template.name }, template.id))) })] }), _jsxs("div", { className: `${styles.exportItem} ${styles.marginTop12}`, children: [_jsx("label", { className: styles.label, children: "Initiative Title" }), _jsx("input", { className: styles.input, placeholder: "e.g. Taskforce Private Beta Launch", value: initiativeTitle, onChange: (e) => setInitiativeTitle(e.target.value) })] }), _jsxs("button", { className: `${styles.secondaryHeaderBtn} ${styles.marginTop12}`, disabled: isCreatingInitiative || !selectedInitiativeTemplateId || !initiativeTitle.trim() || !onCreateInitiativeFromTemplate, onClick: async () => {
863
+ if (!onCreateInitiativeFromTemplate)
864
+ return;
865
+ setIsCreatingInitiative(true);
866
+ const result = await onCreateInitiativeFromTemplate({
867
+ templateId: selectedInitiativeTemplateId,
868
+ title: initiativeTitle.trim(),
869
+ });
870
+ setIsCreatingInitiative(false);
871
+ setSettingsFeedback({
872
+ type: result.success ? 'success' : 'error',
873
+ message: result.success
874
+ ? 'Initiative created from template.'
875
+ : (result.error || 'Failed to create initiative.')
876
+ });
877
+ }, children: [isCreatingInitiative ? _jsx(Loader2, { size: 14, className: styles.spinner }) : _jsx(Zap, { size: 14 }), "Create Initiative"] })] })), activeTab === 'agents' && (_jsx("div", { className: styles.settingGroup, children: _jsxs("div", { children: [_jsx("h4", { className: styles.settingSubTitle, children: "Registered AI Profiles" }), _jsx("p", { className: `${styles.settingsHint} ${styles.marginBottom12}`, children: "AI agents register profiles when connecting via MCP. Merge duplicates created when a token was lost." }), aiProfilesLoading && (_jsxs("div", { className: styles.settingsHint, children: [_jsx(Loader2, { size: 13, className: styles.spinner }), " Loading profiles\u2026"] })), !aiProfilesLoading && aiProfiles.length === 0 && (_jsx("div", { className: styles.settingsHint, children: "No AI profiles registered yet." })), !aiProfilesLoading && aiProfiles.length > 0 && (() => {
878
+ const byName = new Map();
879
+ for (const p of aiProfiles) {
880
+ const key = p.name.toLowerCase();
881
+ if (!byName.has(key))
882
+ byName.set(key, []);
883
+ byName.get(key).push(p);
474
884
  }
475
- });
476
- setIsCloningChecklists(false);
477
- setSettingsFeedback({
478
- type: result.success ? 'success' : 'error',
479
- message: result.success
480
- ? `Checklist blocks cloned to ${result.updated ?? 0} child task(s).`
481
- : (result.error || 'Failed to clone checklist blocks.')
482
- });
483
- }, children: [isCloningChecklists ? _jsx(Loader2, { size: 14, className: styles.spinner }) : _jsx(Copy, { size: 14 }), "Clone Checklists"] })] })), activeTab === 'workflowEditor' && (_jsx(WorkflowEditorPrototype, { availableWorkflows: availableWorkflows, onFetchWorkflowTemplate: onFetchWorkflowTemplate, onFetchWorkflowOverrideNames: onFetchWorkflowOverrideNames, onSaveWorkflowTemplateDraft: onSaveWorkflowTemplateDraft, onResetWorkflowTemplateDraft: onResetWorkflowTemplateDraft })), activeTab === 'agents' && (_jsxs("div", { className: styles.settingGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "AI Specialists (Agents)" }), _jsx("p", { className: `${styles.settingsHint} ${styles.marginBottom12}`, children: "Export specialist definitions to your project as .md files for AI context." }), _jsx("div", { className: `${styles.exportRow} ${styles.exportRowGrid}`, children: _jsxs("div", { className: styles.exportItem, children: [_jsx("label", { className: styles.label, children: "Specialists Path" }), _jsxs("div", { className: styles.pathInputGroup, children: [_jsx("input", { type: "text", value: exportSpecialistsPath, onChange: (e) => onExportSpecialistsPathChange(e.target.value), className: styles.input }), _jsxs("button", { className: styles.secondaryHeaderBtn, onClick: () => onExportResources('specialists', exportSpecialistsPath), disabled: exportingResource === 'specialists', children: [exportingResource === 'specialists' ? _jsx(Loader2, { size: 14, className: styles.spinner }) : _jsx(Users, { size: 14 }), "Export"] })] })] }) }), exportResult && (_jsxs("div", { className: `${exportResult.type === 'success' ? styles.successMessage : styles.errorMessage} ${styles.marginTop12}`, children: [exportResult.type === 'success' ? _jsx(Check, { size: 14 }) : _jsx(AlertTriangle, { size: 14 }), exportResult.message] }))] })), activeTab === 'taxonomy' && (_jsxs("div", { className: `${styles.settingGroup} ${styles.flex1} ${styles.flexCol}`, children: [_jsx("h3", { className: styles.settingTitle, children: "Taxonomy & Classification" }), _jsx("p", { className: styles.settingsHint, children: "Configure categories, task types, and custom classification systems." }), _jsx(TaxonomyManager, { taxonomies: taxonomies, onUpdateTaxonomies: onUpdateTaxonomies,
484
- // Inject Category and Type managers as system taxonomies
485
- categories: categories, pathValidation: pathValidation, onUpdateCategory: onUpdateCategory, onRemoveCategory: onRemoveCategory, onSaveCategory: onSaveCategory, onAddPath: onAddPath, onRemovePath: onRemovePath, onUpdateCategoryIcon: onUpdateCategoryIcon, onUpdateCategoryColor: onUpdateCategoryColor, onBrowseFolders: handleBrowseFolders, types: types, onSaveType: onSaveType, onRemoveType: onRemoveType, priorities: priorities, onUpdatePriorities: onUpdatePriorities, approaches: approaches, onUpdateApproaches: onUpdateApproaches, manualComplexityEnabled: manualComplexityEnabled, onManualComplexityEnabledChange: async (enabled) => {
486
- const success = await onManualComplexityEnabledChange(enabled);
487
- setSettingsFeedback({
488
- type: success ? 'success' : 'error',
489
- message: success ? 'Project complexity setting saved.' : 'Failed to save project complexity setting.'
490
- });
491
- }, initialTab: (initialSection === 'categories' || initialSection === 'types' || initialSection === 'approaches' || initialSection === 'priorities')
492
- ? initialSection
493
- : undefined })] })), activeTab === 'mcp' && (_jsxs("div", { className: styles.settingsGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "MCP Integrations" }), _jsx("p", { className: styles.settingsHint, children: "Connect Taskforce context to Claude Desktop, Cursor, or other MCP clients. Generated configs include tenant/workspace scope env vars." }), _jsxs("div", { className: `${styles.settingsItem} ${styles.marginTop16}`, children: [_jsxs("div", { className: styles.settingLabelGroup, children: [_jsxs("div", { className: styles.labelGroupFlex, children: [_jsx("label", { className: styles.settingLabel, children: "MCP Path Mapping (Host Root)" }), serverHostRoot && !mcpHostRoot && (_jsx("span", { className: styles.configBadge, children: "Server Configured" }))] }), _jsx("span", { className: styles.settingDescription, children: "If running in Docker, WSL, or Remote Dev, provide the absolute path to this project as seen by your host OS (e.g. Mac/Windows)." })] }), _jsx("div", { className: styles.pathInputWrapper, children: _jsx("input", { type: "text", className: styles.settingInput, placeholder: serverHostRoot || "/Users/username/Projects/my-project or C:\\Projects\\my-project", value: mcpHostRoot || '', onChange: (e) => onMcpHostRootChange?.(e.target.value) }) })] }), _jsxs("div", { className: `${styles.codeBlockWrapper} ${styles.codeBlockWrapperCustom}`, children: [_jsxs("div", { className: styles.codeHeader, children: [_jsx("span", { className: styles.codeLabel, children: "MCP Configuration" }), _jsxs("div", { className: styles.codeHeaderActions, children: [_jsxs("button", { className: `${styles.copyBtn} ${copiedConfig === 'snippet' ? styles.copyBtnActive : ''}`, onClick: () => handleCopyConfig('snippet'), title: "Copy just this server snippet", children: [copiedConfig === 'snippet' ? _jsx(Check, { size: 14 }) : _jsx(Copy, { size: 14 }), copiedConfig === 'snippet' ? 'Snippet Copied!' : 'Copy Snippet'] }), _jsxs("button", { className: `${styles.copyBtn} ${copiedConfig === 'full' ? styles.copyBtnActive : ''}`, onClick: () => handleCopyConfig('full'), title: "Copy full configuration file", children: [copiedConfig === 'full' ? _jsx(Check, { size: 14 }) : _jsx(Copy, { size: 14 }), copiedConfig === 'full' ? 'Config Copied!' : 'Copy Full Config'] })] })] }), _jsx("pre", { className: styles.codeBlock, children: _jsx("code", { children: (() => {
494
- const { serverId, serverConfig } = buildMcpServerConfig();
495
- const dimmed = { color: 'rgba(166, 172, 205, 0.4)' };
496
- const highlighted = { color: 'violet-500', fontWeight: 'bold' };
497
- const bracketColor = { color: 'rgba(166, 172, 205, 0.6)' };
498
- return (_jsxs(_Fragment, { children: [_jsx("span", { style: bracketColor, children: "{" }), "\n ", _jsx("span", { style: dimmed, children: "\"mcpServers\"" }), _jsx("span", { style: dimmed, children: ":" }), " ", _jsx("span", { style: bracketColor, children: "{" }), "\n ", _jsxs("span", { style: highlighted, children: [`"${serverId}"`, ": ", JSON.stringify(serverConfig, null, 2).split('\n').map((line, i) => i === 0 ? line : ' ' + line).join('\n')] }), "\n ", _jsx("span", { style: bracketColor, children: "}" }), "\n", _jsx("span", { style: bracketColor, children: "}" })] }));
499
- })() }) })] }), _jsx("div", { className: `${styles.settingGroup} ${styles.marginTop12}`, children: _jsxs("div", { className: styles.settingLabelGroup, children: [_jsx("label", { className: styles.settingLabel, children: "Installation" }), _jsxs("span", { className: styles.settingDescription, children: ["Taskforce MCP uses the global ", _jsx("code", { children: "taskforce" }), " command. Install with ", _jsx("code", { children: "npm install -g @taskforcehq/taskforce" }), "."] })] }) }), _jsx("div", { className: styles.marginTop12, style: { display: 'flex', gap: '8px' }, children: _jsx("button", { className: `${styles.copyBtn} ${showAdvancedMcp ? styles.copyBtnNeutralActive : ''}`, onClick: () => setShowAdvancedMcp((prev) => !prev), title: "Show advanced MCP install options", children: showAdvancedMcp ? 'Hide Advanced' : 'Show Advanced' }) }), showAdvancedMcp && (_jsxs("div", { className: `${styles.settingGroup} ${styles.marginTop12}`, children: [_jsxs("div", { className: styles.settingLabelGroup, children: [_jsx("label", { className: styles.settingLabel, children: "Advanced Installation Mode" }), _jsx("span", { className: styles.settingDescription, children: "Global mode is recommended. Local / npx is intended for Taskforce development workflows." })] }), _jsxs("div", { className: styles.buttonGrid, children: [_jsx("button", { className: `${styles.themeBtn} ${useGlobalMcp ? styles.activeTheme : ''}`, onClick: () => setUseGlobalMcp(true), children: "Global" }), _jsx("button", { className: `${styles.themeBtn} ${!useGlobalMcp ? styles.activeTheme : ''}`, onClick: () => setUseGlobalMcp(false), children: "Local / npx (Dev)" })] })] }))] }))] })] }));
885
+ return (_jsx("div", { className: styles.aiProfilesList, children: Array.from(byName.entries()).map(([, group]) => (_jsxs("div", { className: `${styles.aiProfileGroup} ${group.length > 1 ? styles.aiProfileGroupDuplicate : ''}`, children: [_jsxs("div", { className: styles.aiProfileGroupHeader, children: [_jsx(Bot, { size: 13, style: { color: group[0].color } }), _jsx("span", { className: styles.aiProfileName, children: group[0].name }), group.length > 1 && (_jsxs("span", { className: styles.aiProfileDuplicateBadge, children: [_jsx(AlertTriangle, { size: 11 }), " ", group.length, " duplicates"] }))] }), _jsxs("div", { className: styles.settingsHint, style: { marginTop: 6 }, children: ["@", group[0].username, group[0].role ? ` · ${group[0].role}` : ''] }), group[0].description && (_jsx("div", { className: styles.settingsHint, style: { marginTop: 4 }, children: group[0].description })), (group[0].provider || group[0].model) && (_jsx("div", { className: styles.settingsHint, style: { marginTop: 4 }, children: [group[0].provider, group[0].model].filter(Boolean).join(' · ') })), group.length > 1 && (_jsxs("div", { className: styles.aiProfileMergeSection, children: [group.map((p) => (_jsxs("div", { className: styles.aiProfileMergeRow, children: [_jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 4 }, children: [_jsx("span", { className: styles.aiProfileIdChip, children: p.id }), _jsxs("span", { className: styles.settingsHint, children: ["@", p.username] })] }), aiProfileMergeState?.keepId !== p.id && (_jsx("button", { className: styles.secondaryHeaderBtn, title: "Keep this profile, merge others into it", onClick: () => {
886
+ const otherId = group.find((x) => x.id !== p.id)?.id;
887
+ if (otherId)
888
+ setAiProfileMergeState({ keepId: p.id, mergeId: otherId });
889
+ }, children: "Keep this" })), aiProfileMergeState?.keepId === p.id && (_jsx("span", { className: styles.aiProfileKeepBadge, children: "\u2713 keeping" }))] }, p.id))), aiProfileMergeState && group.some((p) => p.id === aiProfileMergeState.keepId) && (_jsxs("div", { className: styles.aiProfileMergeActions, children: [_jsxs("button", { className: styles.dangerBtn, onClick: () => doMergeAiProfiles(aiProfileMergeState.keepId, aiProfileMergeState.mergeId), children: ["Merge (keep ", aiProfileMergeState.keepId.slice(-6), ", delete ", aiProfileMergeState.mergeId.slice(-6), ")"] }), _jsx("button", { className: styles.secondaryHeaderBtn, onClick: () => setAiProfileMergeState(null), children: "Cancel" })] }))] }))] }, group[0].id))) }));
890
+ })(), aiProfileMergeStatus && (_jsxs("div", { className: `${aiProfileMergeStatus.type === 'success' ? styles.successMessage : styles.errorMessage} ${styles.marginTop12}`, children: [aiProfileMergeStatus.type === 'success' ? _jsx(Check, { size: 14 }) : _jsx(AlertTriangle, { size: 14 }), aiProfileMergeStatus.message] }))] }) })), activeTab === 'taxonomy' && (_jsxs("div", { className: `${styles.settingGroup} ${styles.flex1} ${styles.flexCol}`, children: [_jsx("h3", { className: styles.settingTitle, children: "Taxonomy & Classification" }), _jsx("p", { className: styles.settingsHint, children: "Configure categories, task types, and custom classification systems." }), _jsx(TaxonomyManager, { taxonomies: taxonomies, onUpdateTaxonomies: onUpdateTaxonomies, onApplySystemTaxonomyPack: onApplySystemTaxonomyPack, taxonomyDisplayLabels: taxonomyDisplayLabels, onUpdateTaxonomyDisplayLabels: onUpdateTaxonomyDisplayLabels,
891
+ // Inject Category and Type managers as system taxonomies
892
+ categories: categories, pathValidation: pathValidation, onUpdateCategory: onUpdateCategory, onRemoveCategory: onRemoveCategory, onSaveCategory: onSaveCategory, onAddPath: onAddPath, onRemovePath: onRemovePath, onUpdateCategoryIcon: onUpdateCategoryIcon, onUpdateCategoryColor: onUpdateCategoryColor, onBrowseFolders: handleBrowseFolders, types: types, onSaveType: onSaveType, onRemoveType: onRemoveType, onUpdateType: onUpdateType, priorities: priorities, onUpdatePriorities: onUpdatePriorities, onAnalyzeSystemTaxonomyPack: onAnalyzeSystemTaxonomyPack, manualComplexityEnabled: manualComplexityEnabled, onManualComplexityEnabledChange: async (enabled) => {
893
+ const success = await onManualComplexityEnabledChange(enabled);
894
+ setSettingsFeedback({
895
+ type: success ? 'success' : 'error',
896
+ message: success ? 'Project complexity setting saved.' : 'Failed to save project complexity setting.'
897
+ });
898
+ }, initialTab: (initialSection === 'categories' || initialSection === 'types' || initialSection === 'priorities')
899
+ ? initialSection
900
+ : undefined })] })), activeTab === 'mcp' && (_jsxs("div", { className: styles.settingsGroup, children: [showMcpModeToggle && (_jsxs("div", { className: styles.settingsTabs, children: [_jsx("button", { className: `${styles.settingsTabBtn} ${selectedMcpMode === 'cloud' ? styles.settingsTabBtnActive : ''}`, onClick: () => setSelectedMcpMode('cloud'), children: "Cloud MCP" }), _jsx("button", { className: `${styles.settingsTabBtn} ${selectedMcpMode === 'local' ? styles.settingsTabBtnActive : ''}`, onClick: () => setSelectedMcpMode('local'), children: "Local MCP" })] })), showCloudMcp && (_jsx(_Fragment, { children: selectedMcpClientUsesOAuth ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: `${styles.settingGroup} ${styles.marginTop16}`, children: [_jsxs("div", { className: styles.settingLabelGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "OAuth Connector Setup" }), _jsx("span", { className: styles.settingDescription, children: selectedMcpClient === 'chatgpt-desktop'
901
+ ? 'ChatGPT Desktop uses the Taskforce OAuth connector flow instead of a personal MCP token.'
902
+ : 'Claude Desktop uses the Taskforce OAuth connector flow instead of a personal MCP token.' })] }), _jsx("div", { className: `${selectedConnectorGrant ? styles.successMessage : styles.settingHelper} ${styles.marginTop12}`, children: selectedConnectorGrant ? (_jsxs(_Fragment, { children: [_jsx(Check, { size: 14 }), _jsxs("div", { children: [_jsx("div", { children: "Connector already authorized for this workspace." }), _jsxs("div", { className: styles.settingHelper, children: ["Last used ", selectedConnectorGrant.lastUsedAt
903
+ ? new Date(selectedConnectorGrant.lastUsedAt).toLocaleString()
904
+ : 'not yet'] })] })] })) : ('No active connector authorization for this workspace yet.') }), _jsx("div", { className: styles.settingDescription, style: { marginTop: '12px' }, children: "Use the server URL above in your client, then finish the OAuth authorization flow from the Integrations tab." }), _jsx("div", { style: { display: 'flex', justifyContent: 'flex-end', width: '100%', marginTop: '12px' }, children: _jsx("button", { className: styles.copyBtn, onClick: () => setActiveTab('integrations'), children: "Open Integrations" }) })] }), _jsxs("div", { className: `${styles.settingGroup} ${styles.marginTop16}`, children: [_jsxs("div", { className: `${styles.codeBlockWrapper} ${styles.codeBlockWrapperCustom} ${styles.marginTop12}`, style: { minHeight: '260px' }, children: [_jsxs("div", { className: styles.codeHeader, children: [_jsx("span", { className: styles.codeLabel, children: "Cloud MCP Configuration" }), _jsxs("div", { className: styles.codeHeaderActions, children: [_jsx("select", { className: styles.settingInput, value: selectedMcpClient, onChange: (e) => setSelectedMcpClient(e.target.value), "aria-label": "MCP client", style: { width: 'auto', minWidth: '170px', padding: '6px 12px', fontSize: '12px', borderRadius: '8px' }, children: MCP_CLIENT_OPTIONS.map((option) => (_jsx("option", { value: option.id, disabled: option.disabled, children: option.label }, option.id))) }), _jsx("button", { className: `${styles.copyBtn} ${copiedConfig === 'full' ? styles.copyBtnActive : ''}`, onClick: handleCopyCloudMcpConfig, title: "Copy full configuration file", children: copiedConfig === 'full' ? _jsx(Check, { size: 14 }) : _jsx(Copy, { size: 14 }) })] })] }), _jsx("pre", { className: styles.codeBlock, children: _jsx("code", { children: cloudMcpServerConfig
905
+ ? renderMcpConfigBlock(cloudMcpServerId, cloudMcpServerConfig, cloudClientIntegration.rootKey || 'mcpServers', cloudClientIntegration.wrapperKeys || [])
906
+ : renderTextConfigBlock(cloudClientIntegration.renderedText || '') }) })] }), _jsxs("div", { className: `${styles.codeBlockWrapper} ${styles.marginTop12}`, children: [_jsx("div", { className: styles.codeHeader, children: _jsx("span", { className: styles.codeLabel, children: cloudClientIntegration.instructionLabel }) }), _jsx("div", { style: { padding: '16px 20px' }, children: _jsx("div", { className: styles.settingDescription, children: cloudClientIntegration.instructionText }) })] })] })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: `${styles.settingGroup} ${styles.marginTop16}`, children: [_jsxs("div", { className: styles.settingLabelGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Generate Token" }), _jsx("span", { className: styles.settingDescription, children: "Tokens are shown once. Default scopes allow task read/write. Add workspace read if you want config and skills metadata in the client." })] }), _jsxs("div", { style: { display: 'grid', gridTemplateColumns: 'minmax(0, 2fr) minmax(220px, 1fr)', gap: '12px', alignItems: 'end' }, children: [_jsxs("div", { className: styles.settingsItem, children: [_jsx("div", { className: styles.settingLabelGroup, children: _jsx("span", { className: styles.settingDescription, children: "Token Name" }) }), _jsx("input", { type: "text", className: styles.settingInput, placeholder: "Cursor on MacBook", value: newTokenName, onChange: (e) => setNewTokenName(e.target.value) })] }), _jsxs("div", { className: styles.settingsItem, children: [_jsx("div", { className: styles.settingLabelGroup, children: _jsx("span", { className: styles.settingDescription, children: "Expiry (Optional)" }) }), _jsx("input", { type: "date", className: `${styles.settingInput} ${styles.taskFormDateInput}`, value: newTokenExpiresAt, onChange: (e) => setNewTokenExpiresAt(e.target.value) })] })] }), _jsxs("div", { className: `${styles.settingsItem} ${styles.marginTop12}`, children: [_jsx("div", { className: styles.settingLabelGroup, children: _jsx("span", { className: styles.settingDescription, children: "Scopes" }) }), _jsxs("div", { style: { display: 'grid', gridTemplateColumns: '96px repeat(3, minmax(110px, 1fr))', gap: '10px 16px', alignItems: 'center' }, children: [_jsx("span", {}), _jsx("span", { className: styles.settingDescription, children: "Tasks" }), _jsx("span", { className: styles.settingDescription, children: "Workspace" }), _jsx("span", { className: styles.settingDescription, style: { opacity: 0.55 }, children: "Attachments" }), _jsx("span", { className: styles.settingDescription, children: "Read" }), _jsx("label", { className: styles.checkboxLabel, children: _jsx("input", { type: "checkbox", className: styles.checkboxSmall, checked: newTokenScopes.includes('tasks:read'), onChange: () => toggleTokenScope('tasks:read') }) }), _jsx("label", { className: styles.checkboxLabel, children: _jsx("input", { type: "checkbox", className: styles.checkboxSmall, checked: newTokenScopes.includes('workspace:read'), onChange: () => toggleTokenScope('workspace:read') }) }), _jsx("label", { className: styles.checkboxLabel, style: { opacity: 0.55 }, children: _jsx("input", { type: "checkbox", className: styles.checkboxSmall, checked: false, disabled: true }) }), _jsx("span", { className: styles.settingDescription, children: "Write" }), _jsx("label", { className: styles.checkboxLabel, children: _jsx("input", { type: "checkbox", className: styles.checkboxSmall, checked: newTokenScopes.includes('tasks:write'), onChange: () => toggleTokenScope('tasks:write') }) }), _jsx("label", { className: styles.checkboxLabel, children: _jsx("input", { type: "checkbox", className: styles.checkboxSmall, checked: false, disabled: true }) }), _jsx("label", { className: styles.checkboxLabel, style: { opacity: 0.55 }, children: _jsx("input", { type: "checkbox", className: styles.checkboxSmall, checked: false, disabled: true }) })] })] })] }), _jsxs("div", { className: `${styles.settingGroup} ${styles.marginTop16}`, children: [_jsxs("div", { className: styles.settingLabelGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Automation Identity (Optional)" }), _jsx("span", { className: styles.settingDescription, children: "For recurring or background AI workers, set an AI name here so the generated MCP config includes Taskforce automation headers. After the first run, paste the returned profile token too so the same AI profile is reused across runs without extra bootstrap steps." })] }), aiProfiles.length > 0 && (_jsxs("div", { className: `${styles.settingsItem} ${styles.marginTop12}`, children: [_jsx("div", { className: styles.settingLabelGroup, children: _jsx("span", { className: styles.settingDescription, children: "Use Existing AI Profile" }) }), _jsxs("select", { className: styles.settingInput, "aria-label": "Use existing AI profile", value: selectedAutomationProfileId, onChange: (e) => {
907
+ const nextId = e.target.value;
908
+ if (!nextId) {
909
+ setAutomationAiName('');
910
+ setAutomationAiProfileToken('');
911
+ return;
912
+ }
913
+ const profile = aiProfiles.find((entry) => entry.id === nextId);
914
+ if (!profile)
915
+ return;
916
+ setAutomationAiName(profile.name);
917
+ setAutomationAiProfileToken(String(profile.profileToken || ''));
918
+ }, children: [_jsx("option", { value: "", children: "Custom\u2026" }), aiProfiles.map((profile) => (_jsxs("option", { value: profile.id, children: [profile.name, " (@", profile.username, ")"] }, profile.id)))] })] })), _jsxs("div", { style: { display: 'grid', gridTemplateColumns: 'minmax(0, 1fr) minmax(0, 1fr)', gap: '12px', alignItems: 'end' }, children: [_jsxs("div", { className: styles.settingsItem, children: [_jsx("div", { className: styles.settingLabelGroup, children: _jsx("span", { className: styles.settingDescription, children: "AI Name Header" }) }), _jsx("input", { type: "text", className: styles.settingInput, placeholder: "Automation Codex", value: automationAiName, onChange: (e) => setAutomationAiName(e.target.value) })] }), _jsxs("div", { className: styles.settingsItem, children: [_jsx("div", { className: styles.settingLabelGroup, children: _jsx("span", { className: styles.settingDescription, children: "AI Profile Token Header" }) }), _jsx("input", { type: "text", className: styles.settingInput, placeholder: "tfp_...", value: automationAiProfileToken, onChange: (e) => setAutomationAiProfileToken(e.target.value) })] })] })] }), _jsxs("div", { className: `${styles.settingGroup} ${styles.marginTop16}`, children: [_jsx("div", { className: styles.settingHelper, children: "Generated tokens are only shown once. Copy the token before leaving this page." }), (() => {
919
+ const displayedGeneratedToken = copiedConfig === 'token'
920
+ ? 'Copied to clipboard'
921
+ : (generatedTokenValue || '');
922
+ return (_jsx("div", { style: { display: 'flex', gap: '8px', alignItems: 'stretch' }, children: _jsx("div", { className: styles.codeBlockWrapper, style: { flex: 1, cursor: generatedTokenValue ? 'pointer' : 'default' }, onClick: () => generatedTokenValue && copyToClipboard(generatedTokenValue, 'token'), role: generatedTokenValue ? 'button' : undefined, tabIndex: generatedTokenValue ? 0 : -1, onKeyDown: (e) => {
923
+ if (!generatedTokenValue)
924
+ return;
925
+ if (e.key === 'Enter' || e.key === ' ') {
926
+ e.preventDefault();
927
+ copyToClipboard(generatedTokenValue, 'token');
928
+ }
929
+ }, title: generatedTokenValue ? (copiedConfig === 'token' ? 'Token copied' : 'Click to copy token') : undefined, children: _jsx("pre", { className: styles.codeBlock, style: { textAlign: 'center' }, children: _jsx("code", { children: displayedGeneratedToken }) }) }) }));
930
+ })()] }), _jsxs("div", { className: `${styles.settingGroup} ${styles.marginTop16}`, children: [mcpTokenNotice?.type === 'error' && (_jsxs("div", { className: `${styles.errorMessage} ${styles.marginTop12}`, children: [_jsx(AlertTriangle, { size: 14 }), mcpTokenNotice.message] })), _jsxs("div", { className: `${styles.codeBlockWrapper} ${styles.codeBlockWrapperCustom} ${styles.marginTop12}`, style: { minHeight: '260px' }, children: [_jsxs("div", { className: styles.codeHeader, children: [_jsx("span", { className: styles.codeLabel, children: "Cloud MCP Configuration" }), _jsxs("div", { className: styles.codeHeaderActions, children: [_jsx("select", { className: styles.settingInput, value: selectedMcpClient, onChange: (e) => setSelectedMcpClient(e.target.value), "aria-label": "MCP client", style: { width: 'auto', minWidth: '170px', padding: '6px 12px', fontSize: '12px', borderRadius: '8px' }, children: MCP_CLIENT_OPTIONS.map((option) => (_jsx("option", { value: option.id, disabled: option.disabled, children: option.label }, option.id))) }), _jsxs("button", { className: styles.copyBtn, onClick: () => void handleCreateMcpToken(), disabled: mcpActionBusyId === 'create', title: "Generate Token", "aria-label": "Generate Token", children: [mcpActionBusyId === 'create' ? _jsx(Loader2, { size: 14, className: styles.spinIcon }) : _jsx(Zap, { size: 14 }), _jsx("span", { children: "GENERATE TOKEN" })] }), _jsx("button", { className: `${styles.copyBtn} ${copiedConfig === 'full' ? styles.copyBtnActive : ''}`, onClick: handleCopyCloudMcpConfig, title: "Copy full configuration file", children: copiedConfig === 'full' ? _jsx(Check, { size: 14 }) : _jsx(Copy, { size: 14 }) })] })] }), _jsx("pre", { className: styles.codeBlock, children: _jsx("code", { children: cloudMcpServerConfig
931
+ ? renderMcpConfigBlock(cloudMcpServerId, cloudMcpServerConfig, cloudClientIntegration.rootKey || 'mcpServers', cloudClientIntegration.wrapperKeys || [])
932
+ : renderTextConfigBlock(cloudClientIntegration.renderedText || '') }) })] }), _jsxs("div", { className: `${styles.codeBlockWrapper} ${styles.marginTop12}`, children: [_jsx("div", { className: styles.codeHeader, children: _jsx("span", { className: styles.codeLabel, children: cloudClientIntegration.instructionLabel }) }), _jsx("div", { style: { padding: '16px 20px' }, children: _jsx("div", { className: styles.settingDescription, children: cloudClientIntegration.instructionText }) })] })] }), _jsxs("div", { className: `${styles.settingGroup} ${styles.marginTop16}`, children: [_jsxs("div", { className: styles.toggleHeading, onClick: () => setShowMcpConnectionTest((prev) => !prev), onKeyDown: (e) => {
933
+ if (e.key === 'Enter' || e.key === ' ') {
934
+ e.preventDefault();
935
+ setShowMcpConnectionTest((prev) => !prev);
936
+ }
937
+ }, role: "button", tabIndex: 0, title: showMcpConnectionTest ? 'Hide connection test' : 'Show connection test', children: [_jsx("label", { className: styles.label, children: "Test Connection" }), showMcpConnectionTest ? _jsx(ChevronDown, { size: 14 }) : _jsx(ChevronRight, { size: 14 })] }), showMcpConnectionTest && (_jsxs(_Fragment, { children: [_jsx("div", { className: `${styles.settingDescription} ${styles.marginTop12}`, children: "Validate that a token works for this workspace before you paste it into your MCP client." }), _jsxs("div", { className: `${styles.settingsItem} ${styles.marginTop12}`, children: [_jsx("div", { className: styles.settingLabelGroup, children: _jsx("span", { className: styles.settingDescription, children: "Token to Test" }) }), _jsx("input", { type: "text", className: styles.settingInput, placeholder: "tfmcp_xxxxx_replace-me", value: mcpConnectionToken, onChange: (e) => {
938
+ setMcpConnectionToken(e.target.value);
939
+ setMcpConnectionResult(null);
940
+ } })] }), _jsxs("div", { className: styles.marginTop12, style: { display: 'flex', gap: '8px', flexWrap: 'wrap', justifyContent: 'flex-end' }, children: [generatedTokenValue && (_jsx("button", { className: styles.copyBtn, onClick: () => {
941
+ setMcpConnectionToken(generatedTokenValue);
942
+ setMcpConnectionResult(null);
943
+ }, children: "Use Generated Token" })), _jsxs("button", { className: styles.copyBtn, onClick: () => void handleTestMcpConnection(), disabled: mcpConnectionBusy, children: [mcpConnectionBusy ? _jsx(Loader2, { size: 14, className: styles.spinIcon }) : _jsx(Zap, { size: 14 }), "Test Connection"] })] }), mcpConnectionResult && (_jsxs("div", { className: `${mcpConnectionResult.type === 'success' ? styles.successMessage : styles.errorMessage} ${styles.marginTop12}`, children: [mcpConnectionResult.type === 'success' ? _jsx(Check, { size: 14 }) : _jsx(AlertTriangle, { size: 14 }), _jsxs("div", { children: [_jsx("div", { children: mcpConnectionResult.message }), mcpConnectionResult.type === 'success' && (mcpConnectionResult.workspaceName || mcpConnectionResult.workspaceId) && (_jsxs("div", { className: styles.settingHelper, children: ["Workspace: ", mcpConnectionResult.workspaceName || mcpConnectionResult.workspaceId, mcpConnectionResult.workspaceId ? ` (${mcpConnectionResult.workspaceId})` : ''] })), mcpConnectionResult.type === 'success' && Array.isArray(mcpConnectionResult.scopes) && mcpConnectionResult.scopes.length > 0 && (_jsxs("div", { className: styles.settingHelper, children: ["Granted scopes: ", mcpConnectionResult.scopes.join(', ')] }))] })] }))] }))] }), _jsxs("div", { className: `${styles.settingGroup} ${styles.marginTop16}`, children: [_jsxs("div", { className: styles.toggleHeading, onClick: () => setShowMcpTokensList((prev) => !prev), onKeyDown: (e) => {
944
+ if (e.key === 'Enter' || e.key === ' ') {
945
+ e.preventDefault();
946
+ setShowMcpTokensList((prev) => !prev);
947
+ }
948
+ }, role: "button", tabIndex: 0, title: showMcpTokensList ? 'Hide workspace tokens' : 'Show workspace tokens', children: [_jsx("label", { className: styles.label, children: "Your Tokens" }), showMcpTokensList ? _jsx(ChevronDown, { size: 14 }) : _jsx(ChevronRight, { size: 14 })] }), showMcpTokensList && (_jsxs(_Fragment, { children: [_jsx("div", { className: `${styles.settingDescription} ${styles.marginTop12}`, children: "Manage tokens created for this workspace." }), mcpTokensLoading ? (_jsx("p", { className: styles.settingHelper, children: "Loading tokens\u2026" })) : mcpTokensError ? (_jsxs("div", { className: styles.errorMessage, children: [_jsx(AlertTriangle, { size: 14 }), mcpTokensError] })) : mcpTokens.length === 0 ? (_jsx("p", { className: styles.settingHelper, children: "No MCP tokens yet." })) : (_jsx("div", { className: styles.settingGroup, children: sortedMcpTokens.map((token) => (_jsxs("div", { className: `${styles.settingsItem} ${styles.marginTop12}`, style: {
949
+ padding: '14px 16px',
950
+ borderRadius: '12px',
951
+ border: '1px solid var(--border-primary, rgba(255, 255, 255, 0.1))',
952
+ background: 'rgba(255, 255, 255, 0.03)'
953
+ }, children: [_jsxs("div", { className: styles.settingLabelGroup, children: [_jsxs("div", { className: styles.labelGroupFlex, children: [_jsx("label", { className: styles.settingLabel, children: token.name }), _jsx("span", { className: `${styles.configBadge} ${token.status === 'revoked' ? styles.configBadgeRevoked : token.status === 'expired' ? styles.configBadgeExpired : styles.configBadgeActive}`, children: token.status })] }), _jsx("span", { className: styles.settingDescription, style: { fontFamily: '"JetBrains Mono", "Fira Code", monospace' }, children: token.tokenPrefix }), _jsxs("span", { className: styles.settingDescription, children: ["Scopes: ", token.scopes.join(', ')] }), _jsxs("span", { className: styles.settingDescription, children: ["Created ", new Date(token.createdAt).toLocaleDateString(), token.lastUsedAt ? ` · Last used ${new Date(token.lastUsedAt).toLocaleString()}` : ' · Never used'] })] }), _jsxs("div", { style: { display: 'flex', gap: '8px', flexWrap: 'wrap', justifyContent: 'flex-end' }, children: [token.status !== 'revoked' && (_jsx("button", { className: styles.copyBtn, onClick: () => void handleMcpTokenAction(token.id, 'regenerate'), disabled: mcpActionBusyId === `regenerate:${token.id}`, children: "Regenerate" })), token.status === 'active' && (_jsx("button", { className: styles.copyBtn, onClick: () => void handleMcpTokenAction(token.id, 'revoke'), disabled: mcpActionBusyId === `revoke:${token.id}`, children: "Revoke" }))] })] }, token.id))) }))] }))] })] })) })), showLocalMcp && (_jsxs(_Fragment, { children: [_jsx("div", { className: `${styles.settingGroup} ${styles.marginTop16}`, children: _jsxs("div", { className: styles.settingLabelGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Local MCP" }), _jsx("span", { className: styles.settingDescription, children: "Local MCP runs over stdio and does not require a cloud token. Use this for Codex, Claude Code CLI, Gemini CLI, and similar local MCP clients." })] }) }), _jsxs("div", { className: `${styles.codeBlockWrapper} ${styles.codeBlockWrapperCustom}`, children: [_jsxs("div", { className: styles.codeHeader, children: [_jsx("span", { className: styles.codeLabel, children: "Local MCP Configuration" }), _jsx("div", { className: styles.codeHeaderActions, children: _jsx("button", { className: `${styles.copyBtn} ${copiedConfig === 'full' ? styles.copyBtnActive : ''}`, onClick: () => handleCopyConfig('full'), title: "Copy full configuration file", children: copiedConfig === 'full' ? _jsx(Check, { size: 14 }) : _jsx(Copy, { size: 14 }) }) })] }), _jsx("pre", { className: styles.codeBlock, children: _jsx("code", { children: (() => {
954
+ const { serverId, serverConfig } = buildMcpServerConfig();
955
+ return renderMcpConfigBlock(serverId, serverConfig);
956
+ })() }) })] }), _jsx("div", { className: `${styles.settingGroup} ${styles.marginTop12}`, children: _jsxs("div", { className: styles.toggleHeading, onClick: () => setShowAdvancedMcp((prev) => !prev), onKeyDown: (e) => {
957
+ if (e.key === 'Enter' || e.key === ' ') {
958
+ e.preventDefault();
959
+ setShowAdvancedMcp((prev) => !prev);
960
+ }
961
+ }, role: "button", tabIndex: 0, title: "Show advanced MCP install options", children: [_jsx("label", { className: styles.label, children: "Advanced" }), showAdvancedMcp ? _jsx(ChevronDown, { size: 14 }) : _jsx(ChevronRight, { size: 14 })] }) }), showAdvancedMcp && (_jsxs("div", { className: `${styles.settingGroup} ${styles.marginTop12}`, children: [_jsxs("div", { className: styles.settingLabelGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Advanced Installation Mode" }), _jsx("span", { className: styles.settingDescription, children: "Global mode is recommended. Local / npx is intended for Taskforce development workflows." })] }), _jsxs("div", { className: styles.buttonGrid, children: [_jsx("button", { className: `${styles.themeBtn} ${useGlobalMcp ? styles.activeTheme : ''}`, onClick: () => setUseGlobalMcp(true), children: "Global" }), _jsx("button", { className: `${styles.themeBtn} ${!useGlobalMcp ? styles.activeTheme : ''}`, onClick: () => setUseGlobalMcp(false), children: "Local / npx (Dev)" })] }), _jsxs("div", { className: `${styles.settingsItem} ${styles.marginTop16}`, children: [_jsxs("div", { className: styles.settingLabelGroup, children: [_jsxs("div", { className: styles.labelGroupFlex, children: [_jsx("label", { className: styles.settingLabel, children: "MCP Path Mapping (Host Root)" }), serverHostRoot && !mcpHostRoot && (_jsx("span", { className: styles.configBadge, children: "Server Configured" }))] }), _jsx("span", { className: styles.settingDescription, children: "If running in Docker, WSL, or Remote Dev, provide the absolute path to this project as seen by your host OS." })] }), _jsx("div", { className: styles.pathInputWrapper, children: _jsx("input", { type: "text", className: styles.settingInput, placeholder: serverHostRoot || "/Users/username/Projects/my-project or C:\\Projects\\my-project", value: mcpHostRoot || '', onChange: (e) => onMcpHostRootChange?.(e.target.value) }) })] })] }))] }))] })), activeTab === 'integrations' && (_jsxs("div", { className: styles.settingsGroup, children: [_jsx("div", { className: styles.settingGroup, children: _jsxs("div", { className: styles.settingLabelGroup, children: [_jsx("h3", { className: styles.settingTitle, children: "Integrations" }), _jsx("span", { className: styles.settingDescription, children: "Manage OAuth-based app connectors separately from MCP tokens and local client setup." })] }) }), _jsxs("div", { className: `${styles.settingGroup} ${styles.marginTop16}`, children: [[
962
+ {
963
+ key: 'chatgpt',
964
+ label: 'ChatGPT Connector',
965
+ description: 'Use the dedicated MCP host in ChatGPT Apps & Connectors. Taskforce handles OAuth and binds each connector authorization to one workspace.',
966
+ emptyMessage: 'No active ChatGPT connector grant for this workspace yet.',
967
+ connector: activeChatGptConnector
968
+ },
969
+ {
970
+ key: 'claude',
971
+ label: 'Claude Desktop Connector',
972
+ description: 'Use the dedicated MCP host in Claude Desktop Settings > Connectors. Taskforce handles OAuth and binds each connector authorization to one workspace.',
973
+ emptyMessage: 'No active Claude Desktop connector grant for this workspace yet.',
974
+ connector: activeClaudeConnector
975
+ }
976
+ ].map((item) => {
977
+ const connector = item.connector;
978
+ return (_jsxs("div", { className: `${styles.settingsItem} ${styles.marginTop12}`, style: {
979
+ padding: '16px',
980
+ borderRadius: '14px',
981
+ border: '1px solid var(--border-primary, rgba(255, 255, 255, 0.1))',
982
+ background: 'rgba(255, 255, 255, 0.03)'
983
+ }, children: [_jsxs("div", { className: styles.settingLabelGroup, children: [_jsxs("div", { className: styles.labelGroupFlex, children: [_jsx("label", { className: styles.settingLabel, children: item.label }), _jsx("span", { className: `${styles.configBadge} ${connector ? styles.configBadgeActive : styles.configBadgeRevoked}`, children: connector ? 'connected' : 'not connected' })] }), _jsx("span", { className: styles.settingDescription, children: item.description }), _jsx("span", { className: styles.settingDescription, style: { fontFamily: '"JetBrains Mono", "Fira Code", monospace' }, children: cloudMcpEndpoint }), connector ? (_jsxs(_Fragment, { children: [_jsxs("span", { className: styles.settingDescription, children: ["Authorized workspace: ", currentWorkspaceName || connector.workspaceId] }), _jsxs("span", { className: styles.settingDescription, children: ["Granted scopes: ", connector.scopes.join(', ')] }), _jsxs("span", { className: styles.settingDescription, children: ["Connected ", new Date(connector.createdAt).toLocaleString(), connector.lastUsedAt ? ` · Last used ${new Date(connector.lastUsedAt).toLocaleString()}` : ' · Never used'] })] })) : (_jsx("span", { className: styles.settingDescription, children: item.emptyMessage }))] }), _jsx("div", { style: { display: 'flex', justifyContent: 'flex-end', gap: '8px', flexWrap: 'wrap' }, children: connector && (_jsxs("button", { className: styles.copyBtn, onClick: () => void handleDisconnectConnector(connector.id), disabled: mcpConnectorBusyId === connector.id, children: [mcpConnectorBusyId === connector.id ? _jsx(Loader2, { size: 14, className: styles.spinIcon }) : _jsx(Trash2, { size: 14 }), "Disconnect"] })) })] }, item.key));
984
+ }), mcpConnectorsLoading && (_jsx("p", { className: `${styles.settingHelper} ${styles.marginTop12}`, children: "Loading connector grants\u2026" })), mcpConnectorsError && (_jsxs("div", { className: `${styles.errorMessage} ${styles.marginTop12}`, children: [_jsx(AlertTriangle, { size: 14 }), mcpConnectorsError] }))] })] }))] })] }) }));
500
985
  }