@taskforcehq/taskforce 0.3.309 → 0.3.313

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 (470) hide show
  1. package/README.md +89 -127
  2. package/dist/TaskforceCore.js +1 -1
  3. package/dist/components/context/ContextAttachmentManager.js +4 -3
  4. package/dist/components/features/InitiativesModule.js +1 -1
  5. package/dist/components/features/TaskSettings.js +1 -1
  6. package/dist/components/ui/DisclosureSectionHeader.d.ts +12 -0
  7. package/dist/components/ui/DisclosureSectionHeader.js +8 -0
  8. package/dist/components/views/PlanComparisonPage.js +1 -1
  9. package/dist/components/views/StandaloneLayout.js +18 -4
  10. package/dist/components/views/panels/PlanningDrawer.js +2 -1
  11. package/dist/components/views/standalone/modals/AccountHubModal.js +1 -1
  12. package/dist/components/views/standalone/modals/HelpModal.d.ts +3 -1
  13. package/dist/components/views/standalone/modals/HelpModal.js +17 -2
  14. package/dist/core/PlanEntitlementService.d.ts +2 -0
  15. package/dist/core/PlanEntitlementService.js +57 -4
  16. package/dist/hooks/useFilterSort.js +1 -1
  17. package/dist/hooks/useTaskforce.js +2 -2
  18. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +5 -2
  19. package/dist/localization/locales/en-US.js +1 -1
  20. package/dist/localization/locales/es-419.js +1 -1
  21. package/dist/localization/locales/pt-BR.js +1 -1
  22. package/dist/mcp/runtime.js +49 -14
  23. package/dist/server/routes/billing.js +0 -1
  24. package/dist/ui/assets/AgentsModule-BULqIo8e.js +1 -0
  25. package/dist/ui/assets/{AnnotatedAttachmentWorkspace-CCckzWYZ.js → AnnotatedAttachmentWorkspace-DHr4rHK9.js} +1 -1
  26. package/dist/ui/assets/ContextAttachmentManager-DoMe2OpY.js +3 -0
  27. package/dist/ui/assets/{DocumentWorkspace-BVaWPA25.js → DocumentWorkspace-DumBWhvb.js} +1 -1
  28. package/dist/ui/assets/{EntityActivityTimeline-DSj0ThaK.js → EntityActivityTimeline-sHk8Nzbq.js} +1 -1
  29. package/dist/ui/assets/{InitiativesModule-AxMkWtxH.js → InitiativesModule-3X9UNzHh.js} +1 -1
  30. package/dist/ui/assets/PlansPage-C3A3EYaV.js +1 -0
  31. package/dist/ui/assets/PlansPage-DeAzWYTb.css +1 -0
  32. package/dist/ui/assets/{TaskContextUpload-Dw4rTF4i.js → TaskContextUpload-C8G7pWkX.js} +1 -1
  33. package/dist/ui/assets/{TaskSettings-f2ga42_V.js → TaskSettings-DM1o9Wla.js} +2 -2
  34. package/dist/ui/assets/{WorkflowsModule-E4UL3mov.js → WorkflowsModule-CW0crzvD.js} +1 -1
  35. package/dist/ui/assets/documentReferences-BZB3nMRb.js +1 -0
  36. package/dist/ui/assets/index-BWFQ9mGn.js +5 -0
  37. package/dist/ui/assets/{index-BvAbqx5Q.css → index-DcK_8tuE.css} +1 -1
  38. package/dist/ui/assets/{vendor-icons-B32hGuF2.js → vendor-icons-CLnehDTw.js} +1 -1
  39. package/dist/ui/index.html +3 -3
  40. package/dist/utils/supportContact.d.ts +9 -0
  41. package/dist/utils/supportContact.js +32 -0
  42. package/package.json +12 -4
  43. package/scripts/postinstall.js +4 -3
  44. package/dist/TaskforceCore.CategoryFallback.test.d.ts +0 -1
  45. package/dist/TaskforceCore.CategoryFallback.test.js +0 -101
  46. package/dist/TaskforceCore.filter-persistence.test.d.ts +0 -1
  47. package/dist/TaskforceCore.filter-persistence.test.js +0 -402
  48. package/dist/TaskforceCore.routing.test.d.ts +0 -1
  49. package/dist/TaskforceCore.routing.test.js +0 -311
  50. package/dist/TaskforceCore.test.d.ts +0 -1
  51. package/dist/TaskforceCore.test.js +0 -7910
  52. package/dist/TaskforceWidget.test.d.ts +0 -1
  53. package/dist/TaskforceWidget.test.js +0 -92
  54. package/dist/UnsavedChangesRelaxed.test.d.ts +0 -1
  55. package/dist/UnsavedChangesRelaxed.test.js +0 -16
  56. package/dist/__tests__/localizationCatalogs.test.d.ts +0 -1
  57. package/dist/__tests__/localizationCatalogs.test.js +0 -54
  58. package/dist/__tests__/workflowSimulation.test.d.ts +0 -1
  59. package/dist/__tests__/workflowSimulation.test.js +0 -113
  60. package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.test.d.ts +0 -1
  61. package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.test.js +0 -278
  62. package/dist/annotatedAttachments/payload.test.d.ts +0 -1
  63. package/dist/annotatedAttachments/payload.test.js +0 -67
  64. package/dist/compat/workspaceSyncCompat.test.d.ts +0 -1
  65. package/dist/compat/workspaceSyncCompat.test.js +0 -124
  66. package/dist/components/features/AgentsModule.test.d.ts +0 -1
  67. package/dist/components/features/AgentsModule.test.js +0 -601
  68. package/dist/components/features/AnnotatedAttachmentWorkspace.test.d.ts +0 -1
  69. package/dist/components/features/AnnotatedAttachmentWorkspace.test.js +0 -2883
  70. package/dist/components/features/DocumentWorkspace.test.d.ts +0 -1
  71. package/dist/components/features/DocumentWorkspace.test.js +0 -1439
  72. package/dist/components/features/TaskSettings.test.d.ts +0 -1
  73. package/dist/components/features/TaskSettings.test.js +0 -1674
  74. package/dist/components/features/settings/TaxonomyLibraryManager.test.d.ts +0 -1
  75. package/dist/components/features/settings/TaxonomyLibraryManager.test.js +0 -141
  76. package/dist/components/task/TaskActionHeader.test.d.ts +0 -1
  77. package/dist/components/task/TaskActionHeader.test.js +0 -91
  78. package/dist/components/task/TaskCard.test.d.ts +0 -1
  79. package/dist/components/task/TaskCard.test.js +0 -513
  80. package/dist/components/task/TaskContextUpload.test.d.ts +0 -1
  81. package/dist/components/task/TaskContextUpload.test.js +0 -506
  82. package/dist/components/task/TaskForm.test.d.ts +0 -1
  83. package/dist/components/task/TaskForm.test.js +0 -946
  84. package/dist/components/task/TaskKanban.empty-column-drop.test.d.ts +0 -1
  85. package/dist/components/task/TaskKanban.empty-column-drop.test.js +0 -66
  86. package/dist/components/task/TaskKanban.planning-drop.test.d.ts +0 -1
  87. package/dist/components/task/TaskKanban.planning-drop.test.js +0 -93
  88. package/dist/components/task/TaskKanban.test.d.ts +0 -1
  89. package/dist/components/task/TaskKanban.test.js +0 -99
  90. package/dist/components/task/TaskList.test.d.ts +0 -1
  91. package/dist/components/task/TaskList.test.js +0 -473
  92. package/dist/components/task/TaskStatusActions.test.d.ts +0 -1
  93. package/dist/components/task/TaskStatusActions.test.js +0 -54
  94. package/dist/components/task/taskKanbanDropRules.test.d.ts +0 -1
  95. package/dist/components/task/taskKanbanDropRules.test.js +0 -114
  96. package/dist/components/ui/LevelSelector.test.d.ts +0 -1
  97. package/dist/components/ui/LevelSelector.test.js +0 -55
  98. package/dist/components/ui/Markdown.test.d.ts +0 -1
  99. package/dist/components/ui/Markdown.test.js +0 -38
  100. package/dist/components/ui/MultiSelectFilter.test.d.ts +0 -1
  101. package/dist/components/ui/MultiSelectFilter.test.js +0 -74
  102. package/dist/components/ui/TaxonomyDropdown.test.d.ts +0 -1
  103. package/dist/components/ui/TaxonomyDropdown.test.js +0 -130
  104. package/dist/components/ui/TopNoticeLayer.test.d.ts +0 -1
  105. package/dist/components/ui/TopNoticeLayer.test.js +0 -25
  106. package/dist/components/views/AppShellHeader.test.d.ts +0 -1
  107. package/dist/components/views/AppShellHeader.test.js +0 -42
  108. package/dist/components/views/PlanComparisonPage.test.d.ts +0 -1
  109. package/dist/components/views/PlanComparisonPage.test.js +0 -757
  110. package/dist/components/views/PlansPage.test.d.ts +0 -1
  111. package/dist/components/views/PlansPage.test.js +0 -710
  112. package/dist/components/views/chrome/WorkspaceChromeSections.test.d.ts +0 -1
  113. package/dist/components/views/chrome/WorkspaceChromeSections.test.js +0 -54
  114. package/dist/components/views/chrome/workspaceChrome.test.d.ts +0 -1
  115. package/dist/components/views/chrome/workspaceChrome.test.js +0 -52
  116. package/dist/components/views/panels/DocumentFilterToolbar.test.d.ts +0 -1
  117. package/dist/components/views/panels/DocumentFilterToolbar.test.js +0 -19
  118. package/dist/components/views/panels/FilterToolbar.test.d.ts +0 -1
  119. package/dist/components/views/panels/FilterToolbar.test.js +0 -47
  120. package/dist/components/views/panels/PlanningDrawer.test.d.ts +0 -1
  121. package/dist/components/views/panels/PlanningDrawer.test.js +0 -529
  122. package/dist/components/views/planningScope.test.d.ts +0 -1
  123. package/dist/components/views/planningScope.test.js +0 -60
  124. package/dist/components/views/standalone/modals/AccountHubModal.test.d.ts +0 -1
  125. package/dist/components/views/standalone/modals/AccountHubModal.test.js +0 -66
  126. package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.d.ts +0 -1
  127. package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.js +0 -24
  128. package/dist/components/views/teamManagementAccess.test.d.ts +0 -1
  129. package/dist/components/views/teamManagementAccess.test.js +0 -44
  130. package/dist/config/deployment.test.d.ts +0 -1
  131. package/dist/config/deployment.test.js +0 -90
  132. package/dist/config/envSchema.test.d.ts +0 -1
  133. package/dist/config/envSchema.test.js +0 -125
  134. package/dist/core/AiProfileService.test.d.ts +0 -1
  135. package/dist/core/AiProfileService.test.js +0 -184
  136. package/dist/core/AiProfiles.test.d.ts +0 -1
  137. package/dist/core/AiProfiles.test.js +0 -1873
  138. package/dist/core/AuthTokenService.test.d.ts +0 -1
  139. package/dist/core/AuthTokenService.test.js +0 -78
  140. package/dist/core/BulkUpdateFieldsPreview.test.d.ts +0 -1
  141. package/dist/core/BulkUpdateFieldsPreview.test.js +0 -62
  142. package/dist/core/CompletedAt.test.d.ts +0 -1
  143. package/dist/core/CompletedAt.test.js +0 -44
  144. package/dist/core/CreatedBy.test.d.ts +0 -1
  145. package/dist/core/CreatedBy.test.js +0 -188
  146. package/dist/core/DeletedTaskTrash.test.d.ts +0 -1
  147. package/dist/core/DeletedTaskTrash.test.js +0 -104
  148. package/dist/core/EntitlementsPolicy.test.d.ts +0 -1
  149. package/dist/core/EntitlementsPolicy.test.js +0 -280
  150. package/dist/core/GlobalSettingsService.test.d.ts +0 -1
  151. package/dist/core/GlobalSettingsService.test.js +0 -45
  152. package/dist/core/JsonBackupRuntime.test.d.ts +0 -1
  153. package/dist/core/JsonBackupRuntime.test.js +0 -155
  154. package/dist/core/PlanFeatureCatalog.test.d.ts +0 -1
  155. package/dist/core/PlanFeatureCatalog.test.js +0 -139
  156. package/dist/core/PlanVersionPolicy.test.d.ts +0 -1
  157. package/dist/core/PlanVersionPolicy.test.js +0 -204
  158. package/dist/core/PlanningEntities.test.d.ts +0 -1
  159. package/dist/core/PlanningEntities.test.js +0 -509
  160. package/dist/core/ScheduleFields.test.d.ts +0 -1
  161. package/dist/core/ScheduleFields.test.js +0 -193
  162. package/dist/core/SetupState.test.d.ts +0 -1
  163. package/dist/core/SetupState.test.js +0 -113
  164. package/dist/core/SignupMonetizationSettings.test.d.ts +0 -1
  165. package/dist/core/SignupMonetizationSettings.test.js +0 -515
  166. package/dist/core/Stats.test.d.ts +0 -1
  167. package/dist/core/Stats.test.js +0 -36
  168. package/dist/core/SystemAdmin.test.d.ts +0 -1
  169. package/dist/core/SystemAdmin.test.js +0 -1106
  170. package/dist/core/TaskActivitySync.test.d.ts +0 -1
  171. package/dist/core/TaskActivitySync.test.js +0 -90
  172. package/dist/core/TaskAttachmentsCanonical.test.d.ts +0 -1
  173. package/dist/core/TaskAttachmentsCanonical.test.js +0 -356
  174. package/dist/core/TaskAuditTimeline.test.d.ts +0 -1
  175. package/dist/core/TaskAuditTimeline.test.js +0 -319
  176. package/dist/core/TaskTaxonomyValidation.test.d.ts +0 -1
  177. package/dist/core/TaskTaxonomyValidation.test.js +0 -440
  178. package/dist/core/Taskforce.ids.test.d.ts +0 -1
  179. package/dist/core/Taskforce.ids.test.js +0 -611
  180. package/dist/core/Taskforce.listTasksSlim.test.d.ts +0 -1
  181. package/dist/core/Taskforce.listTasksSlim.test.js +0 -91
  182. package/dist/core/Taskforce.mcpAuth.test.d.ts +0 -1
  183. package/dist/core/Taskforce.mcpAuth.test.js +0 -450
  184. package/dist/core/Taskforce.realtimeMutation.test.d.ts +0 -1
  185. package/dist/core/Taskforce.realtimeMutation.test.js +0 -131
  186. package/dist/core/UserProfileAvatarDrafts.test.d.ts +0 -1
  187. package/dist/core/UserProfileAvatarDrafts.test.js +0 -138
  188. package/dist/core/WorkspaceDelete.test.d.ts +0 -1
  189. package/dist/core/WorkspaceDelete.test.js +0 -159
  190. package/dist/core/WorkspacePermissions.test.d.ts +0 -1
  191. package/dist/core/WorkspacePermissions.test.js +0 -270
  192. package/dist/core/WorkspacePlanMode.test.d.ts +0 -1
  193. package/dist/core/WorkspacePlanMode.test.js +0 -383
  194. package/dist/core/WorkspaceSyncSettings.test.d.ts +0 -1
  195. package/dist/core/WorkspaceSyncSettings.test.js +0 -65
  196. package/dist/core/__tests__/TaskAttachmentsCanonical.test.d.ts +0 -1
  197. package/dist/core/__tests__/TaskAttachmentsCanonical.test.js +0 -212
  198. package/dist/documentReviews/DocumentReviewSessionStore.test.d.ts +0 -1
  199. package/dist/documentReviews/DocumentReviewSessionStore.test.js +0 -127
  200. package/dist/hooks/authGuardPolicy.test.d.ts +0 -1
  201. package/dist/hooks/authGuardPolicy.test.js +0 -76
  202. package/dist/hooks/bootstrapTimeouts.test.d.ts +0 -1
  203. package/dist/hooks/bootstrapTimeouts.test.js +0 -12
  204. package/dist/hooks/sync/controlPlane.test.d.ts +0 -1
  205. package/dist/hooks/sync/controlPlane.test.js +0 -121
  206. package/dist/hooks/sync/lifecyclePolicy.test.d.ts +0 -1
  207. package/dist/hooks/sync/lifecyclePolicy.test.js +0 -124
  208. package/dist/hooks/sync/orchestratorShared.test.d.ts +0 -1
  209. package/dist/hooks/sync/orchestratorShared.test.js +0 -98
  210. package/dist/hooks/sync/pullLifecycle.test.d.ts +0 -1
  211. package/dist/hooks/sync/pullLifecycle.test.js +0 -80
  212. package/dist/hooks/sync/recovery.test.d.ts +0 -1
  213. package/dist/hooks/sync/recovery.test.js +0 -292
  214. package/dist/hooks/sync/transfers.test.d.ts +0 -1
  215. package/dist/hooks/sync/transfers.test.js +0 -928
  216. package/dist/hooks/sync/useRecentSyncEvents.test.d.ts +0 -1
  217. package/dist/hooks/sync/useRecentSyncEvents.test.js +0 -124
  218. package/dist/hooks/sync/useSyncStatusActions.test.d.ts +0 -1
  219. package/dist/hooks/sync/useSyncStatusActions.test.js +0 -133
  220. package/dist/hooks/sync/useSyncStatusControls.test.d.ts +0 -1
  221. package/dist/hooks/sync/useSyncStatusControls.test.js +0 -88
  222. package/dist/hooks/useFilterSort.test.d.ts +0 -1
  223. package/dist/hooks/useFilterSort.test.js +0 -419
  224. package/dist/hooks/useRealtimeSync.test.d.ts +0 -1
  225. package/dist/hooks/useRealtimeSync.test.js +0 -311
  226. package/dist/hooks/useSyncOrchestrator.aiProfiles.test.d.ts +0 -1
  227. package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +0 -54
  228. package/dist/hooks/useSyncOrchestrator.context-assets.test.d.ts +0 -1
  229. package/dist/hooks/useSyncOrchestrator.context-assets.test.js +0 -228
  230. package/dist/hooks/useSyncOrchestrator.retry-closure.test.d.ts +0 -1
  231. package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +0 -2027
  232. package/dist/hooks/useTaskData.test.d.ts +0 -1
  233. package/dist/hooks/useTaskData.test.js +0 -291
  234. package/dist/hooks/useTaskMutations.test.d.ts +0 -1
  235. package/dist/hooks/useTaskMutations.test.js +0 -256
  236. package/dist/hooks/useTaskforce.contract.test.d.ts +0 -1
  237. package/dist/hooks/useTaskforce.contract.test.js +0 -7
  238. package/dist/hooks/useTaskforce.priority-filters.test.d.ts +0 -1
  239. package/dist/hooks/useTaskforce.priority-filters.test.js +0 -28
  240. package/dist/hooks/useTaskforce.runtime-routing.test.d.ts +0 -1
  241. package/dist/hooks/useTaskforce.runtime-routing.test.js +0 -246
  242. package/dist/hooks/useTaskforce.sync-behavior.test.d.ts +0 -1
  243. package/dist/hooks/useTaskforce.sync-behavior.test.js +0 -3644
  244. package/dist/hooks/useWorkspaceSyncController.test.d.ts +0 -1
  245. package/dist/hooks/useWorkspaceSyncController.test.js +0 -192
  246. package/dist/hooks/workspace/useTaskforceApiRouting.test.d.ts +0 -1
  247. package/dist/hooks/workspace/useTaskforceApiRouting.test.js +0 -77
  248. package/dist/hooks/workspace/workspaceLocalState.test.d.ts +0 -1
  249. package/dist/hooks/workspace/workspaceLocalState.test.js +0 -59
  250. package/dist/localization/localizationCatalogs.test.d.ts +0 -1
  251. package/dist/localization/localizationCatalogs.test.js +0 -37
  252. package/dist/mcp/aiProfileBootstrap.test.d.ts +0 -1
  253. package/dist/mcp/aiProfileBootstrap.test.js +0 -68
  254. package/dist/mcp/canonicalAssetHelpers.test.d.ts +0 -1
  255. package/dist/mcp/canonicalAssetHelpers.test.js +0 -67
  256. package/dist/mcp/clientIntegrations.test.d.ts +0 -1
  257. package/dist/mcp/clientIntegrations.test.js +0 -219
  258. package/dist/mcp/optionResolution.test.d.ts +0 -1
  259. package/dist/mcp/optionResolution.test.js +0 -43
  260. package/dist/mcp/runtime.test.d.ts +0 -1
  261. package/dist/mcp/runtime.test.js +0 -5120
  262. package/dist/mcp/structuredCommentValidation.test.d.ts +0 -1
  263. package/dist/mcp/structuredCommentValidation.test.js +0 -31
  264. package/dist/mcp/structuredDocValidation.test.d.ts +0 -1
  265. package/dist/mcp/structuredDocValidation.test.js +0 -35
  266. package/dist/mcp/toolRegistry.test.d.ts +0 -1
  267. package/dist/mcp/toolRegistry.test.js +0 -34
  268. package/dist/migrations/billingSchemaParity.test.d.ts +0 -1
  269. package/dist/migrations/billingSchemaParity.test.js +0 -160
  270. package/dist/migrations/taskSchemaMigrations.test.d.ts +0 -1
  271. package/dist/migrations/taskSchemaMigrations.test.js +0 -225
  272. package/dist/qaOpen.test.d.ts +0 -1
  273. package/dist/qaOpen.test.js +0 -56
  274. package/dist/releaseVersion.test.d.ts +0 -1
  275. package/dist/releaseVersion.test.js +0 -32
  276. package/dist/runtime/appGates.test.d.ts +0 -1
  277. package/dist/runtime/appGates.test.js +0 -42
  278. package/dist/server/aiProfileAvatarAssets.test.d.ts +0 -1
  279. package/dist/server/aiProfileAvatarAssets.test.js +0 -213
  280. package/dist/server/annotatedAttachmentsRoutes.test.d.ts +0 -1
  281. package/dist/server/annotatedAttachmentsRoutes.test.js +0 -532
  282. package/dist/server/auth.test.d.ts +0 -1
  283. package/dist/server/auth.test.js +0 -131
  284. package/dist/server/buildInfo.test.d.ts +0 -1
  285. package/dist/server/buildInfo.test.js +0 -29
  286. package/dist/server/cors.test.d.ts +0 -1
  287. package/dist/server/cors.test.js +0 -77
  288. package/dist/server/documentReviewRoutes.test.d.ts +0 -1
  289. package/dist/server/documentReviewRoutes.test.js +0 -190
  290. package/dist/server/email.test.d.ts +0 -1
  291. package/dist/server/email.test.js +0 -113
  292. package/dist/server/index.cookieProxy.test.d.ts +0 -1
  293. package/dist/server/index.cookieProxy.test.js +0 -67
  294. package/dist/server/index.rateLimit.test.d.ts +0 -1
  295. package/dist/server/index.rateLimit.test.js +0 -22
  296. package/dist/server/index.test.d.ts +0 -1
  297. package/dist/server/index.test.js +0 -283
  298. package/dist/server/rateLimit.test.d.ts +0 -1
  299. package/dist/server/rateLimit.test.js +0 -107
  300. package/dist/server/realtimeSync.auth.test.d.ts +0 -1
  301. package/dist/server/realtimeSync.auth.test.js +0 -62
  302. package/dist/server/realtimeSync.replay.test.d.ts +0 -1
  303. package/dist/server/realtimeSync.replay.test.js +0 -192
  304. package/dist/server/realtimeSync.workspaceIsolation.test.d.ts +0 -1
  305. package/dist/server/realtimeSync.workspaceIsolation.test.js +0 -101
  306. package/dist/server/routes/billing.test.d.ts +0 -1
  307. package/dist/server/routes/billing.test.js +0 -3455
  308. package/dist/server/routes/shared.test.d.ts +0 -1
  309. package/dist/server/routes/shared.test.js +0 -32
  310. package/dist/server/routes/sync.integration.test.d.ts +0 -1
  311. package/dist/server/routes/sync.integration.test.js +0 -2932
  312. package/dist/server/routes/syncAuxRoutes.test.d.ts +0 -1
  313. package/dist/server/routes/syncAuxRoutes.test.js +0 -158
  314. package/dist/server/routes/syncRouteGuards.test.d.ts +0 -1
  315. package/dist/server/routes/syncRouteGuards.test.js +0 -94
  316. package/dist/server/routes.test.d.ts +0 -1
  317. package/dist/server/routes.test.js +0 -15612
  318. package/dist/server/runtimeMode.test.d.ts +0 -1
  319. package/dist/server/runtimeMode.test.js +0 -26
  320. package/dist/server/securityHeaders.test.d.ts +0 -1
  321. package/dist/server/securityHeaders.test.js +0 -70
  322. package/dist/services/templateEngine.test.d.ts +0 -1
  323. package/dist/services/templateEngine.test.js +0 -150
  324. package/dist/services/templates.test.d.ts +0 -1
  325. package/dist/services/templates.test.js +0 -45
  326. package/dist/services/workflowDocumentFixtures.test.d.ts +0 -1
  327. package/dist/services/workflowDocumentFixtures.test.js +0 -78
  328. package/dist/services/workflowExportMatrix.test.d.ts +0 -1
  329. package/dist/services/workflowExportMatrix.test.js +0 -113
  330. package/dist/services/workflowExportSnapshots.test.d.ts +0 -1
  331. package/dist/services/workflowExportSnapshots.test.js +0 -30
  332. package/dist/services/workflowGeneration.test.d.ts +0 -1
  333. package/dist/services/workflowGeneration.test.js +0 -12
  334. package/dist/services/workflowSimulation.test.d.ts +0 -1
  335. package/dist/services/workflowSimulation.test.js +0 -113
  336. package/dist/services/workflowV2Policy.test.d.ts +0 -1
  337. package/dist/services/workflowV2Policy.test.js +0 -80
  338. package/dist/shared/customTaxonomyLibrary.test.d.ts +0 -1
  339. package/dist/shared/customTaxonomyLibrary.test.js +0 -20
  340. package/dist/shared/passwordPolicy.test.d.ts +0 -1
  341. package/dist/shared/passwordPolicy.test.js +0 -34
  342. package/dist/shared/runtimeContract.test.d.ts +0 -1
  343. package/dist/shared/runtimeContract.test.js +0 -23
  344. package/dist/shared/taxonomyLibrary.test.d.ts +0 -1
  345. package/dist/shared/taxonomyLibrary.test.js +0 -26
  346. package/dist/shared/taxonomyState.test.d.ts +0 -1
  347. package/dist/shared/taxonomyState.test.js +0 -71
  348. package/dist/soak/preflight.cli.d.ts +0 -1
  349. package/dist/soak/preflight.cli.js +0 -28
  350. package/dist/soak/preflight.d.ts +0 -26
  351. package/dist/soak/preflight.js +0 -113
  352. package/dist/soak/preflight.test.d.ts +0 -1
  353. package/dist/soak/preflight.test.js +0 -39
  354. package/dist/storage/objectStorageClient.test.d.ts +0 -1
  355. package/dist/storage/objectStorageClient.test.js +0 -82
  356. package/dist/storage/objectStorageConfig.test.d.ts +0 -1
  357. package/dist/storage/objectStorageConfig.test.js +0 -50
  358. package/dist/storage/postgresAdapter.test.d.ts +0 -1
  359. package/dist/storage/postgresAdapter.test.js +0 -29
  360. package/dist/storage/workspaceAssetStore.test.d.ts +0 -1
  361. package/dist/storage/workspaceAssetStore.test.js +0 -588
  362. package/dist/sync/cloudSyncApi.test.d.ts +0 -1
  363. package/dist/sync/cloudSyncApi.test.js +0 -111
  364. package/dist/sync/collaborationSyncPayload.test.d.ts +0 -1
  365. package/dist/sync/collaborationSyncPayload.test.js +0 -125
  366. package/dist/sync/contentSyncPayload.test.d.ts +0 -1
  367. package/dist/sync/contentSyncPayload.test.js +0 -143
  368. package/dist/sync/encryptionService.test.d.ts +0 -1
  369. package/dist/sync/encryptionService.test.js +0 -52
  370. package/dist/sync/planningSyncPayload.test.d.ts +0 -1
  371. package/dist/sync/planningSyncPayload.test.js +0 -92
  372. package/dist/sync/realtimeFeature.test.d.ts +0 -1
  373. package/dist/sync/realtimeFeature.test.js +0 -30
  374. package/dist/sync/realtimeReconcile.test.d.ts +0 -1
  375. package/dist/sync/realtimeReconcile.test.js +0 -43
  376. package/dist/sync/syncApplyHandlers.test.d.ts +0 -1
  377. package/dist/sync/syncApplyHandlers.test.js +0 -626
  378. package/dist/sync/syncService.test.d.ts +0 -1
  379. package/dist/sync/syncService.test.js +0 -903
  380. package/dist/sync/taskSyncPayload.test.d.ts +0 -1
  381. package/dist/sync/taskSyncPayload.test.js +0 -54
  382. package/dist/sync/workspacePullFeed.test.d.ts +0 -1
  383. package/dist/sync/workspacePullFeed.test.js +0 -438
  384. package/dist/sync/workspaceSyncModel.test.d.ts +0 -1
  385. package/dist/sync/workspaceSyncModel.test.js +0 -1442
  386. package/dist/test/setup.d.ts +0 -1
  387. package/dist/test/setup.js +0 -15
  388. package/dist/ui/assets/AgentsModule-BS4Pi_nC.js +0 -1
  389. package/dist/ui/assets/ContextAttachmentManager-CfG_ER7C.js +0 -3
  390. package/dist/ui/assets/PlansPage-B_z-D6Nh.css +0 -1
  391. package/dist/ui/assets/PlansPage-Ndt7mYfo.js +0 -1
  392. package/dist/ui/assets/documentReferences-BOUcJm6-.js +0 -1
  393. package/dist/ui/assets/index-MAHKvFqp.js +0 -4
  394. package/dist/utils/accountProfileSummaryCache.test.d.ts +0 -1
  395. package/dist/utils/accountProfileSummaryCache.test.js +0 -63
  396. package/dist/utils/annotatedAttachments.test.d.ts +0 -1
  397. package/dist/utils/annotatedAttachments.test.js +0 -108
  398. package/dist/utils/assignees.test.d.ts +0 -1
  399. package/dist/utils/assignees.test.js +0 -25
  400. package/dist/utils/avatarUpload.test.d.ts +0 -1
  401. package/dist/utils/avatarUpload.test.js +0 -40
  402. package/dist/utils/canonicalAssetKind.test.d.ts +0 -1
  403. package/dist/utils/canonicalAssetKind.test.js +0 -24
  404. package/dist/utils/coalescedRefresh.test.d.ts +0 -1
  405. package/dist/utils/coalescedRefresh.test.js +0 -30
  406. package/dist/utils/constants.icons.test.d.ts +0 -1
  407. package/dist/utils/constants.icons.test.js +0 -41
  408. package/dist/utils/planParser.test.d.ts +0 -1
  409. package/dist/utils/planParser.test.js +0 -183
  410. package/dist/utils/planningReferences.test.d.ts +0 -1
  411. package/dist/utils/planningReferences.test.js +0 -17
  412. package/dist/utils/syncEventDetails.test.d.ts +0 -1
  413. package/dist/utils/syncEventDetails.test.js +0 -23
  414. package/dist/utils/syncEventPresentation.test.d.ts +0 -1
  415. package/dist/utils/syncEventPresentation.test.js +0 -64
  416. package/dist/utils/syncStatusPresentation.test.d.ts +0 -1
  417. package/dist/utils/syncStatusPresentation.test.js +0 -164
  418. package/dist/utils/taskActivity.test.d.ts +0 -1
  419. package/dist/utils/taskActivity.test.js +0 -218
  420. package/dist/utils/taskDraftDefaults.test.d.ts +0 -1
  421. package/dist/utils/taskDraftDefaults.test.js +0 -34
  422. package/dist/utils/taskDragZones.test.d.ts +0 -1
  423. package/dist/utils/taskDragZones.test.js +0 -14
  424. package/dist/utils/taskNormalization.test.d.ts +0 -1
  425. package/dist/utils/taskNormalization.test.js +0 -158
  426. package/dist/utils/taskSearch.test.d.ts +0 -1
  427. package/dist/utils/taskSearch.test.js +0 -69
  428. package/dist/utils/taskUtils.test.d.ts +0 -1
  429. package/dist/utils/taskUtils.test.js +0 -19
  430. package/dist/utils/taskforceApiClient.test.d.ts +0 -1
  431. package/dist/utils/taskforceApiClient.test.js +0 -44
  432. package/dist/utils/taxonomyFormDefaults.test.d.ts +0 -1
  433. package/dist/utils/taxonomyFormDefaults.test.js +0 -63
  434. package/dist/utils/uiNotice.test.d.ts +0 -1
  435. package/dist/utils/uiNotice.test.js +0 -18
  436. package/dist/utils/workspaceIdentity.test.d.ts +0 -1
  437. package/dist/utils/workspaceIdentity.test.js +0 -61
  438. package/dist/utils/workspaceLifecycle.test.d.ts +0 -1
  439. package/dist/utils/workspaceLifecycle.test.js +0 -64
  440. package/dist/utils/workspaceSyncPresentation.test.d.ts +0 -1
  441. package/dist/utils/workspaceSyncPresentation.test.js +0 -71
  442. package/scripts/bootstrap-playwright-auth.mjs +0 -155
  443. package/scripts/check-cloud-mcp.mjs +0 -83
  444. package/scripts/check-compat-boundaries.mjs +0 -41
  445. package/scripts/check-env.ts +0 -31
  446. package/scripts/check-localization-strings.mjs +0 -49
  447. package/scripts/check-runtime-boundaries.mjs +0 -44
  448. package/scripts/debug-global.mjs +0 -34
  449. package/scripts/debug-login.mjs +0 -32
  450. package/scripts/debug-server.mjs +0 -36
  451. package/scripts/deploy-prod.sh +0 -41
  452. package/scripts/deploy-staging.sh +0 -23
  453. package/scripts/export-sqlite-to-postgres.mjs +0 -123
  454. package/scripts/generate-env-example.ts +0 -8
  455. package/scripts/mcp-stdio-adapter.mjs +0 -160
  456. package/scripts/migrate-task-data-assets.mjs +0 -408
  457. package/scripts/playwright-auth.sh +0 -19
  458. package/scripts/qa-open-lib.mjs +0 -175
  459. package/scripts/qa-open-lib.mjs.d.ts +0 -49
  460. package/scripts/qa-open.mjs +0 -352
  461. package/scripts/release-version-lib.mjs +0 -88
  462. package/scripts/release-version.mjs +0 -72
  463. package/scripts/run-billing-performance-smoke.sh +0 -24
  464. package/scripts/run-dev-proxy.sh +0 -51
  465. package/scripts/run-e2e-realtime.sh +0 -30
  466. package/scripts/run-smoke.sh +0 -35
  467. package/scripts/run-soak.sh +0 -41
  468. package/scripts/test-global.js +0 -143
  469. package/scripts/update-homebrew-formula.sh +0 -108
  470. package/scripts/with-esbuild.sh +0 -11
@@ -265,6 +265,19 @@ export class PlanEntitlementService {
265
265
  }
266
266
  return config && typeof config === 'object' ? { ...config } : {};
267
267
  }
268
+ hydratePlanFeatureConfig(featureKey, access, config) {
269
+ const normalizedFeatureKey = this.canonicalizePlanFeatureKey(featureKey);
270
+ const sanitizedConfig = this.sanitizePlanFeatureConfig(normalizedFeatureKey, access, config);
271
+ if (Object.keys(sanitizedConfig).length > 0)
272
+ return sanitizedConfig;
273
+ const catalogFeature = DEFAULT_PLAN_FEATURE_CATALOG.find((feature) => feature.featureKey === normalizedFeatureKey);
274
+ const template = catalogFeature?.configTemplate && typeof catalogFeature.configTemplate === 'object'
275
+ ? catalogFeature.configTemplate
276
+ : {};
277
+ if (Object.keys(template).length === 0)
278
+ return {};
279
+ return this.sanitizePlanFeatureConfig(normalizedFeatureKey, access, template);
280
+ }
268
281
  isEntitlementStateAllowed(state) {
269
282
  return state === 'active' || state === 'trialing' || state === 'grace';
270
283
  }
@@ -401,6 +414,7 @@ export class PlanEntitlementService {
401
414
  this.migrateLegacySeatLimitFeatureConfigToVersionSeatLimit();
402
415
  this.normalizeLegacyBillingMirrorRows();
403
416
  this.renameLegacyWorkspacesFeatureKey();
417
+ this.hydrateMissingPlanFeatureTemplateConfigs();
404
418
  this.removeLegacyPlanFeatureRows();
405
419
  }
406
420
  renameLegacyWorkspacesFeatureKey() {
@@ -453,6 +467,43 @@ export class PlanEntitlementService {
453
467
  AND feature_key IN (${placeholders})
454
468
  `).run(this.tenantId, ...featureKeys);
455
469
  }
470
+ hydrateMissingPlanFeatureTemplateConfigs() {
471
+ const rows = this.db.prepare(`
472
+ SELECT plan_version_id, feature_key, access, config_json
473
+ FROM plan_feature_matrix
474
+ WHERE tenant_id = ?
475
+ `).all(this.tenantId);
476
+ if (rows.length < 1)
477
+ return;
478
+ const now = new Date().toISOString();
479
+ const updates = [];
480
+ for (const row of rows) {
481
+ const planVersionId = String(row.plan_version_id || '').trim();
482
+ const featureKey = this.canonicalizePlanFeatureKey(row.feature_key);
483
+ if (!planVersionId || !featureKey)
484
+ continue;
485
+ const access = this.normalizeFeatureAccess(row.access);
486
+ const currentConfig = this.parseJsonObject(row.config_json || '{}');
487
+ const hydratedConfig = this.hydratePlanFeatureConfig(featureKey, access, currentConfig);
488
+ const currentConfigJson = JSON.stringify(currentConfig);
489
+ const hydratedConfigJson = JSON.stringify(hydratedConfig);
490
+ if (currentConfigJson === hydratedConfigJson)
491
+ continue;
492
+ updates.push({ planVersionId, featureKey, configJson: hydratedConfigJson });
493
+ }
494
+ if (updates.length < 1)
495
+ return;
496
+ const tx = this.db.transaction(() => {
497
+ for (const update of updates) {
498
+ this.db.prepare(`
499
+ UPDATE plan_feature_matrix
500
+ SET config_json = ?, updated_at = ?
501
+ WHERE tenant_id = ? AND plan_version_id = ? AND feature_key = ?
502
+ `).run(update.configJson, now, this.tenantId, update.planVersionId, update.featureKey);
503
+ }
504
+ });
505
+ tx();
506
+ }
456
507
  migrateLegacySeatLimitFeatureConfigToVersionSeatLimit() {
457
508
  const rows = this.db.prepare(`
458
509
  SELECT pfm.plan_version_id, pfm.config_json, pv.seat_limit
@@ -1281,10 +1332,11 @@ export class PlanEntitlementService {
1281
1332
  const featureKey = String(featureRow.feature_key || '').trim();
1282
1333
  if (!featureKey)
1283
1334
  continue;
1335
+ const access = this.normalizeFeatureAccess(featureRow.access);
1284
1336
  features[featureKey] = {
1285
1337
  featureKey,
1286
- access: this.normalizeFeatureAccess(featureRow.access),
1287
- config: this.parseJsonObject(featureRow.config_json || '{}')
1338
+ access,
1339
+ config: this.hydratePlanFeatureConfig(featureKey, access, this.parseJsonObject(featureRow.config_json || '{}'))
1288
1340
  };
1289
1341
  }
1290
1342
  const metadata = this.parseJsonObject(row.metadata_json || '{}');
@@ -1945,10 +1997,11 @@ export class PlanEntitlementService {
1945
1997
  if (key === WORKSPACES_FEATURE_KEY && originalKey === LEGACY_WORKSPACES_FEATURE_KEY && features[key]) {
1946
1998
  continue;
1947
1999
  }
2000
+ const access = this.normalizeFeatureAccess(featureRow.access);
1948
2001
  features[key] = {
1949
2002
  featureKey: key,
1950
- access: this.normalizeFeatureAccess(featureRow.access),
1951
- config: this.parseJsonObject(featureRow.config_json || '{}')
2003
+ access,
2004
+ config: this.hydratePlanFeatureConfig(key, access, this.parseJsonObject(featureRow.config_json || '{}'))
1952
2005
  };
1953
2006
  }
1954
2007
  const metadata = this.parseJsonObject(row.metadata_json || '{}');
@@ -55,7 +55,7 @@ export function useFilterSort({ tasks, archivedTasks, activeCategories, activeTy
55
55
  setSortOrder(prev => prev === 'asc' ? 'desc' : 'asc');
56
56
  }, []);
57
57
  // === SECTION: View State ===
58
- const [groupBy, setGroupBy] = useState('category');
58
+ const [groupBy, setGroupBy] = useState('status');
59
59
  const [emptyColumnMode, setEmptyColumnMode] = useState('show');
60
60
  const [collapsedCategories, setCollapsedCategories] = useState({});
61
61
  const isAllFilterValuesSelected = useCallback((selected, available) => {
@@ -2291,7 +2291,7 @@ export function useTaskforce({ config = {}, initialTaskId, onTaskCountChange, on
2291
2291
  };
2292
2292
  }
2293
2293
  }
2294
- const entry = await resolvePostAuthCloudEntry();
2294
+ const entry = await resolvePostAuthCloudEntry({ preferredWorkspaceId });
2295
2295
  if (!entry.success) {
2296
2296
  return { success: false, error: entry.error || 'Unable to resolve workspace after invite acceptance.', code: entry.code };
2297
2297
  }
@@ -2335,7 +2335,7 @@ export function useTaskforce({ config = {}, initialTaskId, onTaskCountChange, on
2335
2335
  };
2336
2336
  }
2337
2337
  }
2338
- const entry = await resolvePostAuthCloudEntry();
2338
+ const entry = await resolvePostAuthCloudEntry({ preferredWorkspaceId });
2339
2339
  if (!entry.success) {
2340
2340
  return { success: false, error: entry.error || 'Unable to resolve workspace after invite join.', code: entry.code };
2341
2341
  }
@@ -497,12 +497,15 @@ export function useTaskforceWorkspaceBootstrap(args) {
497
497
  return { success: true, workspaceSetupRequired: true };
498
498
  }
499
499
  const ids = new Set(workspaces.map((workspace) => String(workspace.id || '').trim()).filter(Boolean));
500
- const selectedWorkspaceId = (preferredWorkspaceId && ids.has(preferredWorkspaceId) ? preferredWorkspaceId : '') || (persistedWorkspaceId && ids.has(persistedWorkspaceId) ? persistedWorkspaceId : '') || String(workspaces[0]?.id || '').trim();
500
+ const current = String(currentWorkspaceIdRef.current || '').trim();
501
+ const selectedWorkspaceId = (preferredWorkspaceId && ids.has(preferredWorkspaceId) ? preferredWorkspaceId : '')
502
+ || (current && ids.has(current) ? current : '')
503
+ || (persistedWorkspaceId && ids.has(persistedWorkspaceId) ? persistedWorkspaceId : '')
504
+ || String(workspaces[0]?.id || '').trim();
501
505
  if (!selectedWorkspaceId) {
502
506
  commitCurrentWorkspaceId('default');
503
507
  return { success: true, workspaceSetupRequired: true };
504
508
  }
505
- const current = String(currentWorkspaceIdRef.current || '').trim();
506
509
  if (current !== selectedWorkspaceId) {
507
510
  const switched = await switchWorkspace(selectedWorkspaceId, { hydrate: false });
508
511
  if (!switched.success)
@@ -92,7 +92,7 @@ export const enUS = {
92
92
  enterZenMode: 'Enter Zen Mode',
93
93
  toggleFilters: 'Toggle Filters',
94
94
  addTask: 'Add Task',
95
- helpTutorial: 'Help / Tutorial',
95
+ helpTutorial: 'Help & Support',
96
96
  settings: 'Settings',
97
97
  filtersCaps: 'FILTERS:',
98
98
  categoryLabel: 'Category',
@@ -92,7 +92,7 @@ export const es419 = {
92
92
  enterZenMode: 'Entrar en modo zen',
93
93
  toggleFilters: 'Alternar filtros',
94
94
  addTask: 'Agregar tarea',
95
- helpTutorial: 'Ayuda / Tutorial',
95
+ helpTutorial: 'Ayuda y soporte',
96
96
  settings: 'Configuracion',
97
97
  filtersCaps: 'FILTROS:',
98
98
  categoryLabel: 'Categoria',
@@ -92,7 +92,7 @@ export const ptBR = {
92
92
  enterZenMode: 'Entrar no modo zen',
93
93
  toggleFilters: 'Alternar filtros',
94
94
  addTask: 'Adicionar tarefa',
95
- helpTutorial: 'Ajuda / Tutorial',
95
+ helpTutorial: 'Ajuda e suporte',
96
96
  settings: 'Configuracoes',
97
97
  filtersCaps: 'FILTROS:',
98
98
  categoryLabel: 'Categoria',
@@ -69,25 +69,60 @@ function formatTaskIdentifier(task) {
69
69
  return id;
70
70
  return 'unknown task';
71
71
  }
72
+ const toolLogExcerptKeys = new Set(['description', 'text', 'content']);
73
+ const TOOL_LOG_REDACTED_VALUE = '[redacted]';
74
+ const TOOL_LOG_TRUNCATED_DEPTH_VALUE = '[truncated-depth]';
75
+ const TOOL_LOG_MAX_STRING_LENGTH = 160;
76
+ const TOOL_LOG_MAX_ARRAY_ITEMS = 8;
77
+ const toolLogSensitiveWordSet = new Set(['token', 'tokens', 'password', 'passwords', 'secret', 'secrets', 'authorization']);
78
+ function truncateToolLogString(value) {
79
+ return `${value.slice(0, TOOL_LOG_MAX_STRING_LENGTH)}${value.length > TOOL_LOG_MAX_STRING_LENGTH ? '…' : ''}`;
80
+ }
81
+ function shouldRedactToolLogKey(key) {
82
+ const words = String(key || '')
83
+ .replace(/([a-z0-9])([A-Z])/g, '$1 $2')
84
+ .split(/[^a-zA-Z0-9]+/)
85
+ .map((part) => part.trim().toLowerCase())
86
+ .filter(Boolean);
87
+ if (words.length === 0)
88
+ return false;
89
+ if (words.some((word) => toolLogSensitiveWordSet.has(word)))
90
+ return true;
91
+ const compact = words.join('');
92
+ return compact === 'apikey'
93
+ || compact === 'clientsecret'
94
+ || compact === 'bearertoken'
95
+ || compact === 'proxyauthorization';
96
+ }
72
97
  function sanitizeToolArgsForLog(args) {
73
- if (!args || typeof args !== 'object' || Array.isArray(args))
74
- return args;
75
- const input = args;
76
- const output = {};
77
- for (const [key, value] of Object.entries(input)) {
78
- if (key === 'description' || key === 'text' || key === 'content') {
79
- output[key] = typeof value === 'string'
80
- ? `${String(value).slice(0, 160)}${String(value).length > 160 ? '' : ''}`
98
+ const visit = (value, depth, key) => {
99
+ if (key && shouldRedactToolLogKey(key))
100
+ return TOOL_LOG_REDACTED_VALUE;
101
+ if (value === null || value === undefined)
102
+ return value;
103
+ if (depth > 6)
104
+ return TOOL_LOG_TRUNCATED_DEPTH_VALUE;
105
+ if (typeof value === 'string') {
106
+ return key && toolLogExcerptKeys.has(key)
107
+ ? truncateToolLogString(value)
81
108
  : value;
82
- continue;
83
109
  }
84
110
  if (Array.isArray(value)) {
85
- output[key] = value.length > 8 ? [...value.slice(0, 8), `…(${value.length - 8} more)`] : value;
86
- continue;
111
+ const items = value.slice(0, TOOL_LOG_MAX_ARRAY_ITEMS).map((item) => visit(item, depth + 1));
112
+ if (value.length > TOOL_LOG_MAX_ARRAY_ITEMS) {
113
+ items.push(`…(${value.length - TOOL_LOG_MAX_ARRAY_ITEMS} more)`);
114
+ }
115
+ return items;
87
116
  }
88
- output[key] = value;
89
- }
90
- return output;
117
+ if (typeof value !== 'object')
118
+ return value;
119
+ const output = {};
120
+ for (const [childKey, childValue] of Object.entries(value)) {
121
+ output[childKey] = visit(childValue, depth + 1, childKey);
122
+ }
123
+ return output;
124
+ };
125
+ return visit(args, 0);
91
126
  }
92
127
  function resolveRecoverableToolError(error) {
93
128
  const message = error instanceof Error ? String(error.message || '').trim() : '';
@@ -497,7 +497,6 @@ function resolvePlanVersionIdForPriceIdFallback(core, priceIdRaw) {
497
497
  FROM billing_price_mappings
498
498
  WHERE tenant_id = ?
499
499
  AND stripe_price_id = ?
500
- AND COALESCE(pricing_audience, 'public') = 'public'
501
500
  AND active = 1
502
501
  ORDER BY plan_version_id ASC
503
502
  `).all(tenantId, priceId);
@@ -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-BWFQ9mGn.js";import{a0 as Re,x as $e,h as Ee,B as ne,m as C,b as Le,$ as Be,a5 as Ge}from"./vendor-icons-CLnehDTw.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};
@@ -1,3 +1,3 @@
1
- import{j as t,r as s,R as ta}from"./vendor-react-CKJs5o3c.js";import{R as An,f as ge,e as $t,g as Mn,t as Da,M as aa}from"./index-MAHKvFqp.js";import{a4 as za,w as En,v as Ln,p as Fn,P as Hn,c as na,T as Ua,r as On,h as Ga,ak as Dn,R as zn,al as Un,am as Gn,an as Yn,ao as oa,C as ia,ap as Wn,aq as Ja,ar as Za,as as Qa,at as en,g as Kn,f as Xn,b as la}from"./vendor-icons-B32hGuF2.js";import"./vendor-markdown-BUxTU7dS.js";import"./vendor-dnd-DRzYolkg.js";import"./vendor-router-BbWMxlnO.js";function Vn({copied:r,disabled:l=!1,label:f,onClick:p,title:b="Copy image reference",ariaLabel:x,className:L=""}){return t.jsx(An,{copied:r,disabled:l,label:"",onClick:p,title:b,ariaLabel:x,className:L,children:f})}const qn="_shell_17mlo_1",Jn="_shellWithImageTray_17mlo_18",Zn="_shellImageTrayOpen_17mlo_22",Qn="_imageTrayPanel_17mlo_26",es="_imageTrayPanelOpen_17mlo_50",ts="_imageTrayHeader_17mlo_58",as="_imageTrayTitle_17mlo_73",ns="_imageTraySearch_17mlo_85",ss="_imageTraySearchIcon_17mlo_91",rs="_imageTraySearchInput_17mlo_100",os="_imageTrayList_17mlo_117",is="_imageTrayState_17mlo_129",ls="_imageTrayStateError_17mlo_130",cs="_imageTrayItem_17mlo_142",ds="_imageTrayItemActive_17mlo_164",us="_imageTrayThumb_17mlo_174",ms="_imageTrayItemBody_17mlo_191",fs="_imageTrayItemTitle_17mlo_199",hs="_imageTrayItemTask_17mlo_200",ps="_imageTrayItemMetaDetails_17mlo_201",gs="_imageTrayItemMeta_17mlo_201",ys="_imageTrayItemReference_17mlo_239",bs="_panel_17mlo_246",xs="_sessionPanel_17mlo_252",vs="_detailPanel_17mlo_253",_s="_sessionContextBar_17mlo_259",Is="_sessionContextLeft_17mlo_270",ks="_sessionContextRight_17mlo_271",ws="_sessionContextLabel_17mlo_286",Ss="_sessionContextSpacer_17mlo_292",Ns="_canvasPanel_17mlo_297",Cs="_canvasWorkspace_17mlo_304",js="_canvasMain_17mlo_311",Ts="_panelHeader_17mlo_318",$s="_panelHeaderText_17mlo_327",Rs="_panelTitle_17mlo_331",Ps="_canvasHeading_17mlo_335",Bs="_sessionActions_17mlo_339",As="_sessionList_17mlo_347",Ms="_annotationList_17mlo_348",Es="_markerHelpModalBody_17mlo_363",Ls="_openImageModalBody_17mlo_369",Fs="_openImageField_17mlo_375",Hs="_openImageActions_17mlo_379",Os="_markerHelpItem_17mlo_385",Ds="_markerHelpHeader_17mlo_393",zs="_markerHelpExample_17mlo_405",Us="_sessionCard_17mlo_409",Gs="_annotationCard_17mlo_410",Ys="_sessionEmptyState_17mlo_427",Ws="_sessionCardButton_17mlo_434",Ks="_annotationCardButton_17mlo_444",Xs="_sessionCardBody_17mlo_454",Vs="_sessionCardActive_17mlo_460",qs="_annotationCardActive_17mlo_461",Js="_annotationMeta_17mlo_471",Zs="_annotationInstructionPreview_17mlo_478",Qs="_annotationPreviewFooter_17mlo_486",er="_annotationInstructionEditor_17mlo_493",tr="_annotationTypeField_17mlo_499",ar="_annotationInstructionButton_17mlo_505",nr="_annotationInstructionField_17mlo_514",sr="_sessionMeta_17mlo_518",rr="_sessionTitle_17mlo_525",or="_annotationTitle_17mlo_526",ir="_sessionTimestamp_17mlo_532",lr="_annotationKind_17mlo_533",cr="_annotationInstructionTypeIcon_17mlo_537",dr="_sessionInstructionPreview_17mlo_543",ur="_sessionInstructionEditor_17mlo_551",mr="_sessionCardFooter_17mlo_557",fr="_toolRail_17mlo_564",hr="_canvasToolRail_17mlo_573",pr="_toolbarCluster_17mlo_594",gr="_toolbarViewportCluster_17mlo_601",yr="_toolbarSeparator_17mlo_605",br="_toolBtn_17mlo_611",xr="_toolRailButton_17mlo_615",vr="_toolbarButton_17mlo_625",_r="_toolBtnActive_17mlo_630",Ir="_toolbarActions_17mlo_637",kr="_toolbarSelectionActions_17mlo_646",wr="_toolbarColorPicker_17mlo_654",Sr="_colorPickerButton_17mlo_658",Nr="_colorPickerSwatch_17mlo_663",Cr="_colorPickerPopover_17mlo_671",jr="_colorOption_17mlo_686",Tr="_colorOptionActive_17mlo_696",$r="_toolbarUtilities_17mlo_703",Rr="_toolbarGeometryFields_17mlo_711",Pr="_toolbarGeometryField_17mlo_711",Br="_toolbarGeometryLabel_17mlo_724",Ar="_toolbarGeometryInput_17mlo_730",Mr="_iconButton_17mlo_735",Er="_ghostBtn_17mlo_740",Lr="_payloadBtn_17mlo_741",Fr="_backToTaskBtn_17mlo_742",Hr="_canvasScroller_17mlo_762",Or="_canvasFrame_17mlo_778",Dr="_canvasMedia_17mlo_785",zr="_canvasStatusOverlay_17mlo_793",Ur="_canvasStatusCard_17mlo_805",Gr="_canvasImage_17mlo_818",Yr="_overlay_17mlo_825",Wr="_overlaySelect_17mlo_831",Kr="_overlayPan_17mlo_835",Xr="_overlaySvg_17mlo_839",Vr="_overlayHitLayer_17mlo_848",qr="_arrowHitArea_17mlo_857",Jr="_canvasHandleHit_17mlo_864",Zr="_canvasResizeHandleHit_17mlo_871",Qr="_canvasHandleVisible_17mlo_875",eo="_pin_17mlo_892",to="_note_17mlo_893",ao="_annotationNumberBadge_17mlo_910",no="_box_17mlo_935",so="_boxNumberBadge_17mlo_944",ro="_arrowNumberBadge_17mlo_950",oo="_boxSurface_17mlo_954",io="_selected_17mlo_967",lo="_textInput_17mlo_984",co="_textArea_17mlo_985",uo="_select_17mlo_967",mo="_sessionTitleInput_17mlo_992",fo="_sessionInstructionField_17mlo_997",ho="_detailEmpty_17mlo_1006",po="_emptyState_17mlo_1007",go="_payloadModalBody_17mlo_1019",yo="_payloadModalToolbar_17mlo_1026",bo="_payloadViewToggle_17mlo_1033",xo="_payloadModalActions_17mlo_1034",vo="_payloadModalPreview_17mlo_1041",_o="_statusBar_17mlo_1056",Io="_annotationSummary_17mlo_1068",a={shell:qn,shellWithImageTray:Jn,shellImageTrayOpen:Zn,imageTrayPanel:Qn,imageTrayPanelOpen:es,imageTrayHeader:ts,imageTrayTitle:as,imageTraySearch:ns,imageTraySearchIcon:ss,imageTraySearchInput:rs,imageTrayList:os,imageTrayState:is,imageTrayStateError:ls,imageTrayItem:cs,imageTrayItemActive:ds,imageTrayThumb:us,imageTrayItemBody:ms,imageTrayItemTitle:fs,imageTrayItemTask:hs,imageTrayItemMetaDetails:ps,imageTrayItemMeta:gs,imageTrayItemReference:ys,panel:bs,sessionPanel:xs,detailPanel:vs,sessionContextBar:_s,sessionContextLeft:Is,sessionContextRight:ks,sessionContextLabel:ws,sessionContextSpacer:Ss,canvasPanel:Ns,canvasWorkspace:Cs,canvasMain:js,panelHeader:Ts,panelHeaderText:$s,panelTitle:Rs,canvasHeading:Ps,sessionActions:Bs,sessionList:As,annotationList:Ms,markerHelpModalBody:Es,openImageModalBody:Ls,openImageField:Fs,openImageActions:Hs,markerHelpItem:Os,markerHelpHeader:Ds,markerHelpExample:zs,sessionCard:Us,annotationCard:Gs,sessionEmptyState:Ys,sessionCardButton:Ws,annotationCardButton:Ks,sessionCardBody:Xs,sessionCardActive:Vs,annotationCardActive:qs,annotationMeta:Js,annotationInstructionPreview:Zs,annotationPreviewFooter:Qs,annotationInstructionEditor:er,annotationTypeField:tr,annotationInstructionButton:ar,annotationInstructionField:nr,sessionMeta:sr,sessionTitle:rr,annotationTitle:or,sessionTimestamp:ir,annotationKind:lr,annotationInstructionTypeIcon:cr,sessionInstructionPreview:dr,sessionInstructionEditor:ur,sessionCardFooter:mr,toolRail:fr,canvasToolRail:hr,toolbarCluster:pr,toolbarViewportCluster:gr,toolbarSeparator:yr,toolBtn:br,toolRailButton:xr,toolbarButton:vr,toolBtnActive:_r,toolbarActions:Ir,toolbarSelectionActions:kr,toolbarColorPicker:wr,colorPickerButton:Sr,colorPickerSwatch:Nr,colorPickerPopover:Cr,colorOption:jr,colorOptionActive:Tr,toolbarUtilities:$r,toolbarGeometryFields:Rr,toolbarGeometryField:Pr,toolbarGeometryLabel:Br,toolbarGeometryInput:Ar,iconButton:Mr,ghostBtn:Er,payloadBtn:Lr,backToTaskBtn:Fr,canvasScroller:Hr,canvasFrame:Or,canvasMedia:Dr,canvasStatusOverlay:zr,canvasStatusCard:Ur,canvasImage:Gr,overlay:Yr,overlaySelect:Wr,overlayPan:Kr,overlaySvg:Xr,overlayHitLayer:Vr,arrowHitArea:qr,canvasHandleHit:Jr,canvasResizeHandleHit:Zr,canvasHandleVisible:Qr,pin:eo,note:to,annotationNumberBadge:ao,box:no,boxNumberBadge:so,arrowNumberBadge:ro,boxSurface:oo,selected:io,textInput:lo,textArea:co,select:uo,sessionTitleInput:mo,sessionInstructionField:fo,detailEmpty:ho,emptyState:po,payloadModalBody:go,payloadModalToolbar:yo,payloadViewToggle:bo,payloadModalActions:xo,payloadModalPreview:vo,statusBar:_o,annotationSummary:Io},Ya=[{value:"review",label:"Review"},{value:"change",label:"Change"},{value:"question",label:"Question"}],Wa=[{value:"select",label:"Select",icon:Wn},{value:"pin",label:"Pin",icon:Ja},{value:"box",label:"Box",icon:Za},{value:"arrow",label:"Arrow",icon:Qa},{value:"text-note",label:"Note",icon:en}],ko={pin:Ja,box:Za,arrow:Qa,"text-note":en},wo={pin:"Pin",box:"Box",arrow:"Arrow","text-note":"Note"},So={review:oa,change:la,question:ia,issue:ia,idea:oa},Rt={select:{short:"Select and edit existing markers.",detail:"Use Select to click, drag, reorder, resize, and update markers that are already on the image.",example:"Example: move an existing marker after the screenshot changes."},pin:{short:"Mark a precise spot.",detail:"Use Pin when feedback points to one exact location instead of a broader area.",example:'Example: "This icon is misaligned by 2px."'},box:{short:"Mark an area or component.",detail:"Use Box when the feedback applies to a whole region, card, panel, or bounded UI block.",example:'Example: "This whole card needs tighter padding and a stronger border."'},arrow:{short:"Show direction or relationship.",detail:"Use Arrow when you need to show movement, attachment, flow, or source-to-target intent.",example:'Example: "This tooltip should anchor to this button, not the panel."'},"text-note":{short:"Add a comment-style point marker.",detail:"Use Note when you want a point marker that reads more like a comment or open question.",example:'Example: "Ask design whether this badge should stay."'}},lt={question:"#0f766e",change:"#2563eb",issue:"#dc2626",idea:"#d97706",review:"#7c3aed"},No=["#7c3aed","#2563eb","#0f766e","#dc2626","#d97706","#111827"],ce="review";function Ye(r){const l=String(r.displayName||"").trim();return l?`${l} review`:"Annotated session"}function tn(){return`annotation-${Math.random().toString(36).slice(2,10)}`}function I(r){return!Number.isFinite(r)||r<=0?0:r>=1?1:r}function Ne(r){return I(Math.max(.02,r))}function Ge(r){return r?[String(r.taskId||"").trim(),String(r.assetId||"").trim(),String(r.path||"").trim()].join("::"):""}function Co(r){if(!(r instanceof HTMLElement))return!1;const l=r.tagName.toLowerCase();return r.isContentEditable?!0:l==="input"||l==="textarea"||l==="select"}function Se(r){return r.map((l,f)=>({...l,order:f}))}function sa(r){if(!r)return"Unsaved";const l=new Date(r);return Number.isNaN(l.getTime())?"Unsaved":l.toLocaleString()}function jo(r){const l=typeof r=="number"&&Number.isFinite(r)?Math.max(0,r):0;return l<1024?`${l}B`:l<1024*1024?`${(l/1024).toFixed(1)}KB`:`${(l/(1024*1024)).toFixed(1)}MB`}function To(r){if(!r)return"";const l=new Date(r);if(Number.isNaN(l.getTime()))return"";const p=new Date().getTime()-l.getTime(),b=Math.floor(p/(1e3*60*60*24));return b<=0?"Today":b===1?"Yesterday":b<7?`${b}d ago`:b<30?`${Math.floor(b/7)}w ago`:l.toLocaleDateString()}function Pt(r){const l=String(r.createdByActor?.label||"").trim();return l||null}function $o(r){const l=String(r||"").trim().replace(/\s+/g," ");return l?l.length>110?`${l.slice(0,107)}...`:l:""}function Ka(r,l,f,p=lt[ce]){const b={id:tn(),order:0,instruction:"",markerType:ce,color:p};if(r==="pin")return{...b,kind:r,x:l.x,y:l.y};if(r==="text-note")return{...b,kind:r,x:l.x,y:l.y};if(r==="box"){const L=f||l;return{...b,kind:r,x:I(Math.min(l.x,L.x)),y:I(Math.min(l.y,L.y)),width:Ne(Math.abs(L.x-l.x)),height:Ne(Math.abs(L.y-l.y))}}const x=f||l;return{...b,kind:"arrow",x:l.x,y:l.y,x2:x.x,y2:x.y}}function ra(r){return r.color?r.color:lt[r.markerType||ce]}function Ro(r,l){const f=Math.max(l.width,1),p=Math.max(l.height,1),b=r.x*f,x=r.y*p,L=r.x2*f,ne=r.y2*p,se=L-b,ct=ne-x,Ce=Math.hypot(se,ct)||1,We=se/Ce,je=ct/Ce,G=Math.max(10,Math.min(16,Ce-2)),ye=G*.62,Te=L-We*G,$=ne-je*G,dt=-je,be=We;return{shaftX1:b,shaftY1:x,shaftX2:Te,shaftY2:$,headPoints:[`${L},${ne}`,`${Te+dt*ye},${$+be*ye}`,`${Te-dt*ye},${$-be*ye}`].join(" ")}}function Po(r,l){return{...r,markerType:l,color:r.color||lt[l]}}function Bo(r,l){return{...r,id:tn(),order:l}}function Ao(r,l){const f=String(r||"").trim()||(l?Ye(l):"Annotated session");return/\bcopy$/i.test(f)?`${f} 2`:`${f} copy`}function Mo(r,l,f){if(l===f||l<0||f<0||l>=r.length||f>=r.length)return r;const p=[...r],[b]=p.splice(l,1);return b?(p.splice(f,0,b),Se(p)):r}function ae(r){return String(Math.round(I(r)*1e3)/10)}function Eo(r){const l=Number.parseFloat(r);return Number.isFinite(l)?I(l/100):null}function Lo(r,l,f){return r.kind==="pin"||r.kind==="text-note"?l==="x"||l==="y"?{...r,[l]:I(f)}:r:r.kind==="box"?l==="x"||l==="y"?{...r,[l]:I(f)}:l==="width"||l==="height"?{...r,[l]:Ne(f)}:r:l==="x"||l==="y"||l==="x2"||l==="y2"?{...r,[l]:I(f)}:r}function Fo(r){return r.kind==="pin"||r.kind==="text-note"?[{key:"x",label:"X",value:ae(r.x)},{key:"y",label:"Y",value:ae(r.y)}]:r.kind==="box"?[{key:"x",label:"X",value:ae(r.x)},{key:"y",label:"Y",value:ae(r.y)},{key:"width",label:"Width",value:ae(r.width)},{key:"height",label:"Height",value:ae(r.height)}]:[{key:"x",label:"Start X",value:ae(r.x)},{key:"y",label:"Start Y",value:ae(r.y)},{key:"x2",label:"End X",value:ae(r.x2)},{key:"y2",label:"End Y",value:ae(r.y2)}]}function Ho(r){if(!r)return null;const l=Math.round(r.x*100),f=Math.round(r.y*100),p=Math.round(r.width*100),b=Math.round(r.height*100);return`crop ${l}%, ${f}% size ${p}% x ${b}%`}function Oo(r){return Number.isFinite(r)?Math.min(4,Math.max(.25,Number(r.toFixed(2)))):1}function Xa(r){const l=[`Annotated attachment: ${r.title||r.image.displayName}`,`Image: ${r.image.displayName}`,`Image Reference: ${r.image.referenceLabel||r.image.assetId}`,`Task ID: ${r.taskId}`,r.globalInstruction?`Global instruction: ${r.globalInstruction}`:"Global instruction: None provided.","Markers:"];return r.annotations.length===0?(l.push("0. No markers."),l.join(`
1
+ import{j as t,r as s,R as ta}from"./vendor-react-CKJs5o3c.js";import{R as An,f as ge,e as $t,g as Mn,t as Da,M as aa}from"./index-BWFQ9mGn.js";import{a7 as za,x as En,w as Ln,p as Fn,P as Hn,c as na,T as Ua,r as On,h as Ga,an as Dn,R as zn,ao as Un,ap as Gn,aq as Yn,ar as oa,C as ia,as as Wn,at as Ja,au as Za,av as Qa,aw as en,g as Kn,f as Xn,b as la}from"./vendor-icons-CLnehDTw.js";import"./vendor-markdown-BUxTU7dS.js";import"./vendor-dnd-DRzYolkg.js";import"./vendor-router-BbWMxlnO.js";function Vn({copied:r,disabled:l=!1,label:f,onClick:p,title:b="Copy image reference",ariaLabel:x,className:L=""}){return t.jsx(An,{copied:r,disabled:l,label:"",onClick:p,title:b,ariaLabel:x,className:L,children:f})}const qn="_shell_17mlo_1",Jn="_shellWithImageTray_17mlo_18",Zn="_shellImageTrayOpen_17mlo_22",Qn="_imageTrayPanel_17mlo_26",es="_imageTrayPanelOpen_17mlo_50",ts="_imageTrayHeader_17mlo_58",as="_imageTrayTitle_17mlo_73",ns="_imageTraySearch_17mlo_85",ss="_imageTraySearchIcon_17mlo_91",rs="_imageTraySearchInput_17mlo_100",os="_imageTrayList_17mlo_117",is="_imageTrayState_17mlo_129",ls="_imageTrayStateError_17mlo_130",cs="_imageTrayItem_17mlo_142",ds="_imageTrayItemActive_17mlo_164",us="_imageTrayThumb_17mlo_174",ms="_imageTrayItemBody_17mlo_191",fs="_imageTrayItemTitle_17mlo_199",hs="_imageTrayItemTask_17mlo_200",ps="_imageTrayItemMetaDetails_17mlo_201",gs="_imageTrayItemMeta_17mlo_201",ys="_imageTrayItemReference_17mlo_239",bs="_panel_17mlo_246",xs="_sessionPanel_17mlo_252",vs="_detailPanel_17mlo_253",_s="_sessionContextBar_17mlo_259",Is="_sessionContextLeft_17mlo_270",ks="_sessionContextRight_17mlo_271",ws="_sessionContextLabel_17mlo_286",Ss="_sessionContextSpacer_17mlo_292",Ns="_canvasPanel_17mlo_297",Cs="_canvasWorkspace_17mlo_304",js="_canvasMain_17mlo_311",Ts="_panelHeader_17mlo_318",$s="_panelHeaderText_17mlo_327",Rs="_panelTitle_17mlo_331",Ps="_canvasHeading_17mlo_335",Bs="_sessionActions_17mlo_339",As="_sessionList_17mlo_347",Ms="_annotationList_17mlo_348",Es="_markerHelpModalBody_17mlo_363",Ls="_openImageModalBody_17mlo_369",Fs="_openImageField_17mlo_375",Hs="_openImageActions_17mlo_379",Os="_markerHelpItem_17mlo_385",Ds="_markerHelpHeader_17mlo_393",zs="_markerHelpExample_17mlo_405",Us="_sessionCard_17mlo_409",Gs="_annotationCard_17mlo_410",Ys="_sessionEmptyState_17mlo_427",Ws="_sessionCardButton_17mlo_434",Ks="_annotationCardButton_17mlo_444",Xs="_sessionCardBody_17mlo_454",Vs="_sessionCardActive_17mlo_460",qs="_annotationCardActive_17mlo_461",Js="_annotationMeta_17mlo_471",Zs="_annotationInstructionPreview_17mlo_478",Qs="_annotationPreviewFooter_17mlo_486",er="_annotationInstructionEditor_17mlo_493",tr="_annotationTypeField_17mlo_499",ar="_annotationInstructionButton_17mlo_505",nr="_annotationInstructionField_17mlo_514",sr="_sessionMeta_17mlo_518",rr="_sessionTitle_17mlo_525",or="_annotationTitle_17mlo_526",ir="_sessionTimestamp_17mlo_532",lr="_annotationKind_17mlo_533",cr="_annotationInstructionTypeIcon_17mlo_537",dr="_sessionInstructionPreview_17mlo_543",ur="_sessionInstructionEditor_17mlo_551",mr="_sessionCardFooter_17mlo_557",fr="_toolRail_17mlo_564",hr="_canvasToolRail_17mlo_573",pr="_toolbarCluster_17mlo_594",gr="_toolbarViewportCluster_17mlo_601",yr="_toolbarSeparator_17mlo_605",br="_toolBtn_17mlo_611",xr="_toolRailButton_17mlo_615",vr="_toolbarButton_17mlo_625",_r="_toolBtnActive_17mlo_630",Ir="_toolbarActions_17mlo_637",kr="_toolbarSelectionActions_17mlo_646",wr="_toolbarColorPicker_17mlo_654",Sr="_colorPickerButton_17mlo_658",Nr="_colorPickerSwatch_17mlo_663",Cr="_colorPickerPopover_17mlo_671",jr="_colorOption_17mlo_686",Tr="_colorOptionActive_17mlo_696",$r="_toolbarUtilities_17mlo_703",Rr="_toolbarGeometryFields_17mlo_711",Pr="_toolbarGeometryField_17mlo_711",Br="_toolbarGeometryLabel_17mlo_724",Ar="_toolbarGeometryInput_17mlo_730",Mr="_iconButton_17mlo_735",Er="_ghostBtn_17mlo_740",Lr="_payloadBtn_17mlo_741",Fr="_backToTaskBtn_17mlo_742",Hr="_canvasScroller_17mlo_762",Or="_canvasFrame_17mlo_778",Dr="_canvasMedia_17mlo_785",zr="_canvasStatusOverlay_17mlo_793",Ur="_canvasStatusCard_17mlo_805",Gr="_canvasImage_17mlo_818",Yr="_overlay_17mlo_825",Wr="_overlaySelect_17mlo_831",Kr="_overlayPan_17mlo_835",Xr="_overlaySvg_17mlo_839",Vr="_overlayHitLayer_17mlo_848",qr="_arrowHitArea_17mlo_857",Jr="_canvasHandleHit_17mlo_864",Zr="_canvasResizeHandleHit_17mlo_871",Qr="_canvasHandleVisible_17mlo_875",eo="_pin_17mlo_892",to="_note_17mlo_893",ao="_annotationNumberBadge_17mlo_910",no="_box_17mlo_935",so="_boxNumberBadge_17mlo_944",ro="_arrowNumberBadge_17mlo_950",oo="_boxSurface_17mlo_954",io="_selected_17mlo_967",lo="_textInput_17mlo_984",co="_textArea_17mlo_985",uo="_select_17mlo_967",mo="_sessionTitleInput_17mlo_992",fo="_sessionInstructionField_17mlo_997",ho="_detailEmpty_17mlo_1006",po="_emptyState_17mlo_1007",go="_payloadModalBody_17mlo_1019",yo="_payloadModalToolbar_17mlo_1026",bo="_payloadViewToggle_17mlo_1033",xo="_payloadModalActions_17mlo_1034",vo="_payloadModalPreview_17mlo_1041",_o="_statusBar_17mlo_1056",Io="_annotationSummary_17mlo_1068",a={shell:qn,shellWithImageTray:Jn,shellImageTrayOpen:Zn,imageTrayPanel:Qn,imageTrayPanelOpen:es,imageTrayHeader:ts,imageTrayTitle:as,imageTraySearch:ns,imageTraySearchIcon:ss,imageTraySearchInput:rs,imageTrayList:os,imageTrayState:is,imageTrayStateError:ls,imageTrayItem:cs,imageTrayItemActive:ds,imageTrayThumb:us,imageTrayItemBody:ms,imageTrayItemTitle:fs,imageTrayItemTask:hs,imageTrayItemMetaDetails:ps,imageTrayItemMeta:gs,imageTrayItemReference:ys,panel:bs,sessionPanel:xs,detailPanel:vs,sessionContextBar:_s,sessionContextLeft:Is,sessionContextRight:ks,sessionContextLabel:ws,sessionContextSpacer:Ss,canvasPanel:Ns,canvasWorkspace:Cs,canvasMain:js,panelHeader:Ts,panelHeaderText:$s,panelTitle:Rs,canvasHeading:Ps,sessionActions:Bs,sessionList:As,annotationList:Ms,markerHelpModalBody:Es,openImageModalBody:Ls,openImageField:Fs,openImageActions:Hs,markerHelpItem:Os,markerHelpHeader:Ds,markerHelpExample:zs,sessionCard:Us,annotationCard:Gs,sessionEmptyState:Ys,sessionCardButton:Ws,annotationCardButton:Ks,sessionCardBody:Xs,sessionCardActive:Vs,annotationCardActive:qs,annotationMeta:Js,annotationInstructionPreview:Zs,annotationPreviewFooter:Qs,annotationInstructionEditor:er,annotationTypeField:tr,annotationInstructionButton:ar,annotationInstructionField:nr,sessionMeta:sr,sessionTitle:rr,annotationTitle:or,sessionTimestamp:ir,annotationKind:lr,annotationInstructionTypeIcon:cr,sessionInstructionPreview:dr,sessionInstructionEditor:ur,sessionCardFooter:mr,toolRail:fr,canvasToolRail:hr,toolbarCluster:pr,toolbarViewportCluster:gr,toolbarSeparator:yr,toolBtn:br,toolRailButton:xr,toolbarButton:vr,toolBtnActive:_r,toolbarActions:Ir,toolbarSelectionActions:kr,toolbarColorPicker:wr,colorPickerButton:Sr,colorPickerSwatch:Nr,colorPickerPopover:Cr,colorOption:jr,colorOptionActive:Tr,toolbarUtilities:$r,toolbarGeometryFields:Rr,toolbarGeometryField:Pr,toolbarGeometryLabel:Br,toolbarGeometryInput:Ar,iconButton:Mr,ghostBtn:Er,payloadBtn:Lr,backToTaskBtn:Fr,canvasScroller:Hr,canvasFrame:Or,canvasMedia:Dr,canvasStatusOverlay:zr,canvasStatusCard:Ur,canvasImage:Gr,overlay:Yr,overlaySelect:Wr,overlayPan:Kr,overlaySvg:Xr,overlayHitLayer:Vr,arrowHitArea:qr,canvasHandleHit:Jr,canvasResizeHandleHit:Zr,canvasHandleVisible:Qr,pin:eo,note:to,annotationNumberBadge:ao,box:no,boxNumberBadge:so,arrowNumberBadge:ro,boxSurface:oo,selected:io,textInput:lo,textArea:co,select:uo,sessionTitleInput:mo,sessionInstructionField:fo,detailEmpty:ho,emptyState:po,payloadModalBody:go,payloadModalToolbar:yo,payloadViewToggle:bo,payloadModalActions:xo,payloadModalPreview:vo,statusBar:_o,annotationSummary:Io},Ya=[{value:"review",label:"Review"},{value:"change",label:"Change"},{value:"question",label:"Question"}],Wa=[{value:"select",label:"Select",icon:Wn},{value:"pin",label:"Pin",icon:Ja},{value:"box",label:"Box",icon:Za},{value:"arrow",label:"Arrow",icon:Qa},{value:"text-note",label:"Note",icon:en}],ko={pin:Ja,box:Za,arrow:Qa,"text-note":en},wo={pin:"Pin",box:"Box",arrow:"Arrow","text-note":"Note"},So={review:oa,change:la,question:ia,issue:ia,idea:oa},Rt={select:{short:"Select and edit existing markers.",detail:"Use Select to click, drag, reorder, resize, and update markers that are already on the image.",example:"Example: move an existing marker after the screenshot changes."},pin:{short:"Mark a precise spot.",detail:"Use Pin when feedback points to one exact location instead of a broader area.",example:'Example: "This icon is misaligned by 2px."'},box:{short:"Mark an area or component.",detail:"Use Box when the feedback applies to a whole region, card, panel, or bounded UI block.",example:'Example: "This whole card needs tighter padding and a stronger border."'},arrow:{short:"Show direction or relationship.",detail:"Use Arrow when you need to show movement, attachment, flow, or source-to-target intent.",example:'Example: "This tooltip should anchor to this button, not the panel."'},"text-note":{short:"Add a comment-style point marker.",detail:"Use Note when you want a point marker that reads more like a comment or open question.",example:'Example: "Ask design whether this badge should stay."'}},lt={question:"#0f766e",change:"#2563eb",issue:"#dc2626",idea:"#d97706",review:"#7c3aed"},No=["#7c3aed","#2563eb","#0f766e","#dc2626","#d97706","#111827"],ce="review";function Ye(r){const l=String(r.displayName||"").trim();return l?`${l} review`:"Annotated session"}function tn(){return`annotation-${Math.random().toString(36).slice(2,10)}`}function I(r){return!Number.isFinite(r)||r<=0?0:r>=1?1:r}function Ne(r){return I(Math.max(.02,r))}function Ge(r){return r?[String(r.taskId||"").trim(),String(r.assetId||"").trim(),String(r.path||"").trim()].join("::"):""}function Co(r){if(!(r instanceof HTMLElement))return!1;const l=r.tagName.toLowerCase();return r.isContentEditable?!0:l==="input"||l==="textarea"||l==="select"}function Se(r){return r.map((l,f)=>({...l,order:f}))}function sa(r){if(!r)return"Unsaved";const l=new Date(r);return Number.isNaN(l.getTime())?"Unsaved":l.toLocaleString()}function jo(r){const l=typeof r=="number"&&Number.isFinite(r)?Math.max(0,r):0;return l<1024?`${l}B`:l<1024*1024?`${(l/1024).toFixed(1)}KB`:`${(l/(1024*1024)).toFixed(1)}MB`}function To(r){if(!r)return"";const l=new Date(r);if(Number.isNaN(l.getTime()))return"";const p=new Date().getTime()-l.getTime(),b=Math.floor(p/(1e3*60*60*24));return b<=0?"Today":b===1?"Yesterday":b<7?`${b}d ago`:b<30?`${Math.floor(b/7)}w ago`:l.toLocaleDateString()}function Pt(r){const l=String(r.createdByActor?.label||"").trim();return l||null}function $o(r){const l=String(r||"").trim().replace(/\s+/g," ");return l?l.length>110?`${l.slice(0,107)}...`:l:""}function Ka(r,l,f,p=lt[ce]){const b={id:tn(),order:0,instruction:"",markerType:ce,color:p};if(r==="pin")return{...b,kind:r,x:l.x,y:l.y};if(r==="text-note")return{...b,kind:r,x:l.x,y:l.y};if(r==="box"){const L=f||l;return{...b,kind:r,x:I(Math.min(l.x,L.x)),y:I(Math.min(l.y,L.y)),width:Ne(Math.abs(L.x-l.x)),height:Ne(Math.abs(L.y-l.y))}}const x=f||l;return{...b,kind:"arrow",x:l.x,y:l.y,x2:x.x,y2:x.y}}function ra(r){return r.color?r.color:lt[r.markerType||ce]}function Ro(r,l){const f=Math.max(l.width,1),p=Math.max(l.height,1),b=r.x*f,x=r.y*p,L=r.x2*f,ne=r.y2*p,se=L-b,ct=ne-x,Ce=Math.hypot(se,ct)||1,We=se/Ce,je=ct/Ce,G=Math.max(10,Math.min(16,Ce-2)),ye=G*.62,Te=L-We*G,$=ne-je*G,dt=-je,be=We;return{shaftX1:b,shaftY1:x,shaftX2:Te,shaftY2:$,headPoints:[`${L},${ne}`,`${Te+dt*ye},${$+be*ye}`,`${Te-dt*ye},${$-be*ye}`].join(" ")}}function Po(r,l){return{...r,markerType:l,color:r.color||lt[l]}}function Bo(r,l){return{...r,id:tn(),order:l}}function Ao(r,l){const f=String(r||"").trim()||(l?Ye(l):"Annotated session");return/\bcopy$/i.test(f)?`${f} 2`:`${f} copy`}function Mo(r,l,f){if(l===f||l<0||f<0||l>=r.length||f>=r.length)return r;const p=[...r],[b]=p.splice(l,1);return b?(p.splice(f,0,b),Se(p)):r}function ae(r){return String(Math.round(I(r)*1e3)/10)}function Eo(r){const l=Number.parseFloat(r);return Number.isFinite(l)?I(l/100):null}function Lo(r,l,f){return r.kind==="pin"||r.kind==="text-note"?l==="x"||l==="y"?{...r,[l]:I(f)}:r:r.kind==="box"?l==="x"||l==="y"?{...r,[l]:I(f)}:l==="width"||l==="height"?{...r,[l]:Ne(f)}:r:l==="x"||l==="y"||l==="x2"||l==="y2"?{...r,[l]:I(f)}:r}function Fo(r){return r.kind==="pin"||r.kind==="text-note"?[{key:"x",label:"X",value:ae(r.x)},{key:"y",label:"Y",value:ae(r.y)}]:r.kind==="box"?[{key:"x",label:"X",value:ae(r.x)},{key:"y",label:"Y",value:ae(r.y)},{key:"width",label:"Width",value:ae(r.width)},{key:"height",label:"Height",value:ae(r.height)}]:[{key:"x",label:"Start X",value:ae(r.x)},{key:"y",label:"Start Y",value:ae(r.y)},{key:"x2",label:"End X",value:ae(r.x2)},{key:"y2",label:"End Y",value:ae(r.y2)}]}function Ho(r){if(!r)return null;const l=Math.round(r.x*100),f=Math.round(r.y*100),p=Math.round(r.width*100),b=Math.round(r.height*100);return`crop ${l}%, ${f}% size ${p}% x ${b}%`}function Oo(r){return Number.isFinite(r)?Math.min(4,Math.max(.25,Number(r.toFixed(2)))):1}function Xa(r){const l=[`Annotated attachment: ${r.title||r.image.displayName}`,`Image: ${r.image.displayName}`,`Image Reference: ${r.image.referenceLabel||r.image.assetId}`,`Task ID: ${r.taskId}`,r.globalInstruction?`Global instruction: ${r.globalInstruction}`:"Global instruction: None provided.","Markers:"];return r.annotations.length===0?(l.push("0. No markers."),l.join(`
2
2
  `)):(r.annotations.forEach((f,p)=>{const b=f.markerType||ce,x=Ho(f.cropHint);l.push(`${p+1}. ${f.kind} (${b})`),l.push(`Instruction: ${f.instruction||"No marker instruction."}`),x&&l.push(`Region: ${x}`)}),l.join(`
3
3
  `))}function Bt(r){return{title:r.title,globalInstruction:r.globalInstruction,annotations:Se(r.annotations)}}function Va(r){return JSON.stringify(Bt(r))}function qa(r){const l=JSON.parse(r);return Bt({title:String(l?.title||""),globalInstruction:String(l?.globalInstruction||""),annotations:Array.isArray(l?.annotations)?l.annotations:[]})}function Do(r,l){return Bt({title:r?.title||l,globalInstruction:r?.globalInstruction||"",annotations:r?.annotations||[]})}function Vo({runtimeMode:r="local",apiBaseUrl:l="",cloudAuthBaseUrl:f="",workspaceId:p="default",sessionLoadReady:b=!0,requestedTarget:x=null,requestedSessionId:L=null,requestedOpenVersion:ne=0,imageTrayOpen:se,onCloseImageTray:ct,resolveTaskReferenceLabel:Ce,resolveImageReferenceLabel:We,onRequestedTargetHandled:je,onOpenTarget:G,onContextChange:ye,onBackToTask:Te}){const $=r==="cloud"&&(f||l)||"",[dt,be]=s.useState(x),[ut,$e]=s.useState([]),[v,Re]=s.useState(null),[At,Ke]=s.useState(!1),[Pe,Xe]=s.useState(""),[Be,Ve]=s.useState(""),[j,re]=s.useState([]),[S,F]=s.useState(null),[mt,ca]=s.useState(lt[ce]),[ft,ht]=s.useState(!1),[T,Ae]=s.useState("select"),[an,xe]=s.useState(!1),[pt,da]=s.useState(!1),[V,q]=s.useState(!1),[ua,g]=s.useState(null),[Y,R]=s.useState("saved"),[zo,D]=s.useState(null),[gt,ma]=s.useState(!1),[oe,Mt]=s.useState(null),[de,Et]=s.useState(!1),[nn,Lt]=s.useState(!1),[Ft,fa]=s.useState("json"),[yt,Ht]=s.useState(!1),[bt,Ot]=s.useState(!1),[sn,ha]=s.useState(!1),[rn,xt]=s.useState(!1),[Dt,vt]=s.useState(""),[qe,pa]=s.useState(!1),[zt,on]=s.useState([]),[_t,ln]=s.useState(""),[cn,ga]=s.useState(!1),[ya,ba]=s.useState(null),[ue,Je]=s.useState(!1),[Ut,Ze]=s.useState(!1),[P,Gt]=s.useState(1),[W,Qe]=s.useState(!1),[It,xa]=s.useState(!1),[kt,et]=s.useState({width:0,height:0}),va=s.useRef(null),Me=s.useRef(null),Yt=s.useRef(null),_a=s.useRef(null),me=s.useRef(L),ie=s.useRef(""),wt=s.useRef(0),Wt=s.useRef(""),ve=s.useRef(0),St=s.useRef(null),Ia=s.useRef(0),fe=s.useRef(!1),tt=s.useRef(null),Kt=s.useRef(null),_e=s.useRef(null),H=s.useRef(""),M=s.useRef(""),Nt=s.useRef(null),J=s.useRef(null),Ee=s.useRef(!1),Ct=s.useRef(null),at=s.useRef(null),nt=s.useRef(null),Ie=s.useRef(null),Le=s.useRef(null),Fe=s.useRef(null),He=s.useRef(null),he=s.useRef(null),Z=s.useRef(null),ka=s.useRef(null),wa=s.useRef(null),B=s.useMemo(()=>ut.find(e=>e.id===v)||null,[v,ut]),Q=s.useMemo(()=>`workspaceId=${encodeURIComponent(String(p||"default").trim()||"default")}`,[p]),A=s.useMemo(()=>({"x-taskforce-workspace-id":String(p||"default").trim()||"default"}),[p]),z=s.useMemo(()=>j.find(e=>e.id===S)||null,[j,S]),ee=s.useMemo(()=>Ge(x),[x]),le=typeof G=="function",d=le?x:dt,jt=s.useMemo(()=>{const e=String(d?.taskId||"").trim();if(!e)return"";const n=Ce?.(e).trim()||"";if(n)return n;const o=String(d?.taskReferenceLabel||"").trim();return o&&o!==e?o:n||e},[d?.taskId,d?.taskReferenceLabel,Ce]),st=s.useMemo(()=>{const e=String(d?.assetId||"").trim();if(!e)return"";const n=We?.(e).trim()||"";return n||String(d?.imageReferenceLabel||"").trim()},[d?.assetId,d?.imageReferenceLabel,We]),Xt=s.useMemo(()=>j.findIndex(e=>e.id===S),[j,S]),Vt=z?.color||mt,Sa=s.useMemo(()=>Bt({title:Pe,globalInstruction:Be,annotations:j}),[j,Be,Pe]),Oe=s.useMemo(()=>Va(Sa),[Sa]),Na=Oe!==M.current,y=s.useMemo(()=>({width:Math.max(kt.width*P,0),height:Math.max(kt.height*P,0)}),[kt.height,kt.width,P]),De=s.useMemo(()=>({visibleRadius:7,hitRadius:11}),[]),qt=s.useMemo(()=>`0 0 ${Math.max(y.width,1)} ${Math.max(y.height,1)}`,[y.height,y.width]),rt=typeof se=="boolean",Ca=s.useMemo(()=>{const e=_t.trim().toLowerCase();return e?zt.filter(n=>[n.displayName,n.originalFilename,n.imageReferenceLabel,n.taskReferenceLabel,n.assetId].filter(Boolean).join(" ").toLowerCase().includes(e)):zt},[zt,_t]),ke=s.useMemo(()=>{const e=Me.current;return e?P>1||y.width>e.clientWidth+1||y.height>e.clientHeight+1:P>1},[y.height,y.width,P]),Jt=`${Math.round(P*100)}%`,Zt=s.useMemo(()=>{const e=new Map;return j.forEach((n,o)=>{e.set(n.id,o+1)}),e},[j]);s.useEffect(()=>{me.current=L},[L]),s.useEffect(()=>{const e=_a.current;if(!e||!S)return;e.focus();const n=e.value.length;e.setSelectionRange(n,n)},[S]),s.useEffect(()=>{_e.current=v},[v]),s.useEffect(()=>{Ke(!1)},[v]),s.useEffect(()=>{if(!z){ht(!1);return}ca(z.color||lt[z.markerType||ce])},[z]);const Tt=s.useCallback(async e=>{const n=typeof performance<"u"?performance.now():Date.now(),o=await ge(`/api/taskforce/annotated-attachments/sessions?${Q}`,{method:"POST",credentials:"include",headers:{"Content-Type":"application/json",...A},body:JSON.stringify({taskId:e.taskId,baseImageAssetId:e.assetId,title:Ye(e),globalInstruction:"",annotations:[]})},$),i=await o.json().catch(()=>({}));if(!o.ok)throw new Error(String(i?.error||"Failed to create session."));const c=i?.session;if(!c?.id)throw new Error("Failed to create session.");return $t("annotated_session_create_completed",{assetId:e.assetId,taskId:e.taskId||null,sessionId:c.id,durationMs:Math.round((typeof performance<"u"?performance.now():Date.now())-n),debugTimings:i?.debugTimings||null,serverTiming:typeof o.headers?.get=="function"&&o.headers.get("server-timing")||null}),c},[A,$,Q]),ja=s.useCallback(e=>new Promise((n,o)=>{const i=new FileReader;i.onload=()=>n(typeof i.result=="string"?i.result:""),i.onerror=()=>o(i.error||new Error("Failed to read clipboard image.")),i.readAsDataURL(e)}),[]),N=s.useCallback(()=>{tt.current!==null&&(window.clearTimeout(tt.current),tt.current=null),nt.current!==null&&(window.clearTimeout(nt.current),nt.current=null)},[]),ze=s.useCallback(e=>{Xe(e.title),Ve(e.globalInstruction),re(e.annotations),F(n=>n&&e.annotations.some(o=>o.id===n)?n:e.annotations[0]?.id||null)},[]),pe=s.useCallback((e,n)=>{const o=Ye(n||d||{assetId:e.baseImageAssetId,displayName:"Annotated session"}),i=Do(e,o),c=Va(i);fe.current=!0,N(),ze(i),M.current=c,H.current=c,Nt.current=null,Ee.current=!1,Ct.current=null,at.current=null,D(null),R("saved"),q(!1)},[d,ze,N]),ot=s.useCallback(e=>{fe.current=!0,N(),$e([]),Re(null),xe(!1),Ke(!1),Xe(Ye(e)),Ve(""),re([]),F(null),M.current="",H.current="",Nt.current=null,Ee.current=!1,Ct.current=null,at.current=null,Mt(null),Lt(!1),D(null),R("saved"),q(!1)},[N]),we=s.useCallback(async(e,n,o)=>{const i=_e.current;if(!i)return!0;if(e===M.current)return J.current||(D(null),R("saved")),!0;if(J.current){if(Ee.current=!0,!o?.waitForInFlight||!await J.current)return!1;const m=H.current;return m===M.current?!0:we(m,n,o)}N();const c=qa(e);Ct.current=i,Nt.current=e,q(!0),g(null),D(null),R("saving");const h=(async()=>{try{const u=await ge(`/api/taskforce/annotated-attachments/sessions/${encodeURIComponent(i)}?${Q}`,{method:"PATCH",credentials:"include",headers:{"Content-Type":"application/json",...A},body:JSON.stringify(c)},$),m=await u.json().catch(()=>({}));if(!u.ok)throw new Error(String(m?.error||"Failed to save session."));const _=m?.session;if(!_?.id)throw new Error("Failed to save session.");$e(ea=>{const Ha=ea.findIndex(Bn=>Bn.id===_.id);if(Ha===-1)return[_,...ea];const Oa=[...ea];return Oa[Ha]=_,Oa}),M.current=e,at.current=null,D(null);const w=_e.current===_.id,C=H.current,X=C!==e,it=Ee.current||X;return Ee.current=!1,w&&!it?(fe.current=!0,ze(c),R("saved")):!it&&C===M.current?R("saved"):R("pending"),!0}catch(u){const m=u instanceof Error?u.message:"Failed to save session.";return g(m),D(m),R("error"),at.current!==e&&_e.current===i&&H.current===e&&(at.current=e,nt.current=window.setTimeout(()=>{nt.current=null,!(_e.current!==i||H.current!==e)&&we(e,n,{waitForInFlight:!0})},1500)),!1}finally{Nt.current=null,J.current=null,Ct.current=null,q(!1)}})();J.current=h;const k=await h;if(k){const u=H.current;if(u!==M.current)return we(u,n,o)}return k},[ze,N,A,$,Q]),Ta=s.useCallback(e=>{if(_e.current){if(H.current===M.current){D(null),J.current||R("saved");return}Y!=="saving"&&R("pending"),N(),tt.current=window.setTimeout(()=>{tt.current=null,we(H.current,"structure")},e)}},[N,we,Y]),K=s.useCallback(e=>{Kt.current=e},[]),E=s.useCallback(async e=>{N();const n=H.current;return!_e.current||n===M.current?(D(null),J.current||R("saved"),!0):we(n,e,{waitForInFlight:!0})},[N,we]),dn=s.useCallback(()=>{const e=M.current;e&&(N(),fe.current=!0,ze(qa(e)),D(null),R("saved"),g(null))},[ze,N]),U=s.useCallback(async(e,n)=>{const o=typeof performance<"u"?performance.now():Date.now(),i=JSON.stringify({targetKey:Ge(e),requestedSessionId:n?.requestedSessionId??null,autoCreateIfEmpty:n?.autoCreateIfEmpty===!0});if(St.current===i)return;const c=ve.current+1;ve.current=c,St.current=i,da(!0),g(null);try{const h=new URLSearchParams;p&&h.set("workspaceId",p),e.taskId&&h.set("taskId",e.taskId),h.set("imageAssetId",e.assetId);const k=await ge(`/api/taskforce/annotated-attachments/sessions?${h.toString()}`,{credentials:"include",headers:A,cache:"no-store"},$),u=await k.json().catch(()=>({}));if(!k.ok)throw new Error(String(u?.error||"Failed to load annotated attachment sessions."));const m=Array.isArray(u?.sessions)?u.sessions:[];if($t("annotated_sessions_loaded",{assetId:e.assetId,taskId:e.taskId||null,requestedSessionId:n?.requestedSessionId??null,autoCreateIfEmpty:n?.autoCreateIfEmpty===!0,sessionCount:m.length,durationMs:Math.round((typeof performance<"u"?performance.now():Date.now())-o),serverTiming:typeof k.headers?.get=="function"&&k.headers.get("server-timing")||null}),m.length===0&&n?.autoCreateIfEmpty&&String(e.assetId||"").trim()){const C=n?.requestedSessionId??me.current;if(me.current=null,C&&g("The previously selected annotation session could not be restored."),ve.current!==c)return;const X=await Tt(e);if($t("annotated_sessions_auto_created_after_empty_load",{assetId:e.assetId,taskId:e.taskId||null,sessionId:X.id,totalDurationMs:Math.round((typeof performance<"u"?performance.now():Date.now())-o)}),ve.current!==c)return;$e([X]),Re(X.id),xe(!1),pe(X,e);return}if(ve.current!==c)return;$e(m),xe(m.length===0);const _=n?.requestedSessionId??me.current;me.current=null;const w=m.find(C=>C.id===_)||m[0]||null;_&&!w&&g("The previously selected annotation session could not be restored."),Re(w?.id||null),w?pe(w,e):(fe.current=!0,N(),Xe(Ye(e)),Ve(""),re([]),F(null),M.current="",H.current="",D(null),R("saved"))}catch(h){if(ve.current!==c)return;g(h instanceof Error?h.message:"Failed to load sessions.")}finally{St.current===i&&(St.current=null),ve.current===c&&da(!1)}},[N,Tt,A,$,pe,p]),$a=s.useCallback(async()=>{ga(!0),ba(null);try{const e=new URLSearchParams;e.set("workspaceId",String(p||"default").trim()||"default");const n=await ge(`/api/taskforce/annotated-attachments/images?${e.toString()}`,{credentials:"include",headers:A,cache:"no-store"},$),o=await n.json().catch(()=>({}));if(!n.ok)throw new Error(String(o?.error||"Failed to load images."));on(Array.isArray(o?.images)?o.images:[])}catch(e){ba(e instanceof Error?e.message:"Failed to load images.")}finally{ga(!1)}},[A,$,p]),un=s.useCallback(async()=>{if(typeof navigator>"u"||!navigator.clipboard||typeof navigator.clipboard.read!="function"){g("Clipboard image paste is not supported in this environment.");return}xa(!0),g(null),Ia.current=Date.now()+2e3;try{const n=(await navigator.clipboard.read()).find(_=>_.types.some(w=>w.startsWith("image/"))),o=n?.types.find(_=>_.startsWith("image/"))||"";if(!n||!o)throw new Error("No image found on the clipboard.");const i=await n.getType(o),c=await ja(i);if(!c)throw new Error("Failed to read clipboard image.");const h=o==="image/jpeg"?"jpg":o==="image/webp"?"webp":o==="image/gif"?"gif":"png",k=await fetch("/api/taskforce/context-upload",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json",...A},body:JSON.stringify({file:c,originalName:`pasted-image.${h}`,workspaceId:String(p||"default").trim()||"default"})}),u=await k.json().catch(()=>({}));if(!k.ok||!u?.success||typeof u?.assetId!="string"||typeof u?.path!="string")throw new Error(String(u?.error||"Failed to paste image into Image Notes."));const m={assetId:u.assetId,imageReferenceLabel:typeof u?.referenceLabel=="string"?u.referenceLabel:void 0,path:u.path,displayName:typeof u?.displayName=="string"&&u.displayName.trim().length>0?u.displayName.trim():"Pasted image"};me.current=null,le?(ie.current="",G?.(m,{sessionId:null})):(be(m),ie.current=Ge(m),U(m,{autoCreateIfEmpty:!0}))}catch(e){g(e instanceof Error?e.message:"Failed to paste image.")}finally{xa(!1)}},[le,U,G,ja,A,p]),mn=s.useCallback(async()=>{const e=Dt.trim();if(!e){g("Enter an image reference to open.");return}pa(!0),g(null);try{const n=new URLSearchParams({workspaceId:String(p||"default").trim()||"default"}),o=await ge(`/api/taskforce/annotated-attachments/images/${encodeURIComponent(e)}?${n.toString()}`,{method:"GET",credentials:"include",headers:A}),i=await o.json().catch(()=>({}));if(!o.ok||!i?.target||typeof i.target.assetId!="string"||typeof i.target.path!="string")throw new Error(String(i?.error||"Failed to open image reference."));const c={assetId:i.target.assetId,path:i.target.path,displayName:typeof i.target.displayName=="string"&&i.target.displayName.trim().length>0?i.target.displayName.trim():"Image attachment",taskId:typeof i.target.taskId=="string"&&i.target.taskId.trim().length>0?i.target.taskId.trim():void 0,taskReferenceLabel:typeof i.target.taskReferenceLabel=="string"&&i.target.taskReferenceLabel.trim().length>0?i.target.taskReferenceLabel.trim():void 0,imageReferenceLabel:typeof i.target.imageReferenceLabel=="string"&&i.target.imageReferenceLabel.trim().length>0?i.target.imageReferenceLabel.trim():void 0};me.current=null,xt(!1),vt(""),le?(ie.current="",G?.(c,{sessionId:null})):(be(c),ie.current=Ge(c),U(c,{autoCreateIfEmpty:!0}))}catch(n){g(n instanceof Error?n.message:"Failed to open image reference.")}finally{pa(!1)}},[le,U,G,Dt,A,p]),fn=s.useCallback(async e=>{if(!e.assetId||!e.path||!await E("session-switch"))return;const o={assetId:e.assetId,path:e.path,displayName:String(e.displayName||e.originalFilename||"Image attachment").trim()||"Image attachment",...e.taskId?{taskId:e.taskId}:{},...e.taskReferenceLabel?{taskReferenceLabel:e.taskReferenceLabel}:{},...e.imageReferenceLabel?{imageReferenceLabel:e.imageReferenceLabel}:{}};me.current=null,g(null),le?(ie.current="",G?.(o,{sessionId:null})):(be(o),ie.current=Ge(o),ot(o),U(o,{autoCreateIfEmpty:!0}))},[E,le,U,G,ot]),Ra=s.useCallback(e=>{$e(n=>{const o=n.findIndex(c=>c.id===e.id);if(o===-1)return[e,...n];const i=[...n];return i[o]=e,i}),Re(e.id),pe(e,d)},[d,pe]),Pa=s.useCallback(e=>{$e(n=>{const o=n.filter(c=>c.id!==e),i=o[0]||null;return Re(i?.id||null),i?pe(i,d):(fe.current=!0,N(),Xe(Ye(d||{displayName:"Annotated session"})),Ve(""),re([]),F(null),M.current="",H.current="",D(null),R("saved")),o})},[d,N,pe]);s.useEffect(()=>{if(!x)return;if(le||be(n=>n&&Ge(n)===ee&&n.taskReferenceLabel===x.taskReferenceLabel&&n.imageReferenceLabel===x.imageReferenceLabel&&n.displayName===x.displayName?n:x),!b){ee&&(ee!==ie.current||ne!==wt.current)&&ee!==Wt.current&&(ot(x),Wt.current=ee,wt.current=ne,$t("annotated_sessions_load_deferred",{assetId:x.assetId,taskId:x.taskId||null,requestedTargetKey:ee})),je?.();return}ee&&(ee!==ie.current||ne!==wt.current)&&(ot(x),ie.current=ee,wt.current=ne,Wt.current="",U(x,{autoCreateIfEmpty:!0})),je?.()},[le,U,je,ne,x,ee,ot,L,b]),s.useEffect(()=>{d&&ye?.({target:d,sessionId:v})},[d,ye,v]),s.useEffect(()=>{if(!d||typeof document>"u"||!b)return;const e=()=>{Date.now()<Ia.current||H.current!==M.current||V||pt||U(d,{requestedSessionId:v})},n=()=>{document.visibilityState==="visible"&&e()};return document.addEventListener("visibilitychange",n),()=>{document.removeEventListener("visibilitychange",n)}},[d,U,pt,V,v,b]),s.useEffect(()=>{if(!d?.path){Je(!1),Ze(!1),et({width:0,height:0});return}Je(!0),Ze(!1),et({width:0,height:0}),Gt(1),Qe(!1)},[d?.path]),s.useEffect(()=>{if(!ue)return;const e=Yt.current;!e||!e.complete||e.naturalWidth<=0||e.naturalHeight<=0||(et({width:e.naturalWidth,height:e.naturalHeight}),Je(!1),Ze(!1))},[d?.path,ue]),s.useEffect(()=>{ke||Qe(!1)},[ke]),s.useEffect(()=>{Mt(null)},[v]),s.useEffect(()=>{if(H.current=Oe,fe.current){fe.current=!1;return}if(!v){N(),D(null),R("saved");return}if(Oe===M.current){N(),J.current||(D(null),R("saved"));return}const e=Kt.current;if(Kt.current=null,Y==="error"&&e===null)return;const n=e??600;if(J.current){Ee.current=!0,R("pending");return}Ta(n)},[N,Oe,Y,Ta,v]),s.useEffect(()=>{v&&(J.current||Oe===M.current&&Y!=="error"&&Y!=="saved"&&(D(null),R("saved")))},[Oe,Y,v]),s.useEffect(()=>{!rt||!se||$a()},[$a,se,rt]),s.useEffect(()=>{if(typeof window>"u")return;const e=n=>{H.current!==M.current&&(n.preventDefault(),n.returnValue="")};return window.addEventListener("beforeunload",e),()=>window.removeEventListener("beforeunload",e)},[]),s.useEffect(()=>{if(typeof document>"u")return;const e=()=>{document.visibilityState==="hidden"&&E("visibility-hidden")};return document.addEventListener("visibilitychange",e),()=>document.removeEventListener("visibilitychange",e)},[E]),s.useEffect(()=>{if(!ft||typeof document>"u")return;const e=n=>{const o=n.target;o instanceof Node&&(ka.current?.contains(o)||ht(!1))};return document.addEventListener("mousedown",e),()=>document.removeEventListener("mousedown",e)},[ft]),s.useEffect(()=>{if(!At||typeof document>"u")return;const e=n=>{const o=n.target;o instanceof Node&&(wa.current?.contains(o)||Ke(!1))};return document.addEventListener("mousedown",e),()=>document.removeEventListener("mousedown",e)},[At]),s.useEffect(()=>()=>{N()},[N]),s.useEffect(()=>{if(!de)return;const e=window.setTimeout(()=>Et(!1),2e3);return()=>window.clearTimeout(e)},[de]),s.useEffect(()=>{if(!yt)return;const e=window.setTimeout(()=>Ht(!1),2e3);return()=>window.clearTimeout(e)},[yt]),s.useEffect(()=>{if(!bt)return;const e=window.setTimeout(()=>Ot(!1),2e3);return()=>window.clearTimeout(e)},[bt]);const te=s.useCallback((e,n,o=300)=>{re(i=>Se(i.map(c=>c.id===e?n(c):c))),K(o)},[K]),hn=s.useCallback(e=>{z&&(te(z.id,n=>({...n,color:e})),ca(e),ht(!1))},[z,te]),Ba=s.useCallback(async()=>{if(!(!d||!await E("session-switch"))){q(!0),g(null);try{const n=await Tt(d);xe(!1),await U(d,{requestedSessionId:n.id,autoCreateIfEmpty:!1}),Ae("select")}catch(n){g(n instanceof Error?n.message:"Failed to create session."),xe(!0)}finally{q(!1)}}},[d,Tt,E,U]),pn=s.useCallback(e=>{if(e!=="select"&&!B){Qe(!1),g("No session exists for this image yet."),xe(!0);return}g(null),xe(!1),Qe(!1),Ae(e)},[B]),gn=s.useCallback(async()=>{if(!(!d||!B||!await E("duplicate"))){q(!0),g(null);try{const n=Se(j.map((h,k)=>Bo(h,k))),o=await ge(`/api/taskforce/annotated-attachments/sessions?${Q}`,{method:"POST",credentials:"include",headers:{"Content-Type":"application/json",...A},body:JSON.stringify({taskId:d.taskId,baseImageAssetId:d.assetId,title:Ao(Pe||B.title,d),globalInstruction:Be,annotations:n})},$),i=await o.json().catch(()=>({}));if(!o.ok)throw new Error(String(i?.error||"Failed to duplicate session."));const c=i?.session;if(!c?.id)throw new Error("Failed to duplicate session.");Ra(c),Ae("select")}catch(n){g(n instanceof Error?n.message:"Failed to duplicate session.")}finally{q(!1)}}},[d,j,Be,Pe,Ra,E,A,$,B,Q]),yn=s.useCallback(async()=>E("manual"),[E]),Aa=s.useCallback(async()=>{if(v){ma(!0),g(null);try{const e=await ge(`/api/taskforce/annotated-attachments/sessions/${encodeURIComponent(v)}/payload?${Q}`,{credentials:"include",headers:A},$),n=await e.json().catch(()=>({}));if(!e.ok)throw new Error(String(n?.error||"Failed to load payload preview."));Mt(n?.payload||null)}catch(e){g(e instanceof Error?e.message:"Failed to load payload preview.")}finally{ma(!1)}}},[A,$,v,Q]),bn=s.useCallback(()=>{v&&E("payload-preview").then(e=>{e&&(Lt(!0),Aa())})},[E,Aa,v]),Ma=s.useCallback(async e=>{if(!oe||!navigator.clipboard||typeof navigator.clipboard.writeText!="function"){g("Clipboard copy is not available in this browser.");return}try{const n=e==="json"?JSON.stringify(oe,null,2):Xa(oe);await navigator.clipboard.writeText(n),Et(e)}catch(n){g(n instanceof Error?n.message:"Failed to copy payload content."),Et(!1)}},[oe]),xn=s.useCallback(async()=>{if(!jt||!navigator.clipboard||typeof navigator.clipboard.writeText!="function"){g("Clipboard copy is not available in this browser.");return}try{await navigator.clipboard.writeText(jt),Ht(!0)}catch(e){g(e instanceof Error?e.message:"Failed to copy task id."),Ht(!1)}},[jt]),vn=s.useCallback(async()=>{if(!st||!navigator.clipboard||typeof navigator.clipboard.writeText!="function"){g("Clipboard copy is not available in this browser.");return}try{await navigator.clipboard.writeText(st),Ot(!0)}catch(e){g(e instanceof Error?e.message:"Failed to copy image reference."),Ot(!1)}},[st]),_n=s.useCallback(async()=>{if(!v||!await E("delete-session"))return;const n=(B?.title||"Untitled session").trim()||"Untitled session";if(window.confirm(`Delete the annotated attachment session "${n}"?`)){q(!0),g(null);try{const o=await ge(`/api/taskforce/annotated-attachments/sessions/${encodeURIComponent(v)}?${Q}`,{method:"DELETE",credentials:"include",headers:A},$),i=await o.json().catch(()=>({}));if(!o.ok)throw new Error(String(i?.error||"Failed to delete session."));Pa(v),Ae("select")}catch(o){g(o instanceof Error?o.message:"Failed to delete session.")}finally{q(!1)}}},[E,Pa,A,$,B,v,Q]),Qt=s.useCallback(()=>{S&&(re(e=>Se(e.filter(n=>n.id!==S))),F(null),K(300))},[K,S]),Ue=s.useCallback(e=>{const n=Oo(e),o=Me.current;if(!o||n===P){Gt(n);return}const i=(o.scrollLeft+o.clientWidth/2)*(n/P)-o.clientWidth/2,c=(o.scrollTop+o.clientHeight/2)*(n/P)-o.clientHeight/2;Gt(n),window.requestAnimationFrame(()=>{o.scrollLeft=Math.max(0,i),o.scrollTop=Math.max(0,c)})},[P]),In=s.useCallback(()=>{Ue(P+.25)},[Ue,P]),kn=s.useCallback(()=>{Ue(P-.25)},[Ue,P]),wn=s.useCallback(()=>{Ue(1);const e=Me.current;e&&window.requestAnimationFrame(()=>{e.scrollLeft=0,e.scrollTop=0})},[Ue]),Ea=s.useCallback(e=>{S&&re(n=>{const o=n.findIndex(c=>c.id===S);if(o===-1)return n;const i=e==="up"?o-1:o+1;return i<0||i>=n.length?n:(K(300),Mo(n,o,i))})},[K,S]);s.useEffect(()=>{if(!S)return;const e=n=>{n.key==="Delete"&&(Co(n.target)||(n.preventDefault(),Qt()))};return window.addEventListener("keydown",e),()=>window.removeEventListener("keydown",e)},[Qt,S]);const O=s.useCallback(e=>{const n=va.current?.getBoundingClientRect();return!n||n.width<=0||n.height<=0?null:{x:I((e.clientX-n.left)/n.width),y:I((e.clientY-n.top)/n.height)}},[]),Sn=s.useCallback(e=>{if(W&&ke){const i=Me.current;if(!i)return;Z.current={pointerId:e.pointerId,startX:e.clientX,startY:e.clientY,scrollLeft:i.scrollLeft,scrollTop:i.scrollTop},e.currentTarget.setPointerCapture(e.pointerId),e.preventDefault();return}if(!v)return;if(T==="select"){F(null);return}const n=O(e);if(!n)return;if(T==="pin"||T==="text-note"){const i=Ka(T,n,n,mt);re(c=>Se([...c,i])),F(i.id),K(300),Ae("select");return}Ie.current=n;const o=Ka(T,n,n,mt);he.current={annotationId:o.id,kind:T},e.currentTarget.setPointerCapture?.(e.pointerId),re(i=>Se([...i,o])),F(o.id),K(300)},[ke,mt,K,W,O,v,T]),Nn=s.useCallback(e=>{if(Z.current?.pointerId===e.pointerId){e.currentTarget.releasePointerCapture?.(e.pointerId);return}if(!Ie.current||!he.current||T!=="box"&&T!=="arrow")return;const n=O(e);Ie.current=null,he.current=null,e.currentTarget.releasePointerCapture?.(e.pointerId),n&&Ae("select")},[O,T]),La=s.useCallback((e,n)=>{if(T!=="select"||W)return;const o=O(e);o&&(Le.current={annotationId:n.id,originPointer:o,originAnnotation:n},F(n.id),e.stopPropagation())},[W,O,T]),Cn=s.useCallback(e=>{if(Z.current?.pointerId===e.pointerId){const u=Me.current;if(!u)return;const m=e.clientX-Z.current.startX,_=e.clientY-Z.current.startY;u.scrollLeft=Z.current.scrollLeft-m,u.scrollTop=Z.current.scrollTop-_;return}if(he.current&&Ie.current){const u=O(e);if(!u)return;const{annotationId:m,kind:_}=he.current,w=Ie.current;te(m,C=>_==="box"&&C.kind==="box"?{...C,x:I(Math.min(w.x,u.x)),y:I(Math.min(w.y,u.y)),width:Ne(Math.abs(u.x-w.x)),height:Ne(Math.abs(u.y-w.y))}:_==="arrow"&&C.kind==="arrow"?{...C,x:w.x,y:w.y,x2:u.x,y2:u.y}:C);return}if(Fe.current){const u=O(e);if(!u)return;const{annotationId:m,originPointer:_,originAnnotation:w}=Fe.current,C=u.x-_.x,X=u.y-_.y;te(m,()=>({...w,width:Ne(w.width+C),height:Ne(w.height+X)}));return}if(He.current){const u=O(e);if(!u)return;const{annotationId:m,endpoint:_,originPointer:w,originAnnotation:C}=He.current,X=u.x-w.x,it=u.y-w.y;te(m,()=>_==="tail"?{...C,x:I(C.x+X),y:I(C.y+it)}:{...C,x2:I(C.x2+X),y2:I(C.y2+it)});return}if(!Le.current)return;const n=O(e);if(!n)return;const{annotationId:o,originPointer:i,originAnnotation:c}=Le.current,h=n.x-i.x,k=n.y-i.y;te(o,()=>c.kind==="pin"||c.kind==="text-note"?{...c,x:I(c.x+h),y:I(c.y+k)}:c.kind==="box"?{...c,x:I(c.x+h),y:I(c.y+k)}:{...c,x:I(c.x+h),y:I(c.y+k),x2:I(c.x2+h),y2:I(c.y2+k)})},[O,te]),jn=s.useCallback(()=>{Ie.current=null,Le.current=null,Fe.current=null,He.current=null,he.current=null,Z.current=null},[]),Tn=s.useCallback(()=>{Ie.current=null,Le.current=null,Fe.current=null,He.current=null,he.current=null,Z.current=null},[]),$n=s.useCallback(()=>{Le.current=null,Fe.current=null,He.current=null,he.current=null,Z.current=null},[]),Rn=s.useCallback((e,n)=>{if(T!=="select"||W)return;const o=O(e);o&&(Fe.current={annotationId:n.id,originPointer:o,originAnnotation:n},F(n.id),e.stopPropagation())},[W,O,T]),Fa=s.useCallback((e,n,o)=>{if(T!=="select"||W)return;const i=O(e);i&&(He.current={annotationId:n.id,originPointer:i,originAnnotation:n,endpoint:o},F(n.id),e.stopPropagation())},[W,O,T]),Pn=B?.updatedAt?sa(B.updatedAt):"Not saved yet";return t.jsxs("div",{className:`${a.shell} ${rt?a.shellWithImageTray:""} ${rt&&se?a.shellImageTrayOpen:""}`.trim(),children:[rt?t.jsxs("aside",{className:`${a.imageTrayPanel} ${se?a.imageTrayPanelOpen:""}`.trim(),"aria-label":"Image tray","aria-hidden":!se,children:[t.jsxs("div",{className:a.imageTrayHeader,children:[t.jsxs("span",{className:a.imageTrayTitle,children:[t.jsx(za,{size:14}),"Images"]}),t.jsx("button",{type:"button",className:"tf-control-icon",onClick:ct,title:"Collapse image tray","aria-label":"Collapse image tray",children:t.jsx(En,{size:16})})]}),t.jsxs("div",{className:a.imageTraySearch,children:[t.jsx(Ln,{size:12,className:a.imageTraySearchIcon}),t.jsx("input",{type:"text",placeholder:"Search images...",value:_t,onChange:e=>ln(e.target.value),className:a.imageTraySearchInput})]}),t.jsx("div",{className:`tf-scrollbar ${a.imageTrayList}`,children:cn?t.jsx("div",{className:a.imageTrayState,children:"Loading images..."}):ya?t.jsx("div",{className:a.imageTrayStateError,children:ya}):Ca.length===0?t.jsx("div",{className:a.imageTrayState,children:_t.trim()?"No images match your search.":"No images found."}):Ca.map(e=>{const n=d?.assetId===e.assetId,o=typeof e.attachmentCount=="number"&&Number.isFinite(e.attachmentCount)?Math.max(0,e.attachmentCount):0,i=typeof e.sessionCount=="number"&&Number.isFinite(e.sessionCount)?Math.max(0,e.sessionCount):0,c=o>1?`${o} tasks linked`:o===1?e.taskReferenceLabel||"1 task linked":"Unattached",h=String(e.displayName||e.originalFilename||"Image attachment").trim()||"Image attachment";return t.jsxs("button",{type:"button",className:`${a.imageTrayItem} ${n?a.imageTrayItemActive:""}`.trim(),onClick:()=>{fn(e)},title:h,children:[t.jsx("span",{className:a.imageTrayThumb,children:t.jsx("img",{src:e.path,alt:"",loading:"lazy"})}),t.jsxs("span",{className:a.imageTrayItemBody,children:[t.jsx("span",{className:a.imageTrayItemTitle,children:h}),t.jsx("span",{className:a.imageTrayItemTask,children:c}),t.jsxs("span",{className:a.imageTrayItemMeta,children:[t.jsxs("span",{className:a.imageTrayItemMetaDetails,children:[jo(e.sizeBytes),e.updatedAt?t.jsxs(t.Fragment,{children:[" · ",To(e.updatedAt)]}):null,i>0?t.jsxs(t.Fragment,{children:[" · ",i," session",i===1?"":"s"]}):null]}),e.imageReferenceLabel?t.jsx("span",{className:a.imageTrayItemReference,children:e.imageReferenceLabel}):null]})]})]},e.assetId)})})]}):null,t.jsxs("section",{className:`tf-surface-panel ${a.panel} ${a.sessionPanel}`,children:[t.jsx("div",{className:a.sessionContextBar,children:d?.taskId?t.jsxs(t.Fragment,{children:[t.jsx("div",{className:a.sessionContextLeft,children:Te?t.jsx("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.ghostBtn} ${a.backToTaskBtn}`,onClick:()=>{E("back-to-task").then(e=>{e&&d.taskId&&Te(d.taskId)})},"aria-label":"Back to task",title:"Back to task",children:t.jsx(Fn,{size:16})}):t.jsx("div",{className:a.sessionContextSpacer,"aria-hidden":"true"})}),t.jsx("div",{className:a.sessionContextRight,children:t.jsx(Mn,{copied:yt,onClick:()=>{xn()},title:"Copy task id",ariaLabel:yt?"Copied task id":"Copy task id",label:jt})})]}):t.jsxs(t.Fragment,{children:[t.jsx("div",{className:a.sessionContextLeft,children:t.jsx("span",{className:`tf-label-micro ${a.sessionContextLabel}`,children:"Unattached Image"})}),t.jsx("div",{className:a.sessionContextRight,children:t.jsx("div",{className:a.sessionContextSpacer,"aria-hidden":"true"})})]})}),t.jsxs("div",{className:a.panelHeader,children:[t.jsxs("div",{className:a.panelHeaderText,children:[t.jsx("div",{className:`tf-heading-card ${a.panelTitle}`,children:"Sessions"}),d?null:t.jsx("div",{className:"tf-text-secondary",children:"Open an image attachment to begin"})]}),t.jsx("div",{className:a.sessionActions,children:t.jsx("button",{type:"button",className:`tf-control-icon ${a.iconButton}`,onClick:()=>{Ba()},disabled:!d||V,"aria-label":"Create session",title:"Create session",children:t.jsx(Hn,{size:16})})})]}),d?pt?t.jsx("div",{className:a.emptyState,children:t.jsx("p",{className:"tf-empty-copy",children:"Loading sessions…"})}):t.jsx("div",{className:`tf-scrollbar ${a.sessionList}`,children:ut.length===0?t.jsxs("div",{className:a.sessionEmptyState,children:[t.jsx("div",{className:`tf-heading-card ${a.sessionTitle}`,children:"No sessions yet"}),t.jsx("div",{className:`tf-text-secondary ${a.annotationSummary}`,children:"Create the first annotation session for this image."})]}):ut.map(e=>{const n=v===e.id,o=n&&At,i=$o(n?Be:e.globalInstruction),c=(n?Pe:e.title)||"Untitled session";return t.jsxs("div",{className:`tf-surface-elevated ${a.sessionCard} ${n?a.sessionCardActive:""}`,ref:n?wa:void 0,onBlur:o?h=>{const k=h.relatedTarget;k instanceof Node&&h.currentTarget.contains(k)||Ke(!1)}:void 0,children:[o?t.jsxs("div",{className:a.sessionCardBody,children:[t.jsxs("div",{className:a.sessionMeta,children:[t.jsx("label",{className:"tf-field-label",htmlFor:"annotated-session-title",children:"Session title"}),t.jsx("input",{id:"annotated-session-title",className:`tf-field-shell ${a.textInput} ${a.sessionTitleInput}`,value:Pe,onChange:h=>{Xe(h.target.value),K(600)},placeholder:"Session title"}),t.jsx("span",{className:`tf-text-meta ${a.sessionTimestamp}`,children:sa(e.updatedAt)})]}),Pt(e)?t.jsxs("div",{className:`tf-text-secondary ${a.sessionCreator}`,children:["Created by ",Pt(e)]}):null,t.jsxs("div",{className:a.sessionInstructionEditor,children:[t.jsx("label",{className:"tf-field-label",htmlFor:"annotated-session-instruction",children:"Session instruction"}),t.jsx("textarea",{id:"annotated-session-instruction",className:`tf-field-shell ${a.textArea} ${a.sessionInstructionField}`,value:Be,onChange:h=>{Ve(h.target.value),K(600)},placeholder:"Add overall instructions, context, or framing for this session."})]}),t.jsxs("div",{className:`tf-text-secondary ${a.annotationSummary}`,children:[e.annotations.length," annotation",e.annotations.length===1?"":"s"]})]}):t.jsxs("button",{type:"button",className:a.sessionCardButton,onClick:()=>{if(n){Ke(!0);return}E("session-switch").then(h=>{h&&(Re(e.id),pe(e,d))})},"aria-pressed":n,children:[t.jsxs("div",{className:a.sessionMeta,children:[t.jsx("span",{className:`tf-heading-card ${a.sessionTitle}`,children:c}),t.jsx("span",{className:`tf-text-meta ${a.sessionTimestamp}`,children:sa(e.updatedAt)})]}),Pt(e)?t.jsxs("div",{className:`tf-text-secondary ${a.sessionCreator}`,children:["Created by ",Pt(e)]}):null,i?t.jsx("div",{className:`tf-text-secondary ${a.sessionInstructionPreview}`,children:i}):null,t.jsxs("div",{className:`tf-text-secondary ${a.annotationSummary}`,children:[e.annotations.length," annotation",e.annotations.length===1?"":"s"]})]}),n?t.jsx("div",{className:a.sessionCardFooter,children:t.jsxs(t.Fragment,{children:[t.jsx("button",{type:"button",className:`tf-button-ghost ${a.toolRailButton} ${a.iconButton}`,onClick:()=>{gn()},disabled:V,"aria-label":"Duplicate session",title:`Duplicate session "${c}"`,children:t.jsx(na,{size:16})}),t.jsx("button",{type:"button",className:`tf-button-ghost ${a.toolRailButton} ${a.iconButton}`,onClick:()=>{_n()},disabled:V,"aria-label":"Delete session",title:`Delete session "${c}"`,children:t.jsx(Ua,{size:16})})]})}):null]},e.id)})}):t.jsxs("div",{className:a.emptyState,children:[t.jsx("strong",{className:"tf-empty-title",children:"No image selected"}),t.jsx("p",{className:"tf-empty-copy",children:"Open an image attachment from a task to start an annotated session."})]})]}),t.jsxs("section",{className:`tf-surface-panel ${a.panel} ${a.canvasPanel}`,children:[t.jsxs("div",{className:a.panelHeader,children:[t.jsxs("div",{className:a.canvasHeading,children:[t.jsx("div",{className:"tf-heading-card",children:d?.displayName||"Annotated attachment"}),t.jsx("div",{className:"tf-text-secondary",children:B?`${j.length} markers · ${Pn}`:"Pick or create a session"})]}),st?t.jsx(Vn,{copied:bt,onClick:()=>{vn()},title:"Copy image reference",ariaLabel:bt?"Copied image reference":"Copy image reference",label:st}):null]}),t.jsxs("div",{className:a.toolRail,children:[t.jsxs("div",{className:`${a.toolbarCluster} ${a.toolbarViewportCluster}`,children:[t.jsx("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.ghostBtn} ${a.toolbarButton}`,onClick:()=>{yn()},disabled:!B||V||!Na&&Y!=="error","aria-label":V?"Saving session":"Save session",title:V?"Saving session":"Save session",children:t.jsx(On,{size:18})}),t.jsx("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.ghostBtn} ${a.toolbarButton}`,onClick:()=>xt(!0),disabled:qe,"aria-label":"Open image",title:"Open image",children:t.jsx(za,{size:18})}),t.jsx("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.ghostBtn} ${a.toolbarButton}`,onClick:()=>{un()},disabled:It,"aria-label":It?"Pasting image":"Paste image",title:It?"Pasting image":"Paste image",children:It?t.jsx(Ga,{size:18,className:Da.spin}):t.jsx(Dn,{size:18})}),t.jsx("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.ghostBtn} ${a.toolbarButton}`,onClick:()=>{B&&dn()},disabled:!B||!Na,"aria-label":"Reset unsaved changes",title:"Reset unsaved changes",children:t.jsx(zn,{size:18})}),t.jsx("button",{type:"button",className:`tf-button-ghost ${a.toolRailButton} ${a.iconButton}`,onClick:kn,disabled:!d||ue||P<=.25,"aria-label":"Zoom out",children:t.jsx(Un,{size:18})}),t.jsx("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.ghostBtn} ${a.toolbarButton}`,onClick:wn,disabled:!d||ue||P===1,"aria-label":`Reset zoom to 100 percent (currently ${Jt})`,title:`Reset zoom to 100% (currently ${Jt})`,children:t.jsx("span",{children:Jt})}),t.jsx("button",{type:"button",className:`tf-button-ghost ${a.toolRailButton} ${a.iconButton}`,onClick:In,disabled:!d||ue||P>=4,"aria-label":"Zoom in",children:t.jsx(Gn,{size:18})}),t.jsx("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.toolBtn} ${a.toolbarButton} ${W?a.toolBtnActive:""}`,onClick:()=>Qe(e=>!e),disabled:!d||ue||!ke,"aria-label":"Pan canvas",title:"Pan canvas",children:t.jsx(Yn,{size:18})})]}),t.jsx("span",{className:a.toolbarSeparator,"aria-hidden":"true"}),t.jsxs("div",{className:a.toolbarActions,children:[t.jsx("div",{className:a.toolbarSelectionActions,children:z?t.jsxs(t.Fragment,{children:[t.jsxs("div",{ref:ka,className:a.toolbarColorPicker,children:[t.jsx("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.ghostBtn} ${a.toolbarButton} ${a.colorPickerButton}`,onClick:()=>ht(e=>!e),"aria-label":"Marker color","aria-expanded":ft,title:"Marker color",children:t.jsx("span",{className:a.colorPickerSwatch,style:{backgroundColor:Vt},"aria-hidden":"true"})}),ft?t.jsx("div",{className:a.colorPickerPopover,role:"menu","aria-label":"Marker color options",children:No.map(e=>t.jsx("button",{type:"button",className:`${a.colorOption} ${Vt===e?a.colorOptionActive:""}`,style:{backgroundColor:e},onClick:()=>hn(e),"aria-label":`Use marker color ${e}`,"aria-pressed":Vt===e},e))}):null]}),t.jsx("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.ghostBtn} ${a.toolbarButton}`,onClick:Qt,"aria-label":"Delete marker",title:"Delete selected marker",children:t.jsx(Ua,{size:18})}),t.jsx("div",{className:a.toolbarGeometryFields,"aria-label":"Marker geometry percent controls",children:Fo(z).map(e=>t.jsxs("label",{className:a.toolbarGeometryField,children:[t.jsx("span",{className:`tf-text-meta ${a.toolbarGeometryLabel}`,children:e.label}),t.jsx("input",{className:`tf-field-shell ${a.toolbarGeometryInput}`,type:"number",min:0,max:100,step:.1,value:e.value,onChange:n=>{const o=Eo(n.target.value);o!==null&&te(z.id,i=>Lo(i,e.key,o))},"aria-label":`${e.label} percent`})]},e.key))})]}):null}),t.jsxs("div",{className:a.toolbarUtilities,children:[t.jsx("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.ghostBtn} ${a.payloadBtn} ${a.toolbarButton}`,onClick:bn,disabled:!B||gt,"aria-label":gt?"Loading payload preview":"Preview payload",title:gt?"Loading payload preview":"Preview payload",children:t.jsx(oa,{size:18})}),t.jsx("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.ghostBtn} ${a.toolbarButton}`,onClick:()=>ha(!0),"aria-label":"How to use marker tools",title:"How to use marker tools",children:t.jsx(ia,{size:18})})]})]})]}),t.jsxs("div",{className:a.canvasWorkspace,children:[t.jsx("div",{className:a.canvasToolRail,"aria-label":"Annotation tools",children:Wa.map(e=>{const n=e.icon;return t.jsx("button",{type:"button",className:`tf-button-ghost ${a.toolRailButton} ${T===e.value?a.toolBtnActive:""}`,onClick:()=>pn(e.value),disabled:!d,title:e.label,"aria-label":`${e.label} tool. ${Rt[e.value].short}`,children:t.jsx(n,{size:18})},e.value)})}),t.jsx("div",{className:a.canvasMain,children:t.jsx("div",{ref:Me,className:`tf-scrollbar ${a.canvasScroller}`,children:d?t.jsxs(t.Fragment,{children:[ue&&!Ut?t.jsx("div",{className:a.canvasStatusOverlay,"aria-live":"polite",children:t.jsxs("div",{className:a.canvasStatusCard,children:[t.jsx(Ga,{size:20,className:Da.spinner}),t.jsx("span",{children:"Loading image…"})]})}):null,Ut?t.jsx("div",{className:a.canvasStatusOverlay,"aria-live":"polite",children:t.jsx("div",{className:a.canvasStatusCard,children:t.jsx("span",{children:"Image failed to load."})})}):null,t.jsx("div",{className:a.canvasFrame,children:t.jsxs("div",{className:a.canvasMedia,style:{width:y.width?`${y.width}px`:void 0,height:y.height?`${y.height}px`:void 0},children:[t.jsx("img",{ref:Yt,src:d.path,alt:d.displayName,className:a.canvasImage,onLoad:()=>{const e=Yt.current;et({width:e?.naturalWidth||0,height:e?.naturalHeight||0}),Je(!1),Ze(!1)},onError:()=>{et({width:0,height:0}),Je(!1),Ze(!0)}}),!ue&&!Ut&&B?t.jsxs("div",{ref:va,className:`${a.overlay} ${T==="select"?a.overlaySelect:""} ${W&&ke?a.overlayPan:""}`,onPointerDown:Sn,onPointerMove:Cn,onPointerUp:e=>{Nn(e),$n()},"data-testid":"annotated-attachment-overlay",onPointerLeave:jn,onPointerCancel:Tn,children:[t.jsx("svg",{className:a.overlaySvg,viewBox:qt,preserveAspectRatio:"none","aria-hidden":"true",children:j.filter(e=>e.kind==="arrow").map(e=>{const n=Ro(e,y),o=ra(e),i=S===e.id;return t.jsxs(ta.Fragment,{children:[i?t.jsxs(t.Fragment,{children:[t.jsx("line",{x1:n.shaftX1,y1:n.shaftY1,x2:n.shaftX2,y2:n.shaftY2,stroke:"color-mix(in srgb, var(--surface-elevated) 92%, transparent)",strokeWidth:14,strokeLinecap:"round"}),t.jsx("polygon",{points:n.headPoints,fill:o,stroke:"color-mix(in srgb, var(--surface-elevated) 92%, transparent)",strokeWidth:4,strokeLinejoin:"round"})]}):null,t.jsx("line",{x1:n.shaftX1,y1:n.shaftY1,x2:n.shaftX2,y2:n.shaftY2,stroke:o,strokeWidth:i?10:6,strokeLinecap:"round"}),t.jsx("polygon",{points:n.headPoints,fill:o})]},e.id)})}),t.jsx("svg",{className:a.overlayHitLayer,viewBox:qt,preserveAspectRatio:"none",children:j.filter(e=>e.kind==="arrow").map(e=>t.jsxs(ta.Fragment,{children:[t.jsx("line",{x1:e.x*y.width,y1:e.y*y.height,x2:e.x2*y.width,y2:e.y2*y.height,className:a.arrowHitArea,"data-testid":`annotated-arrow-hit-${e.id}`,"aria-label":`Arrow marker ${Zt.get(e.id)||0}`,onPointerDown:n=>La(n,e),onClick:n=>{n.stopPropagation(),F(e.id)}}),S===e.id?t.jsxs(t.Fragment,{children:[t.jsx("circle",{cx:e.x*y.width,cy:e.y*y.height,r:De.hitRadius,className:a.canvasHandleHit,role:"button",tabIndex:0,"aria-label":"Move arrow tail",onPointerDown:n=>Fa(n,e,"tail")}),t.jsx("circle",{cx:e.x*y.width,cy:e.y*y.height,r:De.visibleRadius,className:a.canvasHandleVisible,"aria-hidden":"true"}),t.jsx("circle",{cx:e.x2*y.width,cy:e.y2*y.height,r:De.hitRadius,className:a.canvasHandleHit,role:"button",tabIndex:0,"aria-label":"Move arrow tip",onPointerDown:n=>Fa(n,e,"tip")}),t.jsx("circle",{cx:e.x2*y.width,cy:e.y2*y.height,r:De.visibleRadius,className:a.canvasHandleVisible,"aria-hidden":"true"})]}):null]},`hit-${e.id}`))}),j.filter(e=>e.kind==="arrow").map(e=>t.jsx("div",{className:`${a.annotationNumberBadge} ${a.arrowNumberBadge}`,style:{left:`${(e.x+e.x2)/2*100}%`,top:`${(e.y+e.y2)/2*100}%`,backgroundColor:ra(e)},"aria-hidden":"true",children:Zt.get(e.id)||0},`arrow-number-${e.id}`)),j.filter(e=>e.kind!=="arrow").map(e=>{const n=ra(e),o=Zt.get(e.id)||0,i={onPointerDown:c=>La(c,e),onClick:c=>{c.stopPropagation(),F(e.id)}};return e.kind==="pin"?t.jsx("button",{type:"button",...i,className:`${a.pin} ${S===e.id?a.selected:""}`,style:{left:`${e.x*100}%`,top:`${e.y*100}%`,backgroundColor:n},children:o},e.id):e.kind==="text-note"?t.jsx("button",{type:"button",...i,className:`${a.note} ${S===e.id?a.selected:""}`,style:{left:`${e.x*100}%`,top:`${e.y*100}%`,backgroundColor:n},children:o},e.id):t.jsxs("div",{className:`${a.box} ${S===e.id?a.selected:""}`,style:{left:`${e.x*100}%`,top:`${e.y*100}%`,width:`${e.width*100}%`,height:`${e.height*100}%`,borderColor:n},children:[t.jsx("span",{className:`${a.annotationNumberBadge} ${a.boxNumberBadge}`,style:{backgroundColor:n},"aria-hidden":"true",children:o}),t.jsx("button",{type:"button",...i,className:a.boxSurface,"aria-label":`Box marker ${o}`})]},e.id)}),t.jsx("svg",{className:a.overlaySvg,viewBox:qt,preserveAspectRatio:"none",children:j.filter(e=>e.kind==="box"&&S===e.id).map(e=>t.jsxs(ta.Fragment,{children:[t.jsx("circle",{cx:(e.x+e.width)*y.width,cy:(e.y+e.height)*y.height,r:De.hitRadius,className:`${a.canvasHandleHit} ${a.canvasResizeHandleHit}`,role:"button",tabIndex:0,"aria-label":"Resize box marker",onPointerDown:n=>Rn(n,e)}),t.jsx("circle",{cx:(e.x+e.width)*y.width,cy:(e.y+e.height)*y.height,r:De.visibleRadius,className:a.canvasHandleVisible,"aria-hidden":"true"})]},`box-handle-${e.id}`))})]}):null]})})]}):t.jsx("div",{className:a.emptyState,children:t.jsx("p",{className:"tf-empty-copy",children:"Select an image attachment to annotate."})})})})]}),t.jsxs("div",{className:a.statusBar,children:[t.jsx("span",{children:Y==="error"?"Save failed. Retry now.":Y==="saving"||Y==="pending"?"Saving…":"Saved"}),ua?t.jsx("span",{children:ua}):t.jsx("span",{children:B?W&&ke?"Drag on the image to pan.":T==="select"?"Select a marker to edit it.":`Click on the image to place a ${T}.`:"Create a session to begin placing markers on this image."}),d&&!B&&an?t.jsx("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.ghostBtn} ${a.toolbarButton}`,onClick:()=>{Ba()},disabled:V||pt,children:V?"Creating…":"Create one now"}):null]})]}),t.jsx("section",{className:`tf-surface-panel ${a.panel} ${a.detailPanel}`,children:B?t.jsxs(t.Fragment,{children:[t.jsxs("div",{className:a.panelHeader,children:[t.jsxs("div",{className:a.panelHeaderText,children:[t.jsx("div",{className:`tf-heading-card ${a.panelTitle}`,children:"Markers"}),t.jsxs("div",{className:"tf-text-secondary",children:[j.length," in this session"]})]}),t.jsxs("div",{className:a.sessionActions,children:[t.jsx("button",{type:"button",className:`tf-control-icon ${a.iconButton}`,onClick:()=>Ea("up"),disabled:!z||Xt<=0,"aria-label":"Move marker up",children:t.jsx(Kn,{size:16})}),t.jsx("button",{type:"button",className:`tf-control-icon ${a.iconButton}`,onClick:()=>Ea("down"),disabled:!z||Xt===-1||Xt>=j.length-1,"aria-label":"Move marker down",children:t.jsx(Xn,{size:16})})]})]}),t.jsx("div",{className:`tf-scrollbar ${a.annotationList}`,children:j.length===0?t.jsx("div",{className:a.detailEmpty,children:t.jsx("p",{className:"tf-empty-copy",children:"Add a marker on the image to begin."})}):j.map((e,n)=>{const o=ko[e.kind],i=wo[e.kind],c=`${i} ${n+1}`,h=So[e.markerType||ce],k=Ya.find(m=>m.value===(e.markerType||ce))?.label||"Review",u=S===e.id;return t.jsxs("div",{className:`tf-surface-elevated ${a.annotationCard} ${u?a.annotationCardActive:""}`,children:[t.jsx("button",{type:"button",className:a.annotationCardButton,onClick:()=>F(e.id),"aria-label":i,children:t.jsxs("div",{className:a.annotationMeta,children:[t.jsx("span",{className:`tf-heading-card ${a.annotationTitle}`,children:c}),t.jsx("span",{className:`tf-text-meta ${a.annotationKind}`,"aria-hidden":"true",children:t.jsx(o,{size:16})})]})}),u?t.jsxs("div",{className:a.annotationInstructionEditor,children:[t.jsx("label",{className:"tf-field-label",htmlFor:"annotated-marker-instruction",children:"Marker instruction"}),t.jsx("textarea",{id:"annotated-marker-instruction",ref:u?_a:null,className:`tf-field-shell ${a.textArea} ${a.annotationInstructionField}`,value:e.instruction,onChange:m=>{te(e.id,_=>({..._,instruction:m.target.value}),600)},onBlur:()=>{E("text")},placeholder:"What should the AI focus on for this marker?"}),t.jsxs("div",{className:a.annotationTypeField,children:[t.jsx("label",{className:"tf-field-label",htmlFor:"annotated-marker-type",children:"Instruction type"}),t.jsx("select",{id:"annotated-marker-type",className:`tf-field-shell ${a.select}`,value:e.markerType||ce,onChange:m=>{te(e.id,_=>Po(_,m.target.value))},children:Ya.map(m=>t.jsx("option",{value:m.value,children:m.label},m.value))})]})]}):t.jsx("button",{type:"button",className:a.annotationInstructionButton,onClick:()=>F(e.id),"aria-label":`Edit ${i} instruction`,children:t.jsxs("div",{className:a.annotationInstructionEditor,children:[t.jsx("div",{className:`tf-text-secondary ${a.annotationInstructionPreview}`,children:e.instruction.trim()||"No marker instruction yet."}),t.jsx("div",{className:a.annotationPreviewFooter,children:t.jsx("span",{className:`tf-text-meta ${a.annotationInstructionTypeIcon}`,"aria-label":`Instruction type: ${k}`,title:k,children:t.jsx(h,{size:16})})})]})})]},e.id)})})]}):t.jsxs("div",{className:a.emptyState,children:[t.jsx("strong",{className:"tf-empty-title",children:"No active session"}),t.jsx("p",{className:"tf-empty-copy",children:"Create or select a session to edit annotations."})]})}),t.jsx(aa,{isOpen:rn,onClose:()=>{qe||(xt(!1),vt(""))},title:"Open Image",size:"sm",children:t.jsxs("form",{className:a.openImageModalBody,onSubmit:e=>{e.preventDefault(),mn()},children:[t.jsx("label",{className:"tf-field-label",htmlFor:"annotated-open-image-reference",children:"Image reference number"}),t.jsx("input",{id:"annotated-open-image-reference",className:`tf-field-shell ${a.textInput} ${a.openImageField}`,value:Dt,onChange:e=>vt(e.target.value),placeholder:"I-24",autoFocus:!0}),t.jsxs("div",{className:a.openImageActions,children:[t.jsx("button",{type:"button",className:"tf-button-ghost tf-button-compact",onClick:()=>{xt(!1),vt("")},disabled:qe,children:"Cancel"}),t.jsx("button",{type:"submit",className:"tf-button-primary tf-button-compact",disabled:qe,children:qe?"Opening…":"Open"})]})]})}),t.jsx(aa,{isOpen:sn,onClose:()=>ha(!1),title:"How To Use Markers",size:"md",children:t.jsx("div",{className:a.markerHelpModalBody,children:Wa.filter(e=>e.value!=="select").map(e=>t.jsxs("div",{className:`tf-surface-inset ${a.markerHelpItem}`,children:[t.jsxs("div",{className:a.markerHelpHeader,children:[t.jsx("strong",{className:"tf-heading-card",children:e.label}),t.jsx("span",{className:"tf-text-meta",children:Rt[e.value].short})]}),t.jsx("p",{className:"tf-text-secondary",children:Rt[e.value].detail}),t.jsx("p",{className:`tf-text-body ${a.markerHelpExample}`,children:Rt[e.value].example})]},e.value))})}),t.jsx(aa,{isOpen:nn,onClose:()=>Lt(!1),title:"AI Payload",size:"lg",children:t.jsxs("div",{className:a.payloadModalBody,children:[t.jsxs("div",{className:a.payloadModalToolbar,children:[t.jsxs("div",{className:a.payloadViewToggle,children:[t.jsx("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.toolBtn} ${Ft==="json"?a.toolBtnActive:""}`,onClick:()=>fa("json"),children:"JSON"}),t.jsx("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.toolBtn} ${Ft==="brief"?a.toolBtnActive:""}`,onClick:()=>fa("brief"),children:"AI Brief"})]}),t.jsxs("div",{className:a.payloadModalActions,children:[t.jsxs("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.ghostBtn}`,onClick:()=>{Ma("json")},disabled:!oe,"aria-label":de==="json"?"Copied JSON":"Copy JSON",title:de==="json"?"Copied JSON":"Copy JSON",children:[de==="json"?t.jsx(la,{size:16}):t.jsx(na,{size:16}),t.jsx("span",{children:"JSON"})]}),t.jsxs("button",{type:"button",className:`tf-button-ghost tf-button-compact ${a.ghostBtn}`,onClick:()=>{Ma("brief")},disabled:!oe,"aria-label":de==="brief"?"Copied AI Brief":"Copy AI Brief",title:de==="brief"?"Copied AI Brief":"Copy AI Brief",children:[de==="brief"?t.jsx(la,{size:16}):t.jsx(na,{size:16}),t.jsx("span",{children:"AI Brief"})]})]})]}),gt?t.jsx("div",{className:a.detailEmpty,children:t.jsx("p",{className:"tf-empty-copy",children:"Loading payload…"})}):oe?t.jsx("pre",{className:`tf-surface-inset tf-scrollbar ${a.payloadModalPreview}`,children:Ft==="json"?JSON.stringify(oe,null,2):Xa(oe)}):t.jsx("div",{className:a.detailEmpty,children:t.jsx("p",{className:"tf-empty-copy",children:"Load a payload preview to inspect the current session contract."})})]})})]})}export{Vo as AnnotatedAttachmentWorkspaceShell};
@@ -0,0 +1,3 @@
1
+ import{r as y,j as e}from"./vendor-react-CKJs5o3c.js";import{t as s,Z as Et,_ as St,$ as pt,a0 as dt,a1 as Lt}from"./index-BWFQ9mGn.js";import{g as Dt}from"./documentReferences-BZB3nMRb.js";import{h as Pt,aM as K,c as X,m as Ut,aN as $t,aI as ut,T as ht,ax as Ft}from"./vendor-icons-CLnehDTw.js";import"./vendor-markdown-BUxTU7dS.js";import"./vendor-dnd-DRzYolkg.js";import"./vendor-router-BbWMxlnO.js";const gt=[".png",".jpg",".jpeg",".webp",".gif",".pdf",".txt",".md",".csv",".json",".doc",".docx",".html",".js",".ts",".tsx",".css",".py",".java",".go",".rs",".sh"].join(","),Rt=new Set(["image/png","image/jpeg","image/webp"]),zt=new Set(gt.split(",").map(o=>o.trim().toLowerCase())),Ot=10*1024*1024,_t=3500;function xt(o){const c=o.trim().toLowerCase(),m=c.lastIndexOf(".");return m===-1?"":c.slice(m)}function J(o){if(o.length===0)return"";const c=o.slice(0,3).join(", "),m=o.length-3;return m>0?`${c}, +${m} more`:c}function Bt(o){return`${o.name.trim().toLowerCase()}::${o.size}::${o.lastModified}`}function Mt(o){return new Promise((c,m)=>{const g=new FileReader;g.onload=()=>c(String(g.result||"")),g.onerror=()=>m(g.error||new Error("Failed to read file")),g.readAsDataURL(o)})}function L(o){return/\.(png|jpe?g|webp|gif)(\?|#|$)/i.test(o)}function Ht(o){const c=o.types;if(!c)return null;for(const m of Array.from(c)){const g=String(m||"").trim().toLowerCase();if(Rt.has(g))return g}return null}function ft(o,c){const m=o.includes("?")?"&":"?";return`${o}${m}download=1&filename=${encodeURIComponent(c)}`}function mt(o){return typeof o=="string"?o.split("/").pop()||"Context file":o.displayName||o.originalFilename||o.caption||o.fsPath||o.path.split("/").pop()||"Context file"}function Kt(o){const c=typeof o=="string"?[o]:[o.originalFilename,o.displayName,o.caption,o.fsPath,o.path];for(const g of c){if(!g)continue;const D=xt(g);if(D)return D.replace(".","").slice(0,5).toUpperCase()}const m=typeof o=="string"?o:o.path;return/^https?:\/\//i.test(m)?"LINK":"FILE"}function Qt(o){const{ownerType:c="task",ownerId:m,ownerReferenceLabel:g,workspaceId:D,attachments:N,onAddAttachment:Y,onRemoveAttachment:G,onUpdateAttachmentCaption:W}=o,v=y.useRef(null),[P,Z]=y.useState(!1),[V,C]=y.useState(null),[$,q]=y.useState(""),[F,A]=y.useState(null),[T,b]=y.useState(null),[R,yt]=y.useState(!1),[wt,z]=y.useState(!1),[Xt,O]=y.useState(0),I=y.useRef(new Set),Q=y.useRef(new Set),tt=t=>(t||"").trim(),U=(t,n)=>{const a=[],r=tt(t),p=tt(n);return r&&a.push(`path:${r}`),p&&a.push(`fs:${p}`),a},et=y.useMemo(()=>{const t=new Set;return N.forEach(n=>{if(typeof n=="string"){U(n).forEach(a=>t.add(a));return}U(n.path,n.fsPath).forEach(a=>t.add(a))}),t},[N]);y.useEffect(()=>{I.current=new Set(et)},[et]);const nt=(t,n)=>n.some(a=>t.has(a)),at=(t,n)=>n.forEach(a=>t.add(a)),E=String(D||"").trim(),j=String(m||"").trim(),st=c==="initiative"?"initiative":c==="workstream"?"workstream":"task",_={ownerType:c,ownerId:j||null,taskId:c==="task"&&j||null},B=(t="application/json")=>{const n={"Content-Type":t};return E&&(n["x-taskforce-workspace-id"]=E),n},ot=(t,n=!0,a=I.current)=>{const r=t.trim();if(!r||!/^https?:\/\//i.test(r))return"invalid";const i=r,f=U(i);if(nt(a,f))return"duplicate";const u=r.split(/[\\/]/).pop()||r;return Y({path:i,caption:u,timestamp:new Date().toISOString()}),at(a,f),n&&q(""),A(null),"added"};y.useEffect(()=>{if(!T)return;const t=window.setTimeout(()=>{b(null)},_t);return()=>window.clearTimeout(t)},[T]);const rt=async t=>{if(t.length===0)return;C(null),b(null);const n=t,a=[],r=[],p=[],i=[],f=new Set(Q.current);n.forEach(x=>{const h=xt(x.name);if(!zt.has(h)){a.push(x.name);return}if(x.size>Ot){r.push(x.name);return}const S=Bt(x);if(f.has(S)){p.push(x.name);return}f.add(S),i.push({file:x,fingerprint:S})});const u=[];if(a.length>0&&u.push(`${a.length} unsupported file${a.length===1?"":"s"} skipped: ${J(a)}.`),r.length>0&&u.push(`${r.length} file${r.length===1?"":"s"} over 10 MB skipped: ${J(r)}.`),p.length>0&&u.push(`${p.length} local duplicate file${p.length===1?"":"s"} skipped before upload: ${J(p)}.`),i.length===0){u.length>0&&b(u.join(" ")),v.current&&(v.current.value="");return}Z(!0);const k=new Set(I.current);let d=0;try{for(const{file:h,fingerprint:S}of i){let l=null;const lt=await fetch("/api/taskforce/context-upload/init",{method:"POST",headers:B(),body:JSON.stringify({originalName:h.name,mimeType:h.type||"application/octet-stream",size:h.size,..._,workspaceId:E||null})});if(lt.ok){const w=await lt.json();if(w?.success&&typeof w?.uploadUrl=="string"&&typeof w?.path=="string"){if(!(await fetch(w.uploadUrl,{method:String(w.method||"PUT"),headers:w.headers||{"Content-Type":h.type||"application/octet-stream"},body:h})).ok)throw new Error(`Upload failed for ${h.name}`);const H=await fetch("/api/taskforce/context-upload/finalize",{method:"POST",headers:B(),body:JSON.stringify({relativePath:w.relativePath,mimeType:h.type||"application/octet-stream",originalName:h.name,size:h.size,..._,workspaceId:E||null})});if(!H.ok){const It=await H.json().catch(()=>({}));throw new Error(It?.error||`Upload failed for ${h.name}`)}l=await H.json().catch(()=>null)}else w?.success&&typeof w?.path=="string"&&(l=w)}if(!l){const w=await Mt(h),M=await fetch("/api/taskforce/context-upload",{method:"POST",headers:B(),body:JSON.stringify({file:w,originalName:h.name,..._,workspaceId:E||null})});if(!M.ok)throw new Error(`Upload failed for ${h.name}`);l=await M.json()}if(!l?.success||!l?.path)throw new Error(`Upload failed for ${h.name}`);const ct=U(l.path,l.fsPath);if(nt(k,ct)){d+=1;continue}Y({path:l.path,fsPath:l.fsPath,caption:typeof l.caption=="string"&&l.caption.trim().length>0?l.caption:h.name,displayName:typeof l.displayName=="string"?l.displayName:void 0,originalFilename:typeof l.originalFilename=="string"?l.originalFilename:h.name,assetId:typeof l.assetId=="string"?l.assetId:void 0,referenceNumber:typeof l.referenceNumber=="number"?l.referenceNumber:null,referenceLabel:typeof l.referenceLabel=="string"?l.referenceLabel:void 0,taskId:c==="task"&&typeof l.taskId=="string"?l.taskId:null,timestamp:typeof l.timestamp=="string"&&l.timestamp.trim().length>0?l.timestamp:new Date().toISOString()}),Lt({workspaceId:E||"default",ownerType:c,ownerId:j||null,taskId:c==="task"&&j||null,reason:"upload"}),at(k,ct),Q.current.add(S)}const x=[...u];d>0&&x.push(`${d} duplicate file${d===1?"":"s"} skipped.`),b(x.length>0?x.join(" "):null),I.current=k}catch(x){C(x instanceof Error?x.message:"Failed to upload context file")}finally{Z(!1),v.current&&(v.current.value="")}},it=async t=>{!t||t.length===0||await rt(Array.from(t))},kt=async()=>{if(C(null),b(null),!navigator.clipboard||typeof navigator.clipboard.read!="function"){C("Clipboard image paste is not available in this browser.");return}try{const t=await navigator.clipboard.read(),n=[];for(const a of t){const r=Ht(a);if(!r)continue;const p=await a.getType(r),i=r.toLowerCase()==="image/png"?"png":r.toLowerCase()==="image/webp"?"webp":"jpg";n.push(new globalThis.File([p],`pasted-image-${Date.now()}.${i}`,{type:r}))}if(n.length===0){C("Clipboard does not currently contain a supported image.");return}await rt(n)}catch(t){C(t?.message||"Failed to read an image from the clipboard.")}},bt=t=>{const n=new Set,a=t.dataTransfer.getData("text/uri-list")||"",r=t.dataTransfer.getData("text/plain")||"",p=`${a}
2
+ ${r}`.split(`
3
+ `).map(i=>i.trim()).filter(i=>!!i&&!i.startsWith("#"));for(const i of p){if(/^file:\/\//i.test(i)){try{const f=new URL(i),u=decodeURIComponent(f.pathname||"").trim();u&&n.add(u)}catch{}continue}n.add(i)}return Array.from(n)},jt=t=>{if(t.preventDefault(),t.stopPropagation(),z(!1),O(0),C(null),A(null),b(null),t.dataTransfer.files&&t.dataTransfer.files.length>0){it(t.dataTransfer.files);return}const n=bt(t);if(n.length===0){A("Drop a file or URL.");return}const a=new Set(I.current);let r=0,p=0,i=0;n.forEach(u=>{const k=ot(u,!1,a);k==="duplicate"&&(r+=1),k==="added"&&(p+=1),k==="invalid"&&(i+=1)});const f=[];r>0&&f.push(`${r} duplicate link${r===1?"":"s"} skipped.`),i>0&&f.push(`${i} local path${i===1?"":"s"} skipped. Upload files to attach them, or drop an http(s) URL to link.`),b(f.length>0?f.join(" "):p>0?null:T),I.current=a},Nt=t=>{t.preventDefault(),t.stopPropagation(),O(n=>n+1),z(!0)},Ct=t=>{t.preventDefault(),t.stopPropagation(),O(n=>{const a=Math.max(0,n-1);return a===0&&z(!1),a})},vt=t=>{t.preventDefault(),t.stopPropagation(),t.dataTransfer.dropEffect="copy"},At=N.filter(t=>{const n=typeof t=="string"?t:t.path;return L(n)}),Tt=N.filter(t=>{const n=typeof t=="string"?t:t.path;return!L(n)});return e.jsxs("div",{className:s.specialistSection,children:[e.jsx(Et,{label:"Context Documents",count:N.length,expanded:R,expandedTitle:"Hide context documents",collapsedTitle:"Show context documents",onToggle:()=>yt(!R)}),R&&e.jsxs(e.Fragment,{children:[e.jsxs("p",{className:s.settingsHint,children:["Upload files into ",st," context storage, or add an external http(s) URL."]}),e.jsxs("div",{className:s.contextUploadPanel,children:[e.jsxs("div",{className:s.contextUploadActions,children:[e.jsxs("button",{type:"button",className:s.secondaryHeaderBtn,onClick:()=>v.current?.click(),disabled:P,children:[P?e.jsx(Pt,{size:12,className:s.spinner}):e.jsx(K,{size:12}),P?"Uploading...":"Upload File"]}),e.jsxs("button",{type:"button",className:s.secondaryHeaderBtn,onClick:()=>{kt()},disabled:P,children:[e.jsx(X,{size:12}),"Paste Image from Clipboard"]})]}),e.jsx("input",{ref:v,type:"file",accept:gt,multiple:!0,className:s.hiddenInput,onChange:t=>{it(t.target.files)}}),V&&e.jsx("div",{className:s.error,children:V}),e.jsxs("div",{className:s.contextLinkRow,children:[e.jsx("input",{type:"text",className:s.input,placeholder:"Add external URL (https://...)",value:$,onChange:t=>{q(t.target.value),F&&A(null),T&&b(null)}}),e.jsx("button",{type:"button",className:s.secondaryHeaderBtn,onClick:()=>{if(!$.trim()){A("Enter an http(s) URL to link.");return}const t=ot($,!0);if(t==="invalid"){A("Only external http(s) URLs can be linked here. Upload files to attach them.");return}t==="duplicate"?b(`Link already exists in ${st} context.`):t==="added"&&b(null)},children:"Add URL"})]}),e.jsxs("div",{className:`${s.contextDropzone} ${wt?s.contextDropzoneActive:""}`,onDragEnter:Nt,onDragLeave:Ct,onDragOver:vt,onDrop:jt,children:[e.jsx(K,{size:14}),e.jsx("span",{children:"Drop files or URLs here"})]})]}),T&&e.jsx("div",{className:s.contextNotice,children:T}),F&&e.jsx("div",{className:s.error,children:F}),At.length>0&&e.jsx("div",{className:s.attachmentGrid,children:N.map((t,n)=>{const a=typeof t=="string"?t:t.path;if(!L(a))return null;const r=typeof t=="string"?void 0:t.fsPath,p=typeof t=="string"?"":t.caption||"",i=mt(t),f=L(a),u=/^https?:\/\//i.test(a),k=c==="task"&&St(t);return e.jsxs("div",{className:s.attachmentCard,children:[e.jsxs("div",{className:s.attachmentPreviewContainer,children:[f?e.jsx("img",{src:a,alt:p||`Context file ${n}`,onClick:()=>{c==="task"&&pt(t,{taskId:j,taskReferenceLabel:g})||window.open(a,"_blank")},onError:d=>{d.target.style.display="none",d.target.parentElement.classList.add(s.brokenImage)}}):e.jsxs("button",{type:"button",className:s.contextFileLink,onClick:()=>{const d=c==="task"?typeof t=="string"?{path:t,taskId:j}:{...t,taskId:j}:t;dt(d,r)||window.open(a,"_blank")},title:"Open file",children:[e.jsx(K,{size:16}),e.jsx("span",{children:p||r||a.split("/").pop()||"Context file"})]}),e.jsxs("div",{className:s.brokenImagePlaceholder,children:[e.jsx(Ut,{size:16}),e.jsx("span",{children:"Preview unavailable"})]}),e.jsxs("div",{className:s.attachmentActions,children:[k&&e.jsx("button",{type:"button",className:s.attachmentActionBtn,onClick:d=>{d.stopPropagation(),pt(t,{taskId:j,taskReferenceLabel:g})},title:"Annotate",children:e.jsx($t,{size:12})}),r&&e.jsx("button",{type:"button",className:s.attachmentActionBtn,onClick:d=>{d.stopPropagation(),navigator.clipboard.writeText(r)},title:`Copy path: ${r}`,children:e.jsx(X,{size:12})}),!u&&e.jsx("button",{type:"button",className:s.attachmentActionBtn,onClick:d=>{d.stopPropagation(),window.open(ft(a,p||i),"_blank")},title:"Download",children:e.jsx(ut,{size:12})}),e.jsx("button",{type:"button",className:s.attachmentActionBtn,onClick:d=>{d.stopPropagation(),G(n)},title:"Delete",children:e.jsx(ht,{size:12})})]})]}),e.jsx("input",{type:"text",className:s.attachmentCaptionInput,placeholder:"Add a label...",value:p,onChange:d=>W(n,d.target.value)})]},n)})}),Tt.length>0&&e.jsx("div",{className:s.documentAttachmentList,children:N.map((t,n)=>{const a=typeof t=="string"?t:t.path;if(L(a))return null;const r=typeof t=="string"?void 0:t.fsPath,p=typeof t=="string"?"":t.caption||"",i=mt(t),f=Kt(t),u=typeof t=="string"?"":Dt(t),k=/^https?:\/\//i.test(a);return e.jsxs("div",{className:s.documentAttachmentItem,children:[e.jsxs("div",{className:s.documentAttachmentRow,children:[e.jsxs("button",{type:"button",className:s.documentAttachmentLink,onClick:()=>{const d=c==="task"?typeof t=="string"?{path:t,taskId:j}:{...t,taskId:j}:t;dt(d,r)||window.open(a,"_blank")},title:i,children:[e.jsxs("span",{className:s.documentAttachmentMain,children:[e.jsx("span",{className:s.documentAttachmentIcon,"aria-hidden":"true",children:e.jsx(Ft,{size:13})}),e.jsxs("span",{className:s.documentAttachmentText,children:[e.jsx("span",{className:s.documentAttachmentName,children:i}),u&&e.jsx("span",{className:s.taskIdBadge,children:u})]})]}),e.jsx("span",{className:s.documentAttachmentType,children:f})]}),e.jsxs("div",{className:s.documentAttachmentActions,children:[r&&e.jsx("button",{type:"button",className:s.documentAttachmentActionBtn,onClick:()=>{navigator.clipboard.writeText(r)},title:`Copy path: ${r}`,children:e.jsx(X,{size:12})}),!k&&e.jsx("button",{type:"button",className:s.documentAttachmentActionBtn,onClick:()=>{window.open(ft(a,p||i),"_blank")},title:"Download",children:e.jsx(ut,{size:12})}),e.jsx("button",{type:"button",className:s.documentAttachmentActionBtn,onClick:()=>G(n),title:"Delete",children:e.jsx(ht,{size:12})})]})]}),e.jsx("input",{type:"text",className:s.documentAttachmentCaptionInput,placeholder:"Add a label...",value:p,onChange:d=>W(n,d.target.value)})]},n)})})]})]})}export{Qt as ContextAttachmentManager};