@taskforcehq/taskforce 0.3.328 → 0.3.329

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 (264) hide show
  1. package/dist/Taskforce.module.css +233 -34
  2. package/dist/TaskforceCore.js +237 -230
  3. package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.js +1 -1
  4. package/dist/cli.js +34 -0
  5. package/dist/cliCloudTargetGuard.d.ts +5 -0
  6. package/dist/cliCloudTargetGuard.js +11 -0
  7. package/dist/components/features/AnnotatedAttachmentWorkspace.js +24 -8
  8. package/dist/components/features/TaskSettings.d.ts +12 -1
  9. package/dist/components/features/TaskSettings.js +147 -40
  10. package/dist/components/features/agentCapabilities/AgentCapabilitiesPrototype.d.ts +1 -1
  11. package/dist/components/features/planning/PlanningModule.js +2 -5
  12. package/dist/components/features/planning/PlanningTaskOrderList.d.ts +1 -1
  13. package/dist/components/features/planning/PlanningTaskOrderList.js +17 -6
  14. package/dist/components/features/planning/planningTaskArrangement.d.ts +1 -0
  15. package/dist/components/features/planning/planningTaskArrangement.js +5 -5
  16. package/dist/components/features/taskforceAgentEditorModel.js +3 -1
  17. package/dist/components/task/TaskCard.d.ts +5 -0
  18. package/dist/components/task/TaskCard.js +65 -10
  19. package/dist/components/task/TaskImageReviews.js +14 -5
  20. package/dist/components/task/TaskKanban.d.ts +6 -1
  21. package/dist/components/task/TaskKanban.js +152 -6
  22. package/dist/components/task/TaskList.d.ts +5 -0
  23. package/dist/components/task/TaskList.js +3 -3
  24. package/dist/components/ui/PasswordInput.d.ts +6 -0
  25. package/dist/components/ui/PasswordInput.js +11 -0
  26. package/dist/components/ui/TopNoticeLayer.js +1 -1
  27. package/dist/components/views/AppShellHeader.js +32 -11
  28. package/dist/components/views/PlanComparisonPage.js +12 -0
  29. package/dist/components/views/StandaloneLayout.js +7 -31
  30. package/dist/components/views/WidgetView.js +3 -3
  31. package/dist/components/views/panels/PlanningDrawer.js +5 -12
  32. package/dist/components/views/standalone/modals/AccountSettingsModal.js +26 -17
  33. package/dist/config/envSchema.js +12 -0
  34. package/dist/config/localServiceRuntimeContract.d.ts +13 -0
  35. package/dist/config/localServiceRuntimeContract.js +135 -0
  36. package/dist/core/AiProfileService.js +46 -8
  37. package/dist/core/DeletedTaskLifecycleService.d.ts +1 -0
  38. package/dist/core/DeletedTaskLifecycleService.js +37 -6
  39. package/dist/core/TaskAttachmentLinksDurableMutationService.d.ts +3 -2
  40. package/dist/core/TaskAttachmentLinksDurableMutationService.js +33 -9
  41. package/dist/core/Taskforce.d.ts +62 -2
  42. package/dist/core/Taskforce.js +635 -32
  43. package/dist/core/types.d.ts +6 -0
  44. package/dist/hooks/sync/useDurableLocalOutboxDrain.d.ts +1 -1
  45. package/dist/hooks/sync/useDurableTaskCreateMutation.js +1 -1
  46. package/dist/hooks/sync/useDurableTaskMetadataMutation.d.ts +1 -0
  47. package/dist/hooks/sync/useDurableTaskMetadataMutation.js +1 -0
  48. package/dist/hooks/sync/useDurableTaskStatusMutation.d.ts +1 -0
  49. package/dist/hooks/tasks/taskHttpMutation.js +1 -0
  50. package/dist/hooks/tasks/useCloudTaskSearch.d.ts +12 -0
  51. package/dist/hooks/tasks/useCloudTaskSearch.js +71 -0
  52. package/dist/hooks/tasks/useTaskDescriptionImageDraftRecovery.d.ts +16 -0
  53. package/dist/hooks/tasks/useTaskDescriptionImageDraftRecovery.js +197 -0
  54. package/dist/hooks/tasks/useTaskEditorNavigation.d.ts +16 -3
  55. package/dist/hooks/tasks/useTaskEditorNavigation.js +72 -13
  56. package/dist/hooks/tasks/useTaskFormActions.d.ts +6 -0
  57. package/dist/hooks/tasks/useTaskFormActions.js +65 -12
  58. package/dist/hooks/ui/useSettingsModel.d.ts +24 -2
  59. package/dist/hooks/ui/useSettingsModel.js +13 -2
  60. package/dist/hooks/ui/useSettingsPersistence.d.ts +12 -1
  61. package/dist/hooks/ui/useSettingsPersistence.js +74 -47
  62. package/dist/hooks/useFilterSort.d.ts +7 -3
  63. package/dist/hooks/useFilterSort.js +15 -5
  64. package/dist/hooks/useTaskData.d.ts +10 -1
  65. package/dist/hooks/useTaskData.js +216 -7
  66. package/dist/hooks/useTaskMutations.d.ts +10 -2
  67. package/dist/hooks/useTaskMutations.js +223 -43
  68. package/dist/hooks/useTaskforce.d.ts +37 -9
  69. package/dist/hooks/useTaskforce.js +349 -39
  70. package/dist/hooks/useUiNotice.d.ts +4 -0
  71. package/dist/hooks/useUiNotice.js +4 -0
  72. package/dist/mcp/adminWorkspaceRegistrar.js +3 -3
  73. package/dist/mcp/documentAssetRegistrar.js +44 -35
  74. package/dist/mcp/documentHelpers.d.ts +1 -0
  75. package/dist/mcp/documentHelpers.js +7 -3
  76. package/dist/mcp/runtime.js +172 -42
  77. package/dist/mcp/taskPlanningRegistrar.js +41 -38
  78. package/dist/mcp/toolCallCompatibility.js +38 -1
  79. package/dist/mcp/toolCatalog.d.ts +1 -0
  80. package/dist/migrations/taskSchemaMigrations.js +12 -0
  81. package/dist/runtime/appGateDefinitions.d.ts +30 -6
  82. package/dist/runtime/appGateDefinitions.js +6 -6
  83. package/dist/runtime/appGates.d.ts +12 -13
  84. package/dist/runtime/appGates.js +29 -13
  85. package/dist/runtime/nodeAppGates.d.ts +8 -0
  86. package/dist/runtime/nodeAppGates.js +27 -0
  87. package/dist/server/cloudCollectionRead.d.ts +1 -1
  88. package/dist/server/cloudCollectionRead.js +2 -2
  89. package/dist/server/index.d.ts +3 -0
  90. package/dist/server/index.js +15 -3
  91. package/dist/server/localServiceLease.d.ts +3 -0
  92. package/dist/server/localServiceLease.js +9 -1
  93. package/dist/server/localWorkspaceSyncServerRuntime.js +10 -3
  94. package/dist/server/rateLimit.d.ts +1 -0
  95. package/dist/server/rateLimit.js +4 -0
  96. package/dist/server/realtimeSyncWs.js +36 -12
  97. package/dist/server/routes/admin.js +1 -0
  98. package/dist/server/routes/agentRoles.js +3 -2
  99. package/dist/server/routes/agentSkills.js +3 -2
  100. package/dist/server/routes/agents.js +118 -16
  101. package/dist/server/routes/annotatedAttachments.js +3 -2
  102. package/dist/server/routes/auth.js +3 -1
  103. package/dist/server/routes/durableTaskHttpRouters.d.ts +9 -2
  104. package/dist/server/routes/localService.js +2 -0
  105. package/dist/server/routes/primitives.d.ts +2 -0
  106. package/dist/server/routes/syncAuxRoutes.js +5 -2
  107. package/dist/server/routes/syncPullApplyRoutes.js +23 -4
  108. package/dist/server/routes/syncV3FeedRoutes.js +18 -16
  109. package/dist/server/routes/syncV3LocalCaptureRoutes.js +28 -2
  110. package/dist/server/routes/syncV3LocalFeedApplyRoutes.d.ts +1 -0
  111. package/dist/server/routes/syncV3LocalFeedApplyRoutes.js +26 -0
  112. package/dist/server/routes/syncV3OperationRoutes.js +10 -0
  113. package/dist/server/routes/tasks.js +103 -11
  114. package/dist/server/routes/workspaces.js +43 -1
  115. package/dist/server/workspaceDeletionAdmission.d.ts +23 -0
  116. package/dist/server/workspaceDeletionAdmission.js +50 -0
  117. package/dist/service/localServiceCli.js +16 -0
  118. package/dist/service/localServiceClientLifecycle.js +36 -10
  119. package/dist/services/codexAppServerModelGateway.d.ts +112 -0
  120. package/dist/services/codexAppServerModelGateway.js +438 -0
  121. package/dist/services/taskforceAgentMcpBridge.d.ts +7 -1
  122. package/dist/services/taskforceAgentMcpBridge.js +23 -3
  123. package/dist/shared/taskforceAgentDefinition.js +7 -1
  124. package/dist/shared/taskforceAgentModels.d.ts +1 -0
  125. package/dist/shared/taskforceAgentModels.js +30 -1
  126. package/dist/storage/postgresAdapter.d.ts +20 -3
  127. package/dist/storage/postgresAdapter.js +106 -14
  128. package/dist/storage/postgresWorker.js +13 -4
  129. package/dist/storage/postgresWorkerProtocol.d.ts +29 -0
  130. package/dist/storage/postgresWorkerProtocol.js +30 -0
  131. package/dist/sync/cloudSyncApi.d.ts +4 -1
  132. package/dist/sync/cloudSyncApi.js +7 -2
  133. package/dist/sync/contentSyncState.d.ts +1 -1
  134. package/dist/sync/coordinator/localSyncExecutionPermitStore.d.ts +1 -0
  135. package/dist/sync/coordinator/localSyncExecutionPermitStore.js +7 -1
  136. package/dist/sync/coordinator/localWorkspaceSyncRunner.js +6 -2
  137. package/dist/sync/engine/workspaceSyncEngineBrowserGatewayRemoteServices.js +20 -2
  138. package/dist/sync/engine/workspaceSyncEngineLocalServices.d.ts +4 -0
  139. package/dist/sync/engine/workspaceSyncEngineLocalServices.js +11 -0
  140. package/dist/sync/engine/workspaceSyncEngineRemoteServices.d.ts +11 -0
  141. package/dist/sync/engine/workspaceSyncEngineRemoteServices.js +2 -1
  142. package/dist/sync/engine/workspaceSyncEngineServerRemoteServices.js +31 -4
  143. package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.d.ts +3 -1
  144. package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.js +25 -8
  145. package/dist/sync/engine/workspaceSyncEngineTransfers.d.ts +1 -1
  146. package/dist/sync/engine/workspaceSyncEngineTransfers.js +8 -3
  147. package/dist/sync/syncService.d.ts +2 -0
  148. package/dist/sync/syncService.js +4 -1
  149. package/dist/sync/v3/combinedFeedCapability.js +4 -0
  150. package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.d.ts +2 -0
  151. package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.js +11 -1
  152. package/dist/sync/v3/durableTaskChecklistMutationRouter.d.ts +2 -0
  153. package/dist/sync/v3/durableTaskChecklistMutationRouter.js +4 -0
  154. package/dist/sync/v3/durableTaskHttpBulkMutationRouter.d.ts +1 -0
  155. package/dist/sync/v3/durableTaskHttpBulkMutationRouter.js +30 -8
  156. package/dist/sync/v3/durableTaskHttpRootMutationRouter.d.ts +5 -3
  157. package/dist/sync/v3/durableTaskHttpRootMutationRouter.js +27 -2
  158. package/dist/sync/v3/localTaskAttachmentLinksOutboxService.d.ts +2 -0
  159. package/dist/sync/v3/localTaskAttachmentLinksOutboxService.js +47 -7
  160. package/dist/sync/v3/localTaskCreateOutboxService.js +15 -6
  161. package/dist/sync/v3/localTaskMetadataClient.d.ts +1 -0
  162. package/dist/sync/v3/localTaskMetadataClient.js +1 -0
  163. package/dist/sync/v3/localTaskMetadataOutboxHandler.js +5 -1
  164. package/dist/sync/v3/localTaskMetadataOutboxService.d.ts +2 -0
  165. package/dist/sync/v3/localTaskMetadataOutboxService.js +7 -0
  166. package/dist/sync/v3/localTaskRestoreOutboxService.js +14 -6
  167. package/dist/sync/v3/localTaskStatusClient.d.ts +1 -0
  168. package/dist/sync/v3/localTaskStatusClient.js +6 -1
  169. package/dist/sync/v3/localTaskStatusOutboxService.d.ts +2 -0
  170. package/dist/sync/v3/localTaskStatusOutboxService.js +54 -13
  171. package/dist/sync/v3/syncDurabilityStore.d.ts +7 -0
  172. package/dist/sync/v3/syncDurabilityStore.js +31 -11
  173. package/dist/sync/v3/taskAttachmentLinksMutationService.d.ts +6 -4
  174. package/dist/sync/v3/taskAttachmentLinksMutationService.js +19 -10
  175. package/dist/sync/v3/taskChecklistMutationService.d.ts +4 -2
  176. package/dist/sync/v3/taskChecklistMutationService.js +4 -0
  177. package/dist/sync/v3/taskCreateMutationService.d.ts +2 -2
  178. package/dist/sync/v3/taskCreateMutationService.js +7 -4
  179. package/dist/sync/v3/taskMetadataMutationService.d.ts +3 -0
  180. package/dist/sync/v3/taskMetadataMutationService.js +4 -0
  181. package/dist/sync/v3/taskRestoreMutationService.d.ts +2 -2
  182. package/dist/sync/v3/taskRestoreMutationService.js +7 -4
  183. package/dist/sync/v3/taskStatusMutationService.d.ts +2 -0
  184. package/dist/sync/v3/taskStatusMutationService.js +4 -0
  185. package/dist/sync/v3/workflowAssignmentSync.d.ts +1 -0
  186. package/dist/sync/v3/workflowAssignmentSync.js +3 -0
  187. package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.d.ts +1 -1
  188. package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.js +13 -3
  189. package/dist/sync/v3/workspaceSyncV3AttachmentApplyObligationStore.d.ts +11 -0
  190. package/dist/sync/v3/workspaceSyncV3AttachmentApplyObligationStore.js +27 -10
  191. package/dist/sync/v3/workspaceSyncV3AttachmentAssetHydration.d.ts +2 -1
  192. package/dist/sync/v3/workspaceSyncV3AttachmentAssetHydration.js +52 -10
  193. package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.js +9 -1
  194. package/dist/sync/v3/workspaceSyncV3CombinedFeedOrchestrator.js +8 -3
  195. package/dist/sync/v3/workspaceSyncV3CombinedLocalApply.js +51 -10
  196. package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.d.ts +7 -0
  197. package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.js +30 -18
  198. package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.d.ts +9 -4
  199. package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.js +98 -47
  200. package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.d.ts +10 -0
  201. package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.js +58 -21
  202. package/dist/sync/v3/workspaceSyncV3CombinedWireContract.d.ts +3 -1
  203. package/dist/sync/v3/workspaceSyncV3CombinedWireContract.js +18 -0
  204. package/dist/sync/v3/workspaceSyncV3CoverageRegistry.js +6 -0
  205. package/dist/sync/v3/workspaceSyncV3FeedProfile.d.ts +1 -1
  206. package/dist/sync/v3/workspaceSyncV3LegacyBoundaryAttestation.d.ts +1 -0
  207. package/dist/sync/v3/workspaceSyncV3LegacyBoundaryAttestation.js +23 -10
  208. package/dist/sync/v3/workspaceSyncV3NestedTaskApply.d.ts +3 -0
  209. package/dist/sync/v3/workspaceSyncV3NestedTaskApply.js +64 -13
  210. package/dist/sync/v3/workspaceSyncV3NestedTaskCodecs.d.ts +9 -0
  211. package/dist/sync/v3/workspaceSyncV3NestedTaskCodecs.js +26 -0
  212. package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.d.ts +15 -5
  213. package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.js +50 -14
  214. package/dist/sync/v3/workspaceSyncV3NestedTaskRepairSnapshot.d.ts +2 -1
  215. package/dist/sync/v3/workspaceSyncV3NestedTaskRepairSnapshot.js +11 -3
  216. package/dist/sync/v3/workspaceSyncV3OperationProtocol.d.ts +2 -0
  217. package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.d.ts +2 -0
  218. package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.js +19 -7
  219. package/dist/sync/v3/workspaceSyncV3TaskCommentAudit.js +9 -2
  220. package/dist/sync/v3/workspaceSyncV3TaskCoverCoverage.d.ts +7 -0
  221. package/dist/sync/v3/workspaceSyncV3TaskCoverCoverage.js +37 -0
  222. package/dist/sync/v3/workspaceSyncV3TaskCoverWireContract.d.ts +6 -0
  223. package/dist/sync/v3/workspaceSyncV3TaskCoverWireContract.js +9 -0
  224. package/dist/sync/workspacePullFeed.js +2 -1
  225. package/dist/sync/workspaceRepair.d.ts +3 -0
  226. package/dist/sync/workspaceRepair.js +67 -6
  227. package/dist/types.d.ts +47 -1
  228. package/dist/types.js +6 -0
  229. package/dist/ui/assets/{AiIdentityRosterCard-MZs7lVED.js → AiIdentityRosterCard-BZM4aQnM.js} +1 -1
  230. package/dist/ui/assets/AiProfilesModule-BbAEWtHH.js +1 -0
  231. package/dist/ui/assets/AnnotatedAttachmentWorkspace-B68Wg-RV.js +3 -0
  232. package/dist/ui/assets/AnnotatedAttachmentWorkspace-TzYu7pkG.css +1 -0
  233. package/dist/ui/assets/{AssetTraySortControl-Kf1pelSy.js → AssetTraySortControl-C8Rztyal.js} +1 -1
  234. package/dist/ui/assets/{ContextAttachmentManager-B8boOs6Q.js → ContextAttachmentManager-Cj3c7X9y.js} +2 -2
  235. package/dist/ui/assets/{DocumentWorkspace-DXH4XUsB.js → DocumentWorkspace-B5uvzems.js} +1 -1
  236. package/dist/ui/assets/{EntityActivityTimeline-BtSTq0ON.js → EntityActivityTimeline-BVFvCB5R.js} +1 -1
  237. package/dist/ui/assets/PlanningModule-B5DWQOGz.js +1 -0
  238. package/dist/ui/assets/PlansPage-AY4cGWco.js +1 -0
  239. package/dist/ui/assets/TaskContextUpload-DZxTVesW.js +1 -0
  240. package/dist/ui/assets/TaskSettings-BeWAuyZj.js +12 -0
  241. package/dist/ui/assets/{TaskforceAgentsModule-BazdUwxZ.js → TaskforceAgentsModule-BifCYtjR.js} +6 -6
  242. package/dist/ui/assets/{WorkflowManagerModule-DWFspC-o.js → WorkflowManagerModule-DEr5di_r.js} +1 -1
  243. package/dist/ui/assets/index-I5zhdtgt.js +7 -0
  244. package/dist/ui/assets/index-VRFsx3wz.css +1 -0
  245. package/dist/ui/assets/{vendor-icons-BkFLXavV.js → vendor-icons-D9Lpw-j4.js} +1 -1
  246. package/dist/ui/index.html +3 -3
  247. package/dist/utils/taskActivity.d.ts +3 -2
  248. package/dist/utils/taskActivity.js +19 -2
  249. package/dist/utils/taskEditorReconciliation.d.ts +40 -0
  250. package/dist/utils/taskEditorReconciliation.js +217 -0
  251. package/dist/utils/taskNormalization.d.ts +1 -0
  252. package/dist/utils/taskNormalization.js +39 -0
  253. package/dist/utils/taskSearch.js +2 -2
  254. package/dist/utils/uiNotice.d.ts +4 -0
  255. package/package.json +16 -4
  256. package/dist/ui/assets/AiProfilesModule-C3i0LOxe.js +0 -1
  257. package/dist/ui/assets/AnnotatedAttachmentWorkspace-CBRZ8rca.css +0 -1
  258. package/dist/ui/assets/AnnotatedAttachmentWorkspace-DVZk5Tln.js +0 -3
  259. package/dist/ui/assets/PlanningModule-BPVyEa-f.js +0 -1
  260. package/dist/ui/assets/PlansPage-ChqgxALc.js +0 -1
  261. package/dist/ui/assets/TaskContextUpload-CB3ol0sN.js +0 -1
  262. package/dist/ui/assets/TaskSettings-g4ECKNOz.js +0 -12
  263. package/dist/ui/assets/index-BUplSsv_.js +0 -7
  264. package/dist/ui/assets/index-gz2EXuoK.css +0 -1
package/dist/cli.js CHANGED
@@ -7,6 +7,8 @@ import { fileURLToPath } from 'url';
7
7
  import { TASKFORCE_CLOUD_ENVIRONMENTS } from './config/cloudEnvironment.js';
8
8
  import { resolveDeploymentConfig } from './config/deployment.js';
9
9
  import { resolveOpenPortSearchMax } from './cliOpenPort.js';
10
+ import { assertSourceCheckoutCloudTarget } from './cliCloudTargetGuard.js';
11
+ import { hydrateSourceCheckoutServiceEnvironment } from './config/localServiceRuntimeContract.js';
10
12
  /**
11
13
  * Taskforce CLI
12
14
  *
@@ -185,6 +187,19 @@ async function main() {
185
187
  return;
186
188
  }
187
189
  if (command === 'service') {
190
+ const serviceAction = String(args[1] || '').trim();
191
+ if (!['status', 'stop'].includes(serviceAction)) {
192
+ const projectArgument = serviceAction === 'start' ? args[2] : args[1];
193
+ hydrateSourceCheckoutServiceEnvironment({
194
+ env: process.env,
195
+ projectRoot: projectArgument || process.cwd(),
196
+ packageRoot: getCliInstallationPaths().packageRoot,
197
+ });
198
+ assertSourceCheckoutCloudTarget({
199
+ packageRoot: getCliInstallationPaths().packageRoot,
200
+ env: process.env,
201
+ });
202
+ }
188
203
  const { runLocalServiceCli } = await import('./service/localServiceCli.js');
189
204
  process.exitCode = await runLocalServiceCli(args.slice(1), {
190
205
  appVersion: getCliVersion(),
@@ -252,6 +267,15 @@ async function main() {
252
267
  // 1. Handle MCP Command
253
268
  if (command === 'mcp') {
254
269
  const projectPath = args[1] || process.cwd();
270
+ hydrateSourceCheckoutServiceEnvironment({
271
+ env: process.env,
272
+ projectRoot: projectPath,
273
+ packageRoot: getCliInstallationPaths().packageRoot,
274
+ });
275
+ assertSourceCheckoutCloudTarget({
276
+ packageRoot: getCliInstallationPaths().packageRoot,
277
+ env: process.env,
278
+ });
255
279
  // Set the path in argv so the mcp server can pick it up
256
280
  process.argv[2] = projectPath;
257
281
  try {
@@ -287,6 +311,11 @@ async function main() {
287
311
  }
288
312
  // 2. Handle Open Command
289
313
  const { preferredPort, preset: openPreset } = parseOpenCommandOptions(args);
314
+ assertSourceCheckoutCloudTarget({
315
+ packageRoot: getCliInstallationPaths().packageRoot,
316
+ env: process.env,
317
+ explicitPreset: openPreset,
318
+ });
290
319
  // Check if Taskforce is installed in the project
291
320
  let projectRoot = findProjectRoot();
292
321
  if (!projectRoot) {
@@ -324,6 +353,11 @@ async function main() {
324
353
  else if (hasExternalCloudEndpoint) {
325
354
  console.log('\x1b[36m[Taskforce] Using cloud endpoint from environment variables\x1b[0m');
326
355
  }
356
+ hydrateSourceCheckoutServiceEnvironment({
357
+ env: process.env,
358
+ projectRoot,
359
+ packageRoot: getCliInstallationPaths().packageRoot,
360
+ });
327
361
  const { openTaskforceViaLocalService, shouldOpenViaLocalService } = await import('./service/localServiceOpen.js');
328
362
  if (shouldOpenViaLocalService(process.env)) {
329
363
  console.log(`\x1b[36m✨ Discovering the shared Taskforce service...\x1b[0m`);
@@ -0,0 +1,5 @@
1
+ export declare function assertSourceCheckoutCloudTarget(input: {
2
+ packageRoot: string;
3
+ env: NodeJS.ProcessEnv;
4
+ explicitPreset?: string | null;
5
+ }): void;
@@ -0,0 +1,11 @@
1
+ import { existsSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { resolveDeploymentConfig } from './config/deployment.js';
4
+ export function assertSourceCheckoutCloudTarget(input) {
5
+ if (!existsSync(join(input.packageRoot, '.git')))
6
+ return;
7
+ if (input.explicitPreset || resolveDeploymentConfig(input.env).cloudBaseUrl)
8
+ return;
9
+ throw new Error('Refusing to default a Taskforce source checkout to production. '
10
+ + 'Use the performance/staging development script or provide an explicit cloud target.');
11
+ }
@@ -427,6 +427,7 @@ export function AnnotatedAttachmentWorkspaceShell({ runtimeMode = 'local', apiBa
427
427
  const [draftGlobalInstruction, setDraftGlobalInstruction] = useState('');
428
428
  const [draftAnnotations, setDraftAnnotations] = useState([]);
429
429
  const [selectedAnnotationId, setSelectedAnnotationId] = useState(null);
430
+ const [hoveredAnnotationId, setHoveredAnnotationId] = useState(null);
430
431
  const [isAnnotationEditorCollapsed, setIsAnnotationEditorCollapsed] = useState(false);
431
432
  const [activeAnnotationId, setActiveAnnotationId] = useState(null);
432
433
  const [defaultMarkerColor, setDefaultMarkerColor] = useState(ANNOTATION_COLORS[DEFAULT_MARKER_TYPE]);
@@ -1218,6 +1219,18 @@ export function AnnotatedAttachmentWorkspaceShell({ runtimeMode = 'local', apiBa
1218
1219
  }
1219
1220
  }, [flushPendingDraft, isTargetControlled, loadSessions, onOpenTarget, resetForTargetLoad]);
1220
1221
  const applySessionLocally = useCallback((session) => {
1222
+ if (isTargetControlled && activeTarget && activeTarget.taskId !== session.taskId) {
1223
+ const nextTarget = { ...activeTarget };
1224
+ if (session.taskId) {
1225
+ nextTarget.taskId = session.taskId;
1226
+ nextTarget.taskReferenceLabel = resolveTaskReferenceLabel?.(session.taskId) || session.taskId;
1227
+ }
1228
+ else {
1229
+ delete nextTarget.taskId;
1230
+ delete nextTarget.taskReferenceLabel;
1231
+ }
1232
+ onOpenTarget?.(nextTarget, { sessionId: session.id });
1233
+ }
1221
1234
  setSessions((current) => {
1222
1235
  const existingIndex = current.findIndex((item) => item.id === session.id);
1223
1236
  if (existingIndex === -1)
@@ -1228,7 +1241,7 @@ export function AnnotatedAttachmentWorkspaceShell({ runtimeMode = 'local', apiBa
1228
1241
  });
1229
1242
  setSelectedSessionId(session.id);
1230
1243
  syncDraftFromSession(session, activeTarget);
1231
- }, [activeTarget, syncDraftFromSession]);
1244
+ }, [activeTarget, isTargetControlled, onOpenTarget, resolveTaskReferenceLabel, syncDraftFromSession]);
1232
1245
  const removeSessionLocally = useCallback((sessionId) => {
1233
1246
  setSessions((current) => {
1234
1247
  const remaining = current.filter((session) => session.id !== sessionId);
@@ -2268,8 +2281,9 @@ export function AnnotatedAttachmentWorkspaceShell({ runtimeMode = 'local', apiBa
2268
2281
  const geometry = getArrowGeometry(annotation, canvasMediaSize);
2269
2282
  const color = mapMarkerColor(annotation);
2270
2283
  const isSelected = selectedAnnotationId === annotation.id;
2271
- return (_jsxs(React.Fragment, { children: [isSelected ? (_jsxs(_Fragment, { children: [_jsx("line", { x1: geometry.shaftX1, y1: geometry.shaftY1, x2: geometry.shaftX2, y2: geometry.shaftY2, stroke: "color-mix(in srgb, var(--surface-elevated) 92%, transparent)", strokeWidth: 14, strokeLinecap: "round" }), _jsx("polygon", { points: geometry.headPoints, fill: color, stroke: "color-mix(in srgb, var(--surface-elevated) 92%, transparent)", strokeWidth: 4, strokeLinejoin: "round" })] })) : null, _jsx("line", { x1: geometry.shaftX1, y1: geometry.shaftY1, x2: geometry.shaftX2, y2: geometry.shaftY2, stroke: color, strokeWidth: isSelected ? 10 : 6, strokeLinecap: "round" }), _jsx("polygon", { points: geometry.headPoints, fill: color })] }, annotation.id));
2272
- }) }), _jsx("svg", { className: styles.overlayHitLayer, viewBox: arrowOverlayViewBox, preserveAspectRatio: "none", children: draftAnnotations.filter((annotation) => annotation.kind === 'arrow').map((annotation) => (_jsxs(React.Fragment, { children: [_jsx("line", { x1: annotation.x * canvasMediaSize.width, y1: annotation.y * canvasMediaSize.height, x2: annotation.x2 * canvasMediaSize.width, y2: annotation.y2 * canvasMediaSize.height, className: styles.arrowHitArea, "data-testid": `annotated-arrow-hit-${annotation.id}`, "aria-label": `Arrow marker ${annotationOrderNumbers.get(annotation.id) || 0}`, onPointerDown: (event) => startDragAnnotation(event, annotation), onClick: (event) => {
2284
+ const isEmphasized = isSelected || hoveredAnnotationId === annotation.id;
2285
+ return (_jsxs(React.Fragment, { children: [isEmphasized ? (_jsxs(_Fragment, { children: [_jsx("line", { x1: geometry.shaftX1, y1: geometry.shaftY1, x2: geometry.shaftX2, y2: geometry.shaftY2, stroke: "color-mix(in srgb, var(--surface-elevated) 92%, transparent)", strokeWidth: 14, strokeLinecap: "round" }), _jsx("polygon", { points: geometry.headPoints, fill: color, stroke: "color-mix(in srgb, var(--surface-elevated) 92%, transparent)", strokeWidth: 4, strokeLinejoin: "round" })] })) : null, _jsx("line", { x1: geometry.shaftX1, y1: geometry.shaftY1, x2: geometry.shaftX2, y2: geometry.shaftY2, stroke: color, strokeWidth: isEmphasized ? 10 : 6, strokeLinecap: "round" }), _jsx("polygon", { points: geometry.headPoints, fill: color })] }, annotation.id));
2286
+ }) }), _jsx("svg", { className: styles.overlayHitLayer, viewBox: arrowOverlayViewBox, preserveAspectRatio: "none", children: draftAnnotations.filter((annotation) => annotation.kind === 'arrow').map((annotation) => (_jsxs(React.Fragment, { children: [_jsx("line", { x1: annotation.x * canvasMediaSize.width, y1: annotation.y * canvasMediaSize.height, x2: annotation.x2 * canvasMediaSize.width, y2: annotation.y2 * canvasMediaSize.height, className: styles.arrowHitArea, "data-testid": `annotated-arrow-hit-${annotation.id}`, "aria-label": `Arrow marker ${annotationOrderNumbers.get(annotation.id) || 0}`, onMouseEnter: () => setHoveredAnnotationId(annotation.id), onMouseLeave: () => setHoveredAnnotationId(null), onPointerDown: (event) => startDragAnnotation(event, annotation), onClick: (event) => {
2273
2287
  event.stopPropagation();
2274
2288
  selectAnnotation(annotation.id);
2275
2289
  } }), selectedAnnotationId === annotation.id ? (_jsxs(_Fragment, { children: [_jsx("circle", { cx: annotation.x * canvasMediaSize.width, cy: annotation.y * canvasMediaSize.height, r: arrowHandleGeometry.hitRadius, className: styles.canvasHandleHit, role: "button", tabIndex: 0, "aria-label": "Move arrow tail", onPointerDown: (event) => startArrowHandleDrag(event, annotation, 'tail') }), _jsx("circle", { cx: annotation.x * canvasMediaSize.width, cy: annotation.y * canvasMediaSize.height, r: arrowHandleGeometry.visibleRadius, className: styles.canvasHandleVisible, "aria-hidden": "true" }), _jsx("circle", { cx: annotation.x2 * canvasMediaSize.width, cy: annotation.y2 * canvasMediaSize.height, r: arrowHandleGeometry.hitRadius, className: styles.canvasHandleHit, role: "button", tabIndex: 0, "aria-label": "Move arrow tip", onPointerDown: (event) => startArrowHandleDrag(event, annotation, 'tip') }), _jsx("circle", { cx: annotation.x2 * canvasMediaSize.width, cy: annotation.y2 * canvasMediaSize.height, r: arrowHandleGeometry.visibleRadius, className: styles.canvasHandleVisible, "aria-hidden": "true" })] })) : null] }, `hit-${annotation.id}`))) }), draftAnnotations.filter((annotation) => annotation.kind === 'arrow').map((annotation) => (_jsx("div", { className: `${styles.annotationNumberBadge} ${styles.arrowNumberBadge}`, style: {
@@ -2281,18 +2295,20 @@ export function AnnotatedAttachmentWorkspaceShell({ runtimeMode = 'local', apiBa
2281
2295
  const annotationOrderNumber = annotationOrderNumbers.get(annotation.id) || 0;
2282
2296
  const sharedProps = {
2283
2297
  onPointerDown: (event) => startDragAnnotation(event, annotation),
2298
+ onMouseEnter: () => setHoveredAnnotationId(annotation.id),
2299
+ onMouseLeave: () => setHoveredAnnotationId(null),
2284
2300
  onClick: (event) => {
2285
2301
  event.stopPropagation();
2286
2302
  selectAnnotation(annotation.id);
2287
2303
  },
2288
2304
  };
2289
2305
  if (annotation.kind === 'pin') {
2290
- return (_jsx("button", { type: "button", ...sharedProps, className: `${styles.pin} ${selectedAnnotationId === annotation.id ? styles.selected : ''}`, style: { left: `${annotation.x * 100}%`, top: `${annotation.y * 100}%`, backgroundColor: color }, children: annotationOrderNumber }, annotation.id));
2306
+ return (_jsx("button", { type: "button", ...sharedProps, className: `${styles.pin} ${selectedAnnotationId === annotation.id ? styles.selected : ''} ${hoveredAnnotationId === annotation.id ? styles.markerHovered : ''}`, style: { left: `${annotation.x * 100}%`, top: `${annotation.y * 100}%`, backgroundColor: color }, children: annotationOrderNumber }, annotation.id));
2291
2307
  }
2292
2308
  if (annotation.kind === 'text-note') {
2293
- return (_jsx("button", { type: "button", ...sharedProps, className: `${styles.note} ${selectedAnnotationId === annotation.id ? styles.selected : ''}`, style: { left: `${annotation.x * 100}%`, top: `${annotation.y * 100}%`, backgroundColor: color }, children: annotationOrderNumber }, annotation.id));
2309
+ return (_jsx("button", { type: "button", ...sharedProps, className: `${styles.note} ${selectedAnnotationId === annotation.id ? styles.selected : ''} ${hoveredAnnotationId === annotation.id ? styles.markerHovered : ''}`, style: { left: `${annotation.x * 100}%`, top: `${annotation.y * 100}%`, backgroundColor: color }, children: annotationOrderNumber }, annotation.id));
2294
2310
  }
2295
- return (_jsxs("div", { className: `${styles.box} ${selectedAnnotationId === annotation.id ? styles.selected : ''}`, style: {
2311
+ return (_jsxs("div", { className: `${styles.box} ${selectedAnnotationId === annotation.id ? styles.selected : ''} ${hoveredAnnotationId === annotation.id ? styles.markerHovered : ''}`, style: {
2296
2312
  left: `${annotation.x * 100}%`,
2297
2313
  top: `${annotation.y * 100}%`,
2298
2314
  width: `${annotation.width * 100}%`,
@@ -2311,7 +2327,7 @@ export function AnnotatedAttachmentWorkspaceShell({ runtimeMode = 'local', apiBa
2311
2327
  const instructionTypeLabel = MARKER_TYPE_OPTIONS.find((option) => option.value === (annotation.markerType || DEFAULT_MARKER_TYPE))?.label || 'Review';
2312
2328
  const isSelected = selectedAnnotationId === annotation.id;
2313
2329
  const isExpanded = isSelected && !isAnnotationEditorCollapsed;
2314
- return (_jsx(SortableAnnotationCard, { id: annotation.id, children: ({ attributes, listeners, setNodeRef, transform, transition, isDragging }) => (_jsxs("div", { className: `tf-surface-elevated ${styles.annotationCard} ${isSelected ? styles.annotationCardActive : ''} ${isDragging ? styles.annotationCardDragging : ''}`, ref: (node) => {
2330
+ return (_jsx(SortableAnnotationCard, { id: annotation.id, children: ({ attributes, listeners, setNodeRef, transform, transition, isDragging }) => (_jsxs("div", { className: `tf-surface-elevated ${styles.annotationCard} ${isSelected ? styles.annotationCardActive : ''} ${hoveredAnnotationId === annotation.id ? styles.annotationCardHovered : ''} ${isDragging ? styles.annotationCardDragging : ''}`, "data-testid": `annotation-card-${annotation.id}`, ref: (node) => {
2315
2331
  setNodeRef(node);
2316
2332
  if (node)
2317
2333
  annotationCardRefs.current.set(annotation.id, node);
@@ -2325,7 +2341,7 @@ export function AnnotatedAttachmentWorkspaceShell({ runtimeMode = 'local', apiBa
2325
2341
  if (!event.currentTarget.contains(event.relatedTarget)) {
2326
2342
  setIsAnnotationEditorCollapsed(true);
2327
2343
  }
2328
- }, children: [_jsxs("div", { className: styles.annotationMeta, children: [_jsx("button", { type: "button", className: styles.annotationDragHandle, "aria-label": `Reorder ${annotationSequenceLabel}`, title: "Drag to reorder. Press Space, then use the arrow keys to reorder with the keyboard.", ...attributes, ...listeners, children: _jsx(GripVertical, { size: 16 }) }), _jsx("button", { type: "button", className: styles.annotationCardButton, onClick: () => {
2344
+ }, onMouseEnter: () => setHoveredAnnotationId(annotation.id), onMouseLeave: () => setHoveredAnnotationId(null), children: [_jsxs("div", { className: styles.annotationMeta, children: [_jsx("button", { type: "button", className: styles.annotationDragHandle, "aria-label": `Reorder ${annotationSequenceLabel}`, title: "Drag to reorder. Press Space, then use the arrow keys to reorder with the keyboard.", ...attributes, ...listeners, children: _jsx(GripVertical, { size: 16 }) }), _jsx("button", { type: "button", className: styles.annotationCardButton, onClick: () => {
2329
2345
  toggleAnnotation(annotation.id);
2330
2346
  }, "aria-label": annotationKindLabel, "aria-expanded": isExpanded, children: _jsx("span", { className: `tf-heading-card ${styles.annotationTitle}`, children: annotationSequenceLabel }) }), _jsx("span", { className: `tf-text-meta ${styles.annotationKind}`, "aria-hidden": "true", children: _jsx(AnnotationKindIcon, { size: 16 }) })] }), isExpanded ? (_jsxs("div", { className: styles.annotationInstructionEditor, children: [_jsx("label", { className: "tf-field-label", htmlFor: "annotated-marker-instruction", children: "Marker instruction" }), _jsx("textarea", { id: "annotated-marker-instruction", ref: isSelected ? selectedInstructionTextareaRef : null, className: `tf-field-shell ${styles.textArea} ${styles.annotationInstructionField}`, value: annotation.instruction, onChange: (event) => {
2331
2347
  updateDraftAnnotation(annotation.id, (current) => ({
@@ -23,6 +23,11 @@ export interface TaskSettingsModel {
23
23
  manualComplexityEnabled: boolean;
24
24
  checklistDropdownEnabled?: boolean;
25
25
  showTaskCardStatusLabel?: boolean;
26
+ showTaskCardDescription?: boolean;
27
+ showTaskCardAttachments?: boolean;
28
+ showTaskCardChecklistProgress?: boolean;
29
+ showTaskCardLatestActivity?: boolean;
30
+ tintTaskCardActivityBackground?: boolean;
26
31
  initialSection?: 'categories' | 'types' | 'general' | 'documents' | 'agents' | 'taxonomy' | 'mcp' | 'integrations' | 'priorities' | 'initiatives' | 'appearance-application' | 'appearance-task-cards' | 'appearance-task-forms' | null;
27
32
  setupState?: {
28
33
  mode: 'core' | 'operations';
@@ -38,15 +43,21 @@ export interface TaskSettingsModel {
38
43
  onThemeChange: (theme: TaskforceTheme) => void;
39
44
  onSaveTheme: (theme: TaskforceTheme) => Promise<boolean>;
40
45
  onSaveGlobalTheme: (theme: TaskforceTheme) => Promise<boolean>;
41
- onResetProjectToGlobal: () => Promise<boolean>;
46
+ onUseGlobalThemeDefault: () => Promise<boolean>;
42
47
  onKeyShortcutChange: (value: string) => void;
43
48
  onJsonBackupEnabledChange: (value: boolean) => Promise<boolean>;
44
49
  onSaveGlobalJsonBackupEnabled: (value: boolean) => Promise<boolean>;
50
+ onUseGlobalJsonBackupDefault: () => Promise<boolean>;
45
51
  onSaveGlobalWeekStartsOn: (value: 'sunday' | 'monday') => Promise<boolean>;
46
52
  onSaveLocale?: (value: string) => Promise<boolean>;
47
53
  onManualComplexityEnabledChange: (value: boolean) => Promise<boolean>;
48
54
  onChecklistDropdownEnabledChange?: (value: boolean) => Promise<boolean>;
49
55
  onShowTaskCardStatusLabelChange?: (value: boolean) => Promise<boolean>;
56
+ onShowTaskCardDescriptionChange?: (value: boolean) => Promise<boolean>;
57
+ onShowTaskCardAttachmentsChange?: (value: boolean) => Promise<boolean>;
58
+ onShowTaskCardChecklistProgressChange?: (value: boolean) => Promise<boolean>;
59
+ onShowTaskCardLatestActivityChange?: (value: boolean) => Promise<boolean>;
60
+ onTintTaskCardActivityBackgroundChange?: (value: boolean) => Promise<boolean>;
50
61
  onSaveSettings: () => Promise<boolean>;
51
62
  onSaveSetupMode?: (mode: 'core' | 'operations') => Promise<boolean>;
52
63
  onSaveWorkspaceProfile?: (input: {
@@ -8,6 +8,7 @@ import { MCP_CLIENT_OPTIONS, buildCloudMcpClientIntegration, buildLocalMcpClient
8
8
  import { resolveTaskforceMcpBaseUrlFromBaseUrl } from '../../config/cloudEnvironment';
9
9
  import { TaxonomyManager } from './settings/TaxonomyManager';
10
10
  import { normalizeTaskforceApplicationBaseUrl } from '../../shared/taskDeepLinks.js';
11
+ import { TaskCard } from '../task/TaskCard';
11
12
  const THEME_ICON_MAP = {
12
13
  sun: Sun,
13
14
  wind: Wind,
@@ -21,13 +22,29 @@ const MCP_CONFIG_CODE_COLORS = {
21
22
  punctuation: '#cbd5e1',
22
23
  text: '#f8fafc'
23
24
  };
25
+ const TASK_CARD_PREVIEW_INITIATIVE = {
26
+ id: 'task-card-settings-preview-initiative',
27
+ referenceNumber: 29,
28
+ referenceLabel: 'IN-29',
29
+ title: 'Task Experience',
30
+ description: null,
31
+ createdAt: '2026-08-14T12:00:00.000Z',
32
+ };
33
+ const TASK_CARD_PREVIEW_WORKSTREAM = {
34
+ id: 'task-card-settings-preview-workstream',
35
+ referenceNumber: 749,
36
+ referenceLabel: 'WS-749',
37
+ initiativeId: TASK_CARD_PREVIEW_INITIATIVE.id,
38
+ title: 'Task Card Polish',
39
+ description: null,
40
+ createdAt: '2026-08-14T12:00:00.000Z',
41
+ };
24
42
  export function TaskSettings(props) {
25
43
  const { settingsModel, onSectionChange, renderMode = 'full' } = props;
26
44
  const isMcpOnly = renderMode === 'mcp-only';
27
- const { currentTheme, globalTheme, themeUseGlobalDefault, keyShortcut, jsonBackupEnabled, globalJsonBackupEnabled, globalWeekStartsOn, locale = 'en-US', supportedLocales = ['en-US', 'es-419', 'pt-BR'], jsonBackupUseGlobalDefault, manualComplexityEnabled, checklistDropdownEnabled = true, showTaskCardStatusLabel = false, initialSection, onThemeChange, onSaveTheme, onSaveGlobalTheme, onResetProjectToGlobal, onKeyShortcutChange, onJsonBackupEnabledChange, onSaveGlobalJsonBackupEnabled, onSaveGlobalWeekStartsOn, onSaveLocale, onManualComplexityEnabledChange, onChecklistDropdownEnabledChange, onShowTaskCardStatusLabelChange, onSaveSettings, 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, checkLocalMcpCliHealth, getLocalUpdateStatus, workspaceSwitchingEnabled = false, currentWorkspaceRole = 'member', currentWorkspaceName = '', onDeleteWorkspace, onMcpHostRootChange, onOpenCloudAuth, isAuthenticated = false, setupState = null, buildInfo = null, onSaveSetupMode, onSaveWorkspaceProfile, initiativeTemplates = [], onRefreshInitiativeTemplates, onCreateInitiativeFromTemplate } = settingsModel;
45
+ const { currentTheme, globalTheme, themeUseGlobalDefault, keyShortcut, jsonBackupEnabled, globalJsonBackupEnabled, globalWeekStartsOn, locale = 'en-US', supportedLocales = ['en-US', 'es-419', 'pt-BR'], jsonBackupUseGlobalDefault, manualComplexityEnabled, checklistDropdownEnabled = true, showTaskCardStatusLabel = false, showTaskCardDescription = true, showTaskCardAttachments = true, showTaskCardChecklistProgress = true, showTaskCardLatestActivity = true, tintTaskCardActivityBackground = false, initialSection, onThemeChange, onSaveTheme, onSaveGlobalTheme, onUseGlobalThemeDefault, onKeyShortcutChange, onJsonBackupEnabledChange, onSaveGlobalJsonBackupEnabled, onUseGlobalJsonBackupDefault, onSaveGlobalWeekStartsOn, onSaveLocale, onManualComplexityEnabledChange, onChecklistDropdownEnabledChange, onShowTaskCardStatusLabelChange, onShowTaskCardDescriptionChange, onShowTaskCardAttachmentsChange, onShowTaskCardChecklistProgressChange, onShowTaskCardLatestActivityChange, onTintTaskCardActivityBackgroundChange, onSaveSettings, 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, checkLocalMcpCliHealth, getLocalUpdateStatus, workspaceSwitchingEnabled = false, currentWorkspaceRole = 'member', currentWorkspaceName = '', onDeleteWorkspace, onMcpHostRootChange, onOpenCloudAuth, isAuthenticated = false, setupState = null, buildInfo = null, onSaveSetupMode, onSaveWorkspaceProfile, initiativeTemplates = [], onRefreshInitiativeTemplates, onCreateInitiativeFromTemplate } = settingsModel;
28
46
  const showJsonBackupSettings = runtimeMode !== 'cloud';
29
47
  const [settingsFeedback, setSettingsFeedback] = useState(null);
30
- const [setupMode, setSetupMode] = useState(() => setupState?.mode === 'operations' ? 'operations' : 'core');
31
48
  const [workspaceDisplayName, setWorkspaceDisplayName] = useState(() => String(setupState?.workspace?.name || '').trim());
32
49
  const [workspaceDescription, setWorkspaceDescription] = useState(() => String(setupState?.workspace?.description || ''));
33
50
  const [selectedInitiativeTemplateId, setSelectedInitiativeTemplateId] = useState('');
@@ -38,6 +55,53 @@ export function TaskSettings(props) {
38
55
  const [generalScopeTab, setGeneralScopeTab] = useState(() => {
39
56
  return 'project';
40
57
  });
58
+ const taskCardPreviewTask = useMemo(() => ({
59
+ id: 'task-card-settings-preview',
60
+ referenceNumber: 1590,
61
+ referenceLabel: 'T-1590',
62
+ title: 'Polish Task card appearance',
63
+ description: 'Make card preferences easy to understand at a glance.',
64
+ category: categories.find((option) => !option.disabled)?.value || 'general',
65
+ type: types[0]?.value || 'feature',
66
+ priority: priorities.find((option) => Number(option.value) === 2)?.value ?? priorities[0]?.value ?? 2,
67
+ complexity: 3,
68
+ status: 'in-progress',
69
+ workstreamId: TASK_CARD_PREVIEW_WORKSTREAM.id,
70
+ createdAt: '2026-08-14T12:00:00.000Z',
71
+ attachments: [{
72
+ path: '/task-card-preview.md',
73
+ displayName: 'task-card-style-guide.md',
74
+ originalFilename: 'task-card-style-guide.md',
75
+ linkRole: 'attachment',
76
+ }],
77
+ commentCount: 2,
78
+ checklistCount: 3,
79
+ completedChecklistCount: 1,
80
+ latestActivity: {
81
+ id: 'task-card-settings-preview-activity',
82
+ type: 'event',
83
+ timestamp: '2026-08-14T12:30:00.000Z',
84
+ event: {
85
+ action: 'task-status-changed',
86
+ actor: 'Cardsmith',
87
+ actorType: 'ai',
88
+ actorProfile: {
89
+ id: 'task-card-settings-preview-actor',
90
+ kind: 'ai',
91
+ label: 'Cardsmith',
92
+ username: 'cardsmith',
93
+ icon: 'Bot',
94
+ color: 'violet-500',
95
+ isNamed: true,
96
+ },
97
+ details: {
98
+ changes: {
99
+ status: { from: 'task', to: 'in-progress' },
100
+ },
101
+ },
102
+ },
103
+ },
104
+ }), [categories, priorities, types]);
41
105
  useEffect(() => {
42
106
  if (initiativeTemplates.length > 0 && !selectedInitiativeTemplateId) {
43
107
  setSelectedInitiativeTemplateId(initiativeTemplates[0].id);
@@ -49,13 +113,31 @@ export function TaskSettings(props) {
49
113
  const timer = setTimeout(() => setSettingsFeedback(null), 2500);
50
114
  return () => clearTimeout(timer);
51
115
  }, [settingsFeedback]);
52
- useEffect(() => {
53
- setSetupMode(setupState?.mode === 'operations' ? 'operations' : 'core');
54
- }, [setupState?.mode]);
116
+ const reportTaskCardPreferenceResult = (success, errorMessage) => {
117
+ setSettingsFeedback(success ? null : { type: 'error', message: errorMessage });
118
+ };
55
119
  useEffect(() => {
56
120
  setWorkspaceDisplayName(String(setupState?.workspace?.name || '').trim());
57
121
  setWorkspaceDescription(String(setupState?.workspace?.description || ''));
58
122
  }, [setupState?.workspace?.name, setupState?.workspace?.description]);
123
+ const resolvedWorkspaceId = String(workspaceId || setupState?.workspaceId || setupState?.workspace?.id || '').trim();
124
+ const handleCopyWorkspaceId = async () => {
125
+ if (!resolvedWorkspaceId) {
126
+ setSettingsFeedback({ type: 'error', message: 'Workspace ID is unavailable.' });
127
+ return;
128
+ }
129
+ if (!navigator.clipboard?.writeText) {
130
+ setSettingsFeedback({ type: 'error', message: 'Clipboard copy is unavailable in this browser.' });
131
+ return;
132
+ }
133
+ try {
134
+ await navigator.clipboard.writeText(resolvedWorkspaceId);
135
+ setSettingsFeedback({ type: 'success', message: 'Workspace ID copied.' });
136
+ }
137
+ catch {
138
+ setSettingsFeedback({ type: 'error', message: 'Failed to copy workspace ID.' });
139
+ }
140
+ };
59
141
  const handleThemeChange = async (theme) => {
60
142
  onThemeChange(theme);
61
143
  const success = await onSaveTheme(theme);
@@ -831,7 +913,13 @@ export function TaskSettings(props) {
831
913
  setActiveTab(tab);
832
914
  onSectionChange?.(section);
833
915
  };
834
- 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)) })] }));
916
+ const renderProjectThemeControls = () => (_jsxs("div", { className: styles.settingGroup, children: [_jsxs("div", { className: styles.settingTitleRow, children: [_jsx("h3", { className: `${styles.settingTitle} tf-heading-section`, children: "Theme" }), !themeUseGlobalDefault && (_jsx("button", { type: "button", className: "tf-button-secondary tf-button-compact", onClick: async () => {
917
+ const success = await onUseGlobalThemeDefault();
918
+ setSettingsFeedback({
919
+ type: success ? 'success' : 'error',
920
+ message: success ? 'Using global theme default.' : 'Failed to use global theme default.'
921
+ });
922
+ }, children: "Use global theme" }))] }), _jsx("div", { className: styles.buttonGrid, children: TASKFORCE_THEME_OPTIONS.map((themeOption) => renderThemeButton(themeOption, currentTheme, handleThemeChange)) })] }));
835
923
  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) => {
836
924
  const success = await onSaveGlobalTheme(theme);
837
925
  setSettingsFeedback({
@@ -848,30 +936,27 @@ export function TaskSettings(props) {
848
936
  message: success ? 'Checklist dropdown setting saved.' : 'Failed to save checklist dropdown setting.'
849
937
  });
850
938
  }, disabled: !onChecklistDropdownEnabledChange }), _jsx("span", { children: "Enable checklist dropdown in task form" })] })] }));
851
- return (_jsx("div", { className: `${styles.settingsTab} ${isMcpOnly ? styles.settingsTabMcpOnly : ''}`.trim(), children: _jsxs("div", { className: `${styles.settingsLayout} ${isMcpOnly ? styles.settingsLayoutMcpOnly : ''}`.trim(), children: [!isMcpOnly && (_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 () => {
852
- const confirmed = window.confirm('Reset project Theme and Backups to global defaults?');
853
- if (!confirmed)
854
- return;
855
- const success = await onResetProjectToGlobal();
856
- setSettingsFeedback({
857
- type: success ? 'success' : 'error',
858
- message: success ? 'Project settings reset to global.' : 'Failed to reset project settings.'
859
- });
860
- }, 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 () => {
861
- if (!onSaveWorkspaceProfile)
862
- return;
863
- const result = await onSaveWorkspaceProfile({
864
- workspaceId: setupState?.workspaceId,
865
- name: workspaceDisplayName,
866
- description: workspaceDescription
867
- });
868
- setSettingsFeedback({
869
- type: result.success ? 'success' : 'error',
870
- message: result.success
871
- ? `${setupMode === 'operations' ? 'Mission' : 'Project'} profile saved.`
872
- : (result.error || 'Failed to save workspace profile.')
873
- });
874
- }, 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) => {
939
+ return (_jsx("div", { className: `${styles.settingsTab} ${isMcpOnly ? styles.settingsTabMcpOnly : ''}`.trim(), children: _jsxs("div", { className: `${styles.settingsLayout} ${isMcpOnly ? styles.settingsLayoutMcpOnly : ''}`.trim(), children: [!isMcpOnly && (_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}`, role: settingsFeedback.type === 'success' ? 'status' : 'alert', "aria-live": settingsFeedback.type === 'success' ? 'polite' : 'assertive', 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.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' && (_jsxs("div", { className: styles.settingGroup, children: [_jsxs("div", { className: styles.workspaceIdentity, children: [_jsx("span", { className: styles.label, children: "Workspace ID:" }), _jsxs("div", { className: styles.workspaceIdentityValueRow, children: [_jsx("code", { className: styles.workspaceIdentityValue, children: resolvedWorkspaceId || 'Unavailable' }), _jsx("button", { type: "button", className: "tf-control-icon tf-control-icon-compact", onClick: () => { void handleCopyWorkspaceId(); }, disabled: !resolvedWorkspaceId, "aria-label": "Copy workspace ID", title: "Copy workspace ID", children: _jsx(Copy, { size: 14, "aria-hidden": "true" }) })] })] }), _jsxs("div", { className: styles.workspaceProfileForm, children: [_jsx("label", { htmlFor: "workspace-name", className: styles.label, children: "Workspace name:" }), _jsx("input", { id: "workspace-name", className: styles.input, type: "text", value: workspaceDisplayName, onChange: (event) => setWorkspaceDisplayName(event.target.value), placeholder: "Workspace name" }), _jsx("label", { htmlFor: "workspace-description", className: `${styles.label} ${styles.workspaceProfileTextareaLabel}`, children: "Description:" }), _jsx("textarea", { id: "workspace-description", className: styles.textarea, value: workspaceDescription, onChange: (event) => setWorkspaceDescription(event.target.value), placeholder: "Describe this workspace (optional)", rows: 3 }), _jsx("div", { className: styles.workspaceProfileActions, children: _jsx("button", { type: "button", onClick: async () => {
940
+ if (!onSaveWorkspaceProfile)
941
+ return;
942
+ const result = await onSaveWorkspaceProfile({
943
+ workspaceId: setupState?.workspaceId,
944
+ name: workspaceDisplayName,
945
+ description: workspaceDescription
946
+ });
947
+ setSettingsFeedback({
948
+ type: result.success ? 'success' : 'error',
949
+ message: result.success
950
+ ? 'Workspace profile saved.'
951
+ : (result.error || 'Failed to save workspace profile.')
952
+ });
953
+ }, className: "tf-button-primary tf-button-compact", disabled: !onSaveWorkspaceProfile, children: "Save" }) })] })] })), generalScopeTab === 'project' && (_jsx("div", { className: styles.settingGroup, children: showJsonBackupSettings && (_jsxs(_Fragment, { children: [_jsxs("div", { className: styles.settingTitleRow, children: [_jsx("h3", { className: styles.settingTitle, children: "Backup" }), !jsonBackupUseGlobalDefault && (_jsx("button", { type: "button", className: "tf-button-secondary tf-button-compact", onClick: async () => {
954
+ const success = await onUseGlobalJsonBackupDefault();
955
+ setSettingsFeedback({
956
+ type: success ? 'success' : 'error',
957
+ message: success ? 'Using global backup default.' : 'Failed to use global backup default.'
958
+ });
959
+ }, children: "Use global backup" }))] }), _jsxs("label", { className: styles.archiveToggle, children: [_jsx("input", { type: "checkbox", checked: jsonBackupEnabled, onChange: async (e) => {
875
960
  const success = await onJsonBackupEnabledChange(e.target.checked);
876
961
  setSettingsFeedback({
877
962
  type: success ? 'success' : 'error',
@@ -907,7 +992,7 @@ export function TaskSettings(props) {
907
992
  type: success ? 'success' : 'error',
908
993
  message: success ? 'Global shortcut saved.' : 'Failed to save global shortcut.'
909
994
  });
910
- }, 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 () => {
995
+ }, 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: "tf-button-destructive tf-button-compact", onClick: async () => {
911
996
  if (!onDeleteWorkspace)
912
997
  return;
913
998
  const normalizedWorkspaceId = String(workspaceId || '').trim();
@@ -944,15 +1029,37 @@ export function TaskSettings(props) {
944
1029
  ? `Workspace deleted with ${warningCount} cleanup warning(s).`
945
1030
  : 'Workspace deleted.'
946
1031
  });
947
- }, 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) => {
948
- if (!onShowTaskCardStatusLabelChange)
949
- return;
950
- const success = await onShowTaskCardStatusLabelChange(e.target.checked);
951
- setSettingsFeedback({
952
- type: success ? 'success' : 'error',
953
- message: success ? 'Task card status label setting saved.' : 'Failed to save task card status label setting.'
954
- });
955
- }, disabled: !onShowTaskCardStatusLabelChange }), _jsx("span", { children: "Show status label" })] })] })), activeTab === 'appearanceTaskForms' && renderTaskFormsControls(), 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) => {
1032
+ }, disabled: !onDeleteWorkspace, children: [_jsx(Trash2, { size: 14, "aria-hidden": "true" }), "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.taskCardSettingsLayout, children: [_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) => {
1033
+ if (!onShowTaskCardStatusLabelChange)
1034
+ return;
1035
+ const success = await onShowTaskCardStatusLabelChange(e.target.checked);
1036
+ reportTaskCardPreferenceResult(success, 'Failed to save task card status label setting.');
1037
+ }, disabled: !onShowTaskCardStatusLabelChange }), _jsx("span", { children: "Show status label" })] }), _jsxs("div", { className: styles.taskCardSettingWithHelp, children: [_jsxs("label", { className: styles.archiveToggle, children: [_jsx("input", { type: "checkbox", checked: runtimeMode !== 'cloud' && showTaskCardDescription, onChange: async (e) => {
1038
+ if (!onShowTaskCardDescriptionChange)
1039
+ return;
1040
+ const success = await onShowTaskCardDescriptionChange(e.target.checked);
1041
+ reportTaskCardPreferenceResult(success, 'Failed to save task card description setting.');
1042
+ }, disabled: runtimeMode === 'cloud' || !onShowTaskCardDescriptionChange, "aria-describedby": runtimeMode === 'cloud' ? 'task-card-description-cloud-help' : undefined }), _jsx("span", { children: "Show description" })] }), runtimeMode === 'cloud' && (_jsx("span", { id: "task-card-description-cloud-help", className: styles.taskCardSettingHelp, children: "Unavailable in cloud to keep task collections fast." }))] }), _jsxs("label", { className: styles.archiveToggle, children: [_jsx("input", { type: "checkbox", checked: showTaskCardAttachments, onChange: async (e) => {
1043
+ if (!onShowTaskCardAttachmentsChange)
1044
+ return;
1045
+ const success = await onShowTaskCardAttachmentsChange(e.target.checked);
1046
+ reportTaskCardPreferenceResult(success, 'Failed to save task card attachments setting.');
1047
+ }, disabled: !onShowTaskCardAttachmentsChange }), _jsx("span", { children: "Show attachments" })] }), _jsxs("label", { className: styles.archiveToggle, children: [_jsx("input", { type: "checkbox", checked: showTaskCardChecklistProgress, onChange: async (e) => {
1048
+ if (!onShowTaskCardChecklistProgressChange)
1049
+ return;
1050
+ const success = await onShowTaskCardChecklistProgressChange(e.target.checked);
1051
+ reportTaskCardPreferenceResult(success, 'Failed to save task card checklist progress setting.');
1052
+ }, disabled: !onShowTaskCardChecklistProgressChange }), _jsx("span", { children: "Show checklist progress" })] }), _jsxs("label", { className: styles.archiveToggle, children: [_jsx("input", { type: "checkbox", checked: showTaskCardLatestActivity, onChange: async (e) => {
1053
+ if (!onShowTaskCardLatestActivityChange)
1054
+ return;
1055
+ const success = await onShowTaskCardLatestActivityChange(e.target.checked);
1056
+ reportTaskCardPreferenceResult(success, 'Failed to save task card latest activity setting.');
1057
+ }, disabled: !onShowTaskCardLatestActivityChange }), _jsx("span", { children: "Show latest activity" })] }), _jsxs("label", { className: `${styles.archiveToggle} ${styles.taskCardDependentSetting}`, children: [_jsx("input", { type: "checkbox", checked: tintTaskCardActivityBackground, onChange: async (e) => {
1058
+ if (!onTintTaskCardActivityBackgroundChange)
1059
+ return;
1060
+ const success = await onTintTaskCardActivityBackgroundChange(e.target.checked);
1061
+ reportTaskCardPreferenceResult(success, 'Failed to save task card activity background setting.');
1062
+ }, disabled: !showTaskCardLatestActivity || !onTintTaskCardActivityBackgroundChange }), _jsx("span", { children: "Tint latest activity background" })] })] }), _jsxs("section", { className: styles.taskCardSettingsPreview, "aria-labelledby": "task-card-preview-title", children: [_jsx("h3", { id: "task-card-preview-title", className: `${styles.settingTitle} tf-heading-section`, children: "Preview" }), _jsx("div", { className: styles.taskCardSettingsPreviewFrame, inert: true, children: _jsx(TaskCard, { task: taskCardPreviewTask, categories: categories, types: types, priorities: priorities, taxonomies: taxonomies, taskInitiative: TASK_CARD_PREVIEW_INITIATIVE, taskWorkstream: TASK_CARD_PREVIEW_WORKSTREAM, showStatusLabel: showTaskCardStatusLabel, showDescription: runtimeMode !== 'cloud' && showTaskCardDescription, showAttachments: showTaskCardAttachments, showChecklistProgress: showTaskCardChecklistProgress, showLatestActivity: showTaskCardLatestActivity, tintActivityBackground: tintTaskCardActivityBackground }) })] })] })), activeTab === 'appearanceTaskForms' && renderTaskFormsControls(), 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) => {
956
1063
  const nextId = e.target.value;
957
1064
  setSelectedInitiativeTemplateId(nextId);
958
1065
  }, 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: "Enter initiative title", value: initiativeTitle, onChange: (e) => setInitiativeTitle(e.target.value) })] }), _jsxs("button", { className: `${styles.secondaryHeaderBtn} ${styles.marginTop12}`, disabled: isCreatingInitiative || !selectedInitiativeTemplateId || !initiativeTitle.trim() || !onCreateInitiativeFromTemplate, onClick: async () => {
@@ -24,7 +24,7 @@ export declare const TASKFORCE_TOOL_MODULES: readonly [{
24
24
  readonly description: "Read workspace configuration, people, and managed Agent identity.";
25
25
  readonly icon: import("react").ForwardRefExoticComponent<Omit<import("lucide-react").LucideProps, "ref"> & import("react").RefAttributes<SVGSVGElement>>;
26
26
  }];
27
- export declare const TASKFORCE_TOOL_MODULE_KEYS: ("tasks" | "planning" | "workspace" | "documents" | "images")[];
27
+ export declare const TASKFORCE_TOOL_MODULE_KEYS: ("images" | "documents" | "tasks" | "planning" | "workspace")[];
28
28
  export type ToolAccessMode = 'active' | 'preview' | 'requirement';
29
29
  export declare function ToolAccessSelector({ selectedKeys, onChange, disabled, mode, title, description, showFutureTools, requireOne, hasCustomOverrides, }: {
30
30
  selectedKeys: string[];
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import React from 'react';
3
- import { AlertTriangle, Archive, ArrowUpDown, ChevronLeft, Eye, EyeOff, Filter, Link2, Loader2, Pencil, Plus, RotateCcw, Search, Unlink, X, } from 'lucide-react';
3
+ import { AlertTriangle, Archive, ArrowUpDown, ChevronLeft, Eye, EyeOff, Filter, Loader2, Pencil, Plus, RotateCcw, Search, Unlink, X, } from 'lucide-react';
4
4
  import { TASK_ASSIGNEE_UNASSIGNED_COLOR, TASK_ASSIGNEE_UNASSIGNED_ICON, } from '../../../utils/assignees';
5
5
  import { resolvePlanningArchiveDetailState } from '../../../utils/planningArchivePresentation';
6
6
  import { formatInitiativeReference, formatWorkstreamReference, } from '../../../utils/planningReferences';
@@ -223,7 +223,6 @@ export function PlanningModule({ model }) {
223
223
  const [showArchivedPlanning, setShowArchivedPlanning] = React.useState(false);
224
224
  const taskArrangeMode = model.taskArrangeMode || 'execution';
225
225
  const [createState, setCreateState] = React.useState(null);
226
- const [showParentLinkPicker, setShowParentLinkPicker] = React.useState(false);
227
226
  const [pendingUnlink, setPendingUnlink] = React.useState(null);
228
227
  const [relationshipRecovery, setRelationshipRecovery] = React.useState(null);
229
228
  const [isChangingRelationship, setIsChangingRelationship] = React.useState(false);
@@ -349,7 +348,6 @@ export function PlanningModule({ model }) {
349
348
  void model.hydrateEntity(selectedEntityType, selectedEntityId);
350
349
  }, [model.hydrateEntity, selectedEntityId, selectedEntityType]);
351
350
  React.useEffect(() => {
352
- setShowParentLinkPicker(false);
353
351
  setPendingUnlink(null);
354
352
  setRelationshipRecovery(null);
355
353
  setIsChangingRelationship(false);
@@ -434,7 +432,6 @@ export function PlanningModule({ model }) {
434
432
  const result = await model.assignWorkstreamToInitiative(selectedWorkstream.id, option.referenceLabel);
435
433
  if (result !== false) {
436
434
  setSelectedInitiativeId(option.id);
437
- setShowParentLinkPicker(false);
438
435
  }
439
436
  }
440
437
  finally {
@@ -562,7 +559,7 @@ export function PlanningModule({ model }) {
562
559
  ? `${formatInitiativeReference(selectedInitiative)} ${selectedInitiative.title}`.trim()
563
560
  : 'its initiative',
564
561
  });
565
- }, title: "Unlink workstream from initiative", ariaLabel: "Unlink workstream from initiative", children: _jsx(Unlink, { size: 14, "aria-hidden": "true" }) })) : (_jsx(HierarchyActionBadge, { disabled: !model.assignWorkstreamToInitiative || isChangingRelationship, onClick: () => setShowParentLinkPicker((current) => !current), title: "Link initiative", ariaLabel: "Link initiative", ariaExpanded: showParentLinkPicker, children: _jsx(Link2, { size: 14, "aria-hidden": "true" }) })), relationshipContent: (_jsx(_Fragment, { children: !selectedWorkstream.initiativeId && showParentLinkPicker ? (_jsxs("div", { className: styles.relationshipPickerRow, children: [_jsx(PlanningLinkPicker, { options: model.linkOptions.initiatives, entityLabel: "initiative", onSelect: linkSelectedWorkstreamToInitiative, disabled: isChangingRelationship }), _jsx("button", { type: "button", className: "tf-control-icon tf-control-icon-compact", disabled: isChangingRelationship, onClick: () => setShowParentLinkPicker(false), title: "Cancel initiative link", "aria-label": "Cancel initiative link", children: _jsx(X, { size: 14, "aria-hidden": "true" }) })] })) : null })) }), _jsx(PlanningLinkPicker, { options: availableTaskLinks, entityLabel: "task", onSelect: (option) => attachRelationship('task', option), disabled: !model.attachTaskToWorkstream || isChangingRelationship }), model.setTaskArrangeMode ? (_jsx(PlanningTaskArrangeControl, { value: taskArrangeMode, onChange: model.setTaskArrangeMode })) : null] })) : null, _jsx(PlanningTaskOrderList, { tasks: visibleTasks, mode: taskArrangeMode, onReorder: selectedWorkstream && model.reorderWorkstreamTasks
562
+ }, title: "Unlink workstream from initiative", ariaLabel: "Unlink workstream from initiative", children: _jsx(Unlink, { size: 14, "aria-hidden": "true" }) })) : (_jsx(PlanningLinkPicker, { options: model.linkOptions.initiatives, entityLabel: "initiative", onSelect: linkSelectedWorkstreamToInitiative, disabled: !model.assignWorkstreamToInitiative || isChangingRelationship, iconTrigger: true, triggerTitle: "Link initiative" })) }), _jsx(PlanningLinkPicker, { options: availableTaskLinks, entityLabel: "task", onSelect: (option) => attachRelationship('task', option), disabled: !model.attachTaskToWorkstream || isChangingRelationship }), model.setTaskArrangeMode ? (_jsx(PlanningTaskArrangeControl, { value: taskArrangeMode, onChange: model.setTaskArrangeMode })) : null] })) : null, _jsx(PlanningTaskOrderList, { tasks: visibleTasks, mode: taskArrangeMode, onReorder: selectedWorkstream && model.reorderWorkstreamTasks
566
563
  ? (taskIds) => model.reorderWorkstreamTasks?.(selectedWorkstream.id, mergeVisiblePlanningTaskOrder(arrangePlanningTasks(selectedWorkstream.tasks ?? [], 'execution'), taskIds))
567
564
  : undefined, children: (task) => {
568
565
  const referenceLabel = getTaskReferenceLabel(task);
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import type { PlanningTaskPreview } from './planningWorkspaceModel';
3
- import type { PlanningTaskArrangeMode } from './planningTaskArrangement';
3
+ import { type PlanningTaskArrangeMode } from './planningTaskArrangement';
4
4
  export declare function PlanningTaskOrderList(props: {
5
5
  tasks: PlanningTaskPreview[];
6
6
  mode: PlanningTaskArrangeMode;