@taskforcehq/taskforce 0.3.306 → 0.3.308

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 (232) hide show
  1. package/README.md +0 -2
  2. package/dist/Taskforce.module.css +317 -27
  3. package/dist/TaskforceCore.js +1 -0
  4. package/dist/TaskforceCore.test.js +178 -0
  5. package/dist/components/activity/EntityActivityTimeline.d.ts +34 -0
  6. package/dist/components/activity/EntityActivityTimeline.js +81 -0
  7. package/dist/components/context/ContextAttachmentManager.js +15 -3
  8. package/dist/components/features/AgentsModule.d.ts +5 -1
  9. package/dist/components/features/AgentsModule.js +142 -39
  10. package/dist/components/features/AgentsModule.test.js +260 -11
  11. package/dist/components/features/AnnotatedAttachmentWorkspace.d.ts +3 -1
  12. package/dist/components/features/AnnotatedAttachmentWorkspace.js +118 -4
  13. package/dist/components/features/AnnotatedAttachmentWorkspace.test.js +52 -0
  14. package/dist/components/features/DocumentIndex.d.ts +2 -2
  15. package/dist/components/features/DocumentIndex.js +3 -4
  16. package/dist/components/features/DocumentViewer.d.ts +3 -1
  17. package/dist/components/features/DocumentViewer.js +6 -5
  18. package/dist/components/features/DocumentWorkspace.d.ts +10 -2
  19. package/dist/components/features/DocumentWorkspace.js +15 -4
  20. package/dist/components/features/DocumentWorkspace.test.js +20 -3
  21. package/dist/components/features/TaskSettings.d.ts +2 -0
  22. package/dist/components/features/TaskSettings.js +83 -78
  23. package/dist/components/features/TaskSettings.test.js +171 -82
  24. package/dist/components/task/TaskActionHeader.js +11 -5
  25. package/dist/components/task/TaskActionHeader.test.js +10 -0
  26. package/dist/components/task/TaskCard.js +6 -2
  27. package/dist/components/task/TaskContextUpload.test.js +3 -3
  28. package/dist/components/task/TaskForm.js +14 -64
  29. package/dist/components/task/TaskKanban.js +0 -8
  30. package/dist/components/task/TaskList.js +5 -1
  31. package/dist/components/task/TaskList.test.js +4 -0
  32. package/dist/components/ui/HierarchyActionBadge.d.ts +10 -0
  33. package/dist/components/ui/HierarchyActionBadge.js +5 -0
  34. package/dist/components/views/AppShellHeader.d.ts +3 -1
  35. package/dist/components/views/AppShellHeader.js +27 -11
  36. package/dist/components/views/AppShellHeader.test.js +18 -1
  37. package/dist/components/views/PlanComparisonPage.d.ts +20 -15
  38. package/dist/components/views/PlanComparisonPage.js +221 -82
  39. package/dist/components/views/PlanComparisonPage.test.js +268 -14
  40. package/dist/components/views/PlansPage.js +16 -10
  41. package/dist/components/views/PlansPage.test.js +4 -2
  42. package/dist/components/views/StandaloneLayout.js +256 -69
  43. package/dist/components/views/WidgetView.js +10 -8
  44. package/dist/components/views/panels/PlanningDrawer.d.ts +19 -6
  45. package/dist/components/views/panels/PlanningDrawer.js +259 -51
  46. package/dist/components/views/panels/PlanningDrawer.test.js +392 -4
  47. package/dist/config/envSchema.js +1 -0
  48. package/dist/core/AiProfileService.d.ts +7 -0
  49. package/dist/core/AiProfileService.js +460 -35
  50. package/dist/core/AiProfiles.test.js +648 -2
  51. package/dist/core/AttachmentLinkService.d.ts +3 -0
  52. package/dist/core/AttachmentLinkService.js +58 -13
  53. package/dist/core/GlobalSettingsService.js +30 -0
  54. package/dist/core/GlobalSettingsService.test.d.ts +1 -0
  55. package/dist/core/GlobalSettingsService.test.js +45 -0
  56. package/dist/core/McpTokenService.d.ts +12 -0
  57. package/dist/core/McpTokenService.js +44 -1
  58. package/dist/core/PlanEntitlementService.d.ts +20 -0
  59. package/dist/core/PlanEntitlementService.js +215 -19
  60. package/dist/core/PlanFeatureCatalog.test.js +55 -0
  61. package/dist/core/PlanningEntities.test.js +366 -4
  62. package/dist/core/TaskActivityService.d.ts +28 -1
  63. package/dist/core/TaskActivityService.js +227 -46
  64. package/dist/core/TaskActivitySync.test.d.ts +1 -0
  65. package/dist/core/TaskActivitySync.test.js +90 -0
  66. package/dist/core/TaskAuditTimeline.test.js +96 -0
  67. package/dist/core/Taskforce.d.ts +204 -26
  68. package/dist/core/Taskforce.ids.test.js +58 -0
  69. package/dist/core/Taskforce.js +781 -71
  70. package/dist/core/Taskforce.mcpAuth.test.js +109 -0
  71. package/dist/core/types.d.ts +10 -0
  72. package/dist/hooks/auth/useTaskforceAuthBootstrap.js +2 -1
  73. package/dist/hooks/bootstrapTimeouts.d.ts +4 -0
  74. package/dist/hooks/bootstrapTimeouts.js +8 -0
  75. package/dist/hooks/bootstrapTimeouts.test.d.ts +1 -0
  76. package/dist/hooks/bootstrapTimeouts.test.js +12 -0
  77. package/dist/hooks/sync/orchestratorShared.d.ts +3 -3
  78. package/dist/hooks/sync/orchestratorShared.js +61 -1
  79. package/dist/hooks/sync/recovery.js +8 -0
  80. package/dist/hooks/sync/recovery.test.js +5 -5
  81. package/dist/hooks/sync/transfers.d.ts +2 -1
  82. package/dist/hooks/sync/transfers.js +36 -9
  83. package/dist/hooks/sync/transfers.test.js +534 -2
  84. package/dist/hooks/useFilterSort.js +13 -13
  85. package/dist/hooks/useFilterSort.test.js +87 -1
  86. package/dist/hooks/useSyncOrchestrator.js +50 -5
  87. package/dist/hooks/useTaskforce.d.ts +85 -50
  88. package/dist/hooks/useTaskforce.js +44 -14
  89. package/dist/hooks/useTaskforce.runtime-routing.test.js +94 -0
  90. package/dist/hooks/useTaskforce.sync-behavior.test.js +99 -0
  91. package/dist/hooks/useWorkspaceSyncController.js +7 -1
  92. package/dist/hooks/useWorkspaceSyncController.test.js +48 -0
  93. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +14 -7
  94. package/dist/mcp/canonicalAssetHelpers.d.ts +16 -4
  95. package/dist/mcp/canonicalAssetHelpers.js +18 -10
  96. package/dist/mcp/canonicalAssetHelpers.test.d.ts +1 -0
  97. package/dist/mcp/canonicalAssetHelpers.test.js +67 -0
  98. package/dist/mcp/clientIntegrations.d.ts +1 -0
  99. package/dist/mcp/clientIntegrations.js +25 -0
  100. package/dist/mcp/clientIntegrations.test.js +14 -3
  101. package/dist/mcp/clientProfileDefaults.js +3 -3
  102. package/dist/mcp/collaborationRegistrar.js +7 -7
  103. package/dist/mcp/documentAssetRegistrar.js +113 -7
  104. package/dist/mcp/runtime.d.ts +1 -0
  105. package/dist/mcp/runtime.js +969 -122
  106. package/dist/mcp/runtime.test.js +1083 -11
  107. package/dist/mcp/taskAttachmentTypes.d.ts +1 -1
  108. package/dist/mcp/taskPlanningRegistrar.js +48 -0
  109. package/dist/mcp/toolRegistry.d.ts +56 -0
  110. package/dist/mcp/toolRegistry.js +8 -0
  111. package/dist/mcp/toolRegistry.test.js +4 -0
  112. package/dist/migrations/taskSchemaMigrations.js +58 -15
  113. package/dist/server/aiProfileAvatarAssets.d.ts +49 -0
  114. package/dist/server/aiProfileAvatarAssets.js +319 -0
  115. package/dist/server/aiProfileAvatarAssets.test.d.ts +1 -0
  116. package/dist/server/aiProfileAvatarAssets.test.js +213 -0
  117. package/dist/server/annotatedAttachmentsRoutes.test.js +66 -7
  118. package/dist/server/index.js +4 -0
  119. package/dist/server/index.test.js +6 -1
  120. package/dist/server/routes/admin.js +328 -9
  121. package/dist/server/routes/annotatedAttachments.js +51 -0
  122. package/dist/server/routes/auth.d.ts +11 -0
  123. package/dist/server/routes/auth.js +189 -27
  124. package/dist/server/routes/authSupport.d.ts +5 -0
  125. package/dist/server/routes/authSupport.js +13 -1
  126. package/dist/server/routes/billing.d.ts +1 -0
  127. package/dist/server/routes/billing.js +116 -63
  128. package/dist/server/routes/billing.test.js +162 -11
  129. package/dist/server/routes/documents.js +10 -0
  130. package/dist/server/routes/shared.js +0 -10
  131. package/dist/server/routes/sync.integration.test.js +221 -0
  132. package/dist/server/routes/sync.js +13 -3
  133. package/dist/server/routes/syncSnapshotRoutes.js +2 -0
  134. package/dist/server/routes/tasks.js +12 -9
  135. package/dist/server/routes.js +87 -8
  136. package/dist/server/routes.test.js +972 -23
  137. package/dist/shared/aiProfileSurfaceType.d.ts +1 -1
  138. package/dist/shared/aiProfileSurfaceType.js +10 -8
  139. package/dist/storage/objectStorage.d.ts +1 -0
  140. package/dist/storage/objectStorage.js +2 -1
  141. package/dist/storage/objectStorageClient.d.ts +1 -0
  142. package/dist/storage/objectStorageClient.js +41 -8
  143. package/dist/storage/objectStorageClient.test.js +26 -1
  144. package/dist/storage/objectStorageConfig.js +3 -1
  145. package/dist/storage/objectStorageConfig.test.js +13 -1
  146. package/dist/sync/collaborationSyncPayload.js +2 -0
  147. package/dist/sync/collaborationSyncPayload.test.js +1 -0
  148. package/dist/sync/collaborationSyncState.d.ts +3 -3
  149. package/dist/sync/collaborationSyncState.js +19 -12
  150. package/dist/sync/contentSyncPayload.d.ts +5 -1
  151. package/dist/sync/contentSyncPayload.js +9 -0
  152. package/dist/sync/contentSyncPayload.test.js +39 -0
  153. package/dist/sync/contentSyncState.d.ts +5 -1
  154. package/dist/sync/contentSyncState.js +231 -37
  155. package/dist/sync/planningSyncPayload.js +5 -0
  156. package/dist/sync/planningSyncPayload.test.js +24 -0
  157. package/dist/sync/syncApplyHandlers.d.ts +4 -4
  158. package/dist/sync/syncApplyHandlers.js +89 -31
  159. package/dist/sync/syncApplyHandlers.test.js +184 -4
  160. package/dist/sync/syncResourceAdapters.d.ts +2 -0
  161. package/dist/sync/syncResourceAdapters.js +2 -0
  162. package/dist/sync/syncService.d.ts +1 -0
  163. package/dist/sync/syncService.js +13 -1
  164. package/dist/sync/syncService.test.js +39 -0
  165. package/dist/sync/workspacePullFeed.d.ts +4 -0
  166. package/dist/sync/workspacePullFeed.js +129 -70
  167. package/dist/sync/workspacePullFeed.test.js +49 -0
  168. package/dist/sync/workspaceSyncModel.d.ts +28 -6
  169. package/dist/sync/workspaceSyncModel.js +159 -45
  170. package/dist/sync/workspaceSyncModel.test.js +269 -3
  171. package/dist/types.d.ts +33 -2
  172. package/dist/ui/agent-logos/ChatGPT.png +0 -0
  173. package/dist/ui/agent-logos/Gemini CLI.jpeg +0 -0
  174. package/dist/ui/agent-logos/antigravity.jpeg +0 -0
  175. package/dist/ui/agent-logos/claude-code.jpeg +0 -0
  176. package/dist/ui/agent-logos/codex.jpeg +0 -0
  177. package/dist/ui/agent-logos/cursor.png +0 -0
  178. package/dist/ui/agent-logos/openclaw.jpeg +0 -0
  179. package/dist/ui/agent-logos/windsurf.png +0 -0
  180. package/dist/ui/assets/AgentsModule-BS4Pi_nC.js +1 -0
  181. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BVKew-mH.css +1 -0
  182. package/dist/ui/assets/AnnotatedAttachmentWorkspace-CCckzWYZ.js +3 -0
  183. package/dist/ui/assets/ContextAttachmentManager-CfG_ER7C.js +3 -0
  184. package/dist/ui/assets/DocumentWorkspace-BVaWPA25.js +252 -0
  185. package/dist/ui/assets/DocumentWorkspace-D4rJKXzd.css +1 -0
  186. package/dist/ui/assets/EntityActivityTimeline-DSj0ThaK.js +1 -0
  187. package/dist/ui/assets/EntityActivityTimeline-DyqvvhuF.css +1 -0
  188. package/dist/ui/assets/{InitiativesModule-9E6ParrY.js → InitiativesModule-AxMkWtxH.js} +1 -1
  189. package/dist/ui/assets/PlansPage-B_z-D6Nh.css +1 -0
  190. package/dist/ui/assets/PlansPage-Ndt7mYfo.js +1 -0
  191. package/dist/ui/assets/TaskContextUpload-Dw4rTF4i.js +1 -0
  192. package/dist/ui/assets/TaskSettings-f2ga42_V.js +9 -0
  193. package/dist/ui/assets/{WorkflowsModule-BA7jcEpH.js → WorkflowsModule-E4UL3mov.js} +4 -4
  194. package/dist/ui/assets/documentReferences-BOUcJm6-.js +1 -0
  195. package/dist/ui/assets/index-BvAbqx5Q.css +1 -0
  196. package/dist/ui/assets/index-MAHKvFqp.js +4 -0
  197. package/dist/ui/assets/{vendor-icons-DuEd_65c.js → vendor-icons-B32hGuF2.js} +1 -1
  198. package/dist/ui/index.html +3 -3
  199. package/dist/ui/og-image.png +0 -0
  200. package/dist/ui/product/agent manager.png +0 -0
  201. package/dist/ui/product/agent_manager_02.png +0 -0
  202. package/dist/utils/aiProfileEvents.d.ts +7 -0
  203. package/dist/utils/aiProfileEvents.js +6 -0
  204. package/dist/utils/assignees.d.ts +6 -0
  205. package/dist/utils/assignees.js +8 -1
  206. package/dist/utils/assignees.test.d.ts +1 -0
  207. package/dist/utils/assignees.test.js +25 -0
  208. package/dist/utils/avatarDisplay.d.ts +1 -0
  209. package/dist/utils/avatarDisplay.js +15 -0
  210. package/dist/utils/contextFiles.d.ts +3 -1
  211. package/dist/utils/contextFiles.js +2 -1
  212. package/dist/utils/taskActivity.d.ts +7 -1
  213. package/dist/utils/taskActivity.js +63 -1
  214. package/dist/utils/taskActivity.test.js +23 -1
  215. package/dist/utils/taskSearch.d.ts +22 -0
  216. package/dist/utils/taskSearch.js +87 -0
  217. package/dist/utils/taskSearch.test.d.ts +1 -0
  218. package/dist/utils/taskSearch.test.js +69 -0
  219. package/dist/utils/taskUtils.js +10 -3
  220. package/dist/utils/taskUtils.test.d.ts +1 -0
  221. package/dist/utils/taskUtils.test.js +19 -0
  222. package/package.json +1 -1
  223. package/dist/ui/assets/AgentsModule-DrLawwNl.js +0 -1
  224. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BaS2VwIr.css +0 -1
  225. package/dist/ui/assets/AnnotatedAttachmentWorkspace-Z9_whf7F.js +0 -3
  226. package/dist/ui/assets/DocumentWorkspace-B03MaSkw.js +0 -252
  227. package/dist/ui/assets/DocumentWorkspace-Dhdso07p.css +0 -1
  228. package/dist/ui/assets/PlansPage-CvfnMiWq.css +0 -1
  229. package/dist/ui/assets/PlansPage-DRXscYxH.js +0 -1
  230. package/dist/ui/assets/TaskSettings-DZX4jk7e.js +0 -9
  231. package/dist/ui/assets/index-9eT8e0Lu.css +0 -1
  232. package/dist/ui/assets/index-C6k75jr8.js +0 -6
@@ -50,6 +50,8 @@ describe('workspaceSyncModel', () => {
50
50
  taskEvents: [
51
51
  {
52
52
  id: 'task-event-1',
53
+ entityType: 'task',
54
+ entityId: 'task-1',
53
55
  taskId: 'task-1',
54
56
  workspaceId: 'workspace-a',
55
57
  action: 'task-status-changed',
@@ -91,6 +93,8 @@ describe('workspaceSyncModel', () => {
91
93
  taskEvents: [
92
94
  {
93
95
  id: 'task-event-keep',
96
+ entityType: 'task',
97
+ entityId: 'task-1',
94
98
  taskId: 'task-1',
95
99
  workspaceId: 'workspace-a',
96
100
  action: 'task-status-changed',
@@ -100,6 +104,8 @@ describe('workspaceSyncModel', () => {
100
104
  },
101
105
  {
102
106
  id: 'task-event-new',
107
+ entityType: 'task',
108
+ entityId: 'task-2',
103
109
  taskId: 'task-2',
104
110
  workspaceId: 'workspace-a',
105
111
  action: 'task-archived',
@@ -147,6 +153,41 @@ describe('workspaceSyncModel', () => {
147
153
  ['docs/new.md', '2026-02-03T00:00:00.000Z']
148
154
  ]);
149
155
  });
156
+ it('emits a document upsert when a synced document receives a newer task link', () => {
157
+ const payload = buildWorkspaceSyncPayloadModel({
158
+ tasks: [],
159
+ archivedTasks: [],
160
+ lastPushedTaskIds: new Set(),
161
+ pendingDeletedTaskIds: new Set(),
162
+ documents: [
163
+ {
164
+ path: 'workspaces/default/assets/documents/asset-doc-1-notes.md',
165
+ updatedAt: '2026-03-18T14:45:00.000Z',
166
+ content: '# Notes',
167
+ assetId: 'asset-doc-1',
168
+ documentId: 'doc-1',
169
+ referenceNumber: 8,
170
+ version: 1,
171
+ taskId: 'task-attach-1',
172
+ originalFilename: 'notes.md',
173
+ linkRole: 'attachment'
174
+ }
175
+ ],
176
+ lastPushedDocumentPaths: new Set(['workspaces/default/assets/documents/asset-doc-1-notes.md']),
177
+ lastPushedDocumentWatermarks: new Map([
178
+ ['workspaces/default/assets/documents/asset-doc-1-notes.md', '2026-03-18T13:30:00.000Z']
179
+ ])
180
+ });
181
+ expect(payload.changes).toEqual(expect.arrayContaining([
182
+ expect.objectContaining({
183
+ op: 'document-upsert',
184
+ path: 'workspaces/default/assets/documents/asset-doc-1-notes.md',
185
+ updatedAt: '2026-03-18T14:45:00.000Z',
186
+ taskId: 'task-attach-1',
187
+ linkRole: 'attachment'
188
+ })
189
+ ]));
190
+ });
150
191
  it('reports send-all diagnostics when a domain has no baseline', () => {
151
192
  const payload = buildWorkspaceSyncPayloadModel({
152
193
  tasks: [],
@@ -385,6 +426,8 @@ describe('workspaceSyncModel', () => {
385
426
  provider: 'OpenAI',
386
427
  model: 'gpt-5.4',
387
428
  surfaceType: 'coding_tool',
429
+ avatarRevision: 0,
430
+ avatarUpdatedAt: null,
388
431
  rosterStateUpdatedAt: '2026-03-22T10:00:00.000Z'
389
432
  })
390
433
  })
@@ -443,6 +486,8 @@ describe('workspaceSyncModel', () => {
443
486
  color: '#0ea5e9',
444
487
  avatarUrl: '/api/taskforce/context/workspaces%2Fws-1%2Fassets%2Fimages%2Fai-profiles%2Fai-profile-1%2Favatar%2Favatar.webp',
445
488
  avatarSourceUrl: '/api/taskforce/context/workspaces%2Fws-1%2Fassets%2Fimages%2Fai-profiles%2Fai-profile-1%2Favatar%2Fsource.webp',
489
+ avatarRevision: 1,
490
+ avatarUpdatedAt: '2026-03-22T10:04:00.000Z',
446
491
  description: 'Terminal-first coding agent',
447
492
  role: 'Implementer',
448
493
  provider: 'OpenAI',
@@ -463,7 +508,9 @@ describe('workspaceSyncModel', () => {
463
508
  profile: expect.objectContaining({
464
509
  id: 'ai-profile-1',
465
510
  avatarUrl: expect.stringContaining('/api/taskforce/context/'),
466
- avatarSourceUrl: expect.stringContaining('/api/taskforce/context/')
511
+ avatarSourceUrl: expect.stringContaining('/api/taskforce/context/'),
512
+ avatarRevision: 1,
513
+ avatarUpdatedAt: '2026-03-22T10:04:00.000Z'
467
514
  })
468
515
  })
469
516
  ]));
@@ -478,6 +525,8 @@ describe('workspaceSyncModel', () => {
478
525
  color: '#0ea5e9',
479
526
  avatarUrl: '/api/taskforce/context/workspaces%2Fws-1%2Fassets%2Fimages%2Fai-profiles%2Fai-profile-1%2Favatar%2Favatar.webp',
480
527
  avatarSourceUrl: '/api/taskforce/context/workspaces%2Fws-1%2Fassets%2Fimages%2Fai-profiles%2Fai-profile-1%2Favatar%2Fsource.webp',
528
+ avatarRevision: 1,
529
+ avatarUpdatedAt: '2026-03-22T10:04:00.000Z',
481
530
  description: 'Terminal-first coding agent',
482
531
  role: 'Implementer',
483
532
  provider: 'OpenAI',
@@ -550,6 +599,12 @@ describe('workspaceSyncModel', () => {
550
599
  createdAt: '2026-03-29T10:00:00.000Z',
551
600
  updatedAt: '2026-03-29T11:00:00.000Z',
552
601
  order: 1,
602
+ attachments: [{
603
+ path: 'workspaces/ws-1/assets/documents/asset-in.md',
604
+ assetId: 'asset-in',
605
+ referenceLabel: 'D-31',
606
+ caption: 'Revenue context'
607
+ }],
553
608
  isArchived: false
554
609
  }],
555
610
  workstreams: [{
@@ -563,6 +618,12 @@ describe('workspaceSyncModel', () => {
563
618
  createdAt: '2026-03-29T10:30:00.000Z',
564
619
  updatedAt: '2026-03-29T11:30:00.000Z',
565
620
  order: 2,
621
+ attachments: [{
622
+ path: 'workspaces/ws-1/assets/documents/asset-ws.md',
623
+ assetId: 'asset-ws',
624
+ referenceLabel: 'D-32',
625
+ caption: 'Checkout context'
626
+ }],
566
627
  isArchived: false
567
628
  }]
568
629
  });
@@ -571,7 +632,13 @@ describe('workspaceSyncModel', () => {
571
632
  op: 'initiative-upsert',
572
633
  initiative: expect.objectContaining({
573
634
  id: 'initiative-1',
574
- title: 'Revenue Expansion'
635
+ title: 'Revenue Expansion',
636
+ attachments: expect.arrayContaining([
637
+ expect.objectContaining({
638
+ path: 'workspaces/ws-1/assets/documents/asset-in.md',
639
+ referenceLabel: 'D-31'
640
+ })
641
+ ])
575
642
  })
576
643
  }),
577
644
  expect.objectContaining({
@@ -579,7 +646,13 @@ describe('workspaceSyncModel', () => {
579
646
  workstream: expect.objectContaining({
580
647
  id: 'workstream-1',
581
648
  initiativeId: 'initiative-1',
582
- title: 'Checkout UX'
649
+ title: 'Checkout UX',
650
+ attachments: expect.arrayContaining([
651
+ expect.objectContaining({
652
+ path: 'workspaces/ws-1/assets/documents/asset-ws.md',
653
+ referenceLabel: 'D-32'
654
+ })
655
+ ])
583
656
  })
584
657
  })
585
658
  ]));
@@ -764,6 +837,138 @@ describe('workspaceSyncModel', () => {
764
837
  })
765
838
  ]));
766
839
  });
840
+ it('does not resend already-acknowledged deleted collaboration records', () => {
841
+ const payload = buildWorkspaceSyncPayloadModel({
842
+ tasks: [],
843
+ archivedTasks: [],
844
+ lastPushedTaskIds: new Set(),
845
+ pendingDeletedTaskIds: new Set(),
846
+ documentReviewSessions: [
847
+ {
848
+ id: 'review-deleted',
849
+ assetId: 'asset-doc-1',
850
+ documentId: 'doc-1',
851
+ documentVersion: 2,
852
+ title: 'Review',
853
+ status: 'open',
854
+ comments: [],
855
+ createdByActorId: null,
856
+ updatedByActorId: null,
857
+ createdAt: '2026-03-24T10:00:00.000Z',
858
+ updatedAt: '2026-03-24T10:05:00.000Z',
859
+ deletedAt: '2026-03-24T10:06:00.000Z'
860
+ }
861
+ ],
862
+ documentReviewComments: [
863
+ {
864
+ id: 'comment-deleted',
865
+ sessionId: 'review-deleted',
866
+ body: 'Delete me.',
867
+ anchor: { kind: 'document' },
868
+ order: 0,
869
+ authorActorId: null,
870
+ createdAt: '2026-03-24T10:00:00.000Z',
871
+ updatedAt: '2026-03-24T10:05:00.000Z',
872
+ deletedAt: '2026-03-24T10:06:30.000Z'
873
+ }
874
+ ],
875
+ annotatedAttachmentSessions: [
876
+ {
877
+ id: 'annotation-deleted',
878
+ workspaceId: 'ws-1',
879
+ taskId: 'task-1',
880
+ baseImageAssetId: 'asset-image-1',
881
+ title: 'Annotations',
882
+ globalInstruction: null,
883
+ annotations: [],
884
+ createdByActorId: null,
885
+ updatedByActorId: null,
886
+ createdAt: '2026-03-24T10:00:00.000Z',
887
+ updatedAt: '2026-03-24T10:05:00.000Z',
888
+ deletedAt: '2026-03-24T10:07:00.000Z'
889
+ }
890
+ ],
891
+ lastPushedDocumentReviewSessionIds: new Set(),
892
+ lastPushedDocumentReviewSessionWatermarks: new Map([
893
+ ['review-deleted', '2026-03-24T10:06:00.000Z']
894
+ ]),
895
+ lastPushedDocumentReviewCommentIds: new Set(),
896
+ lastPushedDocumentReviewCommentWatermarks: new Map([
897
+ ['comment-deleted', '2026-03-24T10:06:30.000Z']
898
+ ]),
899
+ lastPushedAnnotatedAttachmentSessionIds: new Set(),
900
+ lastPushedAnnotatedAttachmentSessionWatermarks: new Map([
901
+ ['annotation-deleted', '2026-03-24T10:07:00.000Z']
902
+ ])
903
+ });
904
+ expect(payload.currentDocumentReviewSessionWatermarks.get('review-deleted')).toBe('2026-03-24T10:06:00.000Z');
905
+ expect(payload.currentDocumentReviewCommentWatermarks.get('comment-deleted')).toBe('2026-03-24T10:06:30.000Z');
906
+ expect(payload.currentAnnotatedAttachmentSessionWatermarks.get('annotation-deleted')).toBe('2026-03-24T10:07:00.000Z');
907
+ expect(payload.changes).not.toEqual(expect.arrayContaining([
908
+ expect.objectContaining({ op: 'document-review-session-delete', sessionId: 'review-deleted' }),
909
+ expect.objectContaining({ op: 'document-review-comment-delete', commentId: 'comment-deleted' }),
910
+ expect.objectContaining({ op: 'annotated-attachment-session-delete', sessionId: 'annotation-deleted' })
911
+ ]));
912
+ expect(payload.deltaDiagnostics?.domains.documentReviewSessions.changeCount).toBe(0);
913
+ expect(payload.deltaDiagnostics?.domains.documentReviewComments.changeCount).toBe(0);
914
+ expect(payload.deltaDiagnostics?.domains.annotatedAttachmentSessions.changeCount).toBe(0);
915
+ });
916
+ it('emits a single delete op when a previously pushed collaboration record is now soft-deleted', () => {
917
+ const payload = buildWorkspaceSyncPayloadModel({
918
+ tasks: [],
919
+ archivedTasks: [],
920
+ lastPushedTaskIds: new Set(),
921
+ pendingDeletedTaskIds: new Set(),
922
+ documentReviewSessions: [{
923
+ id: 'review-deleted',
924
+ assetId: 'asset-doc-1',
925
+ documentId: 'doc-1',
926
+ documentVersion: 2,
927
+ title: 'Review',
928
+ status: 'open',
929
+ comments: [],
930
+ createdByActorId: null,
931
+ updatedByActorId: null,
932
+ createdAt: '2026-03-24T10:00:00.000Z',
933
+ updatedAt: '2026-03-24T10:05:00.000Z',
934
+ deletedAt: '2026-03-24T10:06:00.000Z'
935
+ }],
936
+ documentReviewComments: [{
937
+ id: 'comment-deleted',
938
+ sessionId: 'review-deleted',
939
+ body: 'Delete me.',
940
+ anchor: { kind: 'document' },
941
+ order: 0,
942
+ authorActorId: null,
943
+ createdAt: '2026-03-24T10:00:00.000Z',
944
+ updatedAt: '2026-03-24T10:05:00.000Z',
945
+ deletedAt: '2026-03-24T10:06:30.000Z'
946
+ }],
947
+ annotatedAttachmentSessions: [{
948
+ id: 'annotation-deleted',
949
+ workspaceId: 'ws-1',
950
+ taskId: 'task-1',
951
+ baseImageAssetId: 'asset-image-1',
952
+ title: 'Annotations',
953
+ globalInstruction: null,
954
+ annotations: [],
955
+ createdByActorId: null,
956
+ updatedByActorId: null,
957
+ createdAt: '2026-03-24T10:00:00.000Z',
958
+ updatedAt: '2026-03-24T10:05:00.000Z',
959
+ deletedAt: '2026-03-24T10:07:00.000Z'
960
+ }],
961
+ lastPushedDocumentReviewSessionIds: new Set(['review-deleted']),
962
+ lastPushedDocumentReviewSessionWatermarks: new Map(),
963
+ lastPushedDocumentReviewCommentIds: new Set(['comment-deleted']),
964
+ lastPushedDocumentReviewCommentWatermarks: new Map(),
965
+ lastPushedAnnotatedAttachmentSessionIds: new Set(['annotation-deleted']),
966
+ lastPushedAnnotatedAttachmentSessionWatermarks: new Map()
967
+ });
968
+ expect(payload.changes.filter((change) => change.op === 'document-review-session-delete')).toHaveLength(1);
969
+ expect(payload.changes.filter((change) => change.op === 'document-review-comment-delete')).toHaveLength(1);
970
+ expect(payload.changes.filter((change) => change.op === 'annotated-attachment-session-delete')).toHaveLength(1);
971
+ });
767
972
  });
768
973
  describe('buildWorkspaceSyncSignatureModel', () => {
769
974
  it('includes pending delete operations in the signature hash', () => {
@@ -921,6 +1126,63 @@ describe('workspaceSyncModel', () => {
921
1126
  });
922
1127
  expect(changedSignature).not.toEqual(baseSignature);
923
1128
  });
1129
+ it('changes when initiative or workstream attachments change', () => {
1130
+ const baseSignature = buildWorkspaceSyncSignatureModel({
1131
+ workspaceId: 'ws-1',
1132
+ tasks: [],
1133
+ archivedTasks: [],
1134
+ initiatives: [{
1135
+ id: 'initiative-1',
1136
+ title: 'Revenue Expansion',
1137
+ description: null,
1138
+ createdAt: '2026-03-29T10:00:00.000Z',
1139
+ updatedAt: '2026-03-29T11:00:00.000Z',
1140
+ attachments: []
1141
+ }],
1142
+ workstreams: [{
1143
+ id: 'workstream-1',
1144
+ initiativeId: 'initiative-1',
1145
+ title: 'Checkout UX',
1146
+ description: null,
1147
+ createdAt: '2026-03-29T10:30:00.000Z',
1148
+ updatedAt: '2026-03-29T11:30:00.000Z',
1149
+ attachments: []
1150
+ }]
1151
+ });
1152
+ const changedSignature = buildWorkspaceSyncSignatureModel({
1153
+ workspaceId: 'ws-1',
1154
+ tasks: [],
1155
+ archivedTasks: [],
1156
+ initiatives: [{
1157
+ id: 'initiative-1',
1158
+ title: 'Revenue Expansion',
1159
+ description: null,
1160
+ createdAt: '2026-03-29T10:00:00.000Z',
1161
+ updatedAt: '2026-03-29T11:00:00.000Z',
1162
+ attachments: [{
1163
+ path: 'workspaces/ws-1/assets/documents/asset-in.md',
1164
+ assetId: 'asset-in',
1165
+ referenceLabel: 'D-31',
1166
+ caption: 'Revenue context'
1167
+ }]
1168
+ }],
1169
+ workstreams: [{
1170
+ id: 'workstream-1',
1171
+ initiativeId: 'initiative-1',
1172
+ title: 'Checkout UX',
1173
+ description: null,
1174
+ createdAt: '2026-03-29T10:30:00.000Z',
1175
+ updatedAt: '2026-03-29T11:30:00.000Z',
1176
+ attachments: [{
1177
+ path: 'workspaces/ws-1/assets/documents/asset-ws.md',
1178
+ assetId: 'asset-ws',
1179
+ referenceLabel: 'D-32',
1180
+ caption: 'Checkout context'
1181
+ }]
1182
+ }]
1183
+ });
1184
+ expect(changedSignature).not.toEqual(baseSignature);
1185
+ });
924
1186
  it('changes when document review sessions change', () => {
925
1187
  const baseSignature = buildWorkspaceSyncSignatureModel({
926
1188
  workspaceId: 'ws-1',
@@ -1013,6 +1275,8 @@ describe('workspaceSyncModel', () => {
1013
1275
  archivedTasks: [],
1014
1276
  taskEvents: [{
1015
1277
  id: 'task-event-1',
1278
+ entityType: 'task',
1279
+ entityId: 'task-1',
1016
1280
  taskId: 'task-1',
1017
1281
  workspaceId: 'ws-1',
1018
1282
  action: 'task-status-changed',
@@ -1027,6 +1291,8 @@ describe('workspaceSyncModel', () => {
1027
1291
  archivedTasks: [],
1028
1292
  taskEvents: [{
1029
1293
  id: 'task-event-1',
1294
+ entityType: 'task',
1295
+ entityId: 'task-1',
1030
1296
  taskId: 'task-1',
1031
1297
  workspaceId: 'ws-1',
1032
1298
  action: 'task-status-changed',
package/dist/types.d.ts CHANGED
@@ -29,10 +29,25 @@ export interface TaskEventDetails {
29
29
  changes?: Record<string, TaskEventChange>;
30
30
  [key: string]: unknown;
31
31
  }
32
+ export type ActivityEntityType = 'task' | 'initiative' | 'workstream';
33
+ interface BaseEntityEvent {
34
+ id: string;
35
+ workspaceId: string;
36
+ entityType: ActivityEntityType;
37
+ entityId: string;
38
+ action: string;
39
+ actor: string;
40
+ actorType: 'human' | 'ai' | 'system';
41
+ createdAt: string;
42
+ details?: TaskEventDetails;
43
+ actorProfile?: TaskActor | null;
44
+ }
32
45
  export interface TaskEvent {
33
46
  id: string;
34
47
  taskId: string;
35
48
  workspaceId: string;
49
+ entityType?: 'task';
50
+ entityId?: string;
36
51
  action: string;
37
52
  actor: string;
38
53
  actorType: 'human' | 'ai' | 'system';
@@ -40,6 +55,11 @@ export interface TaskEvent {
40
55
  details?: TaskEventDetails;
41
56
  actorProfile?: TaskActor | null;
42
57
  }
58
+ export interface PlanningEntityEvent extends BaseEntityEvent {
59
+ entityType: 'initiative' | 'workstream';
60
+ entityId: string;
61
+ }
62
+ export type EntityEvent = TaskEvent | PlanningEntityEvent;
43
63
  export interface CommentActivityItem {
44
64
  id: string;
45
65
  type: 'comment';
@@ -53,6 +73,13 @@ export interface AuditActivityItem {
53
73
  event: TaskEvent;
54
74
  }
55
75
  export type TaskActivityItem = CommentActivityItem | AuditActivityItem;
76
+ export interface EntityAuditActivityItem {
77
+ id: string;
78
+ type: 'event';
79
+ timestamp: string;
80
+ event: EntityEvent;
81
+ }
82
+ export type EntityActivityItem = CommentActivityItem | EntityAuditActivityItem;
56
83
  export type DeletedTaskSource = 'ui' | 'mcp' | 'sync' | 'workspace-delete' | 'system';
57
84
  export interface DeletedTaskDetails {
58
85
  reason?: string | null;
@@ -76,9 +103,9 @@ export interface AttachmentItem {
76
103
  caption?: string;
77
104
  displayName?: string;
78
105
  originalFilename?: string;
79
- assetId?: string;
106
+ assetId?: string | null;
80
107
  referenceNumber?: number | null;
81
- referenceLabel?: string;
108
+ referenceLabel?: string | null;
82
109
  taskId?: string | null;
83
110
  timestamp?: string;
84
111
  }
@@ -122,6 +149,8 @@ export interface InitiativeItem {
122
149
  description: string | null;
123
150
  ownerId?: string | null;
124
151
  comments?: Comment[];
152
+ activity?: EntityActivityItem[];
153
+ entityEvents?: PlanningEntityEvent[];
125
154
  attachments?: Array<string | AttachmentItem>;
126
155
  createdAt: string;
127
156
  updatedAt?: string;
@@ -137,6 +166,8 @@ export interface WorkstreamItem {
137
166
  description: string | null;
138
167
  ownerId?: string | null;
139
168
  comments?: Comment[];
169
+ activity?: EntityActivityItem[];
170
+ entityEvents?: PlanningEntityEvent[];
140
171
  attachments?: Array<string | AttachmentItem>;
141
172
  createdAt: string;
142
173
  updatedAt?: string;
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1 @@
1
+ import{r as c,j as e}from"./vendor-react-CKJs5o3c.js";import{s as Ue,p as _,u as ie,v as De,w as se,x as le,y as we,t as r,E as Te,z as Me,B as ke,C as fe,F as b,G as oe}from"./index-MAHKvFqp.js";import{Y as Re,w as $e,h as Ee,B as ne,m as C,b as Le,W as Be,a2 as Ge}from"./vendor-icons-B32hGuF2.js";import"./vendor-markdown-BUxTU7dS.js";import"./vendor-dnd-DRzYolkg.js";import"./vendor-router-BbWMxlnO.js";function Fe(l){return typeof l.avatarUrl=="string"&&l.avatarUrl.trim().length>0}function K(l){return l?fe(l.avatarUrl,l.avatarRevision,l.avatarUpdatedAt):""}function ze(l){return l?fe(l.avatarSourceUrl,l.avatarRevision,l.avatarUpdatedAt):""}function He(l){return l.find(Fe)||l[0]}function ce(l){return`${l.seatScope||"unknown"}:${l.name.trim().toLowerCase()}`}function Oe(l){const m=Math.max(0,l-1);return`${m} duplicate${m===1?"":"s"}`}function de(l){return!l||typeof l!="object"?null:{used:Math.max(0,Number(l.used||0)),limit:l.limit===null||l.limit===void 0?null:Math.max(0,Number(l.limit||0)),remaining:l.remaining===null||l.remaining===void 0?null:Math.max(0,Number(l.remaining||0))}}function pe(l,m){const U=m?.variant==="inline"?`${r.aiProfileSeatScopeIcon} ${r.aiProfileSeatScopeIconInline}`:m?.variant==="detail"?`${r.aiProfileSeatScopeIcon} ${r.aiProfileSeatScopeIconDetail}`:r.aiProfileSeatScopeIcon;return l==="cloud_metered"?e.jsx("span",{className:`${U} ${r.aiProfileSeatScopeIconCloud}`,title:"Cloud MCP","aria-label":"Cloud MCP",children:e.jsx(Be,{size:20})}):l==="local_unmetered"?e.jsx("span",{className:`${U} ${r.aiProfileSeatScopeIconLocal}`,title:"Local MCP","aria-label":"Local MCP",children:e.jsx(Ge,{size:20})}):null}function qe({workspaceId:l,cloudAuthConfigured:m=!1,authSessionResolved:U=!1,isAuthenticated:ue=!1,cloudAiProfileSeatUsage:me=null,agentTrayOpen:E=!1,onCloseAgentTray:he,mcpSettingsNode:V=null}){const[S,L]=c.useState([]),[ve,ge]=c.useState(null),[B,J]=c.useState(!1),[h,D]=c.useState(null),[w,v]=c.useState(null),[T,x]=c.useState(null),[W,G]=c.useState(null),[ye,Y]=c.useState(!1),[P,j]=c.useState(null),[q,Q]=c.useState(null),[X,M]=c.useState(!1),[Pe,g]=c.useState(null),k=c.useCallback(async()=>{if(l){J(!0);try{const a=`/api/taskforce/workspace/assignee-options?workspaceId=${encodeURIComponent(l)}&kind=agent`,t=await fetch(a,{credentials:"include"}),i=t.ok?await t.json().catch(()=>({})):{},o=de(i?.aiProfileSeatUsage),d=Array.isArray(i?.assignees)?i.assignees.filter(s=>s.kind==="agent").map(s=>({id:String(s.value||""),name:String(s.label||s.value||"Unknown Agent"),username:String(s.username||s.value||""),icon:String(s.icon||"Bot"),color:String(s.color||"#6B7280"),avatarUrl:typeof s.avatarUrl=="string"?s.avatarUrl:null,avatarSourceUrl:typeof s.avatarSourceUrl=="string"?s.avatarSourceUrl:null,avatarRevision:Number.isFinite(Number(s.avatarRevision))?Math.max(0,Math.floor(Number(s.avatarRevision))):0,avatarUpdatedAt:typeof s.avatarUpdatedAt=="string"?s.avatarUpdatedAt:null,kind:String(s.kind||"agent"),description:typeof s.description=="string"?s.description:null,role:typeof s.role=="string"?s.role:null,provider:typeof s.provider=="string"?s.provider:null,model:typeof s.model=="string"?s.model:null,surfaceType:_(s.surfaceType),seatScope:Ue(s.seatScope),archivedAt:typeof s.archivedAt=="string"?s.archivedAt:null,createdAt:String(s.createdAt||""),updatedAt:String(s.updatedAt||s.createdAt||""),lastActiveAt:typeof s.lastActiveAt=="string"?s.lastActiveAt:null})):[];L(d),ge(o),x(s=>s&&!d.some(p=>p.id===s.profileId)?null:s),G(s=>s&&!d.some(p=>p.id===s.profileId)?null:s)}finally{J(!1)}}},[l]);c.useEffect(()=>{k()},[k]);const R=c.useMemo(()=>{const a=new Map;for(const t of S){const i=ie(t.surfaceType);a.has(i)||a.set(i,new Map);const o=a.get(i),d=ce(t);o.has(d)||o.set(d,[]),o.get(d).push(t)}return De.map(t=>({section:t,label:se(t),groups:Array.from(a.get(t)?.entries()||[]).map(([i,o])=>({groupId:`${t}:${i}`,section:t,sectionLabel:se(t),profiles:o,primaryProfile:He(o)}))})).filter(t=>t.groups.length>0)},[S]),y=c.useMemo(()=>R.flatMap(a=>a.groups),[R]),n=c.useMemo(()=>y.find(a=>a.groupId===P)||y[0]||null,[y,P]),u=c.useMemo(()=>S.find(a=>a.id===q)||null,[S,q]);c.useEffect(()=>{if(!y.length){P!==null&&j(null);return}(!P||!y.some(a=>a.groupId===P))&&j(y[0].groupId)},[y,P]);const Ae=async(a,t)=>{v(null),x(null);try{const i=await fetch("/api/taskforce/workspace/ai-profiles/merge",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({keepId:a,mergeId:t})}),o=await i.json().catch(()=>({}));if(!i.ok){v({type:"error",message:String(o?.error||"Failed to merge AI profiles.")});return}D(null),v({type:"success",message:"AI profiles merged."}),await k(),b({workspaceId:l,profileId:a,reason:"merge"})}catch{v({type:"error",message:"Failed to merge AI profiles."})}},Z=async a=>{if(window.confirm(`Remove ${a.name} from the active roster? This frees an AI profile seat and preserves task and comment history.`)){x(null),v(null);try{const i=await fetch("/api/taskforce/workspace/ai-profiles/archive",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({profileId:a.id,reason:"manual_archive"})}),o=await i.json().catch(()=>({}));if(!i.ok){x({profileId:a.id,message:String(o?.error||"Failed to remove AI profile from roster.")});return}(h?.keepId===a.id||h?.mergeId===a.id)&&D(null),v({type:"success",message:"AI profile removed from active roster."}),await k(),b({workspaceId:l,profileId:a.id,reason:"archive"})}catch{x({profileId:a.id,message:"Failed to remove AI profile from roster."})}}},Se=async(a,t)=>{const i=_(t),o=new Set(a.profiles.map(p=>p.surfaceType??"")),d=i??"";if(o.size===1&&o.has(d))return;Y(!0),G(null),v(null);const s=[];try{for(const f of a.profiles){const I=await fetch("/api/taskforce/workspace/ai-profiles/surface-type",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({profileId:f.id,surfaceType:i})}),H=await I.json().catch(()=>({}));if(!I.ok||!H?.profile)throw new Error(String(H?.error||"Failed to update AI profile category."));const O=H.profile;s.push({...f,surfaceType:_(O.surfaceType),updatedAt:typeof O.updatedAt=="string"?O.updatedAt:f.updatedAt})}const p=new Map(s.map(f=>[f.id,f]));L(f=>f.map(I=>p.get(I.id)||I));const A=p.get(a.primaryProfile.id)||{...a.primaryProfile,surfaceType:i},Ce=ie(A.surfaceType);j(`${Ce}:${ce(A)}`),v({type:"success",message:"AI profile category updated."});for(const f of s)b({workspaceId:l,profileId:f.id,reason:"update"})}catch(p){G({profileId:a.primaryProfile.id,message:String(p?.message||"Failed to update AI profile category.")})}finally{Y(!1)}},ee=a=>new Promise((t,i)=>{const o=new FileReader;o.onload=()=>t(String(o.result||"")),o.onerror=()=>i(new Error("Failed to read image file.")),o.readAsDataURL(a)}),ae=a=>{const t=String(a?.id||"").trim();t&&L(i=>i.map(o=>o.id===t?{...o,avatarUrl:typeof a.avatarUrl=="string"?a.avatarUrl:null,avatarSourceUrl:typeof a.avatarSourceUrl=="string"?a.avatarSourceUrl:null,avatarRevision:Number.isFinite(Number(a.avatarRevision))?Math.max(0,Math.floor(Number(a.avatarRevision))):o.avatarRevision,avatarUpdatedAt:typeof a.avatarUpdatedAt=="string"?a.avatarUpdatedAt:o.avatarUpdatedAt,updatedAt:typeof a.updatedAt=="string"?a.updatedAt:o.updatedAt}:o))},xe=async(a,t,i)=>{const o=await ee(t),d=i?await ee(i):null,s={profileId:a,displayImage:{dataUrl:o,mimeType:t.type||"application/octet-stream",originalName:t.name||"display-avatar"}};i&&d&&(s.sourceImage={dataUrl:d,mimeType:i.type||"application/octet-stream",originalName:i.name||"source-avatar"});const p=await fetch("/api/taskforce/workspace/ai-profiles/avatar/upload",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)}),A=await p.json().catch(()=>({}));if(!p.ok||!A?.profile)throw new Error(String(A?.error||"Failed to update AI profile avatar."));ae(A.profile),b({workspaceId:l,profileId:a,reason:"avatar"})},je=async a=>{const t=await fetch("/api/taskforce/workspace/ai-profiles/avatar",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({profileId:a,avatarUrl:null,avatarSourceUrl:null})}),i=await t.json().catch(()=>({}));if(!t.ok||!i?.profile)throw new Error(String(i?.error||"Failed to update AI profile avatar."));ae(i.profile),b({workspaceId:l,profileId:a,reason:"avatar"})},Ne=async(a,t)=>{if(!u)return!1;if(!a.type.startsWith("image/"))return g("AI profile photo must be an image file."),!1;M(!0),g(null);try{const i=await oe(a,{maxBytes:5242880});if(i.exceededLimit)throw new Error(a.type==="image/gif"?"Animated GIF AI profile photos must be 5 MB or smaller.":"AI profile photo must be 5 MB or smaller.");const o=i.file;let d=null;if(t){const s=await oe(t,{maxBytes:5242880});if(s.exceededLimit)throw new Error(t.type==="image/gif"?"Animated GIF AI profile photos must be 5 MB or smaller.":"AI profile source photo must be 5 MB or smaller.");d=s.file}return await xe(u.id,o,d),!0}catch(i){return g(String(i?.message||"Failed to update AI profile photo.")),!1}finally{M(!1)}},Ie=async()=>{if(u){M(!0),g(null);try{await je(u.id)}catch(a){g(String(a?.message||"Failed to remove AI profile photo."))}finally{M(!1)}}},N=a=>{const t=String(a||"").trim();if(!t)return"Unknown";const i=Date.parse(t);return Number.isFinite(i)?new Date(i).toLocaleString(void 0,{dateStyle:"medium",timeStyle:"short"}):t},re=c.useMemo(()=>{if(!n)return{attributes:[],dates:[]};const a=n.primaryProfile,t=i=>i||"Not set";return{attributes:[{label:"Category",value:a.surfaceType?le(a.surfaceType):""},{label:"Connection",value:a.seatScope?we(a.seatScope):""},{label:"Provider",value:a.provider||""},{label:"Model",value:a.model||""}].map(i=>({...i,value:t(i.value)})),dates:[{label:"Status",value:a.archivedAt?"Retired":"Active"},{label:"Recruited",value:N(a.createdAt)},{label:"Last updated",value:N(a.updatedAt)},{label:"Last active",value:N(a.lastActiveAt)}].map(i=>({...i,value:t(i.value)}))}},[n]),be=!!n&&n.profiles.length>1,te=m&&U&&!ue,$=m?de(me):ve,F=te?"Log into account for Cloud agents":$?`${$.used}/${$.limit===null?"Unlimited":$.limit}`:null,z=!!V;return e.jsxs("section",{className:`${r.agentsModuleRoot} ${z?r.agentsModuleWithTray:""} ${z&&E?r.agentsModuleTrayOpen:""}`.trim(),children:[z&&e.jsxs("aside",{className:`${r.agentTrayPanel} ${E?r.agentTrayPanelOpen:""}`.trim(),"aria-label":"Agent MCP settings tray","aria-hidden":!E,children:[e.jsxs("div",{className:r.agentTrayHeader,children:[e.jsxs("span",{className:r.agentTrayTitle,children:[e.jsx(Re,{size:14}),"MCP Settings"]}),e.jsx("button",{type:"button",className:"tf-control-icon",onClick:he,title:"Collapse agent tray","aria-label":"Collapse agent tray",children:e.jsx($e,{size:16})})]}),e.jsx("div",{className:`${r.agentTrayContent} tf-scrollbar tf-scrollbar--track-transparent`,children:e.jsx("div",{className:r.agentTrayContentInner,children:V})})]}),e.jsx("div",{className:r.agentsModuleContent,children:e.jsx("div",{className:`${r.settingGroup} ${r.agentsModuleGroup}`,children:e.jsxs("div",{children:[e.jsx("h4",{className:r.settingSubTitle,children:"Registered AI Profiles"}),e.jsx("p",{className:`${r.settingsHint} ${r.marginBottom12}`,children:"AI agents register profiles when connecting via MCP. Merge duplicates created when a token was lost, or remove inactive profiles from the active roster to free seats while preserving history."}),F&&e.jsx("div",{className:r.aiProfileSeatSummary,children:te?F:`Registered Cloud Agents: ${F}`}),B&&e.jsxs("div",{className:r.settingsHint,children:[e.jsx(Ee,{size:13,className:r.spinner})," Loading profiles…"]}),!B&&S.length===0&&e.jsx("div",{className:r.settingsHint,children:"No AI profiles registered yet."}),!B&&R.length>0&&e.jsxs("div",{className:r.aiProfilesExplorer,children:[e.jsx("div",{className:`${r.aiProfilesListPane} tf-scrollbar tf-scrollbar--track-transparent`,children:e.jsx("div",{className:r.aiProfilesList,children:R.map(a=>e.jsxs("div",{className:r.aiProfilesSection,children:[e.jsx("div",{className:r.aiProfilesSectionHeader,children:a.label}),a.groups.map(t=>{const i=n?.groupId===t.groupId,o=t.primaryProfile;return e.jsxs("div",{role:"button",tabIndex:0,className:`${r.aiProfileGroup} ${t.profiles.length>1?r.aiProfileGroupDuplicate:""} ${i?r.aiProfileGroupSelected:""}`,onClick:()=>j(t.groupId),onKeyDown:d=>{d.key!=="Enter"&&d.key!==" "||(d.preventDefault(),j(t.groupId))},"aria-pressed":i,children:[pe(o.seatScope),e.jsxs("div",{className:r.aiProfileGroupHeader,children:[e.jsx("span",{className:r.aiProfileGroupAvatar,style:{color:o.color},children:o.avatarUrl?e.jsx("img",{src:K(o),alt:""}):e.jsx(ne,{size:22})}),e.jsxs("span",{className:r.aiProfileGroupIdentity,children:[e.jsx("span",{className:r.aiProfileName,children:o.name}),e.jsxs("span",{className:r.aiProfileHandle,children:["@",o.username]}),e.jsx("span",{className:r.aiProfileRole,children:o.role||"Role not set"}),t.profiles.length>1&&e.jsxs("span",{className:r.aiProfileDuplicateBadge,children:[e.jsx(C,{size:11})," ",Oe(t.profiles.length)]})]})]})]},t.groupId)})]},a.section))})}),n&&e.jsx("div",{className:r.aiProfileDetailPane,children:e.jsxs("div",{className:r.aiProfileDetailCard,children:[pe(n.primaryProfile.seatScope,{variant:"detail"}),e.jsxs("div",{className:r.aiProfileDetailHero,children:[e.jsx(Te,{label:"Edit AI profile photo",imageUrl:K(n.primaryProfile),fallback:e.jsx(ne,{size:38}),accentColor:n.primaryProfile.color,size:176,width:153,height:207,radius:6,editBadgeSize:28,editIconSize:14,className:r.aiProfileDetailAvatar,onClick:()=>{g(null),Q(n.primaryProfile.id)}}),e.jsxs("div",{className:r.aiProfileDetailHeading,children:[e.jsx("div",{className:r.aiProfileDetailTitleRow,children:e.jsx("h5",{className:r.aiProfileDetailTitle,children:n.primaryProfile.name})}),e.jsxs("div",{className:r.aiProfileDetailMetaRow,children:[e.jsxs("span",{className:r.aiProfileDetailHandle,children:["@",n.primaryProfile.username]}),n.profiles.length>1&&e.jsxs("span",{className:r.aiProfileDetailLinkedCount,children:[n.profiles.length," linked"]})]}),e.jsxs("div",{className:r.aiProfileDetailRole,children:["Role: ",n.primaryProfile.role||"Not set"]}),n.primaryProfile.description&&e.jsx("div",{className:r.aiProfileDetailDescription,children:n.primaryProfile.description}),e.jsxs("div",{className:r.aiProfileSignatureColor,children:[e.jsx("span",{children:"Signature color"}),e.jsx("span",{className:r.aiProfileSignatureSwatch,style:{backgroundColor:n.primaryProfile.color},"aria-hidden":"true"}),e.jsx("span",{children:n.primaryProfile.color})]})]})]}),e.jsxs("div",{className:r.aiProfileDetailDataList,children:[e.jsx("div",{className:r.aiProfileDetailDataGroup,children:re.attributes.map(a=>e.jsxs("div",{className:r.aiProfileDetailDataRow,children:[e.jsx("span",{className:r.aiProfileDetailDataLabel,children:a.label}),a.label==="Category"?e.jsx("span",{className:r.aiProfileDetailDataValue,children:e.jsxs("select",{className:r.aiProfileStatusSelect,"aria-label":"Agent category",value:n.primaryProfile.surfaceType??"",disabled:ye,onChange:t=>{Se(n,t.target.value)},children:[e.jsx("option",{value:"",children:"Unclassified"}),Me.map(t=>e.jsx("option",{value:t,children:le(t)},t))]})}):e.jsx("span",{className:r.aiProfileDetailDataValue,children:a.value})]},a.label))}),e.jsx("div",{className:`${r.aiProfileDetailDataGroup} ${r.aiProfileDetailDateGroup}`,children:re.dates.map(a=>e.jsxs("div",{className:r.aiProfileDetailDataRow,children:[e.jsx("span",{className:r.aiProfileDetailDataLabel,children:a.label}),a.label==="Status"?e.jsx("span",{className:r.aiProfileDetailDataValue,children:e.jsxs("select",{className:r.aiProfileStatusSelect,"aria-label":"Agent roster status",value:n.primaryProfile.archivedAt?"retired":"active",onChange:t=>{t.target.value==="retire"&&Z(n.primaryProfile)},children:[e.jsx("option",{value:"active",children:"Active"}),n.primaryProfile.archivedAt?e.jsx("option",{value:"retired",children:"Retired"}):e.jsx("option",{value:"retire",children:"Retire from roster"})]})}):e.jsx("span",{className:r.aiProfileDetailDataValue,children:a.value})]},a.label))})]}),W?.profileId===n.primaryProfile.id&&e.jsxs("div",{className:r.aiProfileInlineError,role:"alert",children:[e.jsx(C,{size:12}),e.jsx("span",{children:W.message})]}),be?e.jsxs("div",{className:r.aiProfileInstanceSection,children:[e.jsxs("div",{className:r.aiProfileInstanceSectionHeader,children:[e.jsx("span",{children:"Profile instances"}),e.jsx("span",{className:r.settingsHint,children:"Choose a keeper here if duplicates need to be merged."})]}),e.jsx("div",{className:r.aiProfileInstanceList,children:n.profiles.map(a=>e.jsxs("div",{className:r.aiProfileInstanceCard,children:[e.jsxs("div",{className:r.aiProfileInstanceTopRow,children:[e.jsxs("div",{children:[e.jsxs("div",{className:r.aiProfileInstanceName,children:["@",a.username]}),e.jsx("div",{className:r.aiProfileIdChip,children:a.id})]}),h?.keepId===a.id&&e.jsx("span",{className:r.aiProfileKeepBadge,children:"Keeping"})]}),e.jsxs("div",{className:r.aiProfileInstanceMeta,children:[e.jsxs("span",{children:["Created ",N(a.createdAt)]}),e.jsxs("span",{children:["Updated ",N(a.updatedAt)]})]}),h?.keepId!==a.id&&e.jsx("button",{className:r.secondaryHeaderBtn,title:"Keep this profile, merge others into it",onClick:()=>{const t=n.profiles.find(i=>i.id!==a.id)?.id;t&&D({keepId:a.id,mergeId:t})},children:"Keep this"}),T?.profileId===a.id&&e.jsxs("div",{className:r.aiProfileInlineError,role:"alert",children:[e.jsx(C,{size:12}),e.jsx("span",{children:T.message})]}),e.jsx("button",{className:r.aiProfileDangerTextButton,title:"Remove this profile from the active roster",onClick:()=>{Z(a)},children:"Remove from roster"})]},a.id))}),h&&n.profiles.some(a=>a.id===h.keepId)&&e.jsxs("div",{className:r.aiProfileMergeActions,children:[e.jsx("button",{className:r.dangerBtn,onClick:()=>{Ae(h.keepId,h.mergeId)},children:"Merge duplicates"}),e.jsx("button",{className:r.secondaryHeaderBtn,onClick:()=>D(null),children:"Cancel"})]})]}):e.jsxs("div",{className:r.aiProfileIdFooter,children:[e.jsx("div",{className:r.aiProfileIdFooterValue,children:n.primaryProfile.id}),T?.profileId===n.primaryProfile.id&&e.jsxs("div",{className:r.aiProfileInlineError,role:"alert",children:[e.jsx(C,{size:12}),e.jsx("span",{children:T.message})]})]})]})})]}),w&&e.jsxs("div",{className:`${w.type==="success"?r.successMessage:r.errorMessage} ${r.marginTop12}`,children:[w.type==="success"?e.jsx(Le,{size:14}):e.jsx(C,{size:14}),w.message]})]})})}),e.jsx(ke,{isOpen:!!u,theme:"dark",title:"Edit AI Profile Photo",currentImageUrl:K(u),editorImageUrl:ze(u),fallbackInitial:(u?.name||"AI").charAt(0).toUpperCase(),accept:"image/png,image/jpeg,image/webp,image/gif",busy:X,hasPendingImage:!1,canRemove:!!u?.avatarUrl,error:Pe,notice:null,onClose:()=>{X||(Q(null),g(null))},onApplyImage:Ne,onRemoveImage:Ie})]})}export{qe as AgentsModule};
@@ -0,0 +1 @@
1
+ ._shell_17mlo_1{--image-tray-width: min(332px, calc(100vw - 96px) );position:relative;align-self:stretch;width:100%;box-sizing:border-box;display:grid;grid-template-columns:minmax(220px,280px) minmax(0,1fr) minmax(280px,340px);gap:16px;height:100%;min-height:0;padding:16px;background:radial-gradient(circle at top left,color-mix(in srgb,var(--brand-primary) 8%,transparent),transparent 26%),linear-gradient(180deg,color-mix(in srgb,var(--surface-page) 84%,var(--surface-panel)) 0%,var(--surface-page) 100%)}._shellWithImageTray_17mlo_18{transition:padding-left .22s cubic-bezier(.4,0,.2,1)}._shellImageTrayOpen_17mlo_22{padding-left:calc(var(--image-tray-width) + 16px)}._imageTrayPanel_17mlo_26{position:absolute;top:0;bottom:0;left:0;width:var(--image-tray-width);min-width:260px;max-width:332px;display:flex;flex-direction:column;padding:0 12px;box-sizing:border-box;border-right:1px solid var(--border-primary);background:var(--bg-secondary);overflow:hidden;transform:translate(-100%);opacity:0;visibility:hidden;pointer-events:none;z-index:34;box-shadow:4px 0 18px #080a1829;transition:transform .22s cubic-bezier(.4,0,.2,1),opacity .16s ease,visibility 0s linear .22s}._imageTrayPanelOpen_17mlo_50{transform:translate(0);opacity:1;visibility:visible;pointer-events:auto;transition:transform .22s cubic-bezier(.4,0,.2,1),opacity .16s ease,visibility 0s linear 0s}._imageTrayHeader_17mlo_58{position:sticky;top:0;z-index:12;display:flex;align-items:center;justify-content:space-between;gap:.75rem;padding:12px 0 10px;border-bottom:1px solid var(--border-default);background:var(--bg-secondary);box-shadow:0 10px 16px color-mix(in srgb,var(--bg-secondary) 90%,transparent);flex-shrink:0}._imageTrayTitle_17mlo_73{flex:1;display:flex;align-items:center;gap:6px;font-size:.78rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--text-secondary)}._imageTraySearch_17mlo_85{position:relative;padding:12px 0 0;flex-shrink:0}._imageTraySearchIcon_17mlo_91{position:absolute;left:10px;top:50%;transform:translateY(-50%);color:var(--text-muted);pointer-events:none}._imageTraySearchInput_17mlo_100{width:100%;padding:7px 8px 7px 28px;background:color-mix(in srgb,var(--surface-inset) 88%,transparent);border:1px solid var(--border-default);border-radius:var(--radius-md);color:var(--text-primary);font-size:.75rem;font-family:inherit;outline:none;box-sizing:border-box}._imageTraySearchInput_17mlo_100:focus{border-color:var(--brand-primary)}._imageTrayList_17mlo_117{display:flex;flex-direction:column;gap:.375rem;flex:1;overflow-y:auto;min-height:0;padding:12px 0;scrollbar-width:thin;scrollbar-color:var(--scrollbar-thumb) var(--scrollbar-track)}._imageTrayState_17mlo_129,._imageTrayStateError_17mlo_130{padding:24px 16px;font-size:.75rem;color:var(--text-muted);text-align:center;line-height:1.5}._imageTrayStateError_17mlo_130{color:var(--status-error)}._imageTrayItem_17mlo_142{width:100%;display:flex;align-items:flex-start;gap:8px;padding:.55rem .65rem;border-radius:var(--radius-md);border:1px solid var(--border-default);background:color-mix(in srgb,var(--surface-inset) 88%,transparent);cursor:pointer;text-align:left;transition:background var(--transition-base),border-color var(--transition-base),box-shadow var(--transition-base),transform var(--transition-base);font-family:inherit;color:var(--text-primary);min-width:0}._imageTrayItem_17mlo_142:hover{background:color-mix(in srgb,var(--surface-hover) 72%,transparent);transform:translateY(-1px)}._imageTrayItemActive_17mlo_164{border-color:var(--brand-primary-border);background:color-mix(in srgb,var(--brand-primary-soft) 94%,transparent);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--brand-primary-border) 42%,transparent)}._imageTrayItemActive_17mlo_164:hover{background:color-mix(in srgb,var(--brand-primary-soft) 92%,transparent)}._imageTrayThumb_17mlo_174{width:34px;height:34px;flex-shrink:0;border-radius:6px;overflow:hidden;background:var(--surface-inset);border:1px solid var(--border-subtle)}._imageTrayThumb_17mlo_174 img{width:100%;height:100%;object-fit:cover;display:block}._imageTrayItemBody_17mlo_191{display:flex;flex-direction:column;gap:.25rem;min-width:0;flex:1}._imageTrayItemTitle_17mlo_199,._imageTrayItemTask_17mlo_200,._imageTrayItemMetaDetails_17mlo_201{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}._imageTrayItemTitle_17mlo_199{display:block;max-width:100%;font-size:.875rem;font-weight:700;line-height:1.28;color:var(--text-primary)}._imageTrayItemTask_17mlo_200{display:block;max-width:100%;font-size:.75rem;line-height:1.35;color:color-mix(in srgb,var(--text-secondary) 92%,transparent)}._imageTrayItemMeta_17mlo_201{display:flex;align-items:center;justify-content:space-between;gap:8px;width:100%;font-size:.72rem;line-height:1.35;color:color-mix(in srgb,var(--text-secondary) 82%,transparent)}._imageTrayItemMetaDetails_17mlo_201{min-width:0}._imageTrayItemReference_17mlo_239{flex-shrink:0;font-size:.7rem;font-weight:700;color:var(--text-secondary)}._panel_17mlo_246{min-height:0;border-radius:var(--radius-md);box-shadow:0 18px 38px #0f172a14}._sessionPanel_17mlo_252,._detailPanel_17mlo_253{display:flex;flex-direction:column;overflow:hidden}._sessionContextBar_17mlo_259{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:58px;padding:12px 16px;border-bottom:1px solid var(--border-default);background:color-mix(in srgb,var(--surface-inset) 88%,transparent)}._sessionContextLeft_17mlo_270,._sessionContextRight_17mlo_271{display:flex;align-items:center;min-width:0}._sessionContextLeft_17mlo_270{flex:1}._sessionContextRight_17mlo_271{justify-content:flex-end;min-width:118px}._sessionContextLabel_17mlo_286{font-size:.84rem;font-weight:600;color:var(--text-secondary)}._sessionContextSpacer_17mlo_292{width:118px;height:32px}._canvasPanel_17mlo_297{display:flex;flex-direction:column;min-height:0;overflow:hidden}._canvasWorkspace_17mlo_304{display:grid;grid-template-columns:auto minmax(0,1fr);min-height:0;flex:1}._canvasMain_17mlo_311{display:flex;flex-direction:column;min-width:0;min-height:0}._panelHeader_17mlo_318{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:16px;border-bottom:1px solid var(--border-default)}._panelHeaderText_17mlo_327{min-width:0}._panelTitle_17mlo_331{font-size:1rem}._canvasHeading_17mlo_335{min-width:0}._sessionActions_17mlo_339{display:inline-flex;align-items:center;gap:8px;margin-left:auto;flex-shrink:0}._sessionList_17mlo_347,._annotationList_17mlo_348{display:flex;flex:1 1 auto;flex-direction:column;gap:10px;min-height:0;padding:14px;overflow:auto;scrollbar-gutter:stable}._annotationList_17mlo_348{gap:12px}._markerHelpModalBody_17mlo_363{display:flex;flex-direction:column;gap:14px}._openImageModalBody_17mlo_369{display:flex;flex-direction:column;gap:12px}._openImageField_17mlo_375{width:100%}._openImageActions_17mlo_379{display:flex;justify-content:flex-end;gap:8px}._markerHelpItem_17mlo_385{display:flex;flex-direction:column;gap:6px;padding:12px 14px;border-radius:var(--radius-md)}._markerHelpHeader_17mlo_393{display:flex;align-items:baseline;justify-content:space-between;gap:12px}._markerHelpItem_17mlo_385 p{margin:0;line-height:1.45}._markerHelpExample_17mlo_405{font-weight:600}._sessionCard_17mlo_409,._annotationCard_17mlo_410{display:flex;flex-direction:column;gap:8px;padding:12px;border-radius:var(--radius-md);text-align:left;transition:border-color var(--transition-base),box-shadow var(--transition-base),transform var(--transition-base)}._sessionCard_17mlo_409{gap:10px}._sessionEmptyState_17mlo_427{display:flex;flex-direction:column;gap:8px;padding:8px 2px 0}._sessionCardButton_17mlo_434,._annotationCardButton_17mlo_444{display:flex;flex-direction:column;gap:8px;padding:0;border:0;background:transparent;text-align:left}._sessionCardBody_17mlo_454{display:flex;flex-direction:column;gap:8px}._sessionCardActive_17mlo_460,._annotationCardActive_17mlo_461{border-color:var(--button-tile-active-border);box-shadow:0 0 0 1px transparent,0 12px 28px var(--brand-primary-glow-soft)}._sessionCard_17mlo_409:hover,._annotationCard_17mlo_410:hover{transform:translateY(-1px)}._annotationMeta_17mlo_471{display:flex;align-items:center;justify-content:space-between;gap:8px}._annotationInstructionPreview_17mlo_478{display:-webkit-box;overflow:hidden;-webkit-line-clamp:2;-webkit-box-orient:vertical;line-height:1.45}._annotationPreviewFooter_17mlo_486{display:flex;align-items:center;justify-content:flex-start;min-height:16px}._annotationInstructionEditor_17mlo_493,._annotationTypeField_17mlo_499{display:flex;flex-direction:column;gap:8px}._annotationInstructionButton_17mlo_505{display:block;width:100%;padding:0;border:0;background:transparent;text-align:left}._annotationInstructionField_17mlo_514{min-height:92px}._sessionMeta_17mlo_518{display:flex;flex-direction:column;align-items:flex-start;gap:4px}._sessionTitle_17mlo_525,._annotationTitle_17mlo_526{font-size:.98rem;font-weight:700;color:var(--text-primary)}._sessionTimestamp_17mlo_532,._annotationKind_17mlo_533{text-transform:capitalize}._annotationInstructionTypeIcon_17mlo_537{display:inline-flex;align-items:center;justify-content:center}._sessionInstructionPreview_17mlo_543{line-height:1.45;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden}._sessionInstructionEditor_17mlo_551{display:flex;flex-direction:column;gap:8px}._sessionCardFooter_17mlo_557{display:flex;align-items:center;justify-content:flex-end;gap:8px}._toolRail_17mlo_564{display:flex;flex-wrap:wrap;gap:8px;padding:0;border-bottom:1px solid var(--border-default);background:color-mix(in srgb,var(--surface-inset) 92%,transparent)}._canvasToolRail_17mlo_573{display:flex;flex-direction:column;align-items:center;gap:8px;padding:0;border-right:1px solid var(--border-default);background:color-mix(in srgb,var(--surface-inset) 94%,transparent)}._toolGroup_17mlo_583{display:inline-flex;flex-wrap:wrap;gap:8px;align-items:center;padding:4px;border:1px solid var(--border-default);border-radius:16px;background:var(--surface-panel)}._toolbarCluster_17mlo_594{display:inline-flex;flex-wrap:wrap;gap:8px;align-items:center}._toolbarViewportCluster_17mlo_601{margin-left:44px}._toolbarSeparator_17mlo_605{width:1px;align-self:stretch;background:var(--border-default)}._toolBtn_17mlo_611{white-space:nowrap}._toolRailButton_17mlo_615{display:inline-flex;align-items:center;justify-content:center;width:44px;height:44px;padding:0;border-radius:var(--radius-md)}._toolbarButton_17mlo_625{min-height:44px;border-radius:var(--radius-md)}._toolBtnActive_17mlo_630{background:var(--button-tile-active-bg);border-color:var(--button-tile-active-border);color:var(--button-tile-active-text);box-shadow:0 0 0 1px transparent,0 8px 24px var(--brand-primary-glow-soft)}._toolbarActions_17mlo_637{display:inline-flex;flex-wrap:wrap;align-items:center;gap:8px;flex:1 1 auto;min-width:0}._toolbarSelectionActions_17mlo_646{display:inline-flex;align-items:center;gap:8px;min-width:44px;flex-wrap:wrap}._toolbarColorPicker_17mlo_654{position:relative}._colorPickerButton_17mlo_658{min-width:44px;padding:0}._colorPickerSwatch_17mlo_663{width:24px;height:24px;border-radius:var(--radius-sm);border:2px solid color-mix(in srgb,var(--surface-panel) 88%,transparent);box-shadow:inset 0 0 0 1px #0f172a1f}._colorPickerPopover_17mlo_671{position:absolute;top:calc(100% + 8px);left:0;z-index:3;display:grid;grid-template-columns:repeat(3,1fr);gap:8px;padding:10px;border:1px solid var(--border-default);border-radius:var(--radius-md);background:var(--surface-panel);box-shadow:0 18px 32px #0f172a24}._colorOption_17mlo_686{width:24px;height:24px;padding:0;border:2px solid transparent;border-radius:var(--radius-sm);cursor:pointer;box-shadow:inset 0 0 0 1px #0f172a24}._colorOptionActive_17mlo_696{border-color:color-mix(in srgb,var(--surface-panel) 78%,var(--brand-primary));box-shadow:inset 0 0 0 1px #0f172a24,0 0 0 2px color-mix(in srgb,var(--brand-primary) 24%,transparent)}._toolbarUtilities_17mlo_703{margin-left:auto;display:inline-flex;flex-wrap:wrap;align-items:center;gap:8px}._toolbarGeometryFields_17mlo_711{display:inline-flex;align-items:center;gap:8px;flex-wrap:wrap}._toolbarGeometryField_17mlo_711{display:inline-flex;align-items:center;gap:6px}._toolbarGeometryLabel_17mlo_724{margin:0;text-transform:uppercase;white-space:nowrap}._toolbarGeometryInput_17mlo_730{width:68px;text-align:right}._iconButton_17mlo_735{flex-shrink:0}._primaryBtn_17mlo_739,._ghostBtn_17mlo_740,._payloadBtn_17mlo_741,._backToTaskBtn_17mlo_742{white-space:nowrap}._backToTaskBtn_17mlo_742{padding:7px 10px;color:var(--text-secondary);font-size:.88rem;font-weight:600}._backToTaskBtn_17mlo_742:hover,._backToTaskBtn_17mlo_742:focus-visible{color:var(--text-primary)}._payloadBtn_17mlo_741{font-weight:700}._canvasScroller_17mlo_762{position:relative;flex:1;min-height:0;overflow:auto;display:block;scrollbar-gutter:stable;background:linear-gradient(45deg,color-mix(in srgb,var(--surface-inset) 66%,var(--border-default)) 25%,transparent 25%),linear-gradient(-45deg,color-mix(in srgb,var(--surface-inset) 66%,var(--border-default)) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,color-mix(in srgb,var(--surface-inset) 66%,var(--border-default)) 75%),linear-gradient(-45deg,transparent 75%,color-mix(in srgb,var(--surface-inset) 66%,var(--border-default)) 75%);background-size:22px 22px;background-position:0 0,0 11px,11px -11px,-11px 0}._canvasFrame_17mlo_778{position:relative;display:block;width:max-content;min-width:100%}._canvasMedia_17mlo_785{position:relative;display:block;flex-shrink:0;margin:0 auto;overflow:hidden}._canvasStatusOverlay_17mlo_793{position:absolute;inset:0;z-index:2;display:flex;align-items:center;justify-content:center;padding:24px;background:color-mix(in srgb,var(--surface-scrim) 68%,transparent);pointer-events:none}._canvasStatusCard_17mlo_805{display:inline-flex;align-items:center;gap:10px;padding:12px 16px;border:1px solid color-mix(in srgb,var(--border-strong) 44%,white);border-radius:var(--radius-md);background:#0f172ac7;color:#fff;box-shadow:0 18px 30px #0f172a38;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}._canvasImage_17mlo_818{display:block;width:100%;height:100%;-webkit-user-select:none;user-select:none}._overlay_17mlo_825{position:absolute;inset:0;cursor:crosshair}._overlaySelect_17mlo_831{cursor:default}._overlayPan_17mlo_835{cursor:grab}._overlaySvg_17mlo_839{position:absolute;inset:0;display:block;width:100%;height:100%;pointer-events:none}._overlayHitLayer_17mlo_848{position:absolute;inset:0;display:block;width:100%;height:100%;pointer-events:auto}._arrowHitArea_17mlo_857{stroke:transparent;stroke-width:24;pointer-events:stroke;cursor:move}._canvasHandleHit_17mlo_864{fill:transparent;pointer-events:all;cursor:grab;outline:none}._canvasResizeHandleHit_17mlo_871{cursor:nwse-resize}._canvasHandleVisible_17mlo_875{--canvas-handle-fill: var(--brand-primary);--canvas-handle-outline: var(--surface-elevated);--canvas-handle-shadow: 0 6px 12px rgba(15, 23, 42, .18);fill:var(--canvas-handle-fill);stroke:var(--canvas-handle-outline);stroke-width:3;vector-effect:non-scaling-stroke;filter:drop-shadow(var(--canvas-handle-shadow));pointer-events:none}._canvasHandleHit_17mlo_864:focus-visible+._canvasHandleVisible_17mlo_875{stroke:color-mix(in srgb,var(--brand-primary) 72%,var(--surface-elevated));stroke-width:4}._pin_17mlo_892,._note_17mlo_893{position:absolute;transform:translate(-50%,-50%);display:inline-flex;align-items:center;justify-content:center;min-width:28px;min-height:28px;border:2px solid var(--surface-elevated);border-radius:999px;box-shadow:0 8px 18px #0f172a38;color:#fff;font-size:.74rem;font-weight:800;pointer-events:auto}._annotationNumberBadge_17mlo_910{position:absolute;display:inline-flex;align-items:center;justify-content:center;min-width:28px;min-height:28px;padding:0 8px;border:2px solid var(--surface-elevated);border-radius:999px;box-shadow:0 8px 18px #0f172a38;color:#fff;font-size:.74rem;font-weight:800;line-height:1;pointer-events:none;z-index:2}._note_17mlo_893{min-width:38px;padding:0 10px;border-radius:999px}._box_17mlo_935{position:absolute;border:2px solid;border-radius:var(--radius-sm);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--surface-elevated) 34%,transparent);background:color-mix(in srgb,var(--surface-elevated) 10%,transparent);pointer-events:auto}._boxNumberBadge_17mlo_944{top:0;left:0;transform:translate(-28%,-36%)}._arrowNumberBadge_17mlo_950{transform:translate(-50%,-50%)}._boxSurface_17mlo_954{position:absolute;inset:0;border:0;background:transparent;cursor:move}._boxSurface_17mlo_954:focus-visible{outline:2px solid color-mix(in srgb,var(--brand-primary) 34%,var(--surface-elevated));outline-offset:2px}._selected_17mlo_967{outline:3px solid color-mix(in srgb,var(--surface-elevated) 92%,transparent);outline-offset:1px}._fieldGroup_17mlo_972{display:flex;flex-direction:column;gap:8px;padding:14px 16px}._detailPanel_17mlo_253 ._fieldGroup_17mlo_972{padding-top:12px;padding-bottom:12px}._textInput_17mlo_984,._textArea_17mlo_985,._select_17mlo_967{width:100%;box-sizing:border-box;font:inherit}._sessionTitleInput_17mlo_992{font-size:1rem;font-weight:600}._sessionInstructionField_17mlo_997{min-height:112px}._textArea_17mlo_985{min-height:110px;resize:vertical}._detailEmpty_17mlo_1006,._emptyState_17mlo_1007,._errorState_17mlo_1008{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;min-height:240px;padding:24px;text-align:center}._payloadModalBody_17mlo_1019{display:flex;flex-direction:column;gap:12px;min-height:0}._payloadModalToolbar_17mlo_1026{display:flex;align-items:center;justify-content:space-between;gap:12px}._payloadViewToggle_17mlo_1033,._payloadModalActions_17mlo_1034{display:inline-flex;flex-wrap:wrap;align-items:center;gap:8px}._payloadModalPreview_17mlo_1041{margin:0;min-height:360px;max-height:min(70vh,720px);padding:16px;overflow:auto;scrollbar-gutter:stable;white-space:pre-wrap;word-break:break-word;font-size:.78rem;line-height:1.55;border-radius:var(--radius-md);color:var(--text-body)}._statusBar_17mlo_1056{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 16px;border-top:1px solid var(--border-default);color:var(--text-secondary);font-size:.82rem;background:color-mix(in srgb,var(--surface-panel) 88%,var(--surface-inset))}._annotationSummary_17mlo_1068{font-size:.82rem;line-height:1.5}@media(max-width:1180px){._shell_17mlo_1{grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(320px,1fr) auto;gap:12px;padding:12px}._sessionContextBar_17mlo_259,._panelHeader_17mlo_318,._toolRail_17mlo_564,._statusBar_17mlo_1056,._payloadModalToolbar_17mlo_1026,._markerHelpHeader_17mlo_393{flex-wrap:wrap}._sessionContextRight_17mlo_271,._sessionContextLeft_17mlo_270,._canvasHeading_17mlo_335{min-width:0}._sessionContextRight_17mlo_271{width:100%;justify-content:flex-start}._toolbarActions_17mlo_637{width:100%;margin-left:0}._toolbarUtilities_17mlo_703{margin-left:0}._toolGroup_17mlo_583{max-width:100%}._canvasWorkspace_17mlo_304{grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr)}._toolbarViewportCluster_17mlo_601{margin-left:0}._canvasToolRail_17mlo_573{flex-direction:row;justify-content:flex-start;overflow-x:auto;padding:0;border-right:0;border-bottom:1px solid var(--border-default)}._statusBar_17mlo_1056{align-items:flex-start}._detailEmpty_17mlo_1006,._emptyState_17mlo_1007,._errorState_17mlo_1008{min-height:180px}}