@taskforcehq/taskforce 0.3.303 → 0.3.305

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 (237) hide show
  1. package/README.md +140 -247
  2. package/dist/Taskforce.module.css +102 -5
  3. package/dist/TaskforceCore.js +635 -238
  4. package/dist/TaskforceCore.test.js +2243 -495
  5. package/dist/annotatedAttachments/service.d.ts +1 -1
  6. package/dist/annotatedAttachments/types.d.ts +1 -1
  7. package/dist/compat/workspaceSyncCompat.js +6 -0
  8. package/dist/components/features/AgentsModule.js +1 -1
  9. package/dist/components/features/AgentsModule.test.js +1 -1
  10. package/dist/components/features/DocumentIndex.d.ts +1 -1
  11. package/dist/components/features/DocumentIndex.js +1 -1
  12. package/dist/components/features/DocumentViewer.d.ts +1 -1
  13. package/dist/components/features/DocumentViewer.js +32 -9
  14. package/dist/components/features/DocumentWorkspace.d.ts +5 -22
  15. package/dist/components/features/DocumentWorkspace.js +12 -155
  16. package/dist/components/features/DocumentWorkspace.test.js +193 -6
  17. package/dist/components/features/TaskSettings.js +87 -41
  18. package/dist/components/features/TaskSettings.test.js +180 -40
  19. package/dist/components/features/documentWorkspaceModel.d.ts +24 -0
  20. package/dist/components/features/documentWorkspaceModel.js +57 -0
  21. package/dist/components/features/useDocumentWorkspaceController.d.ts +34 -0
  22. package/dist/components/features/useDocumentWorkspaceController.js +113 -0
  23. package/dist/components/task/TaskActionHeader.d.ts +2 -1
  24. package/dist/components/task/TaskActionHeader.js +3 -3
  25. package/dist/components/task/TaskActionHeader.test.js +8 -0
  26. package/dist/components/task/TaskCard.js +16 -1
  27. package/dist/components/task/TaskCard.test.js +31 -0
  28. package/dist/components/task/TaskForm.d.ts +9 -8
  29. package/dist/components/task/TaskForm.js +374 -219
  30. package/dist/components/task/TaskForm.test.js +482 -361
  31. package/dist/components/task/TaskKanban.d.ts +1 -1
  32. package/dist/components/task/TaskKanban.js +33 -161
  33. package/dist/components/task/TaskStatusActions.d.ts +6 -1
  34. package/dist/components/task/TaskStatusActions.js +8 -3
  35. package/dist/components/task/TaskStatusActions.test.js +9 -0
  36. package/dist/components/task/taskKanbanDropRules.d.ts +58 -0
  37. package/dist/components/task/taskKanbanDropRules.js +187 -0
  38. package/dist/components/task/taskKanbanDropRules.test.d.ts +1 -0
  39. package/dist/components/task/taskKanbanDropRules.test.js +114 -0
  40. package/dist/components/ui/Modal.d.ts +1 -1
  41. package/dist/components/ui/Modal.js +1 -0
  42. package/dist/components/views/AppShellHeader.js +5 -1
  43. package/dist/components/views/AppShellHeader.test.js +4 -0
  44. package/dist/components/views/PlanComparisonPage.d.ts +3 -2
  45. package/dist/components/views/PlanComparisonPage.js +9 -10
  46. package/dist/components/views/PlanComparisonPage.test.js +55 -41
  47. package/dist/components/views/PlansPage.d.ts +5 -1
  48. package/dist/components/views/PlansPage.js +150 -81
  49. package/dist/components/views/PlansPage.test.js +367 -41
  50. package/dist/components/views/StandaloneLayout.js +135 -54
  51. package/dist/components/views/WidgetView.js +11 -2
  52. package/dist/components/views/panels/FilterToolbar.test.js +6 -4
  53. package/dist/components/views/standalone/modals/AccountHubModal.d.ts +2 -14
  54. package/dist/components/views/standalone/modals/AccountHubModal.js +12 -14
  55. package/dist/components/views/standalone/modals/AccountHubModal.test.js +24 -1
  56. package/dist/components/views/standalone/modals/SyncStatusModal.js +1 -1
  57. package/dist/config/envSchema.js +1 -1
  58. package/dist/core/AiProfileService.d.ts +6 -1
  59. package/dist/core/AiProfileService.js +161 -16
  60. package/dist/core/AiProfileService.test.js +3 -1
  61. package/dist/core/AiProfiles.test.js +200 -0
  62. package/dist/core/AuthTokenService.test.d.ts +1 -0
  63. package/dist/core/AuthTokenService.test.js +78 -0
  64. package/dist/core/DeletedTaskLifecycleService.d.ts +2 -1
  65. package/dist/core/EntitlementsPolicy.test.js +75 -13
  66. package/dist/core/PlanEntitlementService.d.ts +9 -1
  67. package/dist/core/PlanEntitlementService.js +144 -19
  68. package/dist/core/PlanVersionPolicy.test.js +19 -26
  69. package/dist/core/SignupMonetizationSettings.test.js +75 -15
  70. package/dist/core/SystemAdmin.test.js +212 -56
  71. package/dist/core/TaskActivityService.d.ts +4 -1
  72. package/dist/core/TaskActivityService.js +45 -0
  73. package/dist/core/TaskAuditTimeline.test.js +52 -1
  74. package/dist/core/TaskTaxonomyValidation.test.js +53 -0
  75. package/dist/core/Taskforce.d.ts +18 -11
  76. package/dist/core/Taskforce.js +93 -12
  77. package/dist/core/WorkspacePlanMode.test.js +73 -8
  78. package/dist/core/shared.d.ts +2 -0
  79. package/dist/core/shared.js +11 -0
  80. package/dist/documentReviews/service.d.ts +1 -1
  81. package/dist/documentReviews/types.d.ts +1 -1
  82. package/dist/hooks/auth/useTaskforceAuthBootstrap.d.ts +48 -0
  83. package/dist/hooks/auth/useTaskforceAuthBootstrap.js +219 -0
  84. package/dist/hooks/sync/auth.d.ts +37 -0
  85. package/dist/hooks/sync/auth.js +63 -0
  86. package/dist/hooks/sync/bootstrap.d.ts +34 -0
  87. package/dist/hooks/sync/bootstrap.js +52 -0
  88. package/dist/hooks/sync/orchestratorShared.d.ts +36 -0
  89. package/dist/hooks/sync/orchestratorShared.js +209 -0
  90. package/dist/hooks/sync/orchestratorShared.test.d.ts +1 -0
  91. package/dist/hooks/sync/orchestratorShared.test.js +49 -0
  92. package/dist/hooks/sync/realtime.d.ts +25 -0
  93. package/dist/hooks/sync/realtime.js +60 -0
  94. package/dist/hooks/sync/recovery.d.ts +69 -0
  95. package/dist/hooks/sync/recovery.js +118 -0
  96. package/dist/hooks/sync/transfers.d.ts +123 -0
  97. package/dist/hooks/sync/transfers.js +435 -0
  98. package/dist/hooks/sync/useDataVersionRefresh.d.ts +16 -0
  99. package/dist/hooks/sync/useDataVersionRefresh.js +73 -0
  100. package/dist/hooks/ui/useResourceExport.d.ts +3 -1
  101. package/dist/hooks/ui/useResourceExport.js +5 -2
  102. package/dist/hooks/ui/useWorkflowTemplates.js +11 -6
  103. package/dist/hooks/useRealtimeSync.js +2 -1
  104. package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +8 -0
  105. package/dist/hooks/useSyncOrchestrator.context-assets.test.d.ts +1 -0
  106. package/dist/hooks/useSyncOrchestrator.context-assets.test.js +228 -0
  107. package/dist/hooks/useSyncOrchestrator.d.ts +12 -8
  108. package/dist/hooks/useSyncOrchestrator.js +388 -879
  109. package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +641 -6
  110. package/dist/hooks/useTaskMutations.d.ts +2 -1
  111. package/dist/hooks/useTaskMutations.js +57 -7
  112. package/dist/hooks/useTaskMutations.test.js +176 -0
  113. package/dist/hooks/useTaskforce.d.ts +13 -4
  114. package/dist/hooks/useTaskforce.js +302 -817
  115. package/dist/hooks/useTaskforce.sync-behavior.test.js +78 -0
  116. package/dist/hooks/useWorkspaceSyncController.d.ts +4 -1
  117. package/dist/hooks/useWorkspaceSyncController.js +33 -11
  118. package/dist/hooks/useWorkspaceSyncController.test.js +1 -0
  119. package/dist/hooks/workspace/useTaskforceApiRouting.test.js +17 -0
  120. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.d.ts +166 -0
  121. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +434 -0
  122. package/dist/hooks/workspace/workspaceLocalState.d.ts +19 -0
  123. package/dist/hooks/workspace/workspaceLocalState.js +100 -0
  124. package/dist/hooks/workspace/workspaceLocalState.test.d.ts +1 -0
  125. package/dist/hooks/workspace/workspaceLocalState.test.js +59 -0
  126. package/dist/localization/locales/en-US.js +2 -2
  127. package/dist/mcp/adminWorkspaceRegistrar.d.ts +2 -0
  128. package/dist/mcp/adminWorkspaceRegistrar.js +154 -0
  129. package/dist/mcp/canonicalAssetHelpers.d.ts +70 -0
  130. package/dist/mcp/canonicalAssetHelpers.js +259 -0
  131. package/dist/mcp/clientIntegrations.d.ts +12 -1
  132. package/dist/mcp/clientIntegrations.js +161 -6
  133. package/dist/mcp/clientIntegrations.test.js +76 -4
  134. package/dist/mcp/collaborationRegistrar.d.ts +2 -0
  135. package/dist/mcp/collaborationRegistrar.js +71 -0
  136. package/dist/mcp/documentAssetRegistrar.d.ts +2 -0
  137. package/dist/mcp/documentAssetRegistrar.js +346 -0
  138. package/dist/mcp/documentHelpers.d.ts +100 -0
  139. package/dist/mcp/documentHelpers.js +161 -0
  140. package/dist/mcp/runtime.js +2455 -3925
  141. package/dist/mcp/runtime.test.js +240 -8
  142. package/dist/mcp/taskAttachmentHelpers.d.ts +41 -0
  143. package/dist/mcp/taskAttachmentHelpers.js +60 -0
  144. package/dist/mcp/taskAttachmentTypes.d.ts +37 -0
  145. package/dist/mcp/taskAttachmentTypes.js +1 -0
  146. package/dist/mcp/taskPlanningRegistrar.d.ts +2 -0
  147. package/dist/mcp/taskPlanningRegistrar.js +418 -0
  148. package/dist/mcp/toolCatalog.d.ts +35 -0
  149. package/dist/mcp/toolCatalog.js +3 -0
  150. package/dist/plugins/vite.js +1 -1
  151. package/dist/runtime/appGateDefinitions.d.ts +1 -1
  152. package/dist/runtime/appGateDefinitions.js +1 -1
  153. package/dist/server/index.d.ts +1 -0
  154. package/dist/server/index.js +46 -3
  155. package/dist/server/index.test.js +12 -1
  156. package/dist/server/routes/admin.d.ts +1 -5
  157. package/dist/server/routes/admin.js +151 -80
  158. package/dist/server/routes/annotatedAttachments.d.ts +1 -1
  159. package/dist/server/routes/annotatedAttachments.js +1 -1
  160. package/dist/server/routes/auth.d.ts +1 -4
  161. package/dist/server/routes/auth.js +59 -64
  162. package/dist/server/routes/authSupport.d.ts +30 -0
  163. package/dist/server/routes/authSupport.js +81 -0
  164. package/dist/server/routes/billing.d.ts +1 -1
  165. package/dist/server/routes/billing.js +122 -255
  166. package/dist/server/routes/billing.test.js +257 -86
  167. package/dist/server/routes/documentReviews.d.ts +1 -1
  168. package/dist/server/routes/documentReviews.js +1 -1
  169. package/dist/server/routes/documents.d.ts +4 -2
  170. package/dist/server/routes/documents.js +73 -7
  171. package/dist/server/routes/primitives.d.ts +11 -0
  172. package/dist/server/routes/primitives.js +73 -0
  173. package/dist/server/routes/resources.d.ts +1 -1
  174. package/dist/server/routes/resources.js +1 -1
  175. package/dist/server/routes/shared.d.ts +31 -1
  176. package/dist/server/routes/shared.js +26 -0
  177. package/dist/server/routes/sync.d.ts +1 -1
  178. package/dist/server/routes/sync.integration.test.js +20 -0
  179. package/dist/server/routes/sync.js +111 -238
  180. package/dist/server/routes/tasks.d.ts +1 -1
  181. package/dist/server/routes/tasks.js +50 -8
  182. package/dist/server/routes/workspaces.d.ts +1 -1
  183. package/dist/server/routes/workspaces.js +1 -1
  184. package/dist/server/routes.d.ts +2 -9
  185. package/dist/server/routes.js +84 -181
  186. package/dist/server/routes.test.js +912 -32
  187. package/dist/shared/taskActor.d.ts +10 -0
  188. package/dist/shared/taskActor.js +1 -0
  189. package/dist/sync/collaborationSyncPayload.js +4 -0
  190. package/dist/sync/collaborationSyncPayload.test.js +8 -0
  191. package/dist/sync/collaborationSyncState.d.ts +3 -1
  192. package/dist/sync/collaborationSyncState.js +19 -0
  193. package/dist/sync/contentSyncState.js +28 -17
  194. package/dist/sync/syncApplyHandlers.d.ts +87 -1
  195. package/dist/sync/syncApplyHandlers.js +370 -8
  196. package/dist/sync/syncApplyHandlers.test.d.ts +1 -0
  197. package/dist/sync/syncApplyHandlers.test.js +379 -0
  198. package/dist/sync/syncService.d.ts +9 -1
  199. package/dist/sync/syncService.js +44 -2
  200. package/dist/sync/syncService.test.js +62 -0
  201. package/dist/sync/workspacePullFeed.d.ts +1 -0
  202. package/dist/sync/workspacePullFeed.js +66 -59
  203. package/dist/sync/workspacePullFeed.test.js +72 -4
  204. package/dist/sync/workspaceSyncModel.d.ts +25 -1
  205. package/dist/sync/workspaceSyncModel.js +77 -3
  206. package/dist/sync/workspaceSyncModel.test.js +153 -0
  207. package/dist/sync/workspaceSyncState.d.ts +2 -0
  208. package/dist/sync/workspaceSyncState.js +1 -0
  209. package/dist/types.d.ts +2 -10
  210. package/dist/ui/assets/AgentsModule-N2MnQBZk.js +1 -0
  211. package/dist/ui/assets/{AnnotatedAttachmentWorkspace-C_TmXZwA.js → AnnotatedAttachmentWorkspace-BG6P_GVW.js} +1 -1
  212. package/dist/ui/assets/DocumentWorkspace-B3nV_Gc5.css +1 -0
  213. package/dist/ui/assets/DocumentWorkspace-DRbDMwh8.js +252 -0
  214. package/dist/ui/assets/{InitiativesModule-4-Rh2K2n.js → InitiativesModule-Dhm7M8e7.js} +1 -1
  215. package/dist/ui/assets/{PlansPage-BlVC_lRq.css → PlansPage-C2dd2n1X.css} +1 -1
  216. package/dist/ui/assets/PlansPage-Cq0zXj3I.js +1 -0
  217. package/dist/ui/assets/TaskSettings-ln0aF7xc.js +9 -0
  218. package/dist/ui/assets/{WorkflowsModule-CGk9s3NJ.js → WorkflowsModule-BcS4afRn.js} +1 -1
  219. package/dist/ui/assets/index-C2-OXZV7.css +1 -0
  220. package/dist/ui/assets/index-DcSI5F86.js +6 -0
  221. package/dist/ui/assets/{vendor-icons-pWocEipT.js → vendor-icons-BSUaRwF8.js} +1 -1
  222. package/dist/ui/index.html +4 -4
  223. package/dist/utils/commercialLifecyclePresentation.d.ts +19 -0
  224. package/dist/utils/commercialLifecyclePresentation.js +196 -0
  225. package/dist/utils/taskActivity.js +4 -0
  226. package/dist/utils/taskActivity.test.js +25 -1
  227. package/package.json +10 -1
  228. package/scripts/check-cloud-mcp.mjs +83 -0
  229. package/scripts/playwright-auth.sh +9 -1
  230. package/scripts/run-billing-performance-smoke.sh +24 -0
  231. package/dist/ui/assets/AgentsModule-CpsTmrIW.js +0 -1
  232. package/dist/ui/assets/DocumentWorkspace-C3GyzrWm.js +0 -250
  233. package/dist/ui/assets/DocumentWorkspace-C_8T8oz-.css +0 -1
  234. package/dist/ui/assets/PlansPage-BP7AYOqr.js +0 -1
  235. package/dist/ui/assets/TaskSettings-BOC5F6Ag.js +0 -8
  236. package/dist/ui/assets/index-CLIMgR6g.js +0 -6
  237. package/dist/ui/assets/index-DneETxcu.css +0 -1
@@ -23,8 +23,9 @@ interface TaskActionHeaderProps {
23
23
  handleToggleCancel: (task: TaskItem) => void;
24
24
  handleSetStatus?: (task: TaskItem, status: TaskStatus) => void;
25
25
  handleArchiveTask: (task: TaskItem) => void;
26
+ handleUnarchiveTask?: (taskId: string) => void;
26
27
  handleRestoreDeletedTask?: (deletedRecordId: string) => void;
27
28
  handlePermanentlyDeleteDeletedTask?: (deletedRecordId: string) => void;
28
29
  }
29
- export declare function TaskActionHeader({ editingTaskId, loading, autoSaveState, title, handleSubmit, resetForm, handleCopyId, copiedId, tasks, currentTask: currentTaskProp, currentTaskWorkstream, currentTaskInitiative, workstreamInput, onWorkstreamInputChange, onSetWorkstreamForCurrentTask, handleToggleInProgress, handleToggleReview, handleToggleComplete, handleToggleCancel, handleSetStatus, handleArchiveTask, handleRestoreDeletedTask, handlePermanentlyDeleteDeletedTask }: TaskActionHeaderProps): import("react/jsx-runtime").JSX.Element;
30
+ export declare function TaskActionHeader({ editingTaskId, loading, autoSaveState, title, handleSubmit, resetForm, handleCopyId, copiedId, tasks, currentTask: currentTaskProp, currentTaskWorkstream, currentTaskInitiative, workstreamInput, onWorkstreamInputChange, onSetWorkstreamForCurrentTask, handleToggleInProgress, handleToggleReview, handleToggleComplete, handleToggleCancel, handleSetStatus, handleArchiveTask, handleUnarchiveTask, handleRestoreDeletedTask, handlePermanentlyDeleteDeletedTask }: TaskActionHeaderProps): import("react/jsx-runtime").JSX.Element;
30
31
  export {};
@@ -7,7 +7,7 @@ import { TaskStatusActions } from './TaskStatusActions';
7
7
  import { getTaskReferenceDisplayState } from '../../utils/taskReferences';
8
8
  import { TaskReferenceBadge } from './TaskReferenceBadge';
9
9
  import { formatInitiativeReference, getWorkstreamReferenceLabel } from '../../utils/planningReferences';
10
- export function TaskActionHeader({ editingTaskId, loading, autoSaveState = 'idle', title, handleSubmit, resetForm, handleCopyId, copiedId, tasks, currentTask: currentTaskProp, currentTaskWorkstream, currentTaskInitiative, workstreamInput = '', onWorkstreamInputChange, onSetWorkstreamForCurrentTask, handleToggleInProgress, handleToggleReview, handleToggleComplete, handleToggleCancel, handleSetStatus, handleArchiveTask, handleRestoreDeletedTask, handlePermanentlyDeleteDeletedTask }) {
10
+ export function TaskActionHeader({ editingTaskId, loading, autoSaveState = 'idle', title, handleSubmit, resetForm, handleCopyId, copiedId, tasks, currentTask: currentTaskProp, currentTaskWorkstream, currentTaskInitiative, workstreamInput = '', onWorkstreamInputChange, onSetWorkstreamForCurrentTask, handleToggleInProgress, handleToggleReview, handleToggleComplete, handleToggleCancel, handleSetStatus, handleArchiveTask, handleUnarchiveTask, handleRestoreDeletedTask, handlePermanentlyDeleteDeletedTask }) {
11
11
  const [showWorkstreamEditor, setShowWorkstreamEditor] = React.useState(false);
12
12
  const currentTask = currentTaskProp ?? (editingTaskId ? tasks.find(t => t.id === editingTaskId) || null : null);
13
13
  const isArchivedReadOnly = Boolean(currentTask?.isArchived);
@@ -48,7 +48,7 @@ export function TaskActionHeader({ editingTaskId, loading, autoSaveState = 'idle
48
48
  } }), _jsx("button", { type: "button", className: "tf-control-icon tf-control-icon-compact", onClick: handleWorkstreamConfirm, disabled: !workstreamInput.trim() || loading, title: "Attach workstream", "aria-label": "Attach workstream", children: _jsx(Check, { size: 14 }) }), _jsx("button", { type: "button", className: "tf-control-icon tf-control-icon-compact", onClick: () => {
49
49
  onWorkstreamInputChange?.('');
50
50
  setShowWorkstreamEditor(false);
51
- }, disabled: loading, title: "Cancel workstream attach", "aria-label": "Cancel workstream attach", children: _jsx(X, { size: 14 }) })] })) : null] }), _jsx("div", { className: styles.taskSaveStatusCenter, children: _jsx("div", { className: `${styles.taskSaveStatus} ${autoSaveState === 'error' ? styles.taskSaveStatusError : ''}`, "aria-live": "polite", children: autoSaveState === 'saving' ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { size: 14, className: styles.spinner }), _jsx("span", { children: "Saving\u2026" })] })) : autoSaveState === 'saved' ? (_jsx("span", { children: "Saved" })) : autoSaveState === 'error' ? (_jsx("span", { children: "Save failed" })) : null }) }), _jsx("div", { className: styles.editActionsGroup, children: isDeletedReadOnly && currentTask?.deletedRecordId ? (_jsxs(_Fragment, { children: [handleRestoreDeletedTask && (_jsx("button", { type: "button", className: styles.actionBtn, onClick: () => handleRestoreDeletedTask(currentTask.deletedRecordId || ''), disabled: loading, title: "Restore deleted task", children: _jsx(RotateCcw, { size: 16 }) })), handlePermanentlyDeleteDeletedTask && (_jsx("button", { type: "button", className: `${styles.actionBtn} ${styles.deleteBtn}`, onClick: () => handlePermanentlyDeleteDeletedTask(currentTask.deletedRecordId || ''), disabled: loading, title: "Permanently delete deleted task", children: _jsx(Trash2, { size: 16 }) }))] })) : (_jsx(TaskStatusActions, { task: currentTask, disabled: loading || isArchivedReadOnly, onSetStatus: (task, status) => {
51
+ }, disabled: loading, title: "Cancel workstream attach", "aria-label": "Cancel workstream attach", children: _jsx(X, { size: 14 }) })] })) : null] }), _jsx("div", { className: styles.taskSaveStatusCenter, children: _jsx("div", { className: `${styles.taskSaveStatus} ${autoSaveState === 'error' ? styles.taskSaveStatusError : ''}`, "aria-live": "polite", children: autoSaveState === 'saving' ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { size: 14, className: styles.spinner }), _jsx("span", { children: "Saving\u2026" })] })) : autoSaveState === 'saved' ? (_jsx("span", { children: "Saved" })) : autoSaveState === 'error' ? (_jsx("span", { children: "Save failed" })) : null }) }), _jsx("div", { className: styles.editActionsGroup, children: isDeletedReadOnly && currentTask?.deletedRecordId ? (_jsxs(_Fragment, { children: [handleRestoreDeletedTask && (_jsx("button", { type: "button", className: styles.actionBtn, onClick: () => handleRestoreDeletedTask(currentTask.deletedRecordId || ''), disabled: loading, title: "Restore deleted task", children: _jsx(RotateCcw, { size: 16 }) })), handlePermanentlyDeleteDeletedTask && (_jsx("button", { type: "button", className: `${styles.actionBtn} ${styles.deleteBtn}`, onClick: () => handlePermanentlyDeleteDeletedTask(currentTask.deletedRecordId || ''), disabled: loading, title: "Permanently delete deleted task", children: _jsx(Trash2, { size: 16 }) }))] })) : (_jsx(TaskStatusActions, { task: currentTask, disabled: loading, statusDisabled: loading || isArchivedReadOnly, archiveActionMode: isArchivedReadOnly ? 'unarchive' : 'auto', onSetStatus: (task, status) => {
52
52
  if (handleSetStatus) {
53
53
  handleSetStatus(task, status);
54
54
  return;
@@ -68,5 +68,5 @@ export function TaskActionHeader({ editingTaskId, loading, autoSaveState = 'idle
68
68
  if (status === 'cancelled') {
69
69
  handleToggleCancel(task);
70
70
  }
71
- }, onArchiveTask: handleArchiveTask })) })] })) : (_jsxs(_Fragment, { children: [_jsxs("button", { type: "button", onClick: resetForm, disabled: loading, className: styles.secondaryHeaderBtn, title: t('actionHeader.clearFormTitle'), children: [_jsx(RotateCcw, { size: 16 }), t('actionHeader.clear')] }), _jsxs("button", { type: "button", onClick: (e) => handleSubmit(e), disabled: loading || !title.trim(), className: styles.primaryUpdateBtn, title: t('actionHeader.addTaskTitle'), children: [loading ? _jsx(Loader2, { size: 16, className: styles.spinner }) : _jsx(Plus, { size: 16 }), t('actionHeader.addTask')] })] })) }));
71
+ }, onArchiveTask: handleArchiveTask, onUnarchiveTask: (task) => handleUnarchiveTask?.(task.id) })) })] })) : (_jsxs(_Fragment, { children: [_jsxs("button", { type: "button", onClick: resetForm, disabled: loading, className: styles.secondaryHeaderBtn, title: t('actionHeader.clearFormTitle'), children: [_jsx(RotateCcw, { size: 16 }), t('actionHeader.clear')] }), _jsxs("button", { type: "button", onClick: (e) => handleSubmit(e), disabled: loading || !title.trim(), className: styles.primaryUpdateBtn, title: t('actionHeader.addTaskTitle'), children: [loading ? _jsx(Loader2, { size: 16, className: styles.spinner }) : _jsx(Plus, { size: 16 }), t('actionHeader.addTask')] })] })) }));
72
72
  }
@@ -70,4 +70,12 @@ describe('TaskActionHeader', () => {
70
70
  await user.click(screen.getByRole('button', { name: /cancel workstream attach/i }));
71
71
  expect(onWorkstreamInputChange).toHaveBeenCalledWith('');
72
72
  });
73
+ it('shows an unarchive action for archived tasks and wires it to the task id', async () => {
74
+ const user = userEvent.setup();
75
+ const handleUnarchiveTask = vi.fn();
76
+ render(_jsx(TaskActionHeader, { ...baseProps, editingTaskId: "task-1", title: "Polish task modal", currentTask: { ...baseTask, status: 'done', isArchived: true }, handleUnarchiveTask: handleUnarchiveTask }));
77
+ expect(screen.queryByRole('button', { name: /^Archive task$/i })).not.toBeInTheDocument();
78
+ await user.click(screen.getByRole('button', { name: /unarchive task/i }));
79
+ expect(handleUnarchiveTask).toHaveBeenCalledWith('task-1');
80
+ });
73
81
  });
@@ -54,7 +54,22 @@ const TaskCardInner = ({ task, searchQuery = '', copiedId = null, taxonomies = [
54
54
  const latestActivity = React.useMemo(() => getLatestTaskActivity(task), [task]);
55
55
  const resolvedReadOnlyMode = readOnlyMode || (task.isDeleted ? 'deleted' : (isArchived ? 'archived' : null));
56
56
  const isReadOnly = resolvedReadOnlyMode !== null;
57
- const latestActivityText = React.useMemo(() => summarizeTaskActivity(latestActivity), [latestActivity]);
57
+ const formatActivityFieldValue = React.useCallback((field, value) => {
58
+ const normalizedValue = String(value || '').trim();
59
+ if (!normalizedValue)
60
+ return undefined;
61
+ if (field === 'assignee') {
62
+ return getAssigneeLabel(normalizedValue, assigneeOptions);
63
+ }
64
+ if (field === 'workstreamId' && normalizedValue === taskWorkstream?.id) {
65
+ return workstreamReferenceLabel || taskWorkstream.id;
66
+ }
67
+ if (field === 'initiativeId' && normalizedValue === taskInitiative?.id) {
68
+ return initiativeReferenceLabel || taskInitiative.id;
69
+ }
70
+ return undefined;
71
+ }, [assigneeOptions, initiativeReferenceLabel, taskInitiative, taskWorkstream, workstreamReferenceLabel]);
72
+ const latestActivityText = React.useMemo(() => summarizeTaskActivity(latestActivity, formatActivityFieldValue), [formatActivityFieldValue, latestActivity]);
58
73
  const activityCount = Array.isArray(task.activity) && task.activity.length > 0
59
74
  ? task.activity.length
60
75
  : (task.comments?.length || 0);
@@ -108,6 +108,37 @@ describe('TaskCard parent/child progress', () => {
108
108
  expect(screen.getByText(/Status: task -> review/)).toBeInTheDocument();
109
109
  expect(screen.getByTitle('2 activity items')).toBeInTheDocument();
110
110
  });
111
+ it('uses the current workstream reference in latest activity summaries', () => {
112
+ const task = baseTask({
113
+ id: 'task-relationship-summary',
114
+ title: 'Relationship summary task',
115
+ workstreamId: 'workstream-1',
116
+ activity: [
117
+ {
118
+ id: 'event:event-relationship-1',
119
+ type: 'event',
120
+ timestamp: '2026-03-22T10:00:00.000Z',
121
+ event: {
122
+ id: 'event-relationship-1',
123
+ taskId: 'task-relationship-summary',
124
+ workspaceId: 'default',
125
+ action: 'task-relationship-changed',
126
+ actor: 'user',
127
+ actorType: 'human',
128
+ createdAt: '2026-03-22T10:00:00.000Z',
129
+ details: {
130
+ changes: {
131
+ workstreamId: { from: null, to: 'workstream-1' }
132
+ }
133
+ }
134
+ }
135
+ }
136
+ ]
137
+ });
138
+ render(_jsx(TaskCard, { task: task, taskWorkstream: baseWorkstream({ id: 'workstream-1', referenceNumber: 12 }), onClick: () => { }, onCopyId: () => { } }));
139
+ expect(screen.getByText(/Workstream: none -> WS-12/)).toBeInTheDocument();
140
+ expect(screen.queryByText(/workstream-1/i)).not.toBeInTheDocument();
141
+ });
111
142
  it('renders named AI assignee labels from assignee options', () => {
112
143
  const task = baseTask({
113
144
  id: 'task-ai-assignee',
@@ -1,8 +1,8 @@
1
- import React from 'react';
2
- import type { TaskItem, CategoryConfig, Comment, AttachmentItem, TaskAssignee, ChecklistItem } from '../../types';
3
- import type { TaxonomyDefinition } from '../../types';
4
- import { type TaskAssigneeOption } from '../../utils/assignees';
5
- import type { WorkstreamItem } from '../../types';
1
+ import React from "react";
2
+ import type { TaskItem, CategoryConfig, Comment, AttachmentItem, TaskAssignee, ChecklistItem, InitiativeItem } from "../../types";
3
+ import type { TaxonomyDefinition } from "../../types";
4
+ import { type TaskAssigneeOption } from "../../utils/assignees";
5
+ import type { WorkstreamItem } from "../../types";
6
6
  interface TaskFormProps {
7
7
  editingTaskId: string | null;
8
8
  error: string;
@@ -36,7 +36,7 @@ interface TaskFormProps {
36
36
  label: string;
37
37
  color?: string;
38
38
  icon?: string;
39
- status?: 'active' | 'retired';
39
+ status?: "active" | "retired";
40
40
  }[];
41
41
  priorities: Array<{
42
42
  value: number;
@@ -58,6 +58,7 @@ interface TaskFormProps {
58
58
  assigneeOptions: TaskAssigneeOption[];
59
59
  taxonomies: TaxonomyDefinition[];
60
60
  workstreams?: WorkstreamItem[];
61
+ initiatives?: InitiativeItem[];
61
62
  copiedId: string | null;
62
63
  onTitleChange: (value: string) => void;
63
64
  onDescriptionChange: (value: string) => void;
@@ -77,7 +78,7 @@ interface TaskFormProps {
77
78
  onShowMarkdownHelpChange: (value: boolean) => void;
78
79
  onShowChecklistChange?: (value: boolean) => void;
79
80
  onShowCommentsChange: (value: boolean) => void;
80
- onOpenSettings?: (section: 'categories' | 'types') => void;
81
+ onOpenSettings?: (section: "categories" | "types") => void;
81
82
  onSubmit: (e: React.FormEvent) => void;
82
83
  onAddComment: () => void;
83
84
  onAddContextFile: (file: AttachmentItem) => void;
@@ -88,7 +89,7 @@ interface TaskFormProps {
88
89
  onToggleReview?: (task: TaskItem) => void;
89
90
  onToggleComplete?: (task: TaskItem) => void;
90
91
  onToggleCancel?: (task: TaskItem) => void;
91
- onSetStatus?: (task: TaskItem, status: TaskItem['status']) => void;
92
+ onSetStatus?: (task: TaskItem, status: TaskItem["status"]) => void;
92
93
  onArchiveTask?: (task: TaskItem) => void;
93
94
  onUnarchive?: (taskId: string) => void;
94
95
  onOpenTaskById?: (taskId: string) => void;