@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.
- package/README.md +89 -127
- package/dist/TaskforceCore.js +1 -1
- package/dist/components/context/ContextAttachmentManager.js +4 -3
- package/dist/components/features/InitiativesModule.js +1 -1
- package/dist/components/features/TaskSettings.js +1 -1
- package/dist/components/ui/DisclosureSectionHeader.d.ts +12 -0
- package/dist/components/ui/DisclosureSectionHeader.js +8 -0
- package/dist/components/views/PlanComparisonPage.js +1 -1
- package/dist/components/views/StandaloneLayout.js +18 -4
- package/dist/components/views/panels/PlanningDrawer.js +2 -1
- package/dist/components/views/standalone/modals/AccountHubModal.js +1 -1
- package/dist/components/views/standalone/modals/HelpModal.d.ts +3 -1
- package/dist/components/views/standalone/modals/HelpModal.js +17 -2
- package/dist/core/PlanEntitlementService.d.ts +2 -0
- package/dist/core/PlanEntitlementService.js +57 -4
- package/dist/hooks/useFilterSort.js +1 -1
- package/dist/hooks/useTaskforce.js +2 -2
- package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +5 -2
- package/dist/localization/locales/en-US.js +1 -1
- package/dist/localization/locales/es-419.js +1 -1
- package/dist/localization/locales/pt-BR.js +1 -1
- package/dist/mcp/runtime.js +49 -14
- package/dist/server/routes/billing.js +0 -1
- package/dist/ui/assets/AgentsModule-BULqIo8e.js +1 -0
- package/dist/ui/assets/{AnnotatedAttachmentWorkspace-CCckzWYZ.js → AnnotatedAttachmentWorkspace-DHr4rHK9.js} +1 -1
- package/dist/ui/assets/ContextAttachmentManager-DoMe2OpY.js +3 -0
- package/dist/ui/assets/{DocumentWorkspace-BVaWPA25.js → DocumentWorkspace-DumBWhvb.js} +1 -1
- package/dist/ui/assets/{EntityActivityTimeline-DSj0ThaK.js → EntityActivityTimeline-sHk8Nzbq.js} +1 -1
- package/dist/ui/assets/{InitiativesModule-AxMkWtxH.js → InitiativesModule-3X9UNzHh.js} +1 -1
- package/dist/ui/assets/PlansPage-C3A3EYaV.js +1 -0
- package/dist/ui/assets/PlansPage-DeAzWYTb.css +1 -0
- package/dist/ui/assets/{TaskContextUpload-Dw4rTF4i.js → TaskContextUpload-C8G7pWkX.js} +1 -1
- package/dist/ui/assets/{TaskSettings-f2ga42_V.js → TaskSettings-DM1o9Wla.js} +2 -2
- package/dist/ui/assets/{WorkflowsModule-E4UL3mov.js → WorkflowsModule-CW0crzvD.js} +1 -1
- package/dist/ui/assets/documentReferences-BZB3nMRb.js +1 -0
- package/dist/ui/assets/index-BWFQ9mGn.js +5 -0
- package/dist/ui/assets/{index-BvAbqx5Q.css → index-DcK_8tuE.css} +1 -1
- package/dist/ui/assets/{vendor-icons-B32hGuF2.js → vendor-icons-CLnehDTw.js} +1 -1
- package/dist/ui/index.html +3 -3
- package/dist/utils/supportContact.d.ts +9 -0
- package/dist/utils/supportContact.js +32 -0
- package/package.json +12 -4
- package/scripts/postinstall.js +4 -3
- package/dist/TaskforceCore.CategoryFallback.test.d.ts +0 -1
- package/dist/TaskforceCore.CategoryFallback.test.js +0 -101
- package/dist/TaskforceCore.filter-persistence.test.d.ts +0 -1
- package/dist/TaskforceCore.filter-persistence.test.js +0 -402
- package/dist/TaskforceCore.routing.test.d.ts +0 -1
- package/dist/TaskforceCore.routing.test.js +0 -311
- package/dist/TaskforceCore.test.d.ts +0 -1
- package/dist/TaskforceCore.test.js +0 -7910
- package/dist/TaskforceWidget.test.d.ts +0 -1
- package/dist/TaskforceWidget.test.js +0 -92
- package/dist/UnsavedChangesRelaxed.test.d.ts +0 -1
- package/dist/UnsavedChangesRelaxed.test.js +0 -16
- package/dist/__tests__/localizationCatalogs.test.d.ts +0 -1
- package/dist/__tests__/localizationCatalogs.test.js +0 -54
- package/dist/__tests__/workflowSimulation.test.d.ts +0 -1
- package/dist/__tests__/workflowSimulation.test.js +0 -113
- package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.test.d.ts +0 -1
- package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.test.js +0 -278
- package/dist/annotatedAttachments/payload.test.d.ts +0 -1
- package/dist/annotatedAttachments/payload.test.js +0 -67
- package/dist/compat/workspaceSyncCompat.test.d.ts +0 -1
- package/dist/compat/workspaceSyncCompat.test.js +0 -124
- package/dist/components/features/AgentsModule.test.d.ts +0 -1
- package/dist/components/features/AgentsModule.test.js +0 -601
- package/dist/components/features/AnnotatedAttachmentWorkspace.test.d.ts +0 -1
- package/dist/components/features/AnnotatedAttachmentWorkspace.test.js +0 -2883
- package/dist/components/features/DocumentWorkspace.test.d.ts +0 -1
- package/dist/components/features/DocumentWorkspace.test.js +0 -1439
- package/dist/components/features/TaskSettings.test.d.ts +0 -1
- package/dist/components/features/TaskSettings.test.js +0 -1674
- package/dist/components/features/settings/TaxonomyLibraryManager.test.d.ts +0 -1
- package/dist/components/features/settings/TaxonomyLibraryManager.test.js +0 -141
- package/dist/components/task/TaskActionHeader.test.d.ts +0 -1
- package/dist/components/task/TaskActionHeader.test.js +0 -91
- package/dist/components/task/TaskCard.test.d.ts +0 -1
- package/dist/components/task/TaskCard.test.js +0 -513
- package/dist/components/task/TaskContextUpload.test.d.ts +0 -1
- package/dist/components/task/TaskContextUpload.test.js +0 -506
- package/dist/components/task/TaskForm.test.d.ts +0 -1
- package/dist/components/task/TaskForm.test.js +0 -946
- package/dist/components/task/TaskKanban.empty-column-drop.test.d.ts +0 -1
- package/dist/components/task/TaskKanban.empty-column-drop.test.js +0 -66
- package/dist/components/task/TaskKanban.planning-drop.test.d.ts +0 -1
- package/dist/components/task/TaskKanban.planning-drop.test.js +0 -93
- package/dist/components/task/TaskKanban.test.d.ts +0 -1
- package/dist/components/task/TaskKanban.test.js +0 -99
- package/dist/components/task/TaskList.test.d.ts +0 -1
- package/dist/components/task/TaskList.test.js +0 -473
- package/dist/components/task/TaskStatusActions.test.d.ts +0 -1
- package/dist/components/task/TaskStatusActions.test.js +0 -54
- package/dist/components/task/taskKanbanDropRules.test.d.ts +0 -1
- package/dist/components/task/taskKanbanDropRules.test.js +0 -114
- package/dist/components/ui/LevelSelector.test.d.ts +0 -1
- package/dist/components/ui/LevelSelector.test.js +0 -55
- package/dist/components/ui/Markdown.test.d.ts +0 -1
- package/dist/components/ui/Markdown.test.js +0 -38
- package/dist/components/ui/MultiSelectFilter.test.d.ts +0 -1
- package/dist/components/ui/MultiSelectFilter.test.js +0 -74
- package/dist/components/ui/TaxonomyDropdown.test.d.ts +0 -1
- package/dist/components/ui/TaxonomyDropdown.test.js +0 -130
- package/dist/components/ui/TopNoticeLayer.test.d.ts +0 -1
- package/dist/components/ui/TopNoticeLayer.test.js +0 -25
- package/dist/components/views/AppShellHeader.test.d.ts +0 -1
- package/dist/components/views/AppShellHeader.test.js +0 -42
- package/dist/components/views/PlanComparisonPage.test.d.ts +0 -1
- package/dist/components/views/PlanComparisonPage.test.js +0 -757
- package/dist/components/views/PlansPage.test.d.ts +0 -1
- package/dist/components/views/PlansPage.test.js +0 -710
- package/dist/components/views/chrome/WorkspaceChromeSections.test.d.ts +0 -1
- package/dist/components/views/chrome/WorkspaceChromeSections.test.js +0 -54
- package/dist/components/views/chrome/workspaceChrome.test.d.ts +0 -1
- package/dist/components/views/chrome/workspaceChrome.test.js +0 -52
- package/dist/components/views/panels/DocumentFilterToolbar.test.d.ts +0 -1
- package/dist/components/views/panels/DocumentFilterToolbar.test.js +0 -19
- package/dist/components/views/panels/FilterToolbar.test.d.ts +0 -1
- package/dist/components/views/panels/FilterToolbar.test.js +0 -47
- package/dist/components/views/panels/PlanningDrawer.test.d.ts +0 -1
- package/dist/components/views/panels/PlanningDrawer.test.js +0 -529
- package/dist/components/views/planningScope.test.d.ts +0 -1
- package/dist/components/views/planningScope.test.js +0 -60
- package/dist/components/views/standalone/modals/AccountHubModal.test.d.ts +0 -1
- package/dist/components/views/standalone/modals/AccountHubModal.test.js +0 -66
- package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.d.ts +0 -1
- package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.js +0 -24
- package/dist/components/views/teamManagementAccess.test.d.ts +0 -1
- package/dist/components/views/teamManagementAccess.test.js +0 -44
- package/dist/config/deployment.test.d.ts +0 -1
- package/dist/config/deployment.test.js +0 -90
- package/dist/config/envSchema.test.d.ts +0 -1
- package/dist/config/envSchema.test.js +0 -125
- package/dist/core/AiProfileService.test.d.ts +0 -1
- package/dist/core/AiProfileService.test.js +0 -184
- package/dist/core/AiProfiles.test.d.ts +0 -1
- package/dist/core/AiProfiles.test.js +0 -1873
- package/dist/core/AuthTokenService.test.d.ts +0 -1
- package/dist/core/AuthTokenService.test.js +0 -78
- package/dist/core/BulkUpdateFieldsPreview.test.d.ts +0 -1
- package/dist/core/BulkUpdateFieldsPreview.test.js +0 -62
- package/dist/core/CompletedAt.test.d.ts +0 -1
- package/dist/core/CompletedAt.test.js +0 -44
- package/dist/core/CreatedBy.test.d.ts +0 -1
- package/dist/core/CreatedBy.test.js +0 -188
- package/dist/core/DeletedTaskTrash.test.d.ts +0 -1
- package/dist/core/DeletedTaskTrash.test.js +0 -104
- package/dist/core/EntitlementsPolicy.test.d.ts +0 -1
- package/dist/core/EntitlementsPolicy.test.js +0 -280
- package/dist/core/GlobalSettingsService.test.d.ts +0 -1
- package/dist/core/GlobalSettingsService.test.js +0 -45
- package/dist/core/JsonBackupRuntime.test.d.ts +0 -1
- package/dist/core/JsonBackupRuntime.test.js +0 -155
- package/dist/core/PlanFeatureCatalog.test.d.ts +0 -1
- package/dist/core/PlanFeatureCatalog.test.js +0 -139
- package/dist/core/PlanVersionPolicy.test.d.ts +0 -1
- package/dist/core/PlanVersionPolicy.test.js +0 -204
- package/dist/core/PlanningEntities.test.d.ts +0 -1
- package/dist/core/PlanningEntities.test.js +0 -509
- package/dist/core/ScheduleFields.test.d.ts +0 -1
- package/dist/core/ScheduleFields.test.js +0 -193
- package/dist/core/SetupState.test.d.ts +0 -1
- package/dist/core/SetupState.test.js +0 -113
- package/dist/core/SignupMonetizationSettings.test.d.ts +0 -1
- package/dist/core/SignupMonetizationSettings.test.js +0 -515
- package/dist/core/Stats.test.d.ts +0 -1
- package/dist/core/Stats.test.js +0 -36
- package/dist/core/SystemAdmin.test.d.ts +0 -1
- package/dist/core/SystemAdmin.test.js +0 -1106
- package/dist/core/TaskActivitySync.test.d.ts +0 -1
- package/dist/core/TaskActivitySync.test.js +0 -90
- package/dist/core/TaskAttachmentsCanonical.test.d.ts +0 -1
- package/dist/core/TaskAttachmentsCanonical.test.js +0 -356
- package/dist/core/TaskAuditTimeline.test.d.ts +0 -1
- package/dist/core/TaskAuditTimeline.test.js +0 -319
- package/dist/core/TaskTaxonomyValidation.test.d.ts +0 -1
- package/dist/core/TaskTaxonomyValidation.test.js +0 -440
- package/dist/core/Taskforce.ids.test.d.ts +0 -1
- package/dist/core/Taskforce.ids.test.js +0 -611
- package/dist/core/Taskforce.listTasksSlim.test.d.ts +0 -1
- package/dist/core/Taskforce.listTasksSlim.test.js +0 -91
- package/dist/core/Taskforce.mcpAuth.test.d.ts +0 -1
- package/dist/core/Taskforce.mcpAuth.test.js +0 -450
- package/dist/core/Taskforce.realtimeMutation.test.d.ts +0 -1
- package/dist/core/Taskforce.realtimeMutation.test.js +0 -131
- package/dist/core/UserProfileAvatarDrafts.test.d.ts +0 -1
- package/dist/core/UserProfileAvatarDrafts.test.js +0 -138
- package/dist/core/WorkspaceDelete.test.d.ts +0 -1
- package/dist/core/WorkspaceDelete.test.js +0 -159
- package/dist/core/WorkspacePermissions.test.d.ts +0 -1
- package/dist/core/WorkspacePermissions.test.js +0 -270
- package/dist/core/WorkspacePlanMode.test.d.ts +0 -1
- package/dist/core/WorkspacePlanMode.test.js +0 -383
- package/dist/core/WorkspaceSyncSettings.test.d.ts +0 -1
- package/dist/core/WorkspaceSyncSettings.test.js +0 -65
- package/dist/core/__tests__/TaskAttachmentsCanonical.test.d.ts +0 -1
- package/dist/core/__tests__/TaskAttachmentsCanonical.test.js +0 -212
- package/dist/documentReviews/DocumentReviewSessionStore.test.d.ts +0 -1
- package/dist/documentReviews/DocumentReviewSessionStore.test.js +0 -127
- package/dist/hooks/authGuardPolicy.test.d.ts +0 -1
- package/dist/hooks/authGuardPolicy.test.js +0 -76
- package/dist/hooks/bootstrapTimeouts.test.d.ts +0 -1
- package/dist/hooks/bootstrapTimeouts.test.js +0 -12
- package/dist/hooks/sync/controlPlane.test.d.ts +0 -1
- package/dist/hooks/sync/controlPlane.test.js +0 -121
- package/dist/hooks/sync/lifecyclePolicy.test.d.ts +0 -1
- package/dist/hooks/sync/lifecyclePolicy.test.js +0 -124
- package/dist/hooks/sync/orchestratorShared.test.d.ts +0 -1
- package/dist/hooks/sync/orchestratorShared.test.js +0 -98
- package/dist/hooks/sync/pullLifecycle.test.d.ts +0 -1
- package/dist/hooks/sync/pullLifecycle.test.js +0 -80
- package/dist/hooks/sync/recovery.test.d.ts +0 -1
- package/dist/hooks/sync/recovery.test.js +0 -292
- package/dist/hooks/sync/transfers.test.d.ts +0 -1
- package/dist/hooks/sync/transfers.test.js +0 -928
- package/dist/hooks/sync/useRecentSyncEvents.test.d.ts +0 -1
- package/dist/hooks/sync/useRecentSyncEvents.test.js +0 -124
- package/dist/hooks/sync/useSyncStatusActions.test.d.ts +0 -1
- package/dist/hooks/sync/useSyncStatusActions.test.js +0 -133
- package/dist/hooks/sync/useSyncStatusControls.test.d.ts +0 -1
- package/dist/hooks/sync/useSyncStatusControls.test.js +0 -88
- package/dist/hooks/useFilterSort.test.d.ts +0 -1
- package/dist/hooks/useFilterSort.test.js +0 -419
- package/dist/hooks/useRealtimeSync.test.d.ts +0 -1
- package/dist/hooks/useRealtimeSync.test.js +0 -311
- package/dist/hooks/useSyncOrchestrator.aiProfiles.test.d.ts +0 -1
- package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +0 -54
- package/dist/hooks/useSyncOrchestrator.context-assets.test.d.ts +0 -1
- package/dist/hooks/useSyncOrchestrator.context-assets.test.js +0 -228
- package/dist/hooks/useSyncOrchestrator.retry-closure.test.d.ts +0 -1
- package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +0 -2027
- package/dist/hooks/useTaskData.test.d.ts +0 -1
- package/dist/hooks/useTaskData.test.js +0 -291
- package/dist/hooks/useTaskMutations.test.d.ts +0 -1
- package/dist/hooks/useTaskMutations.test.js +0 -256
- package/dist/hooks/useTaskforce.contract.test.d.ts +0 -1
- package/dist/hooks/useTaskforce.contract.test.js +0 -7
- package/dist/hooks/useTaskforce.priority-filters.test.d.ts +0 -1
- package/dist/hooks/useTaskforce.priority-filters.test.js +0 -28
- package/dist/hooks/useTaskforce.runtime-routing.test.d.ts +0 -1
- package/dist/hooks/useTaskforce.runtime-routing.test.js +0 -246
- package/dist/hooks/useTaskforce.sync-behavior.test.d.ts +0 -1
- package/dist/hooks/useTaskforce.sync-behavior.test.js +0 -3644
- package/dist/hooks/useWorkspaceSyncController.test.d.ts +0 -1
- package/dist/hooks/useWorkspaceSyncController.test.js +0 -192
- package/dist/hooks/workspace/useTaskforceApiRouting.test.d.ts +0 -1
- package/dist/hooks/workspace/useTaskforceApiRouting.test.js +0 -77
- package/dist/hooks/workspace/workspaceLocalState.test.d.ts +0 -1
- package/dist/hooks/workspace/workspaceLocalState.test.js +0 -59
- package/dist/localization/localizationCatalogs.test.d.ts +0 -1
- package/dist/localization/localizationCatalogs.test.js +0 -37
- package/dist/mcp/aiProfileBootstrap.test.d.ts +0 -1
- package/dist/mcp/aiProfileBootstrap.test.js +0 -68
- package/dist/mcp/canonicalAssetHelpers.test.d.ts +0 -1
- package/dist/mcp/canonicalAssetHelpers.test.js +0 -67
- package/dist/mcp/clientIntegrations.test.d.ts +0 -1
- package/dist/mcp/clientIntegrations.test.js +0 -219
- package/dist/mcp/optionResolution.test.d.ts +0 -1
- package/dist/mcp/optionResolution.test.js +0 -43
- package/dist/mcp/runtime.test.d.ts +0 -1
- package/dist/mcp/runtime.test.js +0 -5120
- package/dist/mcp/structuredCommentValidation.test.d.ts +0 -1
- package/dist/mcp/structuredCommentValidation.test.js +0 -31
- package/dist/mcp/structuredDocValidation.test.d.ts +0 -1
- package/dist/mcp/structuredDocValidation.test.js +0 -35
- package/dist/mcp/toolRegistry.test.d.ts +0 -1
- package/dist/mcp/toolRegistry.test.js +0 -34
- package/dist/migrations/billingSchemaParity.test.d.ts +0 -1
- package/dist/migrations/billingSchemaParity.test.js +0 -160
- package/dist/migrations/taskSchemaMigrations.test.d.ts +0 -1
- package/dist/migrations/taskSchemaMigrations.test.js +0 -225
- package/dist/qaOpen.test.d.ts +0 -1
- package/dist/qaOpen.test.js +0 -56
- package/dist/releaseVersion.test.d.ts +0 -1
- package/dist/releaseVersion.test.js +0 -32
- package/dist/runtime/appGates.test.d.ts +0 -1
- package/dist/runtime/appGates.test.js +0 -42
- package/dist/server/aiProfileAvatarAssets.test.d.ts +0 -1
- package/dist/server/aiProfileAvatarAssets.test.js +0 -213
- package/dist/server/annotatedAttachmentsRoutes.test.d.ts +0 -1
- package/dist/server/annotatedAttachmentsRoutes.test.js +0 -532
- package/dist/server/auth.test.d.ts +0 -1
- package/dist/server/auth.test.js +0 -131
- package/dist/server/buildInfo.test.d.ts +0 -1
- package/dist/server/buildInfo.test.js +0 -29
- package/dist/server/cors.test.d.ts +0 -1
- package/dist/server/cors.test.js +0 -77
- package/dist/server/documentReviewRoutes.test.d.ts +0 -1
- package/dist/server/documentReviewRoutes.test.js +0 -190
- package/dist/server/email.test.d.ts +0 -1
- package/dist/server/email.test.js +0 -113
- package/dist/server/index.cookieProxy.test.d.ts +0 -1
- package/dist/server/index.cookieProxy.test.js +0 -67
- package/dist/server/index.rateLimit.test.d.ts +0 -1
- package/dist/server/index.rateLimit.test.js +0 -22
- package/dist/server/index.test.d.ts +0 -1
- package/dist/server/index.test.js +0 -283
- package/dist/server/rateLimit.test.d.ts +0 -1
- package/dist/server/rateLimit.test.js +0 -107
- package/dist/server/realtimeSync.auth.test.d.ts +0 -1
- package/dist/server/realtimeSync.auth.test.js +0 -62
- package/dist/server/realtimeSync.replay.test.d.ts +0 -1
- package/dist/server/realtimeSync.replay.test.js +0 -192
- package/dist/server/realtimeSync.workspaceIsolation.test.d.ts +0 -1
- package/dist/server/realtimeSync.workspaceIsolation.test.js +0 -101
- package/dist/server/routes/billing.test.d.ts +0 -1
- package/dist/server/routes/billing.test.js +0 -3455
- package/dist/server/routes/shared.test.d.ts +0 -1
- package/dist/server/routes/shared.test.js +0 -32
- package/dist/server/routes/sync.integration.test.d.ts +0 -1
- package/dist/server/routes/sync.integration.test.js +0 -2932
- package/dist/server/routes/syncAuxRoutes.test.d.ts +0 -1
- package/dist/server/routes/syncAuxRoutes.test.js +0 -158
- package/dist/server/routes/syncRouteGuards.test.d.ts +0 -1
- package/dist/server/routes/syncRouteGuards.test.js +0 -94
- package/dist/server/routes.test.d.ts +0 -1
- package/dist/server/routes.test.js +0 -15612
- package/dist/server/runtimeMode.test.d.ts +0 -1
- package/dist/server/runtimeMode.test.js +0 -26
- package/dist/server/securityHeaders.test.d.ts +0 -1
- package/dist/server/securityHeaders.test.js +0 -70
- package/dist/services/templateEngine.test.d.ts +0 -1
- package/dist/services/templateEngine.test.js +0 -150
- package/dist/services/templates.test.d.ts +0 -1
- package/dist/services/templates.test.js +0 -45
- package/dist/services/workflowDocumentFixtures.test.d.ts +0 -1
- package/dist/services/workflowDocumentFixtures.test.js +0 -78
- package/dist/services/workflowExportMatrix.test.d.ts +0 -1
- package/dist/services/workflowExportMatrix.test.js +0 -113
- package/dist/services/workflowExportSnapshots.test.d.ts +0 -1
- package/dist/services/workflowExportSnapshots.test.js +0 -30
- package/dist/services/workflowGeneration.test.d.ts +0 -1
- package/dist/services/workflowGeneration.test.js +0 -12
- package/dist/services/workflowSimulation.test.d.ts +0 -1
- package/dist/services/workflowSimulation.test.js +0 -113
- package/dist/services/workflowV2Policy.test.d.ts +0 -1
- package/dist/services/workflowV2Policy.test.js +0 -80
- package/dist/shared/customTaxonomyLibrary.test.d.ts +0 -1
- package/dist/shared/customTaxonomyLibrary.test.js +0 -20
- package/dist/shared/passwordPolicy.test.d.ts +0 -1
- package/dist/shared/passwordPolicy.test.js +0 -34
- package/dist/shared/runtimeContract.test.d.ts +0 -1
- package/dist/shared/runtimeContract.test.js +0 -23
- package/dist/shared/taxonomyLibrary.test.d.ts +0 -1
- package/dist/shared/taxonomyLibrary.test.js +0 -26
- package/dist/shared/taxonomyState.test.d.ts +0 -1
- package/dist/shared/taxonomyState.test.js +0 -71
- package/dist/soak/preflight.cli.d.ts +0 -1
- package/dist/soak/preflight.cli.js +0 -28
- package/dist/soak/preflight.d.ts +0 -26
- package/dist/soak/preflight.js +0 -113
- package/dist/soak/preflight.test.d.ts +0 -1
- package/dist/soak/preflight.test.js +0 -39
- package/dist/storage/objectStorageClient.test.d.ts +0 -1
- package/dist/storage/objectStorageClient.test.js +0 -82
- package/dist/storage/objectStorageConfig.test.d.ts +0 -1
- package/dist/storage/objectStorageConfig.test.js +0 -50
- package/dist/storage/postgresAdapter.test.d.ts +0 -1
- package/dist/storage/postgresAdapter.test.js +0 -29
- package/dist/storage/workspaceAssetStore.test.d.ts +0 -1
- package/dist/storage/workspaceAssetStore.test.js +0 -588
- package/dist/sync/cloudSyncApi.test.d.ts +0 -1
- package/dist/sync/cloudSyncApi.test.js +0 -111
- package/dist/sync/collaborationSyncPayload.test.d.ts +0 -1
- package/dist/sync/collaborationSyncPayload.test.js +0 -125
- package/dist/sync/contentSyncPayload.test.d.ts +0 -1
- package/dist/sync/contentSyncPayload.test.js +0 -143
- package/dist/sync/encryptionService.test.d.ts +0 -1
- package/dist/sync/encryptionService.test.js +0 -52
- package/dist/sync/planningSyncPayload.test.d.ts +0 -1
- package/dist/sync/planningSyncPayload.test.js +0 -92
- package/dist/sync/realtimeFeature.test.d.ts +0 -1
- package/dist/sync/realtimeFeature.test.js +0 -30
- package/dist/sync/realtimeReconcile.test.d.ts +0 -1
- package/dist/sync/realtimeReconcile.test.js +0 -43
- package/dist/sync/syncApplyHandlers.test.d.ts +0 -1
- package/dist/sync/syncApplyHandlers.test.js +0 -626
- package/dist/sync/syncService.test.d.ts +0 -1
- package/dist/sync/syncService.test.js +0 -903
- package/dist/sync/taskSyncPayload.test.d.ts +0 -1
- package/dist/sync/taskSyncPayload.test.js +0 -54
- package/dist/sync/workspacePullFeed.test.d.ts +0 -1
- package/dist/sync/workspacePullFeed.test.js +0 -438
- package/dist/sync/workspaceSyncModel.test.d.ts +0 -1
- package/dist/sync/workspaceSyncModel.test.js +0 -1442
- package/dist/test/setup.d.ts +0 -1
- package/dist/test/setup.js +0 -15
- package/dist/ui/assets/AgentsModule-BS4Pi_nC.js +0 -1
- package/dist/ui/assets/ContextAttachmentManager-CfG_ER7C.js +0 -3
- package/dist/ui/assets/PlansPage-B_z-D6Nh.css +0 -1
- package/dist/ui/assets/PlansPage-Ndt7mYfo.js +0 -1
- package/dist/ui/assets/documentReferences-BOUcJm6-.js +0 -1
- package/dist/ui/assets/index-MAHKvFqp.js +0 -4
- package/dist/utils/accountProfileSummaryCache.test.d.ts +0 -1
- package/dist/utils/accountProfileSummaryCache.test.js +0 -63
- package/dist/utils/annotatedAttachments.test.d.ts +0 -1
- package/dist/utils/annotatedAttachments.test.js +0 -108
- package/dist/utils/assignees.test.d.ts +0 -1
- package/dist/utils/assignees.test.js +0 -25
- package/dist/utils/avatarUpload.test.d.ts +0 -1
- package/dist/utils/avatarUpload.test.js +0 -40
- package/dist/utils/canonicalAssetKind.test.d.ts +0 -1
- package/dist/utils/canonicalAssetKind.test.js +0 -24
- package/dist/utils/coalescedRefresh.test.d.ts +0 -1
- package/dist/utils/coalescedRefresh.test.js +0 -30
- package/dist/utils/constants.icons.test.d.ts +0 -1
- package/dist/utils/constants.icons.test.js +0 -41
- package/dist/utils/planParser.test.d.ts +0 -1
- package/dist/utils/planParser.test.js +0 -183
- package/dist/utils/planningReferences.test.d.ts +0 -1
- package/dist/utils/planningReferences.test.js +0 -17
- package/dist/utils/syncEventDetails.test.d.ts +0 -1
- package/dist/utils/syncEventDetails.test.js +0 -23
- package/dist/utils/syncEventPresentation.test.d.ts +0 -1
- package/dist/utils/syncEventPresentation.test.js +0 -64
- package/dist/utils/syncStatusPresentation.test.d.ts +0 -1
- package/dist/utils/syncStatusPresentation.test.js +0 -164
- package/dist/utils/taskActivity.test.d.ts +0 -1
- package/dist/utils/taskActivity.test.js +0 -218
- package/dist/utils/taskDraftDefaults.test.d.ts +0 -1
- package/dist/utils/taskDraftDefaults.test.js +0 -34
- package/dist/utils/taskDragZones.test.d.ts +0 -1
- package/dist/utils/taskDragZones.test.js +0 -14
- package/dist/utils/taskNormalization.test.d.ts +0 -1
- package/dist/utils/taskNormalization.test.js +0 -158
- package/dist/utils/taskSearch.test.d.ts +0 -1
- package/dist/utils/taskSearch.test.js +0 -69
- package/dist/utils/taskUtils.test.d.ts +0 -1
- package/dist/utils/taskUtils.test.js +0 -19
- package/dist/utils/taskforceApiClient.test.d.ts +0 -1
- package/dist/utils/taskforceApiClient.test.js +0 -44
- package/dist/utils/taxonomyFormDefaults.test.d.ts +0 -1
- package/dist/utils/taxonomyFormDefaults.test.js +0 -63
- package/dist/utils/uiNotice.test.d.ts +0 -1
- package/dist/utils/uiNotice.test.js +0 -18
- package/dist/utils/workspaceIdentity.test.d.ts +0 -1
- package/dist/utils/workspaceIdentity.test.js +0 -61
- package/dist/utils/workspaceLifecycle.test.d.ts +0 -1
- package/dist/utils/workspaceLifecycle.test.js +0 -64
- package/dist/utils/workspaceSyncPresentation.test.d.ts +0 -1
- package/dist/utils/workspaceSyncPresentation.test.js +0 -71
- package/scripts/bootstrap-playwright-auth.mjs +0 -155
- package/scripts/check-cloud-mcp.mjs +0 -83
- package/scripts/check-compat-boundaries.mjs +0 -41
- package/scripts/check-env.ts +0 -31
- package/scripts/check-localization-strings.mjs +0 -49
- package/scripts/check-runtime-boundaries.mjs +0 -44
- package/scripts/debug-global.mjs +0 -34
- package/scripts/debug-login.mjs +0 -32
- package/scripts/debug-server.mjs +0 -36
- package/scripts/deploy-prod.sh +0 -41
- package/scripts/deploy-staging.sh +0 -23
- package/scripts/export-sqlite-to-postgres.mjs +0 -123
- package/scripts/generate-env-example.ts +0 -8
- package/scripts/mcp-stdio-adapter.mjs +0 -160
- package/scripts/migrate-task-data-assets.mjs +0 -408
- package/scripts/playwright-auth.sh +0 -19
- package/scripts/qa-open-lib.mjs +0 -175
- package/scripts/qa-open-lib.mjs.d.ts +0 -49
- package/scripts/qa-open.mjs +0 -352
- package/scripts/release-version-lib.mjs +0 -88
- package/scripts/release-version.mjs +0 -72
- package/scripts/run-billing-performance-smoke.sh +0 -24
- package/scripts/run-dev-proxy.sh +0 -51
- package/scripts/run-e2e-realtime.sh +0 -30
- package/scripts/run-smoke.sh +0 -35
- package/scripts/run-soak.sh +0 -41
- package/scripts/test-global.js +0 -143
- package/scripts/update-homebrew-formula.sh +0 -108
- 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
|
|
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
|
|
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('
|
|
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
|
|
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
|
|
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
|
|
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
|
|
95
|
+
helpTutorial: 'Ajuda e suporte',
|
|
96
96
|
settings: 'Configuracoes',
|
|
97
97
|
filtersCaps: 'FILTROS:',
|
|
98
98
|
categoryLabel: 'Categoria',
|
package/dist/mcp/runtime.js
CHANGED
|
@@ -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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
if (
|
|
79
|
-
|
|
80
|
-
|
|
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
|
-
|
|
86
|
-
|
|
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
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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};
|