@xenosystem/agent-interface-ui 0.1.24 → 0.1.26
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/dist/adapters/agentHostPlatformBridge.d.ts.map +1 -1
- package/dist/adapters/agentHostPlatformBridge.js +96 -16
- package/dist/adapters/agentHostPlatformBridge.js.map +1 -1
- package/dist/adapters/hubAgentPlatformBridge.d.ts.map +1 -1
- package/dist/adapters/hubAgentPlatformBridge.js +2 -0
- package/dist/adapters/hubAgentPlatformBridge.js.map +1 -1
- package/dist/adapters/scopedBackupBridge.d.ts +4 -0
- package/dist/adapters/scopedBackupBridge.d.ts.map +1 -0
- package/dist/adapters/scopedBackupBridge.js +49 -0
- package/dist/adapters/scopedBackupBridge.js.map +1 -0
- package/dist/adapters/xenoAgentCompatibilityBridge.d.ts.map +1 -1
- package/dist/adapters/xenoAgentCompatibilityBridge.js +9 -1
- package/dist/adapters/xenoAgentCompatibilityBridge.js.map +1 -1
- package/dist/agent.css +13227 -0
- package/dist/components/agent/AgentIdentityGenerator.d.ts +16 -0
- package/dist/components/agent/AgentIdentityGenerator.d.ts.map +1 -0
- package/dist/components/agent/AgentIdentityGenerator.js +80 -0
- package/dist/components/agent/AgentIdentityGenerator.js.map +1 -0
- package/dist/components/agent/AgentInterface.d.ts +1 -0
- package/dist/components/agent/AgentInterface.d.ts.map +1 -1
- package/dist/components/agent/AgentInterface.js +1816 -643
- package/dist/components/agent/AgentInterface.js.map +1 -1
- package/dist/components/agent/AgentNotificationBanner.d.ts +10 -0
- package/dist/components/agent/AgentNotificationBanner.d.ts.map +1 -0
- package/dist/components/agent/AgentNotificationBanner.js +28 -0
- package/dist/components/agent/AgentNotificationBanner.js.map +1 -0
- package/dist/components/agent/AgentOnboarding.d.ts +16 -2
- package/dist/components/agent/AgentOnboarding.d.ts.map +1 -1
- package/dist/components/agent/AgentOnboarding.js +93 -201
- package/dist/components/agent/AgentOnboarding.js.map +1 -1
- package/dist/components/agent/AgentView.d.ts.map +1 -1
- package/dist/components/agent/AgentView.js +533 -308
- package/dist/components/agent/AgentView.js.map +1 -1
- package/dist/components/agent/AgentWorkbenchPanel.d.ts +3 -1
- package/dist/components/agent/AgentWorkbenchPanel.d.ts.map +1 -1
- package/dist/components/agent/AgentWorkbenchPanel.js +3 -2
- package/dist/components/agent/AgentWorkbenchPanel.js.map +1 -1
- package/dist/components/agent/AgentWorkspaceBrowserPanel.d.ts +4 -1
- package/dist/components/agent/AgentWorkspaceBrowserPanel.d.ts.map +1 -1
- package/dist/components/agent/AgentWorkspaceBrowserPanel.js +23 -195
- package/dist/components/agent/AgentWorkspaceBrowserPanel.js.map +1 -1
- package/dist/components/agent/AgentsWorkspaceView.d.ts +12 -0
- package/dist/components/agent/AgentsWorkspaceView.d.ts.map +1 -0
- package/dist/components/agent/AgentsWorkspaceView.js +129 -0
- package/dist/components/agent/AgentsWorkspaceView.js.map +1 -0
- package/dist/components/agent/DevelopmentCoordinationPanel.d.ts +7 -0
- package/dist/components/agent/DevelopmentCoordinationPanel.d.ts.map +1 -1
- package/dist/components/agent/DevelopmentCoordinationPanel.js +57 -49
- package/dist/components/agent/DevelopmentCoordinationPanel.js.map +1 -1
- package/dist/components/agent/KnowledgePanel.d.ts.map +1 -1
- package/dist/components/agent/KnowledgePanel.js +17 -67
- package/dist/components/agent/KnowledgePanel.js.map +1 -1
- package/dist/components/agent/LiveConversationCollaboration.d.ts +27 -0
- package/dist/components/agent/LiveConversationCollaboration.d.ts.map +1 -0
- package/dist/components/agent/LiveConversationCollaboration.js +127 -0
- package/dist/components/agent/LiveConversationCollaboration.js.map +1 -0
- package/dist/components/agent/MonacoDiffWorkbenchEditor.d.ts.map +1 -1
- package/dist/components/agent/MonacoDiffWorkbenchEditor.js +1 -1
- package/dist/components/agent/MonacoDiffWorkbenchEditor.js.map +1 -1
- package/dist/components/agent/MonacoWorkbenchEditor.d.ts.map +1 -1
- package/dist/components/agent/MonacoWorkbenchEditor.js +3 -3
- package/dist/components/agent/MonacoWorkbenchEditor.js.map +1 -1
- package/dist/components/agent/OwnedBrowserController.d.ts +55 -0
- package/dist/components/agent/OwnedBrowserController.d.ts.map +1 -0
- package/dist/components/agent/OwnedBrowserController.js +166 -0
- package/dist/components/agent/OwnedBrowserController.js.map +1 -0
- package/dist/components/agent/OwnedWorkforceView.d.ts +10 -0
- package/dist/components/agent/OwnedWorkforceView.d.ts.map +1 -0
- package/dist/components/agent/OwnedWorkforceView.js +256 -0
- package/dist/components/agent/OwnedWorkforceView.js.map +1 -0
- package/dist/components/agent/PluginManager.d.ts +34 -0
- package/dist/components/agent/PluginManager.d.ts.map +1 -1
- package/dist/components/agent/PluginManager.js +187 -126
- package/dist/components/agent/PluginManager.js.map +1 -1
- package/dist/components/agent/ProjectsWorkspaceView.d.ts +14 -0
- package/dist/components/agent/ProjectsWorkspaceView.d.ts.map +1 -0
- package/dist/components/agent/ProjectsWorkspaceView.js +176 -0
- package/dist/components/agent/ProjectsWorkspaceView.js.map +1 -0
- package/dist/components/agent/RunReviewPanel.d.ts +8 -13
- package/dist/components/agent/RunReviewPanel.d.ts.map +1 -1
- package/dist/components/agent/RunReviewPanel.js +120 -106
- package/dist/components/agent/RunReviewPanel.js.map +1 -1
- package/dist/components/agent/ScheduledWorkspaceView.d.ts +19 -0
- package/dist/components/agent/ScheduledWorkspaceView.d.ts.map +1 -0
- package/dist/components/agent/ScheduledWorkspaceView.js +150 -0
- package/dist/components/agent/ScheduledWorkspaceView.js.map +1 -0
- package/dist/components/agent/SdkSessionPanel.d.ts +25 -0
- package/dist/components/agent/SdkSessionPanel.d.ts.map +1 -0
- package/dist/components/agent/SdkSessionPanel.js +15 -0
- package/dist/components/agent/SdkSessionPanel.js.map +1 -0
- package/dist/components/agent/SlashCommandAutocomplete.d.ts +12 -0
- package/dist/components/agent/SlashCommandAutocomplete.d.ts.map +1 -0
- package/dist/components/agent/SlashCommandAutocomplete.js +33 -0
- package/dist/components/agent/SlashCommandAutocomplete.js.map +1 -0
- package/dist/components/agent/TeamsWorkspaceView.d.ts +12 -0
- package/dist/components/agent/TeamsWorkspaceView.d.ts.map +1 -0
- package/dist/components/agent/TeamsWorkspaceView.js +127 -0
- package/dist/components/agent/TeamsWorkspaceView.js.map +1 -0
- package/dist/components/agent/WorkspacePersistenceNotice.d.ts +3 -0
- package/dist/components/agent/WorkspacePersistenceNotice.d.ts.map +1 -0
- package/dist/components/agent/WorkspacePersistenceNotice.js +23 -0
- package/dist/components/agent/WorkspacePersistenceNotice.js.map +1 -0
- package/dist/components/agent/acp/AcpAgentConfigForm.d.ts +1 -0
- package/dist/components/agent/acp/AcpAgentConfigForm.d.ts.map +1 -1
- package/dist/components/agent/acp/AcpAgentConfigForm.js +47 -14
- package/dist/components/agent/acp/AcpAgentConfigForm.js.map +1 -1
- package/dist/components/agent/acp/AcpAgentDiagnosticsPanel.js +1 -1
- package/dist/components/agent/acp/AcpAgentDiagnosticsPanel.js.map +1 -1
- package/dist/components/agent/acp/AcpAgentManager.d.ts.map +1 -1
- package/dist/components/agent/acp/AcpAgentManager.js +18 -18
- package/dist/components/agent/acp/AcpAgentManager.js.map +1 -1
- package/dist/components/agent/acp/AcpAgentTestResultPanel.js +1 -1
- package/dist/components/agent/acp/AcpAgentTestResultPanel.js.map +1 -1
- package/dist/components/agent/acp/AcpApprovalPanel.js +2 -2
- package/dist/components/agent/acp/AcpApprovalPanel.js.map +1 -1
- package/dist/components/agent/acp/AcpCertificationPanel.js +1 -1
- package/dist/components/agent/acp/AcpCertificationPanel.js.map +1 -1
- package/dist/components/agent/acp/AcpLiveProviderWorkflowPanel.js +1 -1
- package/dist/components/agent/acp/AcpLiveProviderWorkflowPanel.js.map +1 -1
- package/dist/components/agent/acp/AcpProviderManagerPanel.js +1 -1
- package/dist/components/agent/acp/AcpProviderManagerPanel.js.map +1 -1
- package/dist/components/agent/acp/AcpProviderModelsPanel.js +1 -1
- package/dist/components/agent/acp/AcpProviderModelsPanel.js.map +1 -1
- package/dist/components/agent/acp/AcpSupportBundlePanel.js +1 -1
- package/dist/components/agent/acp/AcpSupportBundlePanel.js.map +1 -1
- package/dist/components/agent/collaborationWindow.d.ts +11 -0
- package/dist/components/agent/collaborationWindow.d.ts.map +1 -0
- package/dist/components/agent/collaborationWindow.js +10 -0
- package/dist/components/agent/collaborationWindow.js.map +1 -0
- package/dist/components/agent/conversationCollaborationAppendJournal.d.ts +25 -0
- package/dist/components/agent/conversationCollaborationAppendJournal.d.ts.map +1 -0
- package/dist/components/agent/conversationCollaborationAppendJournal.js +118 -0
- package/dist/components/agent/conversationCollaborationAppendJournal.js.map +1 -0
- package/dist/components/agent/conversationCollaborationController.d.ts +96 -0
- package/dist/components/agent/conversationCollaborationController.d.ts.map +1 -0
- package/dist/components/agent/conversationCollaborationController.js +597 -0
- package/dist/components/agent/conversationCollaborationController.js.map +1 -0
- package/dist/components/agent/destructiveConfirmation.d.ts +76 -0
- package/dist/components/agent/destructiveConfirmation.d.ts.map +1 -0
- package/dist/components/agent/destructiveConfirmation.js +231 -0
- package/dist/components/agent/destructiveConfirmation.js.map +1 -0
- package/dist/components/agent/developmentCoordinationController.d.ts +43 -0
- package/dist/components/agent/developmentCoordinationController.d.ts.map +1 -0
- package/dist/components/agent/developmentCoordinationController.js +94 -0
- package/dist/components/agent/developmentCoordinationController.js.map +1 -0
- package/dist/components/agent/developmentCoordinationProjection.d.ts +24 -0
- package/dist/components/agent/developmentCoordinationProjection.d.ts.map +1 -1
- package/dist/components/agent/developmentCoordinationProjection.js +34 -5
- package/dist/components/agent/developmentCoordinationProjection.js.map +1 -1
- package/dist/components/agent/editorOperationAuthority.d.ts +29 -0
- package/dist/components/agent/editorOperationAuthority.d.ts.map +1 -0
- package/dist/components/agent/editorOperationAuthority.js +73 -0
- package/dist/components/agent/editorOperationAuthority.js.map +1 -0
- package/dist/components/agent/knowledgePagination.d.ts +7 -0
- package/dist/components/agent/knowledgePagination.d.ts.map +1 -0
- package/dist/components/agent/knowledgePagination.js +7 -0
- package/dist/components/agent/knowledgePagination.js.map +1 -0
- package/dist/components/agent/knowledgePanelController.d.ts +32 -0
- package/dist/components/agent/knowledgePanelController.d.ts.map +1 -0
- package/dist/components/agent/knowledgePanelController.js +119 -0
- package/dist/components/agent/knowledgePanelController.js.map +1 -0
- package/dist/components/agent/monacoWorkbenchShared.js +1 -1
- package/dist/components/agent/onboardingModels.d.ts +31 -0
- package/dist/components/agent/onboardingModels.d.ts.map +1 -0
- package/dist/components/agent/onboardingModels.js +107 -0
- package/dist/components/agent/onboardingModels.js.map +1 -0
- package/dist/components/agent/personalConversationScope.d.ts +26 -0
- package/dist/components/agent/personalConversationScope.d.ts.map +1 -0
- package/dist/components/agent/personalConversationScope.js +43 -0
- package/dist/components/agent/personalConversationScope.js.map +1 -0
- package/dist/components/agent/reviewRequestScope.d.ts +16 -0
- package/dist/components/agent/reviewRequestScope.d.ts.map +1 -0
- package/dist/components/agent/reviewRequestScope.js +101 -0
- package/dist/components/agent/reviewRequestScope.js.map +1 -0
- package/dist/components/agent/scheduleCreationAttempt.d.ts +12 -0
- package/dist/components/agent/scheduleCreationAttempt.d.ts.map +1 -0
- package/dist/components/agent/scheduleCreationAttempt.js +30 -0
- package/dist/components/agent/scheduleCreationAttempt.js.map +1 -0
- package/dist/components/agent/settings/EntitySettingsLayout.d.ts +1 -1
- package/dist/components/agent/settings/EntitySettingsLayout.d.ts.map +1 -1
- package/dist/components/agent/settings/EntitySettingsLayout.js +64 -44
- package/dist/components/agent/settings/EntitySettingsLayout.js.map +1 -1
- package/dist/components/agent/settings/SettingsNavigation.d.ts.map +1 -1
- package/dist/components/agent/settings/SettingsNavigation.js +17 -17
- package/dist/components/agent/settings/SettingsNavigation.js.map +1 -1
- package/dist/components/agent/settings/entityArchiveState.d.ts +24 -0
- package/dist/components/agent/settings/entityArchiveState.d.ts.map +1 -0
- package/dist/components/agent/settings/entityArchiveState.js +12 -0
- package/dist/components/agent/settings/entityArchiveState.js.map +1 -0
- package/dist/components/agent/settings/sections/AccessMembersSection.d.ts.map +1 -1
- package/dist/components/agent/settings/sections/AccessMembersSection.js +10 -25
- package/dist/components/agent/settings/sections/AccessMembersSection.js.map +1 -1
- package/dist/components/agent/settings/sections/AccountWorkspacePanel.d.ts +16 -0
- package/dist/components/agent/settings/sections/AccountWorkspacePanel.d.ts.map +1 -0
- package/dist/components/agent/settings/sections/AccountWorkspacePanel.js +265 -0
- package/dist/components/agent/settings/sections/AccountWorkspacePanel.js.map +1 -0
- package/dist/components/agent/settings/sections/AgentPermissionRulesPanel.d.ts.map +1 -1
- package/dist/components/agent/settings/sections/AgentPermissionRulesPanel.js +47 -32
- package/dist/components/agent/settings/sections/AgentPermissionRulesPanel.js.map +1 -1
- package/dist/components/agent/settings/sections/DangerZoneSection.d.ts.map +1 -1
- package/dist/components/agent/settings/sections/DangerZoneSection.js +30 -6
- package/dist/components/agent/settings/sections/DangerZoneSection.js.map +1 -1
- package/dist/components/agent/settings/sections/DefaultAgentConfigSection.d.ts.map +1 -1
- package/dist/components/agent/settings/sections/DefaultAgentConfigSection.js +47 -37
- package/dist/components/agent/settings/sections/DefaultAgentConfigSection.js.map +1 -1
- package/dist/components/agent/settings/sections/EnvironmentSecretsSection.d.ts.map +1 -1
- package/dist/components/agent/settings/sections/EnvironmentSecretsSection.js +30 -43
- package/dist/components/agent/settings/sections/EnvironmentSecretsSection.js.map +1 -1
- package/dist/components/agent/settings/sections/ExportBackupSection.d.ts +3 -1
- package/dist/components/agent/settings/sections/ExportBackupSection.d.ts.map +1 -1
- package/dist/components/agent/settings/sections/ExportBackupSection.js +14 -12
- package/dist/components/agent/settings/sections/ExportBackupSection.js.map +1 -1
- package/dist/components/agent/settings/sections/GeneralSection.d.ts.map +1 -1
- package/dist/components/agent/settings/sections/GeneralSection.js +47 -4
- package/dist/components/agent/settings/sections/GeneralSection.js.map +1 -1
- package/dist/components/agent/settings/sections/IntegrationsSection.d.ts.map +1 -1
- package/dist/components/agent/settings/sections/IntegrationsSection.js +14 -21
- package/dist/components/agent/settings/sections/IntegrationsSection.js.map +1 -1
- package/dist/components/agent/settings/sections/NotificationsSection.d.ts.map +1 -1
- package/dist/components/agent/settings/sections/NotificationsSection.js +125 -20
- package/dist/components/agent/settings/sections/NotificationsSection.js.map +1 -1
- package/dist/components/agent/settings/sections/ResourceLimitsSection.d.ts.map +1 -1
- package/dist/components/agent/settings/sections/ResourceLimitsSection.js +7 -7
- package/dist/components/agent/settings/sections/ResourceLimitsSection.js.map +1 -1
- package/dist/components/agent/settings/sections/SecurityComplianceSection.d.ts.map +1 -1
- package/dist/components/agent/settings/sections/SecurityComplianceSection.js +5 -4
- package/dist/components/agent/settings/sections/SecurityComplianceSection.js.map +1 -1
- package/dist/components/agent/settings/sections/UsageAnalyticsSection.d.ts.map +1 -1
- package/dist/components/agent/settings/sections/UsageAnalyticsSection.js +2 -3
- package/dist/components/agent/settings/sections/UsageAnalyticsSection.js.map +1 -1
- package/dist/components/agent/settings/sections/WorkspaceDirectoryAccessSection.d.ts.map +1 -1
- package/dist/components/agent/settings/sections/WorkspaceDirectoryAccessSection.js +39 -26
- package/dist/components/agent/settings/sections/WorkspaceDirectoryAccessSection.js.map +1 -1
- package/dist/components/agent/settings/sections/WorkspaceKeysPanel.d.ts +6 -0
- package/dist/components/agent/settings/sections/WorkspaceKeysPanel.d.ts.map +1 -0
- package/dist/components/agent/settings/sections/WorkspaceKeysPanel.js +205 -0
- package/dist/components/agent/settings/sections/WorkspaceKeysPanel.js.map +1 -0
- package/dist/components/agent/settings/sections/environmentDraftAction.d.ts +3 -0
- package/dist/components/agent/settings/sections/environmentDraftAction.d.ts.map +1 -0
- package/dist/components/agent/settings/sections/environmentDraftAction.js +6 -0
- package/dist/components/agent/settings/sections/environmentDraftAction.js.map +1 -0
- package/dist/components/agent/settings/sections/membershipOperationProjection.d.ts +3 -0
- package/dist/components/agent/settings/sections/membershipOperationProjection.d.ts.map +1 -0
- package/dist/components/agent/settings/sections/membershipOperationProjection.js +9 -0
- package/dist/components/agent/settings/sections/membershipOperationProjection.js.map +1 -0
- package/dist/components/agent/settings/sections/workspaceKeyOperationProjection.d.ts +6 -0
- package/dist/components/agent/settings/sections/workspaceKeyOperationProjection.d.ts.map +1 -0
- package/dist/components/agent/settings/sections/workspaceKeyOperationProjection.js +8 -0
- package/dist/components/agent/settings/sections/workspaceKeyOperationProjection.js.map +1 -0
- package/dist/components/agent/settings/shared/InAppConfirmationDialog.d.ts +25 -0
- package/dist/components/agent/settings/shared/InAppConfirmationDialog.d.ts.map +1 -0
- package/dist/components/agent/settings/shared/InAppConfirmationDialog.js +89 -0
- package/dist/components/agent/settings/shared/InAppConfirmationDialog.js.map +1 -0
- package/dist/components/agent/settings/shared/InputField.d.ts +1 -1
- package/dist/components/agent/settings/shared/InputField.d.ts.map +1 -1
- package/dist/components/agent/settings/shared/InputField.js +4 -3
- package/dist/components/agent/settings/shared/InputField.js.map +1 -1
- package/dist/components/agent/settings/shared/MembersTable.d.ts +3 -3
- package/dist/components/agent/settings/shared/MembersTable.d.ts.map +1 -1
- package/dist/components/agent/settings/shared/MembersTable.js +1 -1
- package/dist/components/agent/settings/shared/MembersTable.js.map +1 -1
- package/dist/components/agent/settings/shared/ScopedAuditPanel.d.ts +5 -0
- package/dist/components/agent/settings/shared/ScopedAuditPanel.d.ts.map +1 -0
- package/dist/components/agent/settings/shared/ScopedAuditPanel.js +70 -0
- package/dist/components/agent/settings/shared/ScopedAuditPanel.js.map +1 -0
- package/dist/components/agent/settings/shared/SettingsCard.d.ts +2 -1
- package/dist/components/agent/settings/shared/SettingsCard.d.ts.map +1 -1
- package/dist/components/agent/settings/shared/SettingsCard.js +2 -2
- package/dist/components/agent/settings/shared/SettingsCard.js.map +1 -1
- package/dist/components/agent/settings/shared/ToggleSwitch.d.ts.map +1 -1
- package/dist/components/agent/settings/shared/ToggleSwitch.js +1 -1
- package/dist/components/agent/settings/shared/ToggleSwitch.js.map +1 -1
- package/dist/components/agent/settings/shared/UsageChart.d.ts +10 -0
- package/dist/components/agent/settings/shared/UsageChart.d.ts.map +1 -1
- package/dist/components/agent/settings/shared/UsageChart.js +16 -10
- package/dist/components/agent/settings/shared/UsageChart.js.map +1 -1
- package/dist/components/agent/settings/shared/WorkspaceRulesControl.d.ts +8 -0
- package/dist/components/agent/settings/shared/WorkspaceRulesControl.d.ts.map +1 -0
- package/dist/components/agent/settings/shared/WorkspaceRulesControl.js +26 -0
- package/dist/components/agent/settings/shared/WorkspaceRulesControl.js.map +1 -0
- package/dist/components/agent/settings/shared/useScopedConfirmation.d.ts +8 -0
- package/dist/components/agent/settings/shared/useScopedConfirmation.d.ts.map +1 -0
- package/dist/components/agent/settings/shared/useScopedConfirmation.js +53 -0
- package/dist/components/agent/settings/shared/useScopedConfirmation.js.map +1 -0
- package/dist/components/agent/settings/shared/useSettingsConfirmation.d.ts +8 -0
- package/dist/components/agent/settings/shared/useSettingsConfirmation.d.ts.map +1 -0
- package/dist/components/agent/settings/shared/useSettingsConfirmation.js +51 -0
- package/dist/components/agent/settings/shared/useSettingsConfirmation.js.map +1 -0
- package/dist/components/agent/settings/shared/workspaceRulesController.d.ts +28 -0
- package/dist/components/agent/settings/shared/workspaceRulesController.d.ts.map +1 -0
- package/dist/components/agent/settings/shared/workspaceRulesController.js +82 -0
- package/dist/components/agent/settings/shared/workspaceRulesController.js.map +1 -0
- package/dist/components/agent/sidebarEntityPins.d.ts +11 -0
- package/dist/components/agent/sidebarEntityPins.d.ts.map +1 -0
- package/dist/components/agent/sidebarEntityPins.js +37 -0
- package/dist/components/agent/sidebarEntityPins.js.map +1 -0
- package/dist/components/agent/workspaceHierarchy.d.ts +24 -0
- package/dist/components/agent/workspaceHierarchy.d.ts.map +1 -0
- package/dist/components/agent/workspaceHierarchy.js +50 -0
- package/dist/components/agent/workspaceHierarchy.js.map +1 -0
- package/dist/components/product/XenoAgentProductHeader.d.ts +4 -2
- package/dist/components/product/XenoAgentProductHeader.d.ts.map +1 -1
- package/dist/components/product/XenoAgentProductHeader.js +22 -4
- package/dist/components/product/XenoAgentProductHeader.js.map +1 -1
- package/dist/components/product/XenoAgentSessionTabs.js +1 -1
- package/dist/components/product/XenoAgentSessionTabs.js.map +1 -1
- package/dist/components/product/XenoAgentWorkspaceSelector.d.ts +7 -0
- package/dist/components/product/XenoAgentWorkspaceSelector.d.ts.map +1 -0
- package/dist/components/product/XenoAgentWorkspaceSelector.js +237 -0
- package/dist/components/product/XenoAgentWorkspaceSelector.js.map +1 -0
- package/dist/components/workspace/WorkspaceCreationWizard.d.ts +6 -0
- package/dist/components/workspace/WorkspaceCreationWizard.d.ts.map +1 -0
- package/dist/components/workspace/WorkspaceCreationWizard.js +48 -0
- package/dist/components/workspace/WorkspaceCreationWizard.js.map +1 -0
- package/dist/hooks/useSidebarLayoutPreference.d.ts +29 -0
- package/dist/hooks/useSidebarLayoutPreference.d.ts.map +1 -0
- package/dist/hooks/useSidebarLayoutPreference.js +83 -0
- package/dist/hooks/useSidebarLayoutPreference.js.map +1 -0
- package/dist/hooks/useWorkspaceCreation.d.ts +8 -0
- package/dist/hooks/useWorkspaceCreation.d.ts.map +1 -0
- package/dist/hooks/useWorkspaceCreation.js +40 -0
- package/dist/hooks/useWorkspaceCreation.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/platformApiTypes.d.ts +77 -36
- package/dist/platformApiTypes.d.ts.map +1 -1
- package/dist/platformBridge.d.ts +4 -0
- package/dist/platformBridge.d.ts.map +1 -1
- package/dist/platformBridge.js +10 -0
- package/dist/platformBridge.js.map +1 -1
- package/dist/stores/agentChatStore.d.ts +120 -2
- package/dist/stores/agentChatStore.d.ts.map +1 -1
- package/dist/stores/agentChatStore.js +344 -35
- package/dist/stores/agentChatStore.js.map +1 -1
- package/dist/stores/agentCreationDefaults.d.ts +25 -0
- package/dist/stores/agentCreationDefaults.d.ts.map +1 -0
- package/dist/stores/agentCreationDefaults.js +11 -0
- package/dist/stores/agentCreationDefaults.js.map +1 -0
- package/dist/stores/entitySettingsStore.d.ts +37 -12
- package/dist/stores/entitySettingsStore.d.ts.map +1 -1
- package/dist/stores/entitySettingsStore.js +558 -585
- package/dist/stores/entitySettingsStore.js.map +1 -1
- package/dist/stores/suggestionStore.d.ts +9 -2
- package/dist/stores/suggestionStore.d.ts.map +1 -1
- package/dist/stores/suggestionStore.js +51 -24
- package/dist/stores/suggestionStore.js.map +1 -1
- package/dist/stores/workspaceCreationAttempt.d.ts +14 -0
- package/dist/stores/workspaceCreationAttempt.d.ts.map +1 -0
- package/dist/stores/workspaceCreationAttempt.js +35 -0
- package/dist/stores/workspaceCreationAttempt.js.map +1 -0
- package/dist/stores/workspaceReconciliation.d.ts +6 -0
- package/dist/stores/workspaceReconciliation.d.ts.map +1 -0
- package/dist/stores/workspaceReconciliation.js +33 -0
- package/dist/stores/workspaceReconciliation.js.map +1 -0
- package/dist/stores/workspaceStore.d.ts +44 -9
- package/dist/stores/workspaceStore.d.ts.map +1 -1
- package/dist/stores/workspaceStore.js +238 -99
- package/dist/stores/workspaceStore.js.map +1 -1
- package/dist/types/agentEditor.d.ts +1 -0
- package/dist/types/agentEditor.d.ts.map +1 -1
- package/dist/utils/advertisedReasoning.d.ts +25 -0
- package/dist/utils/advertisedReasoning.d.ts.map +1 -0
- package/dist/utils/advertisedReasoning.js +62 -0
- package/dist/utils/advertisedReasoning.js.map +1 -0
- package/dist/utils/clipboardCopy.d.ts +4 -0
- package/dist/utils/clipboardCopy.d.ts.map +1 -0
- package/dist/utils/clipboardCopy.js +27 -0
- package/dist/utils/clipboardCopy.js.map +1 -0
- package/dist/utils/providerCommandArgs.d.ts +11 -0
- package/dist/utils/providerCommandArgs.d.ts.map +1 -0
- package/dist/utils/providerCommandArgs.js +18 -0
- package/dist/utils/providerCommandArgs.js.map +1 -0
- package/dist/utils/rendererTeardown.d.ts +6 -0
- package/dist/utils/rendererTeardown.d.ts.map +1 -0
- package/dist/utils/rendererTeardown.js +18 -0
- package/dist/utils/rendererTeardown.js.map +1 -0
- package/package.json +20 -8
- package/src/agent.css +39 -9
|
@@ -11,10 +11,28 @@ import { getAgentPlatformBridge } from '../../platformBridge.js';
|
|
|
11
11
|
*/
|
|
12
12
|
import React, { useState, useMemo, useEffect, useRef, useCallback } from 'react';
|
|
13
13
|
import { createPortal } from 'react-dom';
|
|
14
|
-
import { File, Folder, FolderOpen, GitCompareArrows, Globe2, MoreHorizontal, PanelLeftClose, PanelLeftOpen, PanelRightClose, PanelRightOpen,
|
|
14
|
+
import { ArrowUpRight, BookOpen, Bot, Building2, Check, CheckCircle2, CheckSquare, ChevronDown, ChevronRight, Clock, Code2, Copy, Edit2, File, FileCode, Folder, FolderOpen, FolderPlus, GitBranch, GitCompareArrows, Globe2, Layers, Loader2, MessageSquare, Monitor, MoreHorizontal, Move, Package, PanelLeftClose, PanelLeftOpen, PanelRightClose, PanelRightOpen, Pause, Pin, Play, Plus, Search, Settings, Share2, Sparkles, Terminal, Trash2, Users, X } from 'lucide-react';
|
|
15
15
|
import { EntitySettingsLayout } from './settings/EntitySettingsLayout.js';
|
|
16
|
+
import { WorkspacePersistenceNotice } from './WorkspacePersistenceNotice.js';
|
|
17
|
+
import { EditorOperationAuthority, acknowledgeEditorSave, editorRecoveryFiles, editorSaveFailure, reconcileEditorRefresh, resolveEditorPaneMode } from './editorOperationAuthority.js';
|
|
18
|
+
import { confirmEditorDiscard, editorCloseGuard, engineeringConfirmationActions, usePreparedConfirmation } from './destructiveConfirmation.js';
|
|
19
|
+
import { useSidebarLayoutPreference } from '../../hooks/useSidebarLayoutPreference.js';
|
|
20
|
+
function SidebarLayoutNotice() {
|
|
21
|
+
const { error } = useSidebarLayoutPreference();
|
|
22
|
+
return error ? _jsx("p", { role: "alert", className: "px-4 py-2 text-xs text-red-200", children: error }) : null;
|
|
23
|
+
}
|
|
16
24
|
import { AgentOnboarding } from './AgentOnboarding.js';
|
|
25
|
+
import { WorkspaceCreationAttempt } from '../../stores/workspaceCreationAttempt.js';
|
|
26
|
+
import { validateOnboardingPlacement } from './onboardingModels.js';
|
|
27
|
+
import { entityPinKey, parseEntityPins, toggleEntityPin, SIDEBAR_ENTITY_PINS_KEY } from './sidebarEntityPins.js';
|
|
17
28
|
import { isWideWorkbenchTab } from './AgentWorkbenchPanel.js';
|
|
29
|
+
import { ProjectsWorkspaceView } from './ProjectsWorkspaceView.js';
|
|
30
|
+
import { resolveTeamDirectories, resolveAgentDirectories, resolveWorkspaceScope, projectAssignment } from './workspaceHierarchy.js';
|
|
31
|
+
import { TeamsWorkspaceView } from './TeamsWorkspaceView.js';
|
|
32
|
+
import { AgentsWorkspaceView } from './AgentsWorkspaceView.js';
|
|
33
|
+
import { OwnedWorkforceView } from './OwnedWorkforceView.js';
|
|
34
|
+
import { assertResumeLaunchScope, isPersonalInboxConversation, personalConversationDefaults, scopeFromSdkSessionMetadata } from './personalConversationScope.js';
|
|
35
|
+
import { ScheduledWorkspaceView } from './ScheduledWorkspaceView.js';
|
|
18
36
|
import { PermissionDialog } from './PermissionDialog.js';
|
|
19
37
|
import { runtimeEventSummary } from './runtimeEventSummary.js';
|
|
20
38
|
import { latestContextPressure } from './timelineContextPressure.js';
|
|
@@ -25,6 +43,7 @@ import { planNativeTuiComposerInput, resolveNativeTuiWriterTerminalId } from './
|
|
|
25
43
|
import { createConversationRuntimeBinding, runtimeSelectionForSdk } from '../../utils/conversationRuntime.js';
|
|
26
44
|
import { nativeExecutionPolicyForPermissionProfile, nativeWorkspaceTrustForPermissionProfile, } from '../../utils/acpExecutionAuthority.js';
|
|
27
45
|
import { usePermissionStore } from '../../stores/permissionStore.js';
|
|
46
|
+
import { agentCreationConfiguration } from '../../stores/agentCreationDefaults.js';
|
|
28
47
|
import { useAgentChatStore, loadLocalAgentConversations, projectConversationRuntimeEvents, resetAcpContinuationForWorkspaceChange, } from '../../stores/agentChatStore.js';
|
|
29
48
|
import { useAgentIdeStore } from '../../stores/agentIdeStore.js';
|
|
30
49
|
import { useAgentSearchStore } from '../../stores/agentSearchStore.js';
|
|
@@ -33,6 +52,8 @@ import { useAuthStore } from '../../stores/authStore.js';
|
|
|
33
52
|
import { cycleAgentSessionTabId, nextAgentSessionTabAfterClose, normalizeAgentSessionTabState, orderOpenAgentSessionConversations, reorderAgentSessionTabIds, resolveAgentSessionTabShortcut, } from '../../sessionTabs.js';
|
|
34
53
|
import { XenoAgentProductHeader, } from '../product/XenoAgentProductHeader.js';
|
|
35
54
|
import { XenoAgentSessionTabs, } from '../product/XenoAgentSessionTabs.js';
|
|
55
|
+
import { XenoAgentWorkspaceSelector } from '../product/XenoAgentWorkspaceSelector.js';
|
|
56
|
+
import { WorkspaceCreationWizard } from '../workspace/WorkspaceCreationWizard.js';
|
|
36
57
|
const MonacoWorkbenchEditor = React.lazy(() => import('./MonacoWorkbenchEditor.js'));
|
|
37
58
|
const MonacoDiffWorkbenchEditor = React.lazy(() => import('./MonacoDiffWorkbenchEditor.js'));
|
|
38
59
|
const AgentView = React.lazy(async () => {
|
|
@@ -1060,6 +1081,7 @@ function normalizeCliControlPlaneStatus(value) {
|
|
|
1060
1081
|
}
|
|
1061
1082
|
function normalizeSubagentRunStatus(value) {
|
|
1062
1083
|
return value === 'queued'
|
|
1084
|
+
|| value === 'cancellation-requested'
|
|
1063
1085
|
|| value === 'launch-requested'
|
|
1064
1086
|
|| value === 'running'
|
|
1065
1087
|
|| value === 'waiting-for-permission'
|
|
@@ -1455,7 +1477,7 @@ function normalizeEditorTabs(editorState) {
|
|
|
1455
1477
|
file
|
|
1456
1478
|
}));
|
|
1457
1479
|
}
|
|
1458
|
-
function buildConversationEditorState(tabs, activeTabId) {
|
|
1480
|
+
function buildConversationEditorState(tabs, activeTabId, paneMode) {
|
|
1459
1481
|
const normalizedTabs = tabs.map((tab) => (tab.type === 'diff'
|
|
1460
1482
|
? {
|
|
1461
1483
|
id: tab.id || createDiffTabId(tab.diff.id),
|
|
@@ -1475,6 +1497,7 @@ function buildConversationEditorState(tabs, activeTabId) {
|
|
|
1475
1497
|
? normalizedTabs.find((tab) => tab.id === resolvedActiveTabId && tab.type === 'file')?.file.path || null
|
|
1476
1498
|
: null;
|
|
1477
1499
|
return {
|
|
1500
|
+
paneMode: resolveEditorPaneMode(paneMode, normalizedTabs.length),
|
|
1478
1501
|
openTabs: normalizedTabs,
|
|
1479
1502
|
activeTabId: resolvedActiveTabId,
|
|
1480
1503
|
openFiles,
|
|
@@ -1608,7 +1631,7 @@ function clampRightPanelWidth(width) {
|
|
|
1608
1631
|
: Math.max(RIGHT_PANEL_MIN_WIDTH, Math.min(RIGHT_PANEL_MAX_WIDTH, window.innerWidth - 360));
|
|
1609
1632
|
return Math.min(viewportAwareMax, Math.max(RIGHT_PANEL_MIN_WIDTH, Math.round(width)));
|
|
1610
1633
|
}
|
|
1611
|
-
function FolderSidebar({ conversationId, rootDirectory, allowedDirectories, onOpenFolder, onClose, onOpenFile, activeFilePath, terminalCapabilityEnabled, terminalReady, xenoTuiReady, xenoTuiUnavailableReason, providerSessionTuiReady, providerSessionTuiUnavailableReason, providerSessionTuiLabel, resolvedTerminalCwd, terminalTabs, onPtyInput, onPtyResize, onCreateTerminal, onCreateXenoTui, onCreateProviderTui, onCloseTerminal, onClearTerminal, onRestartTerminal, onStopTerminal, width, onResizeStart, }) {
|
|
1634
|
+
function FolderSidebar({ conversationId, workspaceId, rootDirectory, allowedDirectories, onOpenFolder, onClose, onOpenFile, activeFilePath, terminalCapabilityEnabled, terminalReady, xenoTuiReady, xenoTuiUnavailableReason, providerSessionTuiReady, providerSessionTuiUnavailableReason, providerSessionTuiLabel, resolvedTerminalCwd, terminalTabs, onPtyInput, onPtyResize, onCreateTerminal, onCreateXenoTui, onCreateProviderTui, onCloseTerminal, onClearTerminal, onRestartTerminal, onStopTerminal, width, onResizeStart, }) {
|
|
1612
1635
|
const [rightPanelTab, setRightPanelTab] = useState('files');
|
|
1613
1636
|
const [browserTabs, setBrowserTabs] = useState(() => loadCachedRightPanelBrowserTabs());
|
|
1614
1637
|
const activeBrowserTabId = rightPanelTab.startsWith('browser:') ? rightPanelTab.slice('browser:'.length) : null;
|
|
@@ -1901,7 +1924,7 @@ function FolderSidebar({ conversationId, rootDirectory, allowedDirectories, onOp
|
|
|
1901
1924
|
const visible = activeBrowserTabId === tab.id;
|
|
1902
1925
|
return (_jsx("div", { className: visible
|
|
1903
1926
|
? 'absolute inset-0'
|
|
1904
|
-
: 'absolute inset-0 invisible pointer-events-none opacity-0', "aria-hidden": !visible, children: _jsx(React.Suspense, { fallback: _jsx("div", { className: "h-full bg-[#08080a] px-3 py-2 text-[12px] text-white/40", children: "Loading browser..." }), children: _jsx(AgentWorkspaceBrowserPanel, { browserId: tab.id, browserLabel: tab.label, rootDirectory: effectiveRoot || rootDirectory, allowedDirectories: effectiveAllowedDirectories, onOpenFolder: onOpenFolder }) }) }, tab.id));
|
|
1927
|
+
: 'absolute inset-0 invisible pointer-events-none opacity-0', "aria-hidden": !visible, children: _jsx(React.Suspense, { fallback: _jsx("div", { className: "h-full bg-[#08080a] px-3 py-2 text-[12px] text-white/40", children: "Loading browser..." }), children: _jsx(AgentWorkspaceBrowserPanel, { browserId: tab.id, browserLabel: tab.label, workspaceId: workspaceId, conversationId: conversationId, visible: visible, rootDirectory: effectiveRoot || rootDirectory, allowedDirectories: effectiveAllowedDirectories, onOpenFolder: onOpenFolder }) }) }, tab.id));
|
|
1905
1928
|
}), rightPanelTab === 'files' && effectiveRoot && (_jsxs("div", { children: [_jsxs("button", { type: "button", onClick: () => handleToggleDirectory(effectiveRoot), className: "w-full flex items-center gap-1.5 px-2 py-1.5 text-white/68 hover:text-white hover:bg-white/[0.04] rounded-md transition-colors text-left", children: [_jsx(ChevronDownIcon, { className: `w-3 h-3 flex-shrink-0 transition-transform ${expandedPaths.has(effectiveRoot) ? '' : '-rotate-90'}` }), expandedPaths.has(effectiveRoot) ? (_jsx(FolderOpen, { className: "w-3.5 h-3.5 flex-shrink-0 text-white/55", strokeWidth: 1.8 })) : (_jsx(Folder, { className: "w-3.5 h-3.5 flex-shrink-0 text-white/45", strokeWidth: 1.8 })), _jsx("span", { className: "min-w-0 truncate text-[12px]", children: directoryLeafName(effectiveRoot) })] }), expandedPaths.has(effectiveRoot) && (_jsxs("div", { className: "mt-0.5", children: [isRootLoading && (_jsx(FolderTreeLoadingSkeleton, { depth: 1, rows: 5 })), !isRootLoading && loadErrors[effectiveRoot] && (_jsx("div", { className: "pl-7 py-1 text-[11px] text-red-300/45", children: loadErrors[effectiveRoot] })), !isRootLoading && !loadErrors[effectiveRoot] && (entriesByPath[effectiveRoot] || []).map((entry) => (_jsx(FolderTreeNode, { entry: entry, depth: 1, expandedPaths: expandedPaths, loadingPaths: loadingPaths, loadErrors: loadErrors, entriesByPath: entriesByPath, onToggleDirectory: handleToggleDirectory, onOpenFile: onOpenFile, activeFilePath: activeFilePath }, entry.path)))] }))] })), rightPanelTab === 'files' && !effectiveRoot && (_jsxs("div", { className: "mt-2 rounded-md border border-white/[0.06] bg-white/[0.02] p-3", children: [_jsx("p", { className: "text-[11px] uppercase tracking-[0.18em] text-white/28", children: "Folder Explorer" }), _jsx("p", { className: "mt-2 text-[12px] leading-relaxed text-white/42", children: "Open a folder for this conversation to browse files here and send them into the editor." }), _jsxs("div", { className: "mt-3 space-y-2", children: [_jsx(SkeletonBlock, { className: "h-3 w-[78%]" }), _jsx(SkeletonBlock, { className: "h-3 w-[66%]" }), _jsx(SkeletonBlock, { className: "h-3 w-[72%]" })] })] })), activeTerminalTabId && (_jsx(React.Suspense, { fallback: _jsx("div", { className: "h-full bg-[#050506] px-3 py-2 font-mono text-[12px] text-white/40", children: "Loading terminal..." }), children: _jsx(AgentPtyTerminalPanel, { terminalKey: activeTerminal?.id || null, terminalId: activeTerminal?.terminalId || null, output: activeTerminal?.output || '', terminalCapabilityEnabled: activeTerminal?.kind === 'provider-session' || activeTerminal?.kind === 'xeno-session' ? true : terminalCapabilityEnabled,
|
|
1906
1929
|
// A created control-TUI tab remains renderable even after its
|
|
1907
1930
|
// process exits or its lane moves to reconciliation. Otherwise
|
|
@@ -1911,8 +1934,10 @@ function FolderSidebar({ conversationId, rootDirectory, allowedDirectories, onOp
|
|
|
1911
1934
|
? true
|
|
1912
1935
|
: terminalReady, onInput: (data) => activeTerminal && onPtyInput(activeTerminal.id, data), onResize: (cols, rows) => activeTerminal && onPtyResize(activeTerminal.id, cols, rows) }) }))] })] }));
|
|
1913
1936
|
}
|
|
1914
|
-
function RightSidebarControls({ folderPanelOpen, onOpenFolderPanel, }) {
|
|
1915
|
-
|
|
1937
|
+
function RightSidebarControls({ folderPanelOpen, onOpenFolderPanel, visible = true, }) {
|
|
1938
|
+
if (!visible || folderPanelOpen)
|
|
1939
|
+
return null;
|
|
1940
|
+
return (_jsx("div", { className: "absolute top-2.5 right-3 z-20 flex items-center gap-1.5", children: _jsx("button", { onClick: onOpenFolderPanel, className: "h-7 w-7 rounded-[4px] bg-[#18181a] hover:bg-[#242428] text-[#7f7f86] hover:text-white border border-white/[0.08] flex items-center justify-center transition-colors shadow-xs cursor-pointer", title: "Open right panel (Files & Terminal)", "aria-label": "Open right panel", type: "button", children: _jsx(PanelRightOpen, { className: "w-3.5 h-3.5", strokeWidth: 1.8 }) }) }));
|
|
1916
1941
|
}
|
|
1917
1942
|
function EditorTabs({ tabs, activeTabId, onSelectTab, onCloseTab, }) {
|
|
1918
1943
|
return (_jsxs("div", { className: "h-full min-w-0 flex items-center overflow-hidden", children: [_jsx("div", { className: "h-full w-10 flex-shrink-0 inline-flex items-center justify-center border-r border-white/[0.045] text-white/34", "aria-hidden": "true", children: _jsx(Folder, { className: "w-3.5 h-3.5", strokeWidth: 1.8 }) }), _jsx("div", { className: "h-full min-w-0 flex-1 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", children: _jsx("div", { className: "h-full flex items-center gap-1 px-1.5", children: tabs.map((tab) => {
|
|
@@ -1938,24 +1963,10 @@ const ChevronDownIcon = ({ className = "w-4 h-4" }) => (_jsx("svg", { className:
|
|
|
1938
1963
|
// =============================================================================
|
|
1939
1964
|
function ContextMenuPopup({ menu, workspaces, onClose, onAction, }) {
|
|
1940
1965
|
const menuRef = React.useRef(null);
|
|
1941
|
-
const [
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
onClose();
|
|
1946
|
-
}
|
|
1947
|
-
};
|
|
1948
|
-
const handleEscape = (e) => {
|
|
1949
|
-
if (e.key === 'Escape')
|
|
1950
|
-
onClose();
|
|
1951
|
-
};
|
|
1952
|
-
document.addEventListener('mousedown', handleClickOutside);
|
|
1953
|
-
document.addEventListener('keydown', handleEscape);
|
|
1954
|
-
return () => {
|
|
1955
|
-
document.removeEventListener('mousedown', handleClickOutside);
|
|
1956
|
-
document.removeEventListener('keydown', handleEscape);
|
|
1957
|
-
};
|
|
1958
|
-
}, [onClose]);
|
|
1966
|
+
const [activeSubmenu, setActiveSubmenu] = useState(null);
|
|
1967
|
+
const currentWorkspace = workspaces.find(w => w.id === menu.workspaceId);
|
|
1968
|
+
const currentTeam = currentWorkspace?.teams.find(t => t.id === menu.teamId);
|
|
1969
|
+
const currentAgent = currentTeam?.agents.find(a => a.id === menu.agentId);
|
|
1959
1970
|
// Get available move targets
|
|
1960
1971
|
const getMoveTargets = () => {
|
|
1961
1972
|
if (menu.type === 'agent' && menu.teamId) {
|
|
@@ -1971,10 +1982,248 @@ function ContextMenuPopup({ menu, workspaces, onClose, onAction, }) {
|
|
|
1971
1982
|
return [];
|
|
1972
1983
|
};
|
|
1973
1984
|
const moveTargets = getMoveTargets();
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1985
|
+
// Copy items
|
|
1986
|
+
const copyItems = [
|
|
1987
|
+
{
|
|
1988
|
+
label: menu.type === 'conversation' ? 'Conversation Title' : menu.type === 'agent' ? 'Agent Name' : menu.type === 'team' ? 'Team Name' : 'Workspace Name',
|
|
1989
|
+
action: 'copy-name'
|
|
1990
|
+
},
|
|
1991
|
+
{
|
|
1992
|
+
label: menu.type === 'conversation' ? 'Conversation ID' : menu.type === 'agent' ? 'Agent ID' : menu.type === 'team' ? 'Team ID' : 'Workspace ID',
|
|
1993
|
+
action: 'copy-id'
|
|
1994
|
+
},
|
|
1995
|
+
...(menu.type === 'workspace' && currentWorkspace?.directories?.[0] ? [{ label: 'Root Directory Path', action: 'copy-path' }] : []),
|
|
1996
|
+
...(menu.type === 'conversation' ? [{ label: 'Full Transcript', action: 'copy-transcript' }] : [])
|
|
1997
|
+
];
|
|
1998
|
+
React.useEffect(() => {
|
|
1999
|
+
const handleClickOutside = (e) => {
|
|
2000
|
+
if (menuRef.current && !menuRef.current.contains(e.target)) {
|
|
2001
|
+
onClose();
|
|
2002
|
+
}
|
|
2003
|
+
};
|
|
2004
|
+
const handleKeyDown = (e) => {
|
|
2005
|
+
if (e.key === 'Escape') {
|
|
2006
|
+
onClose();
|
|
2007
|
+
return;
|
|
2008
|
+
}
|
|
2009
|
+
// If activeSubmenu is open, number keys 1-9 trigger submenu items
|
|
2010
|
+
if (activeSubmenu === 'copy') {
|
|
2011
|
+
const num = parseInt(e.key, 10);
|
|
2012
|
+
if (!isNaN(num) && num >= 1 && num <= copyItems.length) {
|
|
2013
|
+
e.preventDefault();
|
|
2014
|
+
onAction(copyItems[num - 1].action);
|
|
2015
|
+
onClose();
|
|
2016
|
+
return;
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
if (activeSubmenu === 'move') {
|
|
2020
|
+
const num = parseInt(e.key, 10);
|
|
2021
|
+
if (!isNaN(num) && num >= 1 && num <= moveTargets.length) {
|
|
2022
|
+
e.preventDefault();
|
|
2023
|
+
const target = moveTargets[num - 1];
|
|
2024
|
+
onAction('move', target.workspaceId, target.teamId);
|
|
2025
|
+
onClose();
|
|
2026
|
+
return;
|
|
2027
|
+
}
|
|
2028
|
+
}
|
|
2029
|
+
// Single-key shortcuts for main menu
|
|
2030
|
+
const key = e.key.toUpperCase();
|
|
2031
|
+
if (menu.type === 'agent') {
|
|
2032
|
+
if (key === 'N') {
|
|
2033
|
+
e.preventDefault();
|
|
2034
|
+
onAction('new-conversation');
|
|
2035
|
+
onClose();
|
|
2036
|
+
}
|
|
2037
|
+
else if (key === 'R') {
|
|
2038
|
+
e.preventDefault();
|
|
2039
|
+
onAction('rename');
|
|
2040
|
+
onClose();
|
|
2041
|
+
}
|
|
2042
|
+
else if (key === 'C') {
|
|
2043
|
+
e.preventDefault();
|
|
2044
|
+
setActiveSubmenu('copy');
|
|
2045
|
+
}
|
|
2046
|
+
else if (key === 'M' && moveTargets.length > 0) {
|
|
2047
|
+
e.preventDefault();
|
|
2048
|
+
setActiveSubmenu('move');
|
|
2049
|
+
}
|
|
2050
|
+
else if (key === 'U') {
|
|
2051
|
+
e.preventDefault();
|
|
2052
|
+
onAction('duplicate');
|
|
2053
|
+
onClose();
|
|
2054
|
+
}
|
|
2055
|
+
else if (key === 'S') {
|
|
2056
|
+
e.preventDefault();
|
|
2057
|
+
onAction('settings');
|
|
2058
|
+
onClose();
|
|
2059
|
+
}
|
|
2060
|
+
else if (key === 'D') {
|
|
2061
|
+
e.preventDefault();
|
|
2062
|
+
onAction('delete');
|
|
2063
|
+
onClose();
|
|
2064
|
+
}
|
|
2065
|
+
}
|
|
2066
|
+
else if (menu.type === 'team') {
|
|
2067
|
+
if (key === 'A') {
|
|
2068
|
+
e.preventDefault();
|
|
2069
|
+
onAction('add-agent');
|
|
2070
|
+
onClose();
|
|
2071
|
+
}
|
|
2072
|
+
else if (key === 'R') {
|
|
2073
|
+
e.preventDefault();
|
|
2074
|
+
onAction('rename');
|
|
2075
|
+
onClose();
|
|
2076
|
+
}
|
|
2077
|
+
else if (key === 'C') {
|
|
2078
|
+
e.preventDefault();
|
|
2079
|
+
setActiveSubmenu('copy');
|
|
2080
|
+
}
|
|
2081
|
+
else if (key === 'M' && moveTargets.length > 0) {
|
|
2082
|
+
e.preventDefault();
|
|
2083
|
+
setActiveSubmenu('move');
|
|
2084
|
+
}
|
|
2085
|
+
else if (key === 'U') {
|
|
2086
|
+
e.preventDefault();
|
|
2087
|
+
onAction('duplicate');
|
|
2088
|
+
onClose();
|
|
2089
|
+
}
|
|
2090
|
+
else if (key === 'S') {
|
|
2091
|
+
e.preventDefault();
|
|
2092
|
+
onAction('settings');
|
|
2093
|
+
onClose();
|
|
2094
|
+
}
|
|
2095
|
+
else if (key === 'D') {
|
|
2096
|
+
e.preventDefault();
|
|
2097
|
+
onAction('delete');
|
|
2098
|
+
onClose();
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
else if (menu.type === 'workspace') {
|
|
2102
|
+
if (key === 'E') {
|
|
2103
|
+
e.preventDefault();
|
|
2104
|
+
onAction('open-explorer');
|
|
2105
|
+
onClose();
|
|
2106
|
+
}
|
|
2107
|
+
else if (key === 'R') {
|
|
2108
|
+
e.preventDefault();
|
|
2109
|
+
onAction('rename');
|
|
2110
|
+
onClose();
|
|
2111
|
+
}
|
|
2112
|
+
else if (key === 'C') {
|
|
2113
|
+
e.preventDefault();
|
|
2114
|
+
setActiveSubmenu('copy');
|
|
2115
|
+
}
|
|
2116
|
+
else if (key === 'F') {
|
|
2117
|
+
e.preventDefault();
|
|
2118
|
+
onAction('add-folder');
|
|
2119
|
+
onClose();
|
|
2120
|
+
}
|
|
2121
|
+
else if (key === 'T') {
|
|
2122
|
+
e.preventDefault();
|
|
2123
|
+
onAction('add-team');
|
|
2124
|
+
onClose();
|
|
2125
|
+
}
|
|
2126
|
+
else if (key === 'U') {
|
|
2127
|
+
e.preventDefault();
|
|
2128
|
+
onAction('duplicate');
|
|
2129
|
+
onClose();
|
|
2130
|
+
}
|
|
2131
|
+
else if (key === 'X') {
|
|
2132
|
+
e.preventDefault();
|
|
2133
|
+
onAction(currentWorkspace?.teams.some(t => !t.isExpanded) ? 'expand' : 'collapse');
|
|
2134
|
+
onClose();
|
|
2135
|
+
}
|
|
2136
|
+
else if (key === 'S') {
|
|
2137
|
+
e.preventDefault();
|
|
2138
|
+
onAction('settings');
|
|
2139
|
+
onClose();
|
|
2140
|
+
}
|
|
2141
|
+
else if (key === 'D') {
|
|
2142
|
+
e.preventDefault();
|
|
2143
|
+
onAction('delete');
|
|
2144
|
+
onClose();
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
else if (menu.type === 'conversation') {
|
|
2148
|
+
if (key === 'R') {
|
|
2149
|
+
e.preventDefault();
|
|
2150
|
+
onAction('rename');
|
|
2151
|
+
onClose();
|
|
2152
|
+
}
|
|
2153
|
+
else if (key === 'C') {
|
|
2154
|
+
e.preventDefault();
|
|
2155
|
+
setActiveSubmenu('copy');
|
|
2156
|
+
}
|
|
2157
|
+
else if (key === 'D') {
|
|
2158
|
+
e.preventDefault();
|
|
2159
|
+
onAction('delete');
|
|
2160
|
+
onClose();
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
};
|
|
2164
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
2165
|
+
document.addEventListener('keydown', handleKeyDown);
|
|
2166
|
+
return () => {
|
|
2167
|
+
document.removeEventListener('mousedown', handleClickOutside);
|
|
2168
|
+
document.removeEventListener('keydown', handleKeyDown);
|
|
2169
|
+
};
|
|
2170
|
+
}, [onClose, activeSubmenu, copyItems, moveTargets, menu.type, currentWorkspace, onAction]);
|
|
2171
|
+
const posX = Math.max(8, Math.min(menu.x, window.innerWidth - 210));
|
|
2172
|
+
const posY = Math.max(8, Math.min(menu.y, window.innerHeight - 340));
|
|
2173
|
+
const opensOnRight = posX + 200 + 190 <= window.innerWidth;
|
|
2174
|
+
const MenuItem = ({ icon: Icon, label, shortcut, onClick, danger = false, hasSubmenu = false, position = 'middle', onMouseEnter, }) => {
|
|
2175
|
+
let radiusClass = 'rounded-[2px]';
|
|
2176
|
+
if (position === 'first')
|
|
2177
|
+
radiusClass = 'rounded-t-[6px] rounded-b-[2px]';
|
|
2178
|
+
else if (position === 'last')
|
|
2179
|
+
radiusClass = 'rounded-b-[6px] rounded-t-[2px]';
|
|
2180
|
+
else if (position === 'single')
|
|
2181
|
+
radiusClass = 'rounded-[6px]';
|
|
2182
|
+
return (_jsxs("button", { type: "button", onClick: onClick, onMouseEnter: onMouseEnter, className: "w-full px-2.5 py-1.5 text-left text-[12px] transition-colors flex items-center gap-2 cursor-pointer select-none " +
|
|
2183
|
+
radiusClass + " " +
|
|
2184
|
+
(danger
|
|
2185
|
+
? "text-red-400 hover:bg-red-500/10 hover:text-red-300"
|
|
2186
|
+
: "text-zinc-300 hover:bg-white/[0.06] hover:text-white"), children: [_jsx(Icon, { className: "w-3.5 h-3.5 flex-shrink-0 " + (danger ? "text-red-400" : "text-zinc-400") }), _jsx("span", { className: "flex-1 truncate", children: label }), shortcut && (_jsx("span", { className: "text-[11px] font-mono text-zinc-500 pl-2 ml-auto flex-shrink-0", children: shortcut })), hasSubmenu && _jsx(ChevronRight, { className: "w-3.5 h-3.5 text-zinc-500 ml-1 flex-shrink-0" })] }));
|
|
2187
|
+
};
|
|
2188
|
+
{ /* SubmenuPanel component with dynamic height comparison */ }
|
|
2189
|
+
const SubmenuPanel = ({ children, width = 'w-[170px]', }) => {
|
|
2190
|
+
const subRef = React.useRef(null);
|
|
2191
|
+
const [extendsBelowParent, setExtendsBelowParent] = React.useState(false);
|
|
2192
|
+
React.useLayoutEffect(() => {
|
|
2193
|
+
if (subRef.current && menuRef.current) {
|
|
2194
|
+
const parentRect = menuRef.current.getBoundingClientRect();
|
|
2195
|
+
const subRect = subRef.current.getBoundingClientRect();
|
|
2196
|
+
setExtendsBelowParent(subRect.bottom > parentRect.bottom + 6);
|
|
2197
|
+
}
|
|
2198
|
+
}, []);
|
|
2199
|
+
return (_jsxs("div", { ref: subRef, className: "absolute top-0 z-[510] " + width + " border border-white/[0.12] bg-[#18181b] p-1 shadow-2xl " + (opensOnRight
|
|
2200
|
+
? (extendsBelowParent ? "left-full ml-2.5 rounded-lg rounded-tl-[2px]" : "left-full ml-2.5 rounded-r-lg rounded-l-[2px]")
|
|
2201
|
+
: (extendsBelowParent ? "right-full mr-2.5 rounded-lg rounded-tr-[2px]" : "right-full mr-2.5 rounded-l-lg rounded-r-[2px]")), children: [_jsx("div", { "aria-hidden": "true", className: "absolute top-0 bottom-0 pointer-events-auto " + (opensOnRight ? "-left-3 w-4" : "-right-3 w-4") }), children(extendsBelowParent)] }));
|
|
2202
|
+
};
|
|
2203
|
+
const getSubmenuItemRadius = (idx, total, extendsBelow) => {
|
|
2204
|
+
const isFirst = idx === 0;
|
|
2205
|
+
const isLast = idx === total - 1;
|
|
2206
|
+
if (isFirst && isLast) {
|
|
2207
|
+
return opensOnRight
|
|
2208
|
+
? (extendsBelow ? 'rounded-lg rounded-tl-[2px]' : 'rounded-r-[6px] rounded-l-[2px]')
|
|
2209
|
+
: (extendsBelow ? 'rounded-lg rounded-tr-[2px]' : 'rounded-l-[6px] rounded-r-[2px]');
|
|
2210
|
+
}
|
|
2211
|
+
if (isFirst) {
|
|
2212
|
+
return opensOnRight
|
|
2213
|
+
? 'rounded-tr-[6px] rounded-tl-[2px] rounded-b-[2px]'
|
|
2214
|
+
: 'rounded-tl-[6px] rounded-tr-[2px] rounded-b-[2px]';
|
|
2215
|
+
}
|
|
2216
|
+
if (isLast) {
|
|
2217
|
+
return opensOnRight
|
|
2218
|
+
? (extendsBelow ? 'rounded-b-[6px] rounded-t-[2px]' : 'rounded-br-[6px] rounded-bl-[2px] rounded-t-[2px]')
|
|
2219
|
+
: (extendsBelow ? 'rounded-b-[6px] rounded-t-[2px]' : 'rounded-bl-[6px] rounded-br-[2px] rounded-t-[2px]');
|
|
2220
|
+
}
|
|
2221
|
+
return 'rounded-[2px]';
|
|
2222
|
+
};
|
|
2223
|
+
return createPortal(_jsxs("div", { ref: menuRef, className: "fixed z-[500] w-[195px] rounded-lg border border-white/[0.12] bg-[#18181b] p-1 shadow-2xl backdrop-blur-md text-[12px] text-zinc-300 select-none animate-in fade-in duration-100", style: { left: posX, top: posY }, children: [menu.type === 'workspace' && (() => {
|
|
2224
|
+
const hasDir = Boolean(currentWorkspace?.directories && currentWorkspace.directories.length > 0);
|
|
2225
|
+
return (_jsxs(_Fragment, { children: [hasDir && (_jsx(MenuItem, { icon: FolderOpen, label: "Open in Explorer", shortcut: "E", position: "first", onClick: () => { onAction('open-explorer'); onClose(); }, onMouseEnter: () => setActiveSubmenu(null) })), _jsx(MenuItem, { icon: Edit2, label: "Rename Workspace", shortcut: "R", position: hasDir ? 'middle' : 'first', onClick: () => { onAction('rename'); onClose(); }, onMouseEnter: () => setActiveSubmenu(null) }), _jsxs("div", { className: "relative", onMouseLeave: () => setActiveSubmenu(null), children: [_jsx(MenuItem, { icon: Copy, label: "Copy", shortcut: "C", hasSubmenu: true, position: "middle", onClick: () => setActiveSubmenu(activeSubmenu === 'copy' ? null : 'copy'), onMouseEnter: () => setActiveSubmenu('copy') }), activeSubmenu === 'copy' && (_jsx(SubmenuPanel, { width: "w-[175px]", children: (extendsBelow) => copyItems.map((item, idx) => (_jsxs("button", { type: "button", onClick: () => { onAction(item.action); onClose(); }, className: "w-full px-2 py-1 text-left text-[11px] text-zinc-300 hover:bg-white/[0.06] hover:text-white transition-colors flex items-center justify-between gap-2 cursor-pointer " + getSubmenuItemRadius(idx, copyItems.length, extendsBelow), children: [_jsxs("div", { className: "flex items-center gap-2 min-w-0 flex-1 truncate", children: [_jsx(Copy, { className: "w-3 h-3 text-zinc-400 flex-shrink-0" }), _jsx("span", { className: "truncate", children: item.label })] }), _jsx("span", { className: "text-[10px] font-mono text-zinc-500 ml-2 flex-shrink-0", children: idx + 1 })] }, item.action))) }))] }), _jsx(MenuItem, { icon: FolderPlus, label: "Add Project Folder...", shortcut: "F", position: "middle", onClick: () => { onAction('add-folder'); onClose(); }, onMouseEnter: () => setActiveSubmenu(null) }), _jsx(MenuItem, { icon: Plus, label: "Add Team", shortcut: "T", position: "middle", onClick: () => { onAction('add-team'); onClose(); }, onMouseEnter: () => setActiveSubmenu(null) }), _jsx(MenuItem, { icon: Copy, label: "Duplicate Workspace", shortcut: "U", position: "middle", onClick: () => { onAction('duplicate'); onClose(); }, onMouseEnter: () => setActiveSubmenu(null) }), _jsx(MenuItem, { icon: Layers, label: currentWorkspace?.teams.some(t => !t.isExpanded) ? "Expand all" : "Collapse all", shortcut: "X", position: "middle", onClick: () => { onAction(currentWorkspace?.teams.some(t => !t.isExpanded) ? 'expand' : 'collapse'); onClose(); }, onMouseEnter: () => setActiveSubmenu(null) }), _jsx("div", { className: "my-1 border-t border-white/[0.06]" }), _jsx(MenuItem, { icon: Settings, label: "Workspace Settings", shortcut: "S", position: "middle", onClick: () => { onAction('settings'); onClose(); }, onMouseEnter: () => setActiveSubmenu(null) }), _jsx("div", { className: "my-1 border-t border-white/[0.06]" }), _jsx(MenuItem, { icon: Trash2, label: "Delete Workspace", shortcut: "D", danger: true, position: "last", onClick: () => { onAction('delete'); onClose(); }, onMouseEnter: () => setActiveSubmenu(null) })] }));
|
|
2226
|
+
})(), menu.type === 'team' && (_jsxs(_Fragment, { children: [_jsx(MenuItem, { icon: Plus, label: "Add Agent to Team", shortcut: "A", position: "first", onClick: () => { onAction('add-agent'); onClose(); }, onMouseEnter: () => setActiveSubmenu(null) }), _jsx(MenuItem, { icon: Edit2, label: "Rename Team", shortcut: "R", position: "middle", onClick: () => { onAction('rename'); onClose(); }, onMouseEnter: () => setActiveSubmenu(null) }), _jsxs("div", { className: "relative", onMouseLeave: () => setActiveSubmenu(null), children: [_jsx(MenuItem, { icon: Copy, label: "Copy", shortcut: "C", hasSubmenu: true, position: "middle", onClick: () => setActiveSubmenu(activeSubmenu === 'copy' ? null : 'copy'), onMouseEnter: () => setActiveSubmenu('copy') }), activeSubmenu === 'copy' && (_jsx(SubmenuPanel, { width: "w-[160px]", children: (extendsBelow) => copyItems.map((item, idx) => (_jsxs("button", { type: "button", onClick: () => { onAction(item.action); onClose(); }, className: "w-full px-2 py-1 text-left text-[11px] text-zinc-300 hover:bg-white/[0.06] hover:text-white transition-colors flex items-center justify-between gap-2 cursor-pointer " + getSubmenuItemRadius(idx, copyItems.length, extendsBelow), children: [_jsxs("div", { className: "flex items-center gap-2 min-w-0 flex-1 truncate", children: [_jsx(Copy, { className: "w-3 h-3 text-zinc-400 flex-shrink-0" }), _jsx("span", { className: "truncate", children: item.label })] }), _jsx("span", { className: "text-[10px] font-mono text-zinc-500 ml-2 flex-shrink-0", children: idx + 1 })] }, item.action))) }))] }), moveTargets.length > 0 && (_jsxs("div", { className: "relative", onMouseLeave: () => setActiveSubmenu(null), children: [_jsx(MenuItem, { icon: Move, label: "Move to workspace", shortcut: "M", hasSubmenu: true, position: "middle", onClick: () => setActiveSubmenu(activeSubmenu === 'move' ? null : 'move'), onMouseEnter: () => setActiveSubmenu('move') }), activeSubmenu === 'move' && (_jsx(SubmenuPanel, { width: "w-[185px]", children: (extendsBelow) => (_jsx("div", { className: "max-h-[220px] overflow-auto", children: moveTargets.map((target, idx) => (_jsxs("button", { type: "button", onClick: () => { onAction('move', target.workspaceId); onClose(); }, className: "w-full px-2 py-1.5 text-left text-[11px] text-zinc-300 hover:bg-white/[0.06] hover:text-white rounded transition-colors flex items-center justify-between gap-2 cursor-pointer " + getSubmenuItemRadius(idx, moveTargets.length, extendsBelow), children: [_jsx("span", { className: "truncate flex-1 min-w-0", children: target.workspaceName }), _jsx("span", { className: "text-[10px] font-mono text-zinc-500 ml-2 flex-shrink-0", children: idx + 1 })] }, target.workspaceId))) })) }))] })), _jsx(MenuItem, { icon: Copy, label: "Duplicate Team", shortcut: "U", position: "middle", onClick: () => { onAction('duplicate'); onClose(); }, onMouseEnter: () => setActiveSubmenu(null) }), _jsx("div", { className: "my-1 border-t border-white/[0.06]" }), _jsx(MenuItem, { icon: Settings, label: "Team Settings", shortcut: "S", position: "middle", onClick: () => { onAction('settings'); onClose(); }, onMouseEnter: () => setActiveSubmenu(null) }), _jsx("div", { className: "my-1 border-t border-white/[0.06]" }), _jsx(MenuItem, { icon: Trash2, label: "Delete Team", shortcut: "D", danger: true, position: "last", onClick: () => { onAction('delete'); onClose(); }, onMouseEnter: () => setActiveSubmenu(null) })] })), menu.type === 'agent' && (_jsxs(_Fragment, { children: [_jsx(MenuItem, { icon: MessageSquare, label: "New Conversation", shortcut: "N", position: "first", onClick: () => { onAction('new-conversation'); onClose(); }, onMouseEnter: () => setActiveSubmenu(null) }), _jsx(MenuItem, { icon: Edit2, label: "Rename Agent", shortcut: "R", position: "middle", onClick: () => { onAction('rename'); onClose(); }, onMouseEnter: () => setActiveSubmenu(null) }), _jsxs("div", { className: "relative", onMouseLeave: () => setActiveSubmenu(null), children: [_jsx(MenuItem, { icon: Copy, label: "Copy", shortcut: "C", hasSubmenu: true, position: "middle", onClick: () => setActiveSubmenu(activeSubmenu === 'copy' ? null : 'copy'), onMouseEnter: () => setActiveSubmenu('copy') }), activeSubmenu === 'copy' && (_jsx(SubmenuPanel, { width: "w-[160px]", children: (extendsBelow) => copyItems.map((item, idx) => (_jsxs("button", { type: "button", onClick: () => { onAction(item.action); onClose(); }, className: "w-full px-2 py-1 text-left text-[11px] text-zinc-300 hover:bg-white/[0.06] hover:text-white transition-colors flex items-center justify-between gap-2 cursor-pointer " + getSubmenuItemRadius(idx, copyItems.length, extendsBelow), children: [_jsxs("div", { className: "flex items-center gap-2 min-w-0 flex-1 truncate", children: [_jsx(Copy, { className: "w-3 h-3 text-zinc-400 flex-shrink-0" }), _jsx("span", { className: "truncate", children: item.label })] }), _jsx("span", { className: "text-[10px] font-mono text-zinc-500 ml-2 flex-shrink-0", children: idx + 1 })] }, item.action))) }))] }), moveTargets.length > 0 && (_jsxs("div", { className: "relative", onMouseLeave: () => setActiveSubmenu(null), children: [_jsx(MenuItem, { icon: Move, label: "Move to team", shortcut: "M", hasSubmenu: true, position: "middle", onClick: () => setActiveSubmenu(activeSubmenu === 'move' ? null : 'move'), onMouseEnter: () => setActiveSubmenu('move') }), activeSubmenu === 'move' && (_jsx(SubmenuPanel, { width: "w-[200px]", children: (extendsBelow) => (_jsx("div", { className: "max-h-[220px] overflow-auto", children: moveTargets.map((target, idx) => (_jsxs("button", { type: "button", onClick: () => { onAction('move', target.workspaceId, target.teamId); onClose(); }, className: "w-full px-2 py-1.5 text-left text-[11px] text-zinc-300 hover:bg-white/[0.06] hover:text-white rounded transition-colors flex items-center justify-between gap-2 cursor-pointer " + getSubmenuItemRadius(idx, moveTargets.length, extendsBelow), children: [_jsxs("span", { className: "truncate flex-1 min-w-0", children: [_jsxs("span", { className: "text-zinc-500", children: [target.workspaceName, " /"] }), " ", target.teamName] }), _jsx("span", { className: "text-[10px] font-mono text-zinc-500 ml-2 flex-shrink-0", children: idx + 1 })] }, `${target.workspaceId}-${target.teamId}`))) })) }))] })), _jsx(MenuItem, { icon: Copy, label: "Duplicate Agent", shortcut: "U", position: "middle", onClick: () => { onAction('duplicate'); onClose(); }, onMouseEnter: () => setActiveSubmenu(null) }), _jsx("div", { className: "my-1 border-t border-white/[0.06]" }), _jsx(MenuItem, { icon: Settings, label: "Agent Settings", shortcut: "S", position: "middle", onClick: () => { onAction('settings'); onClose(); }, onMouseEnter: () => setActiveSubmenu(null) }), _jsx("div", { className: "my-1 border-t border-white/[0.06]" }), _jsx(MenuItem, { icon: Trash2, label: "Delete Agent", shortcut: "D", danger: true, position: "last", onClick: () => { onAction('delete'); onClose(); }, onMouseEnter: () => setActiveSubmenu(null) })] })), menu.type === 'conversation' && (_jsxs(_Fragment, { children: [_jsx(MenuItem, { icon: Edit2, label: "Rename", shortcut: "R", position: "first", onClick: () => { onAction('rename'); onClose(); }, onMouseEnter: () => setActiveSubmenu(null) }), _jsxs("div", { className: "relative", onMouseLeave: () => setActiveSubmenu(null), children: [_jsx(MenuItem, { icon: Copy, label: "Copy", shortcut: "C", hasSubmenu: true, position: "middle", onClick: () => setActiveSubmenu(activeSubmenu === 'copy' ? null : 'copy'), onMouseEnter: () => setActiveSubmenu('copy') }), activeSubmenu === 'copy' && (_jsx(SubmenuPanel, { width: "w-[175px]", children: (extendsBelow) => copyItems.map((item, idx) => (_jsxs("button", { type: "button", onClick: () => { onAction(item.action); onClose(); }, className: "w-full px-2 py-1 text-left text-[11px] text-zinc-300 hover:bg-white/[0.06] hover:text-white transition-colors flex items-center justify-between gap-2 cursor-pointer " + getSubmenuItemRadius(idx, copyItems.length, extendsBelow), children: [_jsxs("div", { className: "flex items-center gap-2 min-w-0 flex-1 truncate", children: [_jsx(Copy, { className: "w-3 h-3 text-zinc-400 flex-shrink-0" }), _jsx("span", { className: "truncate", children: item.label })] }), _jsx("span", { className: "text-[10px] font-mono text-zinc-500 ml-2 flex-shrink-0", children: idx + 1 })] }, item.action))) }))] }), _jsx("div", { className: "my-1 border-t border-white/[0.06]" }), _jsx(MenuItem, { icon: Trash2, label: "Delete Conversation", shortcut: "D", danger: true, position: "last", onClick: () => { onAction('delete'); onClose(); }, onMouseEnter: () => setActiveSubmenu(null) })] }))] }), document.body);
|
|
1978
2227
|
}
|
|
1979
2228
|
// =============================================================================
|
|
1980
2229
|
// SIDEBAR COMPONENT
|
|
@@ -1992,12 +2241,15 @@ function relativeDate(ts) {
|
|
|
1992
2241
|
if (hrs < 24)
|
|
1993
2242
|
return `${hrs}h`;
|
|
1994
2243
|
const days = Math.floor(hrs / 24);
|
|
1995
|
-
if (days <
|
|
2244
|
+
if (days < 7)
|
|
1996
2245
|
return `${days}d`;
|
|
2246
|
+
const weeks = Math.floor(days / 7);
|
|
2247
|
+
if (weeks < 4)
|
|
2248
|
+
return `${weeks}w`;
|
|
1997
2249
|
const months = Math.floor(days / 30);
|
|
1998
2250
|
return `${months}mo`;
|
|
1999
2251
|
}
|
|
2000
|
-
function Sidebar({ collapsed, onToggleCollapse, onOpenSettings, workspaces, setWorkspaces, inboxAgentId, isInboxSelected, selectedInboxConversationId, onSelectInbox, onSelectInboxConversation, selectedAgentId, onSelectAgent, selectedConversationId, onSelectConversation, agentRunAvailability, onSelectPlugins, onSelectKnowledge, onSelectSettings, onOpenSearchResultInEditor, }) {
|
|
2252
|
+
function Sidebar({ collapsed, onToggleCollapse, onOpenSettings, workspaces, setWorkspaces, inboxAgentId, isInboxSelected, selectedInboxConversationId, onSelectInbox, onSelectInboxConversation, selectedAgentId, onSelectAgent, selectedConversationId, onSelectConversation, agentRunAvailability, onSelectPlugins, onSelectKnowledge, onSelectSettings, onSelectProjects, onSelectTeams, onSelectAgents, onSelectScheduled, onStartProjectChat, onOpenSearchResultInEditor, viewMode, isSettingsOpen, }) {
|
|
2001
2253
|
const [isAddingWorkspace, setIsAddingWorkspace] = useState(false);
|
|
2002
2254
|
const [newWorkspaceName, setNewWorkspaceName] = useState('');
|
|
2003
2255
|
const [addingTeamToWorkspace, setAddingTeamToWorkspace] = useState(null);
|
|
@@ -2009,6 +2261,61 @@ function Sidebar({ collapsed, onToggleCollapse, onOpenSettings, workspaces, setW
|
|
|
2009
2261
|
const [convMenuId, setConvMenuId] = useState(null);
|
|
2010
2262
|
const [editingConvId, setEditingConvId] = useState(null);
|
|
2011
2263
|
const [editingConvValue, setEditingConvValue] = useState('');
|
|
2264
|
+
const [pinnedProjects, setPinnedProjects] = useState(() => {
|
|
2265
|
+
try {
|
|
2266
|
+
return JSON.parse(localStorage.getItem('xeno:pinned-projects') || '[]');
|
|
2267
|
+
}
|
|
2268
|
+
catch {
|
|
2269
|
+
return [];
|
|
2270
|
+
}
|
|
2271
|
+
});
|
|
2272
|
+
const [isProjectsCollapsed, setIsProjectsCollapsed] = useState(false);
|
|
2273
|
+
const [entityPins, setEntityPins] = useState([]);
|
|
2274
|
+
const [pinError, setPinError] = useState(null);
|
|
2275
|
+
useEffect(() => {
|
|
2276
|
+
const read = () => {
|
|
2277
|
+
try {
|
|
2278
|
+
setEntityPins(parseEntityPins(localStorage.getItem(SIDEBAR_ENTITY_PINS_KEY)));
|
|
2279
|
+
setPinError(null);
|
|
2280
|
+
}
|
|
2281
|
+
catch {
|
|
2282
|
+
setPinError('Pinned items could not be loaded. Existing preferences were not overwritten.');
|
|
2283
|
+
}
|
|
2284
|
+
};
|
|
2285
|
+
read();
|
|
2286
|
+
const onStorage = (event) => { if (event.key === SIDEBAR_ENTITY_PINS_KEY)
|
|
2287
|
+
read(); };
|
|
2288
|
+
window.addEventListener('storage', onStorage);
|
|
2289
|
+
return () => window.removeEventListener('storage', onStorage);
|
|
2290
|
+
}, []);
|
|
2291
|
+
const togglePinnedEntity = (pin) => {
|
|
2292
|
+
try {
|
|
2293
|
+
const next = toggleEntityPin(parseEntityPins(localStorage.getItem(SIDEBAR_ENTITY_PINS_KEY)), pin);
|
|
2294
|
+
localStorage.setItem(SIDEBAR_ENTITY_PINS_KEY, JSON.stringify(next));
|
|
2295
|
+
setEntityPins(next);
|
|
2296
|
+
setPinError(null);
|
|
2297
|
+
}
|
|
2298
|
+
catch {
|
|
2299
|
+
setPinError('The pin could not be saved. Existing preferences were retained.');
|
|
2300
|
+
}
|
|
2301
|
+
};
|
|
2302
|
+
const pinnedEntities = entityPins.flatMap(pin => {
|
|
2303
|
+
const workspace = workspaces.find(w => w.id === pin.workspaceId);
|
|
2304
|
+
const team = workspace?.teams.find(t => t.id === pin.teamId);
|
|
2305
|
+
const agent = team?.agents.find(a => a.id === pin.agentId);
|
|
2306
|
+
const entity = pin.type === 'workspace' ? workspace : pin.type === 'team' ? team : agent;
|
|
2307
|
+
return entity ? [{ pin, name: entity.name }] : [];
|
|
2308
|
+
});
|
|
2309
|
+
const togglePinProject = (dir) => {
|
|
2310
|
+
setPinnedProjects((prev) => {
|
|
2311
|
+
const next = prev.includes(dir) ? prev.filter((d) => d !== dir) : [...prev, dir];
|
|
2312
|
+
try {
|
|
2313
|
+
localStorage.setItem('xeno:pinned-projects', JSON.stringify(next));
|
|
2314
|
+
}
|
|
2315
|
+
catch { }
|
|
2316
|
+
return next;
|
|
2317
|
+
});
|
|
2318
|
+
};
|
|
2012
2319
|
const [selectMode, setSelectMode] = useState(false);
|
|
2013
2320
|
const [selectedConvIds, setSelectedConvIds] = useState(new Set());
|
|
2014
2321
|
const [convMenuPos, setConvMenuPos] = useState({ x: 0, y: 0 });
|
|
@@ -2040,6 +2347,274 @@ function Sidebar({ collapsed, onToggleCollapse, onOpenSettings, workspaces, setW
|
|
|
2040
2347
|
const repairAgentSearch = useAgentSearchStore(s => s.repair);
|
|
2041
2348
|
const refreshAgentSearchStatus = useAgentSearchStore(s => s.refreshStatus);
|
|
2042
2349
|
const [searchAttachNotice, setSearchAttachNotice] = useState(null);
|
|
2350
|
+
const createConversation = useAgentChatStore(s => s.createConversation);
|
|
2351
|
+
// Top navigation indicators
|
|
2352
|
+
const isChatsActive = viewMode === 'inbox' || viewMode === 'agent' || !viewMode;
|
|
2353
|
+
const isProjectsActive = viewMode === 'projects';
|
|
2354
|
+
const isTeamsActive = viewMode === 'teams';
|
|
2355
|
+
const isAgentsActive = viewMode === 'agents';
|
|
2356
|
+
const isScheduledActive = viewMode === 'scheduled';
|
|
2357
|
+
// Top navigation tab: 'chats' | 'projects' | 'library' | 'settings' | 'scheduled'
|
|
2358
|
+
const [activeNavTab, setActiveNavTab] = useState('chats');
|
|
2359
|
+
const [projectSearch, setProjectSearch] = useState('');
|
|
2360
|
+
const [librarySearch, setLibrarySearch] = useState('');
|
|
2361
|
+
const [libraryFilter, setLibraryFilter] = useState('all');
|
|
2362
|
+
const [expandedProjectIds, setExpandedProjectIds] = useState(new Set());
|
|
2363
|
+
// Sidebar view mode: 'tree' | 'stacked' - Stacked view is the default look
|
|
2364
|
+
const sidebarLayout = useSidebarLayoutPreference();
|
|
2365
|
+
const sidebarViewMode = sidebarLayout.mode;
|
|
2366
|
+
const handleToggleSidebarViewMode = () => sidebarLayout.setMode(sidebarViewMode === 'tree' ? 'stacked' : 'tree');
|
|
2367
|
+
// Pinned conversations state
|
|
2368
|
+
const [pinnedConvIds, setPinnedConvIds] = useState(() => {
|
|
2369
|
+
try {
|
|
2370
|
+
const saved = localStorage.getItem('xeno:pinned-conversations');
|
|
2371
|
+
return saved ? new Set(JSON.parse(saved)) : new Set();
|
|
2372
|
+
}
|
|
2373
|
+
catch {
|
|
2374
|
+
return new Set();
|
|
2375
|
+
}
|
|
2376
|
+
});
|
|
2377
|
+
const togglePinConversation = (convId) => {
|
|
2378
|
+
setPinnedConvIds(prev => {
|
|
2379
|
+
const next = new Set(prev);
|
|
2380
|
+
if (next.has(convId))
|
|
2381
|
+
next.delete(convId);
|
|
2382
|
+
else
|
|
2383
|
+
next.add(convId);
|
|
2384
|
+
try {
|
|
2385
|
+
localStorage.setItem('xeno:pinned-conversations', JSON.stringify([...next]));
|
|
2386
|
+
}
|
|
2387
|
+
catch { }
|
|
2388
|
+
return next;
|
|
2389
|
+
});
|
|
2390
|
+
};
|
|
2391
|
+
// Universal Hover Preview Card state for workspaces, teams, agents, and chats
|
|
2392
|
+
const [hoveredPreview, setHoveredPreview] = useState(null);
|
|
2393
|
+
const previewTimerRef = useRef(null);
|
|
2394
|
+
const previewPin = !hoveredPreview || hoveredPreview.type === 'conversation' ? null
|
|
2395
|
+
: hoveredPreview.type === 'workspace' ? { type: 'workspace', workspaceId: hoveredPreview.workspaceId || hoveredPreview.id }
|
|
2396
|
+
: hoveredPreview.workspaceId && (hoveredPreview.type === 'team' || hoveredPreview.teamId)
|
|
2397
|
+
? { type: hoveredPreview.type, workspaceId: hoveredPreview.workspaceId,
|
|
2398
|
+
teamId: hoveredPreview.type === 'team' ? hoveredPreview.teamId || hoveredPreview.id : hoveredPreview.teamId,
|
|
2399
|
+
...(hoveredPreview.type === 'agent' ? { agentId: hoveredPreview.agentId || hoveredPreview.id } : {}) }
|
|
2400
|
+
: null;
|
|
2401
|
+
const previewEntityPinned = previewPin !== null && entityPins.some(pin => entityPinKey(pin) === entityPinKey(previewPin));
|
|
2402
|
+
const closeTimerRef = useRef(null);
|
|
2403
|
+
// Card inline rename state
|
|
2404
|
+
const [isEditingCardName, setIsEditingCardName] = useState(false);
|
|
2405
|
+
const [editingCardName, setEditingCardName] = useState('');
|
|
2406
|
+
const handleAddProjectToWorkspace = async (workspaceId) => {
|
|
2407
|
+
try {
|
|
2408
|
+
const bridge = getAgentPlatformBridge();
|
|
2409
|
+
if (typeof bridge?.workspace?.pickDirectory === 'function') {
|
|
2410
|
+
const picked = await bridge.workspace.pickDirectory();
|
|
2411
|
+
if (picked) {
|
|
2412
|
+
useWorkspaceStore.getState().addDirectoryToWorkspace(workspaceId, picked);
|
|
2413
|
+
return;
|
|
2414
|
+
}
|
|
2415
|
+
}
|
|
2416
|
+
}
|
|
2417
|
+
catch (err) {
|
|
2418
|
+
console.error('Failed to pick directory:', err);
|
|
2419
|
+
}
|
|
2420
|
+
const path = window.prompt('Enter project folder directory path:');
|
|
2421
|
+
if (path && path.trim()) {
|
|
2422
|
+
useWorkspaceStore.getState().addDirectoryToWorkspace(workspaceId, path.trim());
|
|
2423
|
+
}
|
|
2424
|
+
};
|
|
2425
|
+
const handleOpenPathInExplorer = async (dirPath) => {
|
|
2426
|
+
try {
|
|
2427
|
+
const result = await getAgentPlatformBridge().workspace.openFileWith({
|
|
2428
|
+
path: dirPath, target: 'explorer', allowedDirs: [dirPath],
|
|
2429
|
+
});
|
|
2430
|
+
if (!result.success)
|
|
2431
|
+
throw new Error(result.error || 'Unable to open Explorer.');
|
|
2432
|
+
}
|
|
2433
|
+
catch (error) {
|
|
2434
|
+
window.alert(error instanceof Error ? error.message : 'Unable to open Explorer.');
|
|
2435
|
+
}
|
|
2436
|
+
};
|
|
2437
|
+
const handleSaveCardRename = () => {
|
|
2438
|
+
if (!hoveredPreview || !editingCardName.trim()) {
|
|
2439
|
+
setIsEditingCardName(false);
|
|
2440
|
+
return;
|
|
2441
|
+
}
|
|
2442
|
+
const newName = editingCardName.trim();
|
|
2443
|
+
if (hoveredPreview.type === 'workspace') {
|
|
2444
|
+
const wsId = hoveredPreview.workspaceId || hoveredPreview.id;
|
|
2445
|
+
updateWorkspace(wsId, { name: newName });
|
|
2446
|
+
setHoveredPreview(prev => prev ? { ...prev, title: newName } : null);
|
|
2447
|
+
}
|
|
2448
|
+
else if (hoveredPreview.type === 'team' && hoveredPreview.workspaceId) {
|
|
2449
|
+
const teamId = hoveredPreview.teamId || hoveredPreview.id;
|
|
2450
|
+
updateTeam(hoveredPreview.workspaceId, teamId, { name: newName });
|
|
2451
|
+
setHoveredPreview(prev => prev ? { ...prev, title: newName } : null);
|
|
2452
|
+
}
|
|
2453
|
+
else if (hoveredPreview.type === 'agent' && hoveredPreview.workspaceId && hoveredPreview.teamId) {
|
|
2454
|
+
const agentId = hoveredPreview.agentId || hoveredPreview.id;
|
|
2455
|
+
updateAgent(hoveredPreview.workspaceId, hoveredPreview.teamId, agentId, { name: newName });
|
|
2456
|
+
setHoveredPreview(prev => prev ? { ...prev, title: newName } : null);
|
|
2457
|
+
}
|
|
2458
|
+
else if (hoveredPreview.type === 'conversation') {
|
|
2459
|
+
renameConversation(hoveredPreview.id, newName);
|
|
2460
|
+
setHoveredPreview(prev => prev ? { ...prev, title: newName } : null);
|
|
2461
|
+
}
|
|
2462
|
+
setIsEditingCardName(false);
|
|
2463
|
+
};
|
|
2464
|
+
const formatUpdatedTime = (timestamp) => {
|
|
2465
|
+
if (!timestamp)
|
|
2466
|
+
return 'Updated recently';
|
|
2467
|
+
const date = new Date(timestamp);
|
|
2468
|
+
const now = new Date();
|
|
2469
|
+
const isToday = date.toDateString() === now.toDateString();
|
|
2470
|
+
if (isToday) {
|
|
2471
|
+
const hours = date.getHours().toString().padStart(2, '0');
|
|
2472
|
+
const minutes = date.getMinutes().toString().padStart(2, '0');
|
|
2473
|
+
return `Updated ${hours}:${minutes}`;
|
|
2474
|
+
}
|
|
2475
|
+
return `Updated ${relativeDate(timestamp)}`;
|
|
2476
|
+
};
|
|
2477
|
+
const handleConvMouseEnter = (e, conv, workspaceName, workspaceId) => {
|
|
2478
|
+
if (closeTimerRef.current) {
|
|
2479
|
+
clearTimeout(closeTimerRef.current);
|
|
2480
|
+
closeTimerRef.current = null;
|
|
2481
|
+
}
|
|
2482
|
+
if (previewTimerRef.current)
|
|
2483
|
+
clearTimeout(previewTimerRef.current);
|
|
2484
|
+
const target = e.currentTarget;
|
|
2485
|
+
previewTimerRef.current = setTimeout(() => {
|
|
2486
|
+
const rect = target.getBoundingClientRect();
|
|
2487
|
+
// 1. Resolve full conversation from store
|
|
2488
|
+
const fullConv = conversations[conv.id] || conv;
|
|
2489
|
+
const resolvedWsId = fullConv.workspaceId || conv.workspaceId || workspaceId || activeWorkspaceScope;
|
|
2490
|
+
const ws = workspaces.find(w => w.id === resolvedWsId) ||
|
|
2491
|
+
(scopedWorkspace?.id === resolvedWsId ? scopedWorkspace : undefined) ||
|
|
2492
|
+
workspaces.find(w => w.name === workspaceName);
|
|
2493
|
+
// 2. Resolve directory path(s)
|
|
2494
|
+
const dirs = [];
|
|
2495
|
+
if (fullConv.rootDirectory)
|
|
2496
|
+
dirs.push(fullConv.rootDirectory);
|
|
2497
|
+
if (Array.isArray(fullConv.grantedDirectories)) {
|
|
2498
|
+
for (const d of fullConv.grantedDirectories) {
|
|
2499
|
+
if (!dirs.includes(d))
|
|
2500
|
+
dirs.push(d);
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
if (dirs.length === 0 && ws?.directories && ws.directories.length > 0) {
|
|
2504
|
+
dirs.push(...ws.directories);
|
|
2505
|
+
}
|
|
2506
|
+
if (dirs.length === 0 && (ws?.name || workspaceName)) {
|
|
2507
|
+
dirs.push(ws?.name || workspaceName);
|
|
2508
|
+
}
|
|
2509
|
+
// 3. Determine if running or idle
|
|
2510
|
+
const msgs = fullConv.messages || [];
|
|
2511
|
+
const isRunning = msgs.some((m) => m.isStreaming) || ((agentRunAvailability[fullConv.agentId] || 0) > 0);
|
|
2512
|
+
setHoveredPreview({
|
|
2513
|
+
type: 'conversation',
|
|
2514
|
+
id: conv.id,
|
|
2515
|
+
title: conv.title || 'New conversation',
|
|
2516
|
+
timestamp: conv.lastMessageAt || conv.createdAt || conv.timestamp || Date.now(),
|
|
2517
|
+
status: isRunning ? 'Running' : 'Idle',
|
|
2518
|
+
workspaceName: ws?.name || workspaceName || 'Workspace',
|
|
2519
|
+
workspaceId: ws?.id || resolvedWsId,
|
|
2520
|
+
directories: dirs.length > 0 ? dirs : undefined,
|
|
2521
|
+
isPinned: pinnedConvIds.has(conv.id),
|
|
2522
|
+
rect,
|
|
2523
|
+
});
|
|
2524
|
+
}, 180);
|
|
2525
|
+
};
|
|
2526
|
+
const handleWorkspaceMouseEnter = (e, ws) => {
|
|
2527
|
+
if (closeTimerRef.current) {
|
|
2528
|
+
clearTimeout(closeTimerRef.current);
|
|
2529
|
+
closeTimerRef.current = null;
|
|
2530
|
+
}
|
|
2531
|
+
if (previewTimerRef.current)
|
|
2532
|
+
clearTimeout(previewTimerRef.current);
|
|
2533
|
+
const target = e.currentTarget;
|
|
2534
|
+
previewTimerRef.current = setTimeout(() => {
|
|
2535
|
+
const rect = target.getBoundingClientRect();
|
|
2536
|
+
const allChats = ws.teams.flatMap(t => t.agents.flatMap(a => conversationsByAgent[a.id] || []));
|
|
2537
|
+
setHoveredPreview({
|
|
2538
|
+
type: 'workspace',
|
|
2539
|
+
id: ws.id,
|
|
2540
|
+
title: ws.name,
|
|
2541
|
+
taskCount: allChats.length,
|
|
2542
|
+
directories: ws.directories && ws.directories.length > 0 ? ws.directories : undefined,
|
|
2543
|
+
appNames: ws.apps && ws.apps.length > 0 ? ws.apps.map(a => a.name) : undefined,
|
|
2544
|
+
workspaceId: ws.id,
|
|
2545
|
+
workspaceName: ws.name,
|
|
2546
|
+
rect,
|
|
2547
|
+
});
|
|
2548
|
+
}, 200);
|
|
2549
|
+
};
|
|
2550
|
+
const handleTeamMouseEnter = (e, ws, team) => {
|
|
2551
|
+
if (closeTimerRef.current) {
|
|
2552
|
+
clearTimeout(closeTimerRef.current);
|
|
2553
|
+
closeTimerRef.current = null;
|
|
2554
|
+
}
|
|
2555
|
+
if (previewTimerRef.current)
|
|
2556
|
+
clearTimeout(previewTimerRef.current);
|
|
2557
|
+
const target = e.currentTarget;
|
|
2558
|
+
previewTimerRef.current = setTimeout(() => {
|
|
2559
|
+
const rect = target.getBoundingClientRect();
|
|
2560
|
+
const teamChats = team.agents.flatMap((a) => conversationsByAgent[a.id] || []);
|
|
2561
|
+
setHoveredPreview({
|
|
2562
|
+
type: 'team',
|
|
2563
|
+
id: team.id,
|
|
2564
|
+
title: team.name,
|
|
2565
|
+
taskCount: teamChats.length,
|
|
2566
|
+
directories: team.allowedDirectories && team.allowedDirectories.length > 0 ? team.allowedDirectories : (ws.directories && ws.directories.length > 0 ? ws.directories : undefined),
|
|
2567
|
+
agentNames: team.agents.map((a) => a.name),
|
|
2568
|
+
workspaceId: ws.id,
|
|
2569
|
+
teamId: team.id,
|
|
2570
|
+
workspaceName: ws.name,
|
|
2571
|
+
teamName: team.name,
|
|
2572
|
+
rect,
|
|
2573
|
+
});
|
|
2574
|
+
}, 200);
|
|
2575
|
+
};
|
|
2576
|
+
const handleAgentMouseEnter = (e, ws, team, agent) => {
|
|
2577
|
+
if (closeTimerRef.current) {
|
|
2578
|
+
clearTimeout(closeTimerRef.current);
|
|
2579
|
+
closeTimerRef.current = null;
|
|
2580
|
+
}
|
|
2581
|
+
if (previewTimerRef.current)
|
|
2582
|
+
clearTimeout(previewTimerRef.current);
|
|
2583
|
+
const target = e.currentTarget;
|
|
2584
|
+
previewTimerRef.current = setTimeout(() => {
|
|
2585
|
+
const rect = target.getBoundingClientRect();
|
|
2586
|
+
const agentChats = conversationsByAgent[agent.id] || [];
|
|
2587
|
+
setHoveredPreview({
|
|
2588
|
+
type: 'agent',
|
|
2589
|
+
id: agent.id,
|
|
2590
|
+
title: agent.name,
|
|
2591
|
+
taskCount: agentChats.length,
|
|
2592
|
+
model: agent.model,
|
|
2593
|
+
workspaceId: ws.id,
|
|
2594
|
+
teamId: team.id,
|
|
2595
|
+
agentId: agent.id,
|
|
2596
|
+
workspaceName: ws.name,
|
|
2597
|
+
teamName: team.name,
|
|
2598
|
+
rect,
|
|
2599
|
+
});
|
|
2600
|
+
}, 200);
|
|
2601
|
+
};
|
|
2602
|
+
const handleConvMouseLeave = () => {
|
|
2603
|
+
if (isEditingCardName)
|
|
2604
|
+
return;
|
|
2605
|
+
if (previewTimerRef.current) {
|
|
2606
|
+
clearTimeout(previewTimerRef.current);
|
|
2607
|
+
previewTimerRef.current = null;
|
|
2608
|
+
}
|
|
2609
|
+
if (closeTimerRef.current) {
|
|
2610
|
+
clearTimeout(closeTimerRef.current);
|
|
2611
|
+
}
|
|
2612
|
+
closeTimerRef.current = setTimeout(() => {
|
|
2613
|
+
setHoveredPreview(null);
|
|
2614
|
+
setIsEditingCardName(false);
|
|
2615
|
+
closeTimerRef.current = null;
|
|
2616
|
+
}, 280);
|
|
2617
|
+
};
|
|
2043
2618
|
// Sidebar metadata is derived from chat store conversations (source of truth).
|
|
2044
2619
|
const conversationsByAgent = useMemo(() => {
|
|
2045
2620
|
const grouped = {};
|
|
@@ -2059,12 +2634,107 @@ function Sidebar({ collapsed, onToggleCollapse, onOpenSettings, workspaces, setW
|
|
|
2059
2634
|
}
|
|
2060
2635
|
return grouped;
|
|
2061
2636
|
}, [conversations]);
|
|
2637
|
+
// Unify all conversations across all agents, teams, and workspaces
|
|
2638
|
+
const allUnifiedConversations = useMemo(() => {
|
|
2639
|
+
const map = new Map();
|
|
2640
|
+
// 1. From chat store conversations (source of truth for live active chats)
|
|
2641
|
+
for (const conv of Object.values(conversations || {})) {
|
|
2642
|
+
if (!conv || !conv.id)
|
|
2643
|
+
continue;
|
|
2644
|
+
const isInbox = conv.agentId === inboxAgentId;
|
|
2645
|
+
map.set(conv.id, {
|
|
2646
|
+
...conv,
|
|
2647
|
+
id: conv.id,
|
|
2648
|
+
title: conv.title || 'New conversation',
|
|
2649
|
+
agentId: conv.agentId || inboxAgentId,
|
|
2650
|
+
workspaceId: conv.workspaceId,
|
|
2651
|
+
rootDirectory: conv.rootDirectory,
|
|
2652
|
+
lastMessageAt: conv.lastMessageAt || conv.createdAt || conv.timestamp,
|
|
2653
|
+
timestamp: conv.createdAt || conv.timestamp,
|
|
2654
|
+
isInbox,
|
|
2655
|
+
});
|
|
2656
|
+
}
|
|
2657
|
+
// 2. From workspaces -> teams -> agents -> conversations
|
|
2658
|
+
for (const ws of workspaces || []) {
|
|
2659
|
+
for (const t of ws.teams || []) {
|
|
2660
|
+
for (const a of t.agents || []) {
|
|
2661
|
+
for (const c of a.conversations || []) {
|
|
2662
|
+
if (!c || !c.id)
|
|
2663
|
+
continue;
|
|
2664
|
+
const existing = map.get(c.id);
|
|
2665
|
+
if (existing) {
|
|
2666
|
+
existing.workspaceId = existing.workspaceId || ws.id;
|
|
2667
|
+
existing.workspaceName = ws.name;
|
|
2668
|
+
existing.teamId = existing.teamId || t.id;
|
|
2669
|
+
existing.teamName = t.name;
|
|
2670
|
+
existing.agentId = existing.agentId || a.id;
|
|
2671
|
+
existing.agentName = a.name;
|
|
2672
|
+
if (!existing.rootDirectory && ws.directories && ws.directories[0]) {
|
|
2673
|
+
existing.rootDirectory = ws.directories[0];
|
|
2674
|
+
}
|
|
2675
|
+
}
|
|
2676
|
+
else {
|
|
2677
|
+
map.set(c.id, {
|
|
2678
|
+
...c,
|
|
2679
|
+
id: c.id,
|
|
2680
|
+
title: c.title || 'New conversation',
|
|
2681
|
+
agentId: a.id,
|
|
2682
|
+
workspaceId: ws.id,
|
|
2683
|
+
workspaceName: ws.name,
|
|
2684
|
+
teamId: t.id,
|
|
2685
|
+
teamName: t.name,
|
|
2686
|
+
agentName: a.name,
|
|
2687
|
+
rootDirectory: ws.directories && ws.directories[0],
|
|
2688
|
+
lastMessageAt: c.lastMessageAt || c.timestamp,
|
|
2689
|
+
timestamp: c.timestamp,
|
|
2690
|
+
isInbox: false,
|
|
2691
|
+
});
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
}
|
|
2695
|
+
}
|
|
2696
|
+
}
|
|
2697
|
+
// Enrich missing workspace/folder labels
|
|
2698
|
+
for (const item of map.values()) {
|
|
2699
|
+
if (!item.workspaceName && item.workspaceId) {
|
|
2700
|
+
const ws = workspaces.find(w => w.id === item.workspaceId);
|
|
2701
|
+
if (ws)
|
|
2702
|
+
item.workspaceName = ws.name;
|
|
2703
|
+
}
|
|
2704
|
+
if (!item.workspaceName && item.rootDirectory) {
|
|
2705
|
+
const ws = workspaces.find(w => w.directories?.some((d) => item.rootDirectory?.startsWith(d)));
|
|
2706
|
+
if (ws)
|
|
2707
|
+
item.workspaceName = ws.name;
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2710
|
+
const list = Array.from(map.values());
|
|
2711
|
+
list.sort((a, b) => {
|
|
2712
|
+
const aTime = a.lastMessageAt || a.timestamp || a.createdAt || 0;
|
|
2713
|
+
const bTime = b.lastMessageAt || b.timestamp || b.createdAt || 0;
|
|
2714
|
+
return bTime - aTime;
|
|
2715
|
+
});
|
|
2716
|
+
return list;
|
|
2717
|
+
}, [conversations, workspaces, inboxAgentId]);
|
|
2718
|
+
// Collect all pinned conversations from the unified pool
|
|
2719
|
+
const pinnedConversations = useMemo(() => {
|
|
2720
|
+
if (pinnedConvIds.size === 0)
|
|
2721
|
+
return [];
|
|
2722
|
+
return allUnifiedConversations
|
|
2723
|
+
.filter((c) => pinnedConvIds.has(c.id))
|
|
2724
|
+
.sort((a, b) => (b.lastMessageAt || b.timestamp || 0) - (a.lastMessageAt || a.timestamp || 0));
|
|
2725
|
+
}, [pinnedConvIds, allUnifiedConversations]);
|
|
2062
2726
|
const inboxConversations = conversationsByAgent[inboxAgentId] || [];
|
|
2727
|
+
const activeConversationPool = allUnifiedConversations;
|
|
2063
2728
|
const normalizedInboxSearchQuery = inboxSearchQuery.trim().toLowerCase();
|
|
2064
2729
|
const showGlobalSearchResults = inboxSearchMode && normalizedInboxSearchQuery.length > 0;
|
|
2065
2730
|
const visibleInboxConversations = normalizedInboxSearchQuery
|
|
2066
|
-
?
|
|
2067
|
-
|
|
2731
|
+
? activeConversationPool.filter((conv) => {
|
|
2732
|
+
const titleMatch = (conv.title || 'New conversation').toLowerCase().includes(normalizedInboxSearchQuery);
|
|
2733
|
+
const wsMatch = (conv.workspaceName || '').toLowerCase().includes(normalizedInboxSearchQuery);
|
|
2734
|
+
const agentMatch = (conv.agentName || '').toLowerCase().includes(normalizedInboxSearchQuery);
|
|
2735
|
+
return titleMatch || wsMatch || agentMatch;
|
|
2736
|
+
})
|
|
2737
|
+
: activeConversationPool;
|
|
2068
2738
|
const areAllVisibleInboxConversationsSelected = visibleInboxConversations.length > 0
|
|
2069
2739
|
&& visibleInboxConversations.every((conv) => selectedConvIds.has(conv.id));
|
|
2070
2740
|
const entityNames = useMemo(() => {
|
|
@@ -2359,7 +3029,7 @@ function Sidebar({ collapsed, onToggleCollapse, onOpenSettings, workspaces, setW
|
|
|
2359
3029
|
const handleContextAction = (action, targetWorkspaceId, targetTeamId) => {
|
|
2360
3030
|
if (!contextMenu)
|
|
2361
3031
|
return;
|
|
2362
|
-
const { type, workspaceId, teamId, agentId } = contextMenu;
|
|
3032
|
+
const { type, workspaceId, teamId, agentId, conversationId } = contextMenu;
|
|
2363
3033
|
switch (action) {
|
|
2364
3034
|
case 'rename':
|
|
2365
3035
|
startRename();
|
|
@@ -2367,6 +3037,74 @@ function Sidebar({ collapsed, onToggleCollapse, onOpenSettings, workspaces, setW
|
|
|
2367
3037
|
case 'duplicate':
|
|
2368
3038
|
handleDuplicate();
|
|
2369
3039
|
break;
|
|
3040
|
+
case 'open-explorer':
|
|
3041
|
+
if (type === 'workspace') {
|
|
3042
|
+
const ws = workspaces.find(w => w.id === workspaceId);
|
|
3043
|
+
if (ws?.directories && ws.directories[0]) {
|
|
3044
|
+
const bridge = getAgentPlatformBridge();
|
|
3045
|
+
if (typeof bridge?.window?.openExternal === 'function') {
|
|
3046
|
+
void bridge.window.openExternal(ws.directories[0]);
|
|
3047
|
+
}
|
|
3048
|
+
}
|
|
3049
|
+
}
|
|
3050
|
+
break;
|
|
3051
|
+
case 'copy-name': {
|
|
3052
|
+
let textToCopy = '';
|
|
3053
|
+
if (type === 'workspace')
|
|
3054
|
+
textToCopy = workspaces.find(w => w.id === workspaceId)?.name || '';
|
|
3055
|
+
else if (type === 'team')
|
|
3056
|
+
textToCopy = workspaces.find(w => w.id === workspaceId)?.teams.find(t => t.id === teamId)?.name || '';
|
|
3057
|
+
else if (type === 'agent')
|
|
3058
|
+
textToCopy = workspaces.find(w => w.id === workspaceId)?.teams.find(t => t.id === teamId)?.agents.find(a => a.id === agentId)?.name || '';
|
|
3059
|
+
else if (type === 'conversation' && conversationId)
|
|
3060
|
+
textToCopy = conversations[conversationId]?.title || 'New conversation';
|
|
3061
|
+
if (textToCopy && typeof navigator !== 'undefined' && navigator.clipboard) {
|
|
3062
|
+
void navigator.clipboard.writeText(textToCopy);
|
|
3063
|
+
}
|
|
3064
|
+
break;
|
|
3065
|
+
}
|
|
3066
|
+
case 'copy-id': {
|
|
3067
|
+
const idToCopy = conversationId || agentId || teamId || workspaceId;
|
|
3068
|
+
if (idToCopy && typeof navigator !== 'undefined' && navigator.clipboard) {
|
|
3069
|
+
void navigator.clipboard.writeText(idToCopy);
|
|
3070
|
+
}
|
|
3071
|
+
break;
|
|
3072
|
+
}
|
|
3073
|
+
case 'copy-path': {
|
|
3074
|
+
const ws = workspaces.find(w => w.id === workspaceId);
|
|
3075
|
+
if (ws?.directories && ws.directories[0] && typeof navigator !== 'undefined' && navigator.clipboard) {
|
|
3076
|
+
void navigator.clipboard.writeText(ws.directories[0]);
|
|
3077
|
+
}
|
|
3078
|
+
break;
|
|
3079
|
+
}
|
|
3080
|
+
case 'copy-transcript': {
|
|
3081
|
+
if (conversationId) {
|
|
3082
|
+
const conv = useAgentChatStore.getState().getConversation(conversationId);
|
|
3083
|
+
if (conv && typeof navigator !== 'undefined' && navigator.clipboard) {
|
|
3084
|
+
const transcript = (conv.messages || []).map(m => `[${m.role.toUpperCase()}]: ${m.content}`).join('\n\n');
|
|
3085
|
+
void navigator.clipboard.writeText(transcript);
|
|
3086
|
+
}
|
|
3087
|
+
}
|
|
3088
|
+
break;
|
|
3089
|
+
}
|
|
3090
|
+
case 'new-conversation': {
|
|
3091
|
+
if (agentId) {
|
|
3092
|
+
onSelectAgent(agentId);
|
|
3093
|
+
}
|
|
3094
|
+
break;
|
|
3095
|
+
}
|
|
3096
|
+
case 'add-agent': {
|
|
3097
|
+
if (teamId) {
|
|
3098
|
+
setAddingAgentToTeam(teamId);
|
|
3099
|
+
}
|
|
3100
|
+
break;
|
|
3101
|
+
}
|
|
3102
|
+
case 'add-team': {
|
|
3103
|
+
if (workspaceId) {
|
|
3104
|
+
setAddingTeamToWorkspace(workspaceId);
|
|
3105
|
+
}
|
|
3106
|
+
break;
|
|
3107
|
+
}
|
|
2370
3108
|
case 'add-folder':
|
|
2371
3109
|
if (type === 'workspace') {
|
|
2372
3110
|
void (async () => {
|
|
@@ -2458,11 +3196,9 @@ function Sidebar({ collapsed, onToggleCollapse, onOpenSettings, workspaces, setW
|
|
|
2458
3196
|
...w,
|
|
2459
3197
|
teams: w.teams.map(t => {
|
|
2460
3198
|
if (t.id === teamId) {
|
|
2461
|
-
// Remove from source team
|
|
2462
3199
|
return { ...t, agents: t.agents.filter(a => a.id !== agentId) };
|
|
2463
3200
|
}
|
|
2464
3201
|
if (t.id === targetTeamId) {
|
|
2465
|
-
// Add to target team
|
|
2466
3202
|
return { ...t, agents: [...t.agents, sanitizedAgent] };
|
|
2467
3203
|
}
|
|
2468
3204
|
return t;
|
|
@@ -2673,6 +3409,9 @@ function Sidebar({ collapsed, onToggleCollapse, onOpenSettings, workspaces, setW
|
|
|
2673
3409
|
const { type, workspaceId, teamId, agentId, conversationId } = contextMenu;
|
|
2674
3410
|
if (type === 'workspace') {
|
|
2675
3411
|
setWorkspaces(workspaces.filter(w => w.id !== workspaceId));
|
|
3412
|
+
if (activeWorkspaceScope === workspaceId) {
|
|
3413
|
+
setActiveWorkspaceScope(null);
|
|
3414
|
+
}
|
|
2676
3415
|
}
|
|
2677
3416
|
else if (type === 'team' && teamId) {
|
|
2678
3417
|
setWorkspaces(workspaces.map(w => w.id === workspaceId
|
|
@@ -2754,6 +3493,80 @@ function Sidebar({ collapsed, onToggleCollapse, onOpenSettings, workspaces, setW
|
|
|
2754
3493
|
};
|
|
2755
3494
|
// Agent actions
|
|
2756
3495
|
const storeAddAgent = useWorkspaceStore(s => s.addAgent);
|
|
3496
|
+
const activeWorkspaceScope = useWorkspaceStore(s => s.activeWorkspaceScope);
|
|
3497
|
+
const setActiveWorkspaceScope = useWorkspaceStore(s => s.setActiveWorkspaceScope);
|
|
3498
|
+
const openWorkspaceWizard = useWorkspaceStore(s => s.openWorkspaceWizard);
|
|
3499
|
+
const updateWorkspace = useWorkspaceStore(s => s.updateWorkspace);
|
|
3500
|
+
const updateTeam = useWorkspaceStore(s => s.updateTeam);
|
|
3501
|
+
const updateAgent = useWorkspaceStore(s => s.updateAgent);
|
|
3502
|
+
const scopedWorkspace = useMemo(() => {
|
|
3503
|
+
if (!activeWorkspaceScope)
|
|
3504
|
+
return null;
|
|
3505
|
+
return workspaces.find(w => w.id === activeWorkspaceScope && !w.isArchived) || null;
|
|
3506
|
+
}, [workspaces, activeWorkspaceScope]);
|
|
3507
|
+
const scopedMainAgentInfo = useMemo(() => {
|
|
3508
|
+
if (!scopedWorkspace)
|
|
3509
|
+
return null;
|
|
3510
|
+
for (const team of scopedWorkspace.teams) {
|
|
3511
|
+
const main = team.agents.find(a => a.isMainAssistant);
|
|
3512
|
+
if (main)
|
|
3513
|
+
return { agent: main, team };
|
|
3514
|
+
}
|
|
3515
|
+
if (scopedWorkspace.teams[0]?.agents[0]) {
|
|
3516
|
+
return { agent: scopedWorkspace.teams[0].agents[0], team: scopedWorkspace.teams[0] };
|
|
3517
|
+
}
|
|
3518
|
+
return null;
|
|
3519
|
+
}, [scopedWorkspace]);
|
|
3520
|
+
const currentWorkspace = useMemo(() => {
|
|
3521
|
+
if (activeWorkspaceScope) {
|
|
3522
|
+
const found = workspaces.find((w) => w.id === activeWorkspaceScope && !w.isArchived);
|
|
3523
|
+
if (found)
|
|
3524
|
+
return found;
|
|
3525
|
+
}
|
|
3526
|
+
return workspaces.find((w) => !w.isArchived) || workspaces[0] || null;
|
|
3527
|
+
}, [workspaces, activeWorkspaceScope]);
|
|
3528
|
+
const currentWorkspaceProjects = useMemo(() => {
|
|
3529
|
+
if (currentWorkspace?.directories)
|
|
3530
|
+
return currentWorkspace.directories;
|
|
3531
|
+
return Array.from(new Set(workspaces.flatMap((w) => w.directories || [])));
|
|
3532
|
+
}, [currentWorkspace, workspaces]);
|
|
3533
|
+
const pinnedProjectItems = useMemo(() => {
|
|
3534
|
+
return pinnedProjects.map((dir) => {
|
|
3535
|
+
const name = dir.split(/[\\/]/).filter(Boolean).pop() || dir;
|
|
3536
|
+
const parentWs = workspaces.find((w) => w.directories?.includes(dir));
|
|
3537
|
+
return { dir, name, workspaceName: parentWs?.name || 'Workspace' };
|
|
3538
|
+
});
|
|
3539
|
+
}, [pinnedProjects, workspaces]);
|
|
3540
|
+
const handleSelectScopedWorkspaceChat = () => {
|
|
3541
|
+
if (!scopedWorkspace)
|
|
3542
|
+
return;
|
|
3543
|
+
if (scopedMainAgentInfo) {
|
|
3544
|
+
onSelectAgent(scopedMainAgentInfo.agent.id);
|
|
3545
|
+
}
|
|
3546
|
+
else {
|
|
3547
|
+
const newTeamId = generateId();
|
|
3548
|
+
const newAgentId = generateId();
|
|
3549
|
+
const newTeam = {
|
|
3550
|
+
id: newTeamId,
|
|
3551
|
+
name: 'Core',
|
|
3552
|
+
allowedDirectories: [],
|
|
3553
|
+
allowedApps: [],
|
|
3554
|
+
isExpanded: true,
|
|
3555
|
+
agents: [{
|
|
3556
|
+
...agentCreationConfiguration(scopedWorkspace, undefined),
|
|
3557
|
+
id: newAgentId,
|
|
3558
|
+
name: 'Lead Assistant',
|
|
3559
|
+
isMainAssistant: true,
|
|
3560
|
+
allowedDirectories: [],
|
|
3561
|
+
allowedApps: [],
|
|
3562
|
+
conversations: [],
|
|
3563
|
+
isExpanded: true,
|
|
3564
|
+
}]
|
|
3565
|
+
};
|
|
3566
|
+
setWorkspaces(workspaces.map(w => w.id === scopedWorkspace.id ? { ...w, teams: [...w.teams, newTeam] } : w));
|
|
3567
|
+
onSelectAgent(newAgentId);
|
|
3568
|
+
}
|
|
3569
|
+
};
|
|
2757
3570
|
const handleAddAgent = (workspaceId, teamId) => {
|
|
2758
3571
|
if (newAgentName.trim()) {
|
|
2759
3572
|
storeAddAgent(workspaceId, teamId, newAgentName.trim());
|
|
@@ -2766,9 +3579,41 @@ function Sidebar({ collapsed, onToggleCollapse, onOpenSettings, workspaces, setW
|
|
|
2766
3579
|
return renamingItem?.type === type && renamingItem?.id === id;
|
|
2767
3580
|
};
|
|
2768
3581
|
if (collapsed) {
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
3582
|
+
const targetWs = scopedWorkspace || currentWorkspace || workspaces[0];
|
|
3583
|
+
return (_jsxs("aside", { className: "flex-shrink-0 bg-[#0c0c0e] border-r border-white/[0.06] flex flex-col items-center py-2.5 gap-1.5 w-[50px] select-none", children: [_jsx("button", { onClick: onToggleCollapse, className: "p-1.5 rounded-[4px] text-[#7f7f86] hover:text-white hover:bg-white/[0.06] transition-colors cursor-pointer", title: "Expand sidebar", children: _jsx(PanelLeftOpen, { className: "w-4 h-4" }) }), _jsx("button", { type: "button", onClick: () => {
|
|
3584
|
+
const targetAgentId = scopedWorkspace ? (scopedMainAgentInfo?.agent?.id || inboxAgentId) : inboxAgentId;
|
|
3585
|
+
const newId = createConversation(targetAgentId);
|
|
3586
|
+
onSelectConversation(targetAgentId, newId);
|
|
3587
|
+
}, className: "p-1.5 rounded-[4px] bg-white/[0.06] hover:bg-white/[0.1] text-white transition-colors cursor-pointer", title: "New Chat", children: _jsx(Plus, { className: "w-4 h-4" }) }), _jsx("div", { className: "w-6 h-px bg-white/[0.06] my-1" }), _jsx("button", { type: "button", onClick: () => {
|
|
3588
|
+
if (scopedWorkspace) {
|
|
3589
|
+
handleSelectScopedWorkspaceChat();
|
|
3590
|
+
}
|
|
3591
|
+
else {
|
|
3592
|
+
onSelectInbox();
|
|
3593
|
+
}
|
|
3594
|
+
}, className: `p-1.5 rounded-[4px] transition-colors cursor-pointer ${isChatsActive
|
|
3595
|
+
? 'bg-white/[0.08] text-white'
|
|
3596
|
+
: 'text-[#7f7f86] hover:text-white hover:bg-white/[0.04]'}`, title: currentWorkspace ? `${currentWorkspace.name} Main Chat` : 'Chat', children: _jsx(MessageSquare, { className: "w-4 h-4" }) }), _jsx("button", { type: "button", onClick: onSelectProjects, className: `p-1.5 rounded-[4px] transition-colors cursor-pointer ${viewMode === 'projects'
|
|
3597
|
+
? 'bg-white/[0.08] text-white'
|
|
3598
|
+
: 'text-[#7f7f86] hover:text-white hover:bg-white/[0.04]'}`, title: "Projects", children: _jsx(Folder, { className: "w-4 h-4" }) }), _jsx("button", { type: "button", onClick: onSelectTeams, className: `p-1.5 rounded-[4px] transition-colors cursor-pointer ${viewMode === 'teams'
|
|
3599
|
+
? 'bg-white/[0.08] text-white'
|
|
3600
|
+
: 'text-[#7f7f86] hover:text-white hover:bg-white/[0.04]'}`, title: "Teams", children: _jsx(Users, { className: "w-4 h-4" }) }), _jsx("button", { type: "button", onClick: onSelectAgents, className: `p-1.5 rounded-[4px] transition-colors cursor-pointer ${viewMode === 'agents'
|
|
3601
|
+
? 'bg-white/[0.08] text-white'
|
|
3602
|
+
: 'text-[#7f7f86] hover:text-white hover:bg-white/[0.04]'}`, title: "Agents", children: _jsx(Bot, { className: "w-4 h-4" }) }), _jsx("button", { type: "button", onClick: onSelectKnowledge, className: "p-1.5 rounded-[4px] text-[#7f7f86] hover:text-white hover:bg-white/[0.04] transition-colors cursor-pointer", title: "Library", children: _jsx(BookOpen, { className: "w-4 h-4" }) }), _jsx("button", { type: "button", onClick: onSelectScheduled, className: `p-1.5 rounded-[4px] transition-colors cursor-pointer ${viewMode === 'scheduled'
|
|
3603
|
+
? 'bg-white/[0.08] text-white'
|
|
3604
|
+
: 'text-[#7f7f86] hover:text-white hover:bg-white/[0.04]'}`, title: "Scheduled Tasks", children: _jsx(Clock, { className: "w-4 h-4" }) }), _jsx("div", { className: "flex-1" }), _jsx("button", { type: "button", onClick: () => {
|
|
3605
|
+
if (targetWs) {
|
|
3606
|
+
onOpenSettings({
|
|
3607
|
+
type: 'workspace',
|
|
3608
|
+
workspaceId: targetWs.id,
|
|
3609
|
+
workspaceName: targetWs.name,
|
|
3610
|
+
teamCount: targetWs.teams.length,
|
|
3611
|
+
agentCount: targetWs.teams.reduce((acc, t) => acc + t.agents.length, 0),
|
|
3612
|
+
});
|
|
3613
|
+
}
|
|
3614
|
+
}, className: `p-1.5 rounded-[4px] transition-colors cursor-pointer ${isSettingsOpen
|
|
3615
|
+
? 'bg-white/[0.08] text-white'
|
|
3616
|
+
: 'text-[#7f7f86] hover:text-white hover:bg-white/[0.04]'}`, title: "Workspace Settings", children: _jsx(Settings, { className: "w-4 h-4" }) })] }));
|
|
2772
3617
|
}
|
|
2773
3618
|
return (_jsxs("aside", { className: "flex-shrink-0 bg-[#0c0c0e] border-r border-white/[0.06] flex flex-col", style: { width: SIDEBAR_WIDTH }, children: [_jsx("style", { children: `
|
|
2774
3619
|
@keyframes conversationDeleteParticle {
|
|
@@ -2776,212 +3621,389 @@ function Sidebar({ collapsed, onToggleCollapse, onOpenSettings, workspaces, setW
|
|
|
2776
3621
|
15% { opacity: 1; }
|
|
2777
3622
|
100% { opacity: 0; transform: translate3d(var(--dx, 18px), var(--dy, -10px), 0) scale(1.35); }
|
|
2778
3623
|
}
|
|
2779
|
-
` }), _jsxs("nav", { className: "flex-1 overflow-auto p-2", children: [_jsxs("div", { className: "
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
3624
|
+
` }), _jsxs("nav", { className: "flex-1 overflow-auto p-2 space-y-3 [&::-webkit-scrollbar]:hidden", children: [_jsxs("div", { className: "pb-1.5 space-y-1", children: [_jsxs("div", { className: "flex items-center justify-between gap-1 pb-1", children: [_jsxs("button", { type: "button", onClick: () => {
|
|
3625
|
+
const targetAgentId = scopedWorkspace ? (scopedMainAgentInfo?.agent?.id || inboxAgentId) : inboxAgentId;
|
|
3626
|
+
const newId = createConversation(targetAgentId);
|
|
3627
|
+
onSelectConversation(targetAgentId, newId);
|
|
3628
|
+
}, className: "flex-1 flex items-center gap-2 px-2.5 py-1.5 rounded-md bg-white/[0.06] hover:bg-white/[0.1] text-white text-[12.5px] font-medium transition-colors cursor-pointer", children: [_jsx(Plus, { className: "w-3.5 h-3.5 text-zinc-300" }), _jsx("span", { children: "New" })] }), _jsx("button", { onClick: onToggleCollapse, className: "p-1.5 rounded-md text-zinc-500 hover:text-zinc-200 hover:bg-white/[0.04] transition-colors flex-shrink-0 cursor-pointer", title: "Collapse sidebar", children: _jsx(PanelLeftClose, { className: "w-4 h-4" }) })] }), _jsxs("div", { className: "space-y-0.5", children: [_jsxs("button", { type: "button", onClick: () => {
|
|
3629
|
+
if (scopedWorkspace) {
|
|
3630
|
+
handleSelectScopedWorkspaceChat();
|
|
2783
3631
|
}
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
},
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
return;
|
|
2827
|
-
event.preventDefault();
|
|
2828
|
-
void summarizeSearchResult(event, result);
|
|
2829
|
-
}, className: "rounded border border-white/[0.08] px-1.5 py-0.5 text-[9px] uppercase tracking-[0.12em] text-white/38 transition-colors group-hover/search:text-white/68 hover:border-white/[0.2] hover:bg-white/[0.08]", children: "Summary" })), canAttach && (_jsx("button", { type: "button", onClick: (event) => { void attachSearchResult(event, result); }, onKeyDown: (event) => {
|
|
2830
|
-
if (event.key !== 'Enter' && event.key !== ' ')
|
|
2831
|
-
return;
|
|
2832
|
-
event.preventDefault();
|
|
2833
|
-
void attachSearchResult(event, result);
|
|
2834
|
-
}, className: "rounded border border-white/[0.08] px-1.5 py-0.5 text-[9px] uppercase tracking-[0.12em] text-white/38 transition-colors group-hover/search:text-white/68 hover:border-white/[0.2] hover:bg-white/[0.08]", children: "Attach" }))] })] }), _jsx("p", { className: "mt-0.5 truncate text-[10px] uppercase tracking-[0.12em] text-[color:var(--xeno-ink-faint)]", children: getSearchResultMeta(result) }), result.snippet && (_jsx("p", { className: "mt-1 max-h-10 overflow-hidden text-[11px] leading-5 text-[color:var(--xeno-ink-muted)]", children: result.snippet }))] }, result.id));
|
|
2835
|
-
}) })), !searchLoading && !searchError && searchResults.length === 0 && (_jsx("p", { className: "px-2 py-1 text-[11px] text-[color:var(--xeno-ink-faint)]", children: "No conversations, tool calls, runtime events, or workspace metadata match this search." }))] })), !showGlobalSearchResults && visibleInboxConversations.length > 0 && (_jsxs("div", { className: "ml-3 mt-1 max-h-[240px] space-y-0.5 overflow-y-auto border-l pl-2 xeno-border-subtle [&::-webkit-scrollbar]:hidden", children: [visibleInboxConversations.slice(0, inboxExpanded ? undefined : 5).map(conv => {
|
|
2836
|
-
const isDeleting = deletingConvIds.has(conv.id);
|
|
2837
|
-
return (_jsxs("div", { className: `relative overflow-hidden transition-all duration-300 ease-[cubic-bezier(0.22,1,0.36,1)] ${isDeleting
|
|
2838
|
-
? 'max-h-0 opacity-0 -translate-y-2 scale-y-75 pointer-events-none'
|
|
2839
|
-
: 'max-h-20 opacity-100 translate-y-0 scale-y-100'}`, style: { transformOrigin: 'top left' }, children: [_jsxs("div", { className: `group/conv relative flex items-center rounded-md transition-all duration-300 ${selectedInboxConversationId === conv.id
|
|
2840
|
-
? 'bg-white/[0.06]'
|
|
2841
|
-
: 'hover:bg-white/[0.02]'} ${isDeleting ? 'translate-x-3 scale-[0.985] saturate-50' : 'translate-x-0 scale-100'}`, onMouseEnter: () => !isDeleting && setHoveredConvId(conv.id), onMouseLeave: () => { if (!isDeleting && convMenuId !== conv.id)
|
|
2842
|
-
setHoveredConvId(null); }, onContextMenu: (e) => {
|
|
2843
|
-
if (isDeleting)
|
|
2844
|
-
return;
|
|
2845
|
-
e.preventDefault();
|
|
2846
|
-
setConvMenuPos({ x: e.clientX, y: e.clientY });
|
|
2847
|
-
setConvMenuId(conv.id);
|
|
2848
|
-
setHoveredConvId(conv.id);
|
|
2849
|
-
}, children: [selectMode && (_jsx("button", { onClick: (e) => {
|
|
2850
|
-
if (isDeleting)
|
|
2851
|
-
return;
|
|
2852
|
-
e.stopPropagation();
|
|
2853
|
-
setSelectedConvIds(prev => {
|
|
2854
|
-
const next = new Set(prev);
|
|
2855
|
-
if (next.has(conv.id))
|
|
2856
|
-
next.delete(conv.id);
|
|
3632
|
+
else {
|
|
3633
|
+
onSelectInbox();
|
|
3634
|
+
}
|
|
3635
|
+
}, className: `w-full flex items-center gap-2.5 px-2.5 py-1.5 rounded-md text-left text-[12.5px] transition-colors cursor-pointer select-none ${isChatsActive
|
|
3636
|
+
? 'bg-white/[0.08] text-white font-medium'
|
|
3637
|
+
: 'text-zinc-400 hover:text-white hover:bg-white/[0.04]'}`, children: [_jsx(MessageSquare, { className: "w-3.5 h-3.5 text-zinc-400 flex-shrink-0" }), _jsx("span", { className: "flex-1 truncate", children: "Chat" })] }), _jsxs("button", { type: "button", onClick: () => {
|
|
3638
|
+
onSelectProjects();
|
|
3639
|
+
}, className: `w-full flex items-center gap-2.5 px-2.5 py-1.5 rounded-md text-left text-[12.5px] transition-colors cursor-pointer select-none ${isProjectsActive
|
|
3640
|
+
? 'bg-white/[0.08] text-white font-medium'
|
|
3641
|
+
: 'text-zinc-400 hover:text-white hover:bg-white/[0.04]'}`, children: [_jsx(Folder, { className: "w-3.5 h-3.5 text-zinc-400 flex-shrink-0" }), _jsx("span", { className: "flex-1 truncate", children: "Projects" })] }), _jsxs("button", { type: "button", onClick: () => {
|
|
3642
|
+
onSelectTeams?.();
|
|
3643
|
+
}, className: `w-full flex items-center gap-2.5 px-2.5 py-1.5 rounded-md text-left text-[12.5px] transition-colors cursor-pointer select-none ${isTeamsActive
|
|
3644
|
+
? 'bg-white/[0.08] text-white font-medium'
|
|
3645
|
+
: 'text-zinc-400 hover:text-white hover:bg-white/[0.04]'}`, children: [_jsx(Users, { className: "w-3.5 h-3.5 text-zinc-400 flex-shrink-0" }), _jsx("span", { className: "flex-1 truncate", children: "Teams" })] }), _jsxs("button", { type: "button", onClick: () => {
|
|
3646
|
+
onSelectAgents?.();
|
|
3647
|
+
}, className: `w-full flex items-center gap-2.5 px-2.5 py-1.5 rounded-md text-left text-[12.5px] transition-colors cursor-pointer select-none ${isAgentsActive
|
|
3648
|
+
? 'bg-white/[0.08] text-white font-medium'
|
|
3649
|
+
: 'text-zinc-400 hover:text-white hover:bg-white/[0.04]'}`, children: [_jsx(Bot, { className: "w-3.5 h-3.5 text-zinc-400 flex-shrink-0" }), _jsx("span", { className: "flex-1 truncate", children: "Agents" })] }), _jsxs("button", { type: "button", onClick: () => {
|
|
3650
|
+
onSelectKnowledge();
|
|
3651
|
+
}, className: "w-full flex items-center gap-2.5 px-2.5 py-1.5 rounded-md text-left text-[12.5px] text-zinc-400 hover:text-white hover:bg-white/[0.04] transition-colors cursor-pointer select-none", children: [_jsx(BookOpen, { className: "w-3.5 h-3.5 text-zinc-400 flex-shrink-0" }), _jsx("span", { className: "flex-1 truncate", children: "Library" })] }), _jsxs("button", { type: "button", onClick: () => {
|
|
3652
|
+
onSelectScheduled?.();
|
|
3653
|
+
}, className: `w-full flex items-center gap-2.5 px-2.5 py-1.5 rounded-md text-left text-[12.5px] transition-colors cursor-pointer select-none ${isScheduledActive
|
|
3654
|
+
? 'bg-white/[0.08] text-white font-medium'
|
|
3655
|
+
: 'text-zinc-400 hover:text-white hover:bg-white/[0.04]'}`, children: [_jsx(Clock, { className: "w-3.5 h-3.5 text-zinc-400 flex-shrink-0" }), _jsx("span", { className: "flex-1 truncate", children: "Scheduled" })] }), _jsxs("button", { type: "button", onClick: () => {
|
|
3656
|
+
const targetWs = scopedWorkspace || currentWorkspace || workspaces[0];
|
|
3657
|
+
if (targetWs) {
|
|
3658
|
+
onOpenSettings({
|
|
3659
|
+
type: 'workspace',
|
|
3660
|
+
workspaceId: targetWs.id,
|
|
3661
|
+
workspaceName: targetWs.name,
|
|
3662
|
+
teamCount: targetWs.teams.length,
|
|
3663
|
+
agentCount: targetWs.teams.reduce((acc, t) => acc + t.agents.length, 0),
|
|
3664
|
+
});
|
|
3665
|
+
}
|
|
3666
|
+
}, className: `w-full flex items-center gap-2.5 px-2.5 py-1.5 rounded-md text-left text-[12.5px] transition-colors cursor-pointer select-none ${isSettingsOpen
|
|
3667
|
+
? 'bg-white/[0.08] text-white font-medium'
|
|
3668
|
+
: 'text-zinc-400 hover:text-white hover:bg-white/[0.04]'}`, children: [_jsx(Settings, { className: "w-3.5 h-3.5 text-zinc-400 flex-shrink-0" }), _jsx("span", { className: "flex-1 truncate", children: "Settings" })] })] })] }), _jsxs("div", { className: "space-y-3 pt-1", children: [pinError && _jsx("p", { role: "alert", className: "px-2 text-[11px] text-amber-300", children: pinError }), (pinnedProjectItems.length > 0 || pinnedConversations.length > 0 || pinnedEntities.length > 0) && (_jsxs("div", { className: "pt-1 pb-1", children: [_jsxs("div", { className: "flex items-center justify-between px-2 pb-1 select-none", children: [_jsx("span", { className: "text-[11px] font-medium tracking-wide text-zinc-400", children: "Pinned" }), _jsx("span", { className: "text-[9px] font-mono px-1 py-0.2 rounded bg-white/[0.06] text-zinc-500", children: pinnedProjectItems.length + pinnedConversations.length + pinnedEntities.length })] }), _jsxs("div", { className: "space-y-0.5", children: [pinnedEntities.map(({ pin, name }) => (_jsxs("div", { className: "flex items-center gap-1 rounded-md px-2 py-1 text-[12px] text-zinc-300", children: [_jsxs("button", { type: "button", className: "min-w-0 flex-1 truncate text-left hover:text-white", onClick: () => {
|
|
3669
|
+
setActiveWorkspaceScope(pin.workspaceId);
|
|
3670
|
+
if (pin.type === 'agent')
|
|
3671
|
+
onSelectAgent(pin.agentId);
|
|
3672
|
+
else if (pin.type === 'team')
|
|
3673
|
+
onOpenSettings({ type: 'team', workspaceId: pin.workspaceId, teamId: pin.teamId, teamName: name });
|
|
2857
3674
|
else
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
}, children: selectedConvIds.has(conv.id) && (_jsx("svg", { width: "10", height: "10", viewBox: "0 0 24 24", fill: "none", stroke: "#09090b", strokeWidth: 3, strokeLinecap: "round", strokeLinejoin: "round", children: _jsx("polyline", { points: "20 6 9 17 4 12" }) })) })), editingConvId === conv.id ? (_jsx("input", { type: "text", value: editingConvValue, onChange: (e) => setEditingConvValue(e.target.value), onKeyDown: (e) => {
|
|
2865
|
-
if (e.key === 'Enter') {
|
|
2866
|
-
if (editingConvValue.trim())
|
|
2867
|
-
renameConversation(conv.id, editingConvValue.trim());
|
|
2868
|
-
setEditingConvId(null);
|
|
3675
|
+
onOpenSettings({ type: 'workspace', workspaceId: pin.workspaceId, workspaceName: name });
|
|
3676
|
+
}, children: [name, " ", _jsx("span", { className: "text-[9px] text-zinc-500", children: pin.type })] }), _jsx("button", { type: "button", "aria-label": `Unpin ${pin.type} ${name}`, onClick: () => togglePinnedEntity(pin), className: "p-1 text-[#8ad7ff] hover:text-white", children: _jsx(Pin, { className: "h-3 w-3 rotate-45 fill-current" }) })] }, entityPinKey(pin)))), pinnedProjectItems.map((p) => {
|
|
3677
|
+
const leadAgent = currentWorkspace?.teams?.[0]?.agents?.[0] || { id: inboxAgentId };
|
|
3678
|
+
return (_jsxs("div", { onClick: () => {
|
|
3679
|
+
if (onStartProjectChat) {
|
|
3680
|
+
onStartProjectChat(leadAgent.id, p.dir);
|
|
2869
3681
|
}
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
}, onBlur: () => {
|
|
2873
|
-
if (editingConvValue.trim())
|
|
2874
|
-
renameConversation(conv.id, editingConvValue.trim());
|
|
2875
|
-
setEditingConvId(null);
|
|
2876
|
-
}, className: "flex-1 px-2 py-1 bg-black/40 border border-white/[0.15] rounded text-[12px] text-white focus:outline-none", autoFocus: true })) : (_jsxs(_Fragment, { children: [_jsx("button", { onClick: () => { if (!isDeleting)
|
|
2877
|
-
onSelectInboxConversation(conv.id); }, className: `min-w-0 flex-1 px-2 py-1.5 text-left transition-colors ${selectedInboxConversationId === conv.id
|
|
2878
|
-
? 'text-[color:var(--xeno-ink-secondary)]'
|
|
2879
|
-
: 'text-[color:var(--xeno-ink-muted)] hover:text-[color:var(--xeno-ink-secondary)]'}`, children: _jsx("p", { className: "text-[12px] truncate", children: conv.title || 'New conversation' }) }), _jsx("div", { className: "flex-shrink-0 pr-1.5 flex items-center", children: hoveredConvId === conv.id ? (_jsx("div", { className: "relative", children: _jsx("button", { onClick: (e) => {
|
|
2880
|
-
if (isDeleting)
|
|
2881
|
-
return;
|
|
2882
|
-
e.stopPropagation();
|
|
2883
|
-
const rect = e.currentTarget.getBoundingClientRect();
|
|
2884
|
-
setConvMenuPos({ x: rect.right, y: rect.bottom + 4 });
|
|
2885
|
-
setConvMenuId(convMenuId === conv.id ? null : conv.id);
|
|
2886
|
-
}, className: "rounded p-0.5 text-[color:var(--xeno-ink-faint)] transition-colors hover:bg-white/[0.06] hover:text-[color:var(--xeno-ink-secondary)]", children: _jsxs("svg", { className: "w-3.5 h-3.5", fill: "currentColor", viewBox: "0 0 16 16", children: [_jsx("circle", { cx: "8", cy: "3", r: "1.5" }), _jsx("circle", { cx: "8", cy: "8", r: "1.5" }), _jsx("circle", { cx: "8", cy: "13", r: "1.5" })] }) }) })) : (_jsx("span", { className: "text-[9px] tabular-nums text-[color:var(--xeno-ink-faint)]", children: relativeDate(conv.lastMessageAt || conv.timestamp) })) })] }))] }), isDeleting && (_jsxs("div", { className: "pointer-events-none absolute inset-0 overflow-hidden rounded-md", children: [_jsx("div", { className: "absolute inset-0 bg-gradient-to-r from-red-400/10 via-orange-300/10 to-transparent" }), _jsx("span", { className: "absolute left-4 top-1/2 h-1 w-1 rounded-[1px] bg-red-300/80", style: { animation: 'conversationDeleteParticle 320ms ease-out forwards', ['--dx']: '10px', ['--dy']: '-14px' } }), _jsx("span", { className: "absolute left-10 top-1/2 h-1 w-1 rounded-[1px] bg-orange-200/80", style: { animation: 'conversationDeleteParticle 320ms ease-out forwards', animationDelay: '20ms', ['--dx']: '26px', ['--dy']: '-6px' } }), _jsx("span", { className: "absolute left-16 top-1/2 h-1.5 w-1.5 rounded-[2px] bg-white/70", style: { animation: 'conversationDeleteParticle 320ms ease-out forwards', animationDelay: '35ms', ['--dx']: '18px', ['--dy']: '10px' } }), _jsx("span", { className: "absolute left-24 top-1/2 h-1 w-1 rounded-[1px] bg-red-200/70", style: { animation: 'conversationDeleteParticle 320ms ease-out forwards', animationDelay: '15ms', ['--dx']: '30px', ['--dy']: '-18px' } })] }))] }, conv.id));
|
|
2887
|
-
}), visibleInboxConversations.length > 5 && (_jsx("button", { onClick: () => setInboxExpanded(!inboxExpanded), className: "w-full px-2 py-1 text-left text-[11px] text-[color:var(--xeno-ink-faint)] transition-colors hover:text-[color:var(--xeno-ink-muted)]", children: inboxExpanded ? 'Show less' : `${visibleInboxConversations.length - 5} more...` }))] })), !showGlobalSearchResults && inboxSearchMode && visibleInboxConversations.length === 0 && (_jsx("div", { className: "ml-3 mt-1 border-l pl-2 xeno-border-subtle", children: _jsx("p", { className: "px-2 py-1 text-[11px] text-[color:var(--xeno-ink-faint)]", children: "No inbox chats match your search." }) })), _jsxs("div", { className: "mt-4", children: [_jsx("div", { className: "px-2 flex items-center justify-between mb-2", children: _jsx("span", { className: "text-[12px] font-medium uppercase tracking-wider text-[color:var(--xeno-ink-faint)]", children: "Workspaces" }) }), _jsxs("div", { className: "space-y-1", children: [workspaces.filter(w => !w.isArchived).map((workspace) => (_jsxs("div", { children: [isRenaming('workspace', workspace.id) ? (_jsx("div", { className: "px-1 py-0.5", children: _jsx("input", { type: "text", value: renameValue, onChange: (e) => setRenameValue(e.target.value), onKeyDown: (e) => {
|
|
2888
|
-
if (e.key === 'Enter')
|
|
2889
|
-
handleRename();
|
|
2890
|
-
if (e.key === 'Escape') {
|
|
2891
|
-
setRenamingItem(null);
|
|
2892
|
-
setRenameValue('');
|
|
3682
|
+
else {
|
|
3683
|
+
onSelectProjects();
|
|
2893
3684
|
}
|
|
2894
|
-
},
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
3685
|
+
}, className: "group/pinned relative flex items-center justify-between rounded-md px-2.5 py-1.5 transition-colors cursor-pointer select-none text-zinc-300 hover:text-white hover:bg-white/[0.04]", title: `Project: ${p.dir}`, children: [_jsxs("div", { className: "flex items-center gap-2 min-w-0 flex-1", children: [_jsx("div", { className: "p-1 rounded bg-[#8ad7ff]/10 text-[#8ad7ff] flex-shrink-0", children: _jsx(Folder, { className: "w-3.5 h-3.5" }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("span", { className: "text-[12px] font-medium text-white truncate block", children: p.name }), _jsx("span", { className: "text-[10px] text-zinc-500 truncate block font-mono", children: p.workspaceName })] })] }), _jsxs("div", { className: "flex items-center gap-1 ml-auto flex-shrink-0", children: [_jsx("button", { type: "button", onClick: (e) => {
|
|
3686
|
+
e.stopPropagation();
|
|
3687
|
+
handleOpenPathInExplorer(p.dir);
|
|
3688
|
+
}, className: "hidden group-hover/pinned:flex p-1 rounded text-zinc-400 hover:text-white transition-colors", title: "Open in Explorer", children: _jsx(ArrowUpRight, { className: "w-3 h-3" }) }), _jsx("button", { type: "button", onClick: (e) => {
|
|
3689
|
+
e.stopPropagation();
|
|
3690
|
+
togglePinProject(p.dir);
|
|
3691
|
+
}, className: "hidden group-hover/pinned:flex p-1 rounded text-[#8ad7ff] hover:text-white transition-colors", title: "Unpin project", children: _jsx(Pin, { className: "w-3 h-3 rotate-45 fill-current" }) })] })] }, p.dir));
|
|
3692
|
+
}), pinnedConversations.map((conv) => {
|
|
3693
|
+
const isSelected = selectedInboxConversationId === conv.id || selectedConversationId === conv.id;
|
|
3694
|
+
const ws = workspaces.find((w) => w.id === conv.workspaceId) ||
|
|
3695
|
+
workspaces.find((w) => w.directories?.some((d) => conv.rootDirectory?.startsWith(d)));
|
|
3696
|
+
const folderLabel = conv.rootDirectory
|
|
3697
|
+
? (conv.rootDirectory.split(/[\\/]/).pop() || conv.rootDirectory)
|
|
3698
|
+
: (ws?.name || 'Workspace');
|
|
3699
|
+
return (_jsxs("div", { onClick: () => {
|
|
3700
|
+
const targetAgentId = conv.agentId || inboxAgentId;
|
|
3701
|
+
onSelectConversation(targetAgentId, conv.id);
|
|
3702
|
+
}, onMouseEnter: (e) => handleConvMouseEnter(e, conv, ws?.name || 'Pinned', ws?.id), onMouseLeave: handleConvMouseLeave, onContextMenu: (e) => {
|
|
3703
|
+
e.preventDefault();
|
|
3704
|
+
setConvMenuPos({ x: e.clientX, y: e.clientY });
|
|
3705
|
+
setConvMenuId(conv.id);
|
|
3706
|
+
}, className: `group/pinned relative rounded-md px-2.5 py-1.5 transition-colors cursor-pointer select-none ${isSelected
|
|
3707
|
+
? 'bg-white/[0.08] text-white font-medium'
|
|
3708
|
+
: 'text-zinc-300 hover:text-white hover:bg-white/[0.04]'}`, children: [_jsxs("div", { className: "flex items-center justify-between gap-1.5 min-w-0", children: [_jsx("span", { className: "text-[12px] font-medium text-white truncate flex-1 min-w-0", children: conv.title || 'New conversation' }), _jsx("span", { className: "text-[10px] font-mono text-zinc-500 flex-shrink-0 group-hover/pinned:hidden", children: relativeDate(conv.lastMessageAt || conv.timestamp || conv.createdAt || Date.now()) }), _jsx("button", { type: "button", onClick: (e) => {
|
|
3709
|
+
e.stopPropagation();
|
|
3710
|
+
togglePinConversation(conv.id);
|
|
3711
|
+
}, className: "hidden group-hover/pinned:flex p-0.5 rounded text-[#8ad7ff] hover:text-white transition-colors", title: "Unpin conversation", children: _jsx(Pin, { className: "w-3 h-3 rotate-45 fill-current" }) })] }), _jsxs("div", { className: "flex items-center gap-1.5 text-[11px] text-zinc-500 group-hover/pinned:text-zinc-400 transition-colors mt-0.5 truncate", children: [_jsx(Folder, { className: "w-3 h-3 text-zinc-500 flex-shrink-0" }), _jsx("span", { className: "truncate font-mono text-[10.5px]", children: folderLabel })] })] }, conv.id));
|
|
3712
|
+
})] })] })), _jsx("div", { className: "pt-1", children: (() => {
|
|
3713
|
+
const targetWs = scopedWorkspace;
|
|
3714
|
+
const mainAgentInfo = scopedMainAgentInfo || (() => {
|
|
3715
|
+
if (!targetWs)
|
|
3716
|
+
return null;
|
|
3717
|
+
for (const team of targetWs.teams) {
|
|
3718
|
+
const main = team.agents.find(a => a.isMainAssistant);
|
|
3719
|
+
if (main)
|
|
3720
|
+
return { agent: main, team };
|
|
3721
|
+
}
|
|
3722
|
+
if (targetWs.teams[0]?.agents[0]) {
|
|
3723
|
+
return { agent: targetWs.teams[0].agents[0], team: targetWs.teams[0] };
|
|
3724
|
+
}
|
|
3725
|
+
return null;
|
|
3726
|
+
})();
|
|
3727
|
+
const targetAgentId = mainAgentInfo?.agent?.id || inboxAgentId;
|
|
3728
|
+
const targetTeamId = mainAgentInfo?.team?.id;
|
|
3729
|
+
// Workspace-scoped conversations: strictly isolated to this workspace
|
|
3730
|
+
const workspaceConversations = (() => {
|
|
3731
|
+
if (!targetWs)
|
|
3732
|
+
return inboxConversations.filter(c => isPersonalInboxConversation(conversations[c.id], inboxAgentId));
|
|
3733
|
+
const agentConvs = mainAgentInfo ? (conversationsByAgent[mainAgentInfo.agent.id] || []) : [];
|
|
3734
|
+
const boundInboxConvs = Object.values(conversations || {})
|
|
3735
|
+
.filter((c) => c && c.agentId === inboxAgentId && c.workspaceId === targetWs.id)
|
|
3736
|
+
.map((c) => ({
|
|
3737
|
+
id: c.id,
|
|
3738
|
+
title: c.title || 'New conversation',
|
|
3739
|
+
timestamp: c.createdAt,
|
|
3740
|
+
lastMessageAt: c.lastMessageAt,
|
|
3741
|
+
}));
|
|
3742
|
+
const map = new Map();
|
|
3743
|
+
for (const c of [...agentConvs, ...boundInboxConvs]) {
|
|
3744
|
+
if (c && c.id)
|
|
3745
|
+
map.set(c.id, c);
|
|
3746
|
+
}
|
|
3747
|
+
return Array.from(map.values()).sort((a, b) => {
|
|
3748
|
+
const aPinned = pinnedConvIds.has(a.id);
|
|
3749
|
+
const bPinned = pinnedConvIds.has(b.id);
|
|
3750
|
+
if (aPinned && !bPinned)
|
|
3751
|
+
return -1;
|
|
3752
|
+
if (!aPinned && bPinned)
|
|
3753
|
+
return 1;
|
|
3754
|
+
return (b.lastMessageAt || b.timestamp || 0) - (a.lastMessageAt || a.timestamp || 0);
|
|
3755
|
+
});
|
|
3756
|
+
})();
|
|
3757
|
+
const isMainChatActive = (selectedAgentId === targetAgentId && !selectedConversationId) ||
|
|
3758
|
+
(viewMode === 'inbox' && !scopedWorkspace && !selectedInboxConversationId);
|
|
3759
|
+
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "group/mainchat w-full flex items-center justify-between px-2.5 py-1.5 rounded-md transition-colors text-left select-none cursor-pointer " + (isMainChatActive
|
|
3760
|
+
? "bg-white/[0.08] text-white font-medium"
|
|
3761
|
+
: "text-zinc-300 hover:text-white hover:bg-white/[0.04]"), onClick: () => {
|
|
3762
|
+
if (scopedWorkspace) {
|
|
3763
|
+
handleSelectScopedWorkspaceChat();
|
|
3764
|
+
}
|
|
3765
|
+
else {
|
|
3766
|
+
onSelectInbox();
|
|
3767
|
+
}
|
|
3768
|
+
}, children: [_jsxs("div", { className: "flex items-center gap-2 min-w-0 flex-1", children: [_jsx(InboxIcon, {}), _jsx("span", { className: "text-[12.5px] font-medium truncate", children: "Main Chat" })] }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsx("button", { type: "button", onClick: (e) => {
|
|
3769
|
+
e.stopPropagation();
|
|
3770
|
+
if (scopedWorkspace) {
|
|
3771
|
+
const targetId = mainAgentInfo?.agent?.id;
|
|
3772
|
+
if (targetId) {
|
|
3773
|
+
const newId = createConversation(targetId);
|
|
3774
|
+
onSelectConversation(targetId, newId);
|
|
3775
|
+
}
|
|
3776
|
+
else {
|
|
3777
|
+
handleSelectScopedWorkspaceChat();
|
|
2900
3778
|
}
|
|
2901
|
-
}
|
|
2902
|
-
|
|
2903
|
-
const
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
3779
|
+
}
|
|
3780
|
+
else {
|
|
3781
|
+
const newId = createConversation(inboxAgentId);
|
|
3782
|
+
onSelectConversation(inboxAgentId, newId);
|
|
3783
|
+
}
|
|
3784
|
+
}, className: "p-1 rounded text-zinc-500 hover:text-white transition-colors cursor-pointer", title: "New conversation in Main Chat", children: _jsx(Plus, { className: "w-3.5 h-3.5" }) }), _jsx("button", { type: "button", onClick: (e) => {
|
|
3785
|
+
e.stopPropagation();
|
|
3786
|
+
setInboxExpanded((prev) => !prev);
|
|
3787
|
+
}, className: "p-1 rounded text-zinc-500 hover:text-white transition-colors cursor-pointer", title: inboxExpanded ? "Collapse conversations" : "Expand conversations", children: _jsx(ChevronDown, { className: "w-3 h-3 transition-transform " + (inboxExpanded ? "" : "-rotate-90") }) })] })] }), inboxExpanded && workspaceConversations.length > 0 && (_jsx("div", { className: "space-y-0.5 pt-0.5", children: workspaceConversations.map((conv) => {
|
|
3788
|
+
const isActive = (selectedAgentId === targetAgentId && selectedConversationId === conv.id) ||
|
|
3789
|
+
(viewMode === 'inbox' && selectedInboxConversationId === conv.id);
|
|
3790
|
+
const isPinned = pinnedConvIds.has(conv.id);
|
|
3791
|
+
return (_jsxs("div", { className: "group/conv relative flex items-center justify-between rounded-md transition-colors px-2.5 py-1.5 cursor-pointer " + (isActive
|
|
3792
|
+
? "bg-white/[0.08] text-white font-medium"
|
|
3793
|
+
: "text-zinc-400 hover:text-zinc-200 hover:bg-white/[0.04]"), onClick: () => {
|
|
3794
|
+
if (targetWs) {
|
|
3795
|
+
setActiveWorkspaceScope(targetWs.id);
|
|
3796
|
+
}
|
|
3797
|
+
onSelectConversation(targetAgentId, conv.id);
|
|
3798
|
+
}, onMouseEnter: (e) => handleConvMouseEnter(e, conv, targetWs ? `${targetWs.name} / Main Chat` : 'Personal / Main Chat', targetWs?.id), onMouseLeave: handleConvMouseLeave, onContextMenu: (e) => {
|
|
3799
|
+
if (targetWs)
|
|
3800
|
+
handleContextMenu(e, 'conversation', targetWs.id, targetTeamId, targetAgentId, conv.id);
|
|
3801
|
+
else {
|
|
3802
|
+
e.preventDefault();
|
|
3803
|
+
e.stopPropagation();
|
|
3804
|
+
setConvMenuPos({ x: e.clientX, y: e.clientY });
|
|
3805
|
+
setConvMenuId(conv.id);
|
|
3806
|
+
}
|
|
3807
|
+
}, children: [_jsxs("div", { className: "flex items-center gap-2 min-w-0 flex-1", children: [_jsx("div", { className: "w-4 h-4 flex items-center justify-center mr-1 flex-shrink-0", children: isActive ? (_jsx("span", { className: "w-2 h-2 rounded-[2px] bg-white" })) : (_jsx("span", { className: "w-2 h-2 rounded-[2px] border border-zinc-500/80" })) }), _jsx("span", { className: "text-[12px] truncate flex-1 min-w-0", children: conv.title || 'New conversation' })] }), _jsxs("div", { className: "flex items-center gap-1 ml-auto flex-shrink-0", children: [_jsx("button", { type: "button", onClick: (e) => {
|
|
3808
|
+
e.stopPropagation();
|
|
3809
|
+
togglePinConversation(conv.id);
|
|
3810
|
+
}, className: "p-0.5 rounded transition-colors " + (isPinned
|
|
3811
|
+
? "text-[#8ad7ff] hover:text-white"
|
|
3812
|
+
: "text-zinc-500 hover:text-white opacity-0 group-hover/conv:opacity-100"), title: isPinned ? "Unpin conversation" : "Pin conversation", children: _jsx(Pin, { className: "w-3.5 h-3.5 " + (isPinned ? "rotate-45 fill-current" : "") }) }), _jsx("button", { type: "button", onClick: (e) => {
|
|
3813
|
+
e.stopPropagation();
|
|
3814
|
+
if (targetWs)
|
|
3815
|
+
handleContextMenu(e, 'conversation', targetWs.id, targetTeamId, targetAgentId, conv.id);
|
|
3816
|
+
else {
|
|
3817
|
+
e.preventDefault();
|
|
3818
|
+
setConvMenuPos({ x: e.clientX, y: e.clientY });
|
|
3819
|
+
setConvMenuId(conv.id);
|
|
3820
|
+
}
|
|
3821
|
+
}, className: "p-0.5 rounded text-zinc-500 hover:text-white transition-colors opacity-0 group-hover/conv:opacity-100", title: "Conversation options", children: _jsx(MoreHorizontal, { className: "w-3.5 h-3.5" }) })] })] }, conv.id));
|
|
3822
|
+
}) }))] }));
|
|
3823
|
+
})() }), _jsxs("div", { className: "pt-1", children: [_jsxs("div", { className: "flex items-center justify-between px-2 pb-1 select-none", children: [_jsxs("button", { type: "button", onClick: () => setIsProjectsCollapsed((prev) => !prev), className: "flex items-center gap-1 text-[11px] font-medium uppercase tracking-wider text-zinc-500 hover:text-zinc-300 transition-colors cursor-pointer", children: [_jsx("span", { children: "Projects" }), _jsx("span", { className: "text-[9px] font-mono px-1 py-0.2 rounded bg-white/[0.06] text-zinc-400", children: currentWorkspaceProjects.length }), _jsx(ChevronDown, { className: `w-3 h-3 transition-transform ${isProjectsCollapsed ? '-rotate-90' : ''}` })] }), _jsx("button", { type: "button", onClick: () => {
|
|
3824
|
+
const targetWsId = currentWorkspace ? currentWorkspace.id : workspaces[0]?.id;
|
|
3825
|
+
if (targetWsId)
|
|
3826
|
+
void handleAddProjectToWorkspace(targetWsId);
|
|
3827
|
+
}, className: "p-1 rounded text-zinc-500 hover:text-white hover:bg-white/[0.04] transition-colors", title: "Link project folder", children: _jsx(Plus, { className: "w-3.5 h-3.5" }) })] }), !isProjectsCollapsed && (_jsx("div", { className: "space-y-0.5", children: currentWorkspaceProjects.length === 0 ? (_jsx("div", { className: "px-2 py-1 text-[11px] text-zinc-600 italic select-none", children: "No projects linked yet" })) : (currentWorkspaceProjects.map((dir) => {
|
|
3828
|
+
const projectName = dir.split(/[\\/]/).filter(Boolean).pop() || dir;
|
|
3829
|
+
const isPinned = pinnedProjects.includes(dir);
|
|
3830
|
+
const leadAgent = currentWorkspace?.teams?.[0]?.agents?.[0];
|
|
3831
|
+
return (_jsxs("div", { onClick: () => {
|
|
3832
|
+
if (leadAgent && onStartProjectChat) {
|
|
3833
|
+
onStartProjectChat(leadAgent.id, dir);
|
|
3834
|
+
}
|
|
3835
|
+
else {
|
|
3836
|
+
onSelectProjects();
|
|
3837
|
+
}
|
|
3838
|
+
}, className: "group/proj relative flex items-center justify-between rounded-md px-2.5 py-1.5 transition-colors cursor-pointer select-none text-zinc-400 hover:text-white hover:bg-white/[0.04]", title: dir, children: [_jsxs("div", { className: "flex items-center gap-2 min-w-0 flex-1", children: [_jsx(Folder, { className: "w-3.5 h-3.5 text-zinc-500 group-hover/proj:text-[#8ad7ff] transition-colors flex-shrink-0" }), _jsx("span", { className: "text-[12px] truncate flex-1", children: projectName })] }), _jsxs("div", { className: "flex items-center gap-0.5 opacity-0 group-hover/proj:opacity-100 transition-opacity ml-auto flex-shrink-0", children: [_jsx("button", { type: "button", onClick: (e) => {
|
|
3839
|
+
e.stopPropagation();
|
|
3840
|
+
togglePinProject(dir);
|
|
3841
|
+
}, className: `p-1 rounded transition-colors ${isPinned ? 'text-[#8ad7ff]' : 'text-zinc-500 hover:text-white'}`, title: isPinned ? 'Unpin project' : 'Pin project to top', children: _jsx(Pin, { className: `w-3 h-3 ${isPinned ? 'rotate-45 fill-current' : ''}` }) }), _jsx("button", { type: "button", onClick: (e) => {
|
|
3842
|
+
e.stopPropagation();
|
|
3843
|
+
handleOpenPathInExplorer(dir);
|
|
3844
|
+
}, className: "p-1 rounded text-zinc-500 hover:text-white transition-colors", title: "Open in Windows Explorer", children: _jsx(ArrowUpRight, { className: "w-3 h-3" }) })] })] }, dir));
|
|
3845
|
+
})) }))] }), _jsxs("div", { className: "pt-1", children: [_jsxs("div", { className: "flex items-center justify-between px-2 pb-1.5 select-none", children: [_jsx("span", { className: "text-[11px] font-medium uppercase tracking-wider text-zinc-500", children: "Teams" }), _jsxs("div", { className: "flex items-center gap-0.5", children: [_jsx("button", { type: "button", onClick: handleToggleSidebarViewMode, "aria-label": "Stacked sidebar layout", "aria-pressed": sidebarViewMode === 'stacked', className: "p-1 rounded transition-colors " + (sidebarViewMode === 'stacked' ? "text-[#8ad7ff] hover:text-white" : "text-zinc-500 hover:text-zinc-200 hover:bg-white/[0.04]"), title: sidebarViewMode === 'tree' ? 'Switch to Stacked View' : 'Switch to Tree View', children: sidebarViewMode === 'tree' ? _jsx(Layers, { className: "w-3.5 h-3.5" }) : _jsx(GitBranch, { className: "w-3.5 h-3.5" }) }), _jsx("button", { onClick: () => {
|
|
3846
|
+
const targetWsId = currentWorkspace ? currentWorkspace.id : workspaces[0]?.id;
|
|
3847
|
+
if (targetWsId)
|
|
3848
|
+
setAddingTeamToWorkspace(targetWsId);
|
|
3849
|
+
}, className: "p-1 rounded text-zinc-500 hover:text-zinc-200 hover:bg-white/[0.04] transition-colors", title: "Add team", children: _jsx(Plus, { className: "w-3.5 h-3.5" }) })] })] }), _jsx("div", { className: "space-y-3 pt-1", children: workspaces
|
|
3850
|
+
.filter((w) => !w.isArchived && (!activeWorkspaceScope || w.id === activeWorkspaceScope))
|
|
3851
|
+
.flatMap((workspace) => workspace.teams.map((team) => {
|
|
3852
|
+
const teamConversations = team.agents.flatMap((agent) => (conversationsByAgent[agent.id] || []).map((conv) => ({ conv, agent }))).sort((a, b) => {
|
|
3853
|
+
const aPinned = pinnedConvIds.has(a.conv.id);
|
|
3854
|
+
const bPinned = pinnedConvIds.has(b.conv.id);
|
|
3855
|
+
if (aPinned && !bPinned)
|
|
3856
|
+
return -1;
|
|
3857
|
+
if (!aPinned && bPinned)
|
|
3858
|
+
return 1;
|
|
3859
|
+
return (b.conv.lastMessageAt || b.conv.timestamp || 0) - (a.conv.lastMessageAt || a.conv.timestamp || 0);
|
|
3860
|
+
});
|
|
3861
|
+
const leadAgent = team.agents[0];
|
|
3862
|
+
return (_jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "group/header flex items-center justify-between px-2 py-1 rounded-md bg-white/[0.02] hover:bg-white/[0.04] transition-colors text-[11.5px]", onMouseEnter: (e) => handleTeamMouseEnter(e, workspace, team), onMouseLeave: handleConvMouseLeave, children: [_jsxs("div", { className: "flex items-center gap-1.5 min-w-0 flex-1 truncate", children: [_jsx("button", { type: "button", onClick: () => setActiveWorkspaceScope(workspace.id), onContextMenu: (e) => handleContextMenu(e, 'workspace', workspace.id), className: "text-zinc-400 hover:text-white truncate font-medium transition-colors cursor-pointer", title: `Scope into workspace: ${workspace.name}`, children: workspace.name }), _jsx("span", { className: "text-zinc-600 font-mono select-none flex-shrink-0", children: "/" }), _jsx("button", { type: "button", onClick: () => onOpenSettings({
|
|
3863
|
+
type: 'team',
|
|
3864
|
+
workspaceId: workspace.id,
|
|
3865
|
+
teamId: team.id,
|
|
3866
|
+
teamName: team.name,
|
|
3867
|
+
workspaceName: workspace.name,
|
|
3868
|
+
}), onContextMenu: (e) => handleContextMenu(e, 'team', workspace.id, team.id), className: "text-zinc-300 hover:text-white truncate transition-colors cursor-pointer", title: `Team: ${team.name}`, children: team.name })] }), _jsxs("div", { className: "flex items-center gap-0.5 opacity-0 group-hover/header:opacity-100 transition-opacity flex-shrink-0", children: [leadAgent && (_jsx("button", { type: "button", onClick: () => {
|
|
3869
|
+
const newId = createConversation(leadAgent.id);
|
|
3870
|
+
onSelectConversation(leadAgent.id, newId);
|
|
3871
|
+
}, className: "p-0.5 rounded text-zinc-500 hover:text-white transition-colors", title: `New chat in ${team.name}`, children: _jsx(Plus, { className: "w-3.5 h-3.5", strokeWidth: 1.75 }) })), _jsx("button", { type: "button", onClick: (e) => handleContextMenu(e, 'team', workspace.id, team.id), className: "p-0.5 rounded text-zinc-500 hover:text-white transition-colors", title: "Team options", children: _jsx(MoreHorizontal, { className: "w-3.5 h-3.5" }) })] })] }), _jsx("div", { className: "space-y-0.5 pl-2", children: teamConversations.length === 0 ? (_jsx("div", { className: "px-2 py-1 text-[11px] text-zinc-600 italic select-none", children: "No chats yet" })) : (teamConversations.map(({ conv, agent }) => {
|
|
3872
|
+
const isActive = selectedConversationId === conv.id;
|
|
3873
|
+
const isPinned = pinnedConvIds.has(conv.id);
|
|
3874
|
+
return (_jsxs("div", { className: "group/conv relative flex items-center justify-between rounded-md transition-colors px-2.5 py-1.5 cursor-pointer " + (isActive
|
|
3875
|
+
? "bg-white/[0.08] text-white font-medium"
|
|
3876
|
+
: "text-zinc-400 hover:text-zinc-200 hover:bg-white/[0.04]"), onClick: () => {
|
|
3877
|
+
setActiveWorkspaceScope(workspace.id);
|
|
3878
|
+
onSelectConversation(agent.id, conv.id);
|
|
3879
|
+
}, onMouseEnter: (e) => handleConvMouseEnter(e, conv, `${workspace.name} / ${team.name}`, workspace.id), onMouseLeave: handleConvMouseLeave, onContextMenu: (e) => {
|
|
3880
|
+
handleContextMenu(e, 'conversation', workspace.id, team.id, agent.id, conv.id);
|
|
3881
|
+
}, children: [_jsxs("div", { className: "flex items-center gap-2 min-w-0 flex-1", children: [_jsx("div", { className: "w-4 h-4 flex items-center justify-center mr-1 flex-shrink-0", children: isActive ? (_jsx("span", { className: "w-2 h-2 rounded-[2px] bg-white" })) : (_jsx("span", { className: "w-2 h-2 rounded-[2px] border border-zinc-500/80" })) }), _jsx("span", { className: "text-[12px] truncate flex-1 min-w-0", children: conv.title || 'New conversation' })] }), _jsxs("div", { className: "flex items-center gap-1 ml-auto flex-shrink-0", children: [_jsx("button", { type: "button", onClick: (e) => {
|
|
3882
|
+
e.stopPropagation();
|
|
3883
|
+
togglePinConversation(conv.id);
|
|
3884
|
+
}, className: "p-0.5 rounded transition-colors " + (isPinned ? "text-[#8ad7ff] hover:text-white" : "text-zinc-500 hover:text-white opacity-0 group-hover/conv:opacity-100"), title: isPinned ? "Unpin conversation" : "Pin conversation", children: _jsx(Pin, { className: "w-3.5 h-3.5 " + (isPinned ? "rotate-45 fill-current" : "") }) }), _jsx("button", { type: "button", onClick: (e) => {
|
|
3885
|
+
e.stopPropagation();
|
|
3886
|
+
handleContextMenu(e, 'conversation', workspace.id, team.id, agent.id, conv.id);
|
|
3887
|
+
}, className: "p-0.5 rounded text-zinc-500 hover:text-white transition-colors", title: "Conversation options", children: _jsx(MoreHorizontal, { className: "w-3.5 h-3.5" }) })] })] }, conv.id));
|
|
3888
|
+
})) })] }, `${workspace.id}-${team.id}`));
|
|
3889
|
+
})) })] })] })] }), _jsxs("div", { className: "flex h-[48px] items-center gap-1 border-t px-2 xeno-border-subtle", children: [_jsxs("button", { onClick: onSelectKnowledge, className: "flex flex-1 items-center justify-center gap-1.5 rounded-md py-1.5 text-[color:var(--xeno-ink-muted)] transition-colors hover:bg-white/[0.04] hover:text-[color:var(--xeno-ink-secondary)]", children: [_jsx(BookIcon, {}), _jsx("span", { className: "text-[11px]", children: "Knowledge" })] }), _jsx("div", { className: "h-4 w-px xeno-border-subtle bg-[var(--xeno-border-subtle)]" }), _jsxs("button", { onClick: onSelectPlugins, className: "flex flex-1 items-center justify-center gap-1.5 rounded-md py-1.5 text-[color:var(--xeno-ink-muted)] transition-colors hover:bg-white/[0.04] hover:text-[color:var(--xeno-ink-secondary)]", "aria-label": "Plugins", children: [_jsx(Package, { className: "w-4 h-4", strokeWidth: 1.5 }), _jsx("span", { className: "text-[11px]", children: "Plugins" })] }), _jsx("div", { className: "h-4 w-px xeno-border-subtle bg-[var(--xeno-border-subtle)]" }), _jsxs("button", { onClick: onSelectSettings, className: "flex flex-1 items-center justify-center gap-1.5 rounded-md py-1.5 text-[color:var(--xeno-ink-muted)] transition-colors hover:bg-white/[0.04] hover:text-[color:var(--xeno-ink-secondary)]", children: [_jsx(SettingsIcon, {}), _jsx("span", { className: "text-[11px]", children: "Settings" })] })] }), contextMenu && (_jsx(ContextMenuPopup, { menu: contextMenu, workspaces: workspaces, onClose: () => setContextMenu(null), onAction: handleContextAction })), inboxMenuPos && createPortal(_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-[499]", onClick: () => setInboxMenuPos(null), onContextMenu: (e) => {
|
|
2966
3890
|
e.preventDefault();
|
|
2967
3891
|
setInboxMenuPos(null);
|
|
2968
|
-
} }), _jsxs("div", { className: "fixed z-[
|
|
3892
|
+
} }), _jsxs("div", { className: "fixed z-[500] w-[195px] rounded-lg border border-white/[0.12] bg-[#18181b] p-1 shadow-2xl backdrop-blur-md text-[12px] text-zinc-300 select-none animate-in fade-in duration-100", style: {
|
|
3893
|
+
left: Math.max(8, Math.min(inboxMenuPos.x, window.innerWidth - 210)),
|
|
3894
|
+
top: Math.max(8, Math.min(inboxMenuPos.y, window.innerHeight - 240))
|
|
3895
|
+
}, children: [_jsxs("button", { type: "button", onClick: () => {
|
|
3896
|
+
if (scopedWorkspace) {
|
|
3897
|
+
handleSelectScopedWorkspaceChat();
|
|
3898
|
+
}
|
|
3899
|
+
else {
|
|
3900
|
+
onSelectInbox();
|
|
3901
|
+
}
|
|
3902
|
+
setInboxMenuPos(null);
|
|
3903
|
+
}, className: "w-full px-2.5 py-1.5 rounded-t-[6px] rounded-b-[2px] text-left text-[12px] text-zinc-300 hover:bg-white/[0.06] hover:text-white transition-colors flex items-center gap-2 cursor-pointer select-none", children: [_jsx(MessageSquare, { className: "w-3.5 h-3.5 text-zinc-400 flex-shrink-0" }), _jsx("span", { className: "flex-1 truncate", children: "New Conversation" }), _jsx("span", { className: "text-[11px] font-mono text-zinc-500 pl-2 ml-auto flex-shrink-0", children: "N" })] }), _jsxs("button", { type: "button", onClick: () => {
|
|
3904
|
+
handleInboxSearchStart();
|
|
3905
|
+
setInboxMenuPos(null);
|
|
3906
|
+
}, className: "w-full px-2.5 py-1.5 rounded-[2px] text-left text-[12px] text-zinc-300 hover:bg-white/[0.06] hover:text-white transition-colors flex items-center gap-2 cursor-pointer select-none", children: [_jsx(Search, { className: "w-3.5 h-3.5 text-zinc-400 flex-shrink-0" }), _jsx("span", { className: "flex-1 truncate", children: "Search Chats" }), _jsx("span", { className: "text-[11px] font-mono text-zinc-500 pl-2 ml-auto flex-shrink-0", children: "F" })] }), _jsxs("button", { type: "button", onClick: () => {
|
|
3907
|
+
handleInboxSelectAll();
|
|
3908
|
+
setInboxMenuPos(null);
|
|
3909
|
+
}, className: "w-full px-2.5 py-1.5 rounded-[2px] text-left text-[12px] text-zinc-300 hover:bg-white/[0.06] hover:text-white transition-colors flex items-center gap-2 cursor-pointer select-none", children: [_jsx(CheckSquare, { className: "w-3.5 h-3.5 text-zinc-400 flex-shrink-0" }), _jsx("span", { className: "flex-1 truncate", children: areAllVisibleInboxConversationsSelected ? 'Unselect All' : 'Select All' }), _jsx("span", { className: "text-[11px] font-mono text-zinc-500 pl-2 ml-auto flex-shrink-0", children: "A" })] }), _jsxs("button", { type: "button", onClick: () => {
|
|
3910
|
+
if (scopedWorkspace) {
|
|
3911
|
+
onOpenSettings({
|
|
3912
|
+
type: 'workspace',
|
|
3913
|
+
workspaceId: scopedWorkspace.id,
|
|
3914
|
+
workspaceName: scopedWorkspace.name,
|
|
3915
|
+
teamCount: scopedWorkspace.teams.length,
|
|
3916
|
+
agentCount: scopedWorkspace.teams.reduce((acc, t) => acc + t.agents.length, 0),
|
|
3917
|
+
});
|
|
3918
|
+
}
|
|
3919
|
+
else {
|
|
3920
|
+
onSelectSettings();
|
|
3921
|
+
}
|
|
3922
|
+
setInboxMenuPos(null);
|
|
3923
|
+
}, className: "w-full px-2.5 py-1.5 rounded-[2px] text-left text-[12px] text-zinc-300 hover:bg-white/[0.06] hover:text-white transition-colors flex items-center gap-2 cursor-pointer select-none", children: [_jsx(Settings, { className: "w-3.5 h-3.5 text-zinc-400 flex-shrink-0" }), _jsx("span", { className: "flex-1 truncate", children: scopedWorkspace ? 'Workspace Settings' : 'Chat Settings' }), _jsx("span", { className: "text-[11px] font-mono text-zinc-500 pl-2 ml-auto flex-shrink-0", children: "S" })] }), visibleInboxConversations.length > 0 && (_jsxs(_Fragment, { children: [_jsx("div", { className: "my-1 border-t border-white/[0.06]" }), _jsxs("button", { type: "button", onClick: () => {
|
|
3924
|
+
animateDeleteConversations(visibleInboxConversations.map(c => c.id), null);
|
|
3925
|
+
setInboxMenuPos(null);
|
|
3926
|
+
}, className: "w-full px-2.5 py-1.5 rounded-b-[6px] rounded-t-[2px] text-left text-[12px] text-red-400 hover:bg-red-500/10 hover:text-red-300 transition-colors flex items-center gap-2 cursor-pointer select-none", children: [_jsx(Trash2, { className: "w-3.5 h-3.5 text-red-400 flex-shrink-0" }), _jsx("span", { className: "flex-1 truncate", children: "Clear All Conversations" }), _jsx("span", { className: "text-[11px] font-mono text-zinc-500 pl-2 ml-auto flex-shrink-0", children: "D" })] })] }))] })] }), document.body), convMenuId && createPortal(_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-[499]", onClick: () => { setConvMenuId(null); setHoveredConvId(null); }, onContextMenu: (e) => { e.preventDefault(); setConvMenuId(null); setHoveredConvId(null); } }), _jsxs("div", { className: "fixed z-[500] w-[175px] rounded-lg border border-white/[0.12] bg-[#18181b] p-1 shadow-2xl backdrop-blur-md text-[12px] text-zinc-300 select-none animate-in fade-in duration-100", style: {
|
|
3927
|
+
left: Math.max(8, Math.min(convMenuPos.x, window.innerWidth - 190)),
|
|
3928
|
+
top: Math.max(8, Math.min(convMenuPos.y, window.innerHeight - 150))
|
|
3929
|
+
}, children: [_jsxs("button", { type: "button", onClick: () => {
|
|
2969
3930
|
const conv = inboxConversations.find(c => c.id === convMenuId);
|
|
2970
3931
|
setEditingConvId(convMenuId);
|
|
2971
3932
|
setEditingConvValue(conv?.title || '');
|
|
2972
3933
|
setConvMenuId(null);
|
|
2973
|
-
}, className: "
|
|
3934
|
+
}, className: "w-full px-2.5 py-1.5 rounded-t-[6px] rounded-b-[2px] text-left text-[12px] text-zinc-300 hover:bg-white/[0.06] hover:text-white transition-colors flex items-center gap-2 cursor-pointer select-none", children: [_jsx(Edit2, { className: "w-3.5 h-3.5 text-zinc-400 flex-shrink-0" }), _jsx("span", { className: "flex-1 truncate", children: "Rename" }), _jsx("span", { className: "text-[11px] font-mono text-zinc-500 pl-2 ml-auto flex-shrink-0", children: "R" })] }), _jsxs("button", { type: "button", onClick: () => {
|
|
2974
3935
|
setSelectMode(true);
|
|
2975
3936
|
setSelectedConvIds(new Set([convMenuId]));
|
|
2976
3937
|
setConvMenuId(null);
|
|
2977
|
-
}, className: "
|
|
3938
|
+
}, className: "w-full px-2.5 py-1.5 rounded-[2px] text-left text-[12px] text-zinc-300 hover:bg-white/[0.06] hover:text-white transition-colors flex items-center gap-2 cursor-pointer select-none", children: [_jsx(CheckSquare, { className: "w-3.5 h-3.5 text-zinc-400 flex-shrink-0" }), _jsx("span", { className: "flex-1 truncate", children: "Select" }), _jsx("span", { className: "text-[11px] font-mono text-zinc-500 pl-2 ml-auto flex-shrink-0", children: "S" })] }), _jsx("div", { className: "my-1 border-t border-white/[0.06]" }), _jsxs("button", { type: "button", onClick: () => {
|
|
2978
3939
|
if (selectMode && selectedConvIds.size > 1 && selectedConvIds.has(convMenuId)) {
|
|
2979
3940
|
animateDeleteConversations(Array.from(selectedConvIds), null);
|
|
2980
3941
|
}
|
|
2981
3942
|
else {
|
|
2982
3943
|
animateDeleteConversation(convMenuId, null);
|
|
2983
3944
|
}
|
|
2984
|
-
}, className: "w-full
|
|
3945
|
+
}, className: "w-full px-2.5 py-1.5 rounded-b-[6px] rounded-t-[2px] text-left text-[12px] text-red-400 hover:bg-red-500/10 hover:text-red-300 transition-colors flex items-center gap-2 cursor-pointer select-none", children: [_jsx(Trash2, { className: "w-3.5 h-3.5 text-red-400 flex-shrink-0" }), _jsx("span", { className: "flex-1 truncate", children: "Delete" }), _jsx("span", { className: "text-[11px] font-mono text-zinc-500 pl-2 ml-auto flex-shrink-0", children: "D" })] })] })] }), document.body), hoveredPreview && !contextMenu && !inboxMenuPos && !convMenuId && createPortal(_jsxs("div", { className: "fixed z-[450] w-[260px] rounded-[6px] border border-white/[0.1] bg-[#111113]/98 p-2 shadow-2xl shadow-black/90 backdrop-blur-md animate-in fade-in duration-100 select-none pointer-events-auto before:absolute before:-left-3 before:top-0 before:bottom-0 before:w-4 before:content-[''] space-y-1.5", style: {
|
|
3946
|
+
left: Math.min(hoveredPreview.rect.right + 6, window.innerWidth - 275),
|
|
3947
|
+
top: Math.max(8, Math.min(hoveredPreview.rect.top - 2, window.innerHeight - 200)),
|
|
3948
|
+
}, onMouseEnter: () => {
|
|
3949
|
+
if (closeTimerRef.current) {
|
|
3950
|
+
clearTimeout(closeTimerRef.current);
|
|
3951
|
+
closeTimerRef.current = null;
|
|
3952
|
+
}
|
|
3953
|
+
if (previewTimerRef.current) {
|
|
3954
|
+
clearTimeout(previewTimerRef.current);
|
|
3955
|
+
previewTimerRef.current = null;
|
|
3956
|
+
}
|
|
3957
|
+
}, onMouseLeave: handleConvMouseLeave, children: [_jsxs("div", { className: "flex items-center justify-between gap-1.5", children: [_jsxs("div", { className: "flex items-center gap-1.5 min-w-0 flex-1", children: [_jsxs("div", { className: "w-5 h-5 rounded-[4px] bg-white/[0.04] border border-white/[0.08] flex items-center justify-center flex-shrink-0 text-zinc-300", children: [hoveredPreview.type === 'workspace' && _jsx(Folder, { className: "w-3 h-3 text-zinc-300" }), hoveredPreview.type === 'team' && _jsx(Users, { className: "w-3 h-3 text-zinc-300" }), hoveredPreview.type === 'agent' && _jsx(Bot, { className: "w-3 h-3 text-zinc-300" }), hoveredPreview.type === 'conversation' && _jsx(MessageSquare, { className: "w-3 h-3 text-zinc-300" })] }), isEditingCardName ? (_jsx("input", { type: "text", value: editingCardName, onChange: (e) => setEditingCardName(e.target.value), onKeyDown: (e) => {
|
|
3958
|
+
if (e.key === 'Enter')
|
|
3959
|
+
handleSaveCardRename();
|
|
3960
|
+
if (e.key === 'Escape')
|
|
3961
|
+
setIsEditingCardName(false);
|
|
3962
|
+
}, onBlur: handleSaveCardRename, className: "w-full px-1.5 py-0.5 rounded-[4px] border border-[#3b82f6] ring-1 ring-[#3b82f6]/50 bg-black/60 text-white font-semibold text-[12px] focus:outline-none", autoFocus: true })) : (_jsxs("button", { type: "button", onClick: () => {
|
|
3963
|
+
setEditingCardName(hoveredPreview.title);
|
|
3964
|
+
setIsEditingCardName(true);
|
|
3965
|
+
}, className: "group/name flex items-center gap-1 px-1 py-0.5 -ml-1 rounded-[4px] border border-transparent hover:border-[#3b82f6]/60 hover:bg-[#3b82f6]/10 transition-all cursor-text text-left max-w-full", title: "Click to rename", children: [_jsx("span", { className: "font-semibold text-white text-[12px] truncate", children: hoveredPreview.title }), _jsx(Edit2, { className: "w-2.5 h-2.5 text-zinc-500 opacity-0 group-hover/name:opacity-100 transition-opacity flex-shrink-0" })] }))] }), _jsxs("div", { className: "flex items-center gap-1 flex-shrink-0", children: [_jsx("span", { className: "text-[8.5px] font-mono uppercase tracking-wider px-1.5 py-0.2 rounded-[3px] bg-white/[0.04] text-zinc-400 border border-white/[0.06]", children: hoveredPreview.type === 'workspace' ? 'PROJECT' : hoveredPreview.type.toUpperCase() }), hoveredPreview.type === 'conversation' ? (_jsx("button", { type: "button", onClick: (e) => {
|
|
3966
|
+
e.stopPropagation();
|
|
3967
|
+
togglePinConversation(hoveredPreview.id);
|
|
3968
|
+
setHoveredPreview(prev => prev ? { ...prev, isPinned: !prev.isPinned } : null);
|
|
3969
|
+
}, className: "p-0.5 rounded-[3px] transition-colors " + (hoveredPreview.isPinned ? "text-[#8ad7ff] hover:text-white" : "text-zinc-500 hover:text-white hover:bg-white/[0.06]"), title: hoveredPreview.isPinned ? "Unpin chat" : "Pin chat", children: _jsx(Pin, { className: "w-3 h-3 " + (hoveredPreview.isPinned ? "rotate-45 fill-current" : "") }) })) : (_jsx("button", { type: "button", className: "p-0.5 rounded-[3px] text-zinc-500 hover:text-white hover:bg-white/[0.06] transition-colors cursor-pointer", disabled: !previewPin, onClick: () => { if (previewPin)
|
|
3970
|
+
togglePinnedEntity(previewPin); }, "aria-pressed": previewEntityPinned, title: previewEntityPinned ? 'Unpin item' : 'Pin item', children: _jsx(Pin, { className: "w-3 h-3" }) }))] })] }), hoveredPreview.type === 'conversation' ? (
|
|
3971
|
+
/* Conversation Card: Pure minimalist layout matching media references */
|
|
3972
|
+
_jsxs("div", { className: "space-y-1.5 pt-0.5", children: [hoveredPreview.directories && hoveredPreview.directories.length > 0 ? (hoveredPreview.directories.slice(0, 1).map((dir) => (_jsxs("button", { type: "button", onClick: () => handleOpenPathInExplorer(dir), className: "group/path flex items-center justify-between w-full px-1.5 py-0.5 rounded-[4px] bg-white/[0.02] hover:bg-white/[0.06] border border-transparent hover:border-white/[0.06] transition-colors cursor-pointer text-left select-none -mx-1", title: `Open in Explorer: ${dir}`, children: [_jsxs("div", { className: "flex items-center gap-1.5 min-w-0 flex-1", children: [_jsx(Folder, { className: "w-3.5 h-3.5 text-zinc-400 group-hover/path:text-white transition-colors flex-shrink-0" }), _jsx("span", { className: "font-mono text-[11px] truncate text-zinc-300 group-hover/path:text-white transition-colors", title: dir, children: dir })] }), _jsx(ArrowUpRight, { className: "w-3 h-3 text-zinc-500 opacity-0 group-hover/path:opacity-100 group-hover/path:text-[#8ad7ff] transition-all flex-shrink-0 ml-1" })] }, dir)))) : (_jsxs("div", { className: "flex items-center gap-1.5 px-0.5 py-0.5 text-zinc-400 text-[11px] font-mono", children: [_jsx(Folder, { className: "w-3.5 h-3.5 text-zinc-500 flex-shrink-0" }), _jsx("span", { className: "truncate", children: hoveredPreview.workspaceName || 'Main Chat' })] })), _jsx("div", { className: "flex items-center gap-1.5 px-0.5 text-[11px] font-mono", children: hoveredPreview.status === 'Running' ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "w-3.5 h-3.5 text-[#8ad7ff] animate-spin flex-shrink-0" }), _jsx("span", { className: "text-[#8ad7ff] font-medium", children: "Running" })] })) : (_jsxs(_Fragment, { children: [_jsx(CheckCircle2, { className: "w-3.5 h-3.5 text-zinc-500 flex-shrink-0" }), _jsx("span", { className: "text-zinc-400", children: "Idle" })] })) }), _jsxs("div", { className: "flex items-center gap-1.5 px-0.5 text-[11px] font-mono text-zinc-400", children: [_jsx(Clock, { className: "w-3.5 h-3.5 text-zinc-500 flex-shrink-0" }), _jsx("span", { children: formatUpdatedTime(hoveredPreview.timestamp) })] })] })) : (
|
|
3973
|
+
/* Workspace / Team / Agent cards */
|
|
3974
|
+
_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center gap-2 text-[11px] font-mono text-zinc-400 px-0.5", children: [_jsxs("span", { className: "flex items-center gap-1 text-zinc-300", children: [_jsx(MessageSquare, { className: "w-2.5 h-2.5 text-zinc-500" }), `${hoveredPreview.taskCount || 0} tasks`] }), _jsx("span", { className: "text-zinc-700 text-[9px]", children: "\u2022" }), _jsx("span", { className: "truncate text-zinc-400", children: hoveredPreview.type === 'agent' ? (hoveredPreview.model ? hoveredPreview.model.split('/').pop() : 'Standard') :
|
|
3975
|
+
(hoveredPreview.directories && hoveredPreview.directories.length > 0 ? `${hoveredPreview.directories.length} root${hoveredPreview.directories.length > 1 ? 's' : ''}` : 'Ready') })] }), hoveredPreview.directories && hoveredPreview.directories.length > 0 ? (_jsx("div", { className: "space-y-0.5 pt-0.5", children: hoveredPreview.directories.slice(0, 2).map((dir) => (_jsxs("button", { type: "button", onClick: () => handleOpenPathInExplorer(dir), className: "group/path flex items-center justify-between w-full px-1.5 py-1 rounded-[4px] bg-white/[0.02] hover:bg-white/[0.06] border border-white/[0.04] hover:border-white/[0.08] transition-colors cursor-pointer text-left select-none", title: `Open in Explorer: ${dir}`, children: [_jsxs("div", { className: "flex items-center gap-1.5 min-w-0 flex-1", children: [_jsx(Folder, { className: "w-3 h-3 text-zinc-500 group-hover/path:text-white transition-colors flex-shrink-0" }), _jsx("span", { className: "font-mono text-[10px] truncate text-zinc-400 group-hover/path:text-white transition-colors", title: dir, children: dir })] }), _jsx(ArrowUpRight, { className: "w-3 h-3 text-zinc-500 opacity-0 group-hover/path:opacity-100 group-hover/path:text-[#8ad7ff] transition-all flex-shrink-0 ml-1" })] }, dir))) })) : hoveredPreview.agentNames && hoveredPreview.agentNames.length > 0 ? (_jsxs("div", { className: "flex items-center gap-1.5 px-1.5 py-1 rounded-[4px] bg-white/[0.02] border border-white/[0.04]", children: [_jsx(Bot, { className: "w-3 h-3 text-zinc-500 flex-shrink-0" }), _jsx("span", { className: "font-mono text-[10px] text-zinc-300 truncate", children: hoveredPreview.agentNames.join(', ') })] })) : hoveredPreview.workspaceName ? (_jsxs("div", { className: "flex items-center gap-1.5 px-1.5 py-1 rounded-[4px] bg-white/[0.02] border border-white/[0.04]", children: [_jsx(Folder, { className: "w-3 h-3 text-zinc-500 flex-shrink-0" }), _jsxs("span", { className: "font-mono text-[10px] text-zinc-300 truncate", children: [hoveredPreview.workspaceName, hoveredPreview.teamName ? ` / ${hoveredPreview.teamName}` : ''] })] })) : null, _jsx("div", { className: "pt-1 border-t border-white/[0.06]", children: _jsxs("button", { type: "button", onClick: () => {
|
|
3976
|
+
if (hoveredPreview.type === 'workspace') {
|
|
3977
|
+
const ws = workspaces.find(w => w.id === (hoveredPreview.workspaceId || hoveredPreview.id));
|
|
3978
|
+
onOpenSettings({
|
|
3979
|
+
type: 'workspace',
|
|
3980
|
+
workspaceId: hoveredPreview.workspaceId || hoveredPreview.id,
|
|
3981
|
+
workspaceName: hoveredPreview.workspaceName || hoveredPreview.title,
|
|
3982
|
+
teamCount: ws?.teams.length,
|
|
3983
|
+
agentCount: ws?.teams.reduce((acc, t) => acc + t.agents.length, 0),
|
|
3984
|
+
});
|
|
3985
|
+
}
|
|
3986
|
+
else if (hoveredPreview.type === 'team' && hoveredPreview.workspaceId) {
|
|
3987
|
+
onOpenSettings({
|
|
3988
|
+
type: 'team',
|
|
3989
|
+
workspaceId: hoveredPreview.workspaceId,
|
|
3990
|
+
teamId: hoveredPreview.teamId || hoveredPreview.id,
|
|
3991
|
+
teamName: hoveredPreview.teamName || hoveredPreview.title,
|
|
3992
|
+
workspaceName: hoveredPreview.workspaceName,
|
|
3993
|
+
});
|
|
3994
|
+
}
|
|
3995
|
+
else if (hoveredPreview.type === 'agent' && hoveredPreview.workspaceId && hoveredPreview.teamId) {
|
|
3996
|
+
onOpenSettings({
|
|
3997
|
+
type: 'agent',
|
|
3998
|
+
workspaceId: hoveredPreview.workspaceId,
|
|
3999
|
+
teamId: hoveredPreview.teamId,
|
|
4000
|
+
agentId: hoveredPreview.agentId || hoveredPreview.id,
|
|
4001
|
+
agentName: hoveredPreview.title,
|
|
4002
|
+
});
|
|
4003
|
+
}
|
|
4004
|
+
setHoveredPreview(null);
|
|
4005
|
+
}, className: "flex items-center justify-between w-full px-2 py-1 rounded-[4px] bg-white/[0.03] hover:bg-white/[0.08] text-zinc-400 hover:text-white transition-colors cursor-pointer text-[11px] font-medium border border-white/[0.04]", children: [_jsxs("span", { className: "flex items-center gap-1.5", children: [_jsx(Settings, { className: "w-3 h-3 text-zinc-400" }), _jsx("span", { children: hoveredPreview.type === 'workspace' ? 'Configure Project' :
|
|
4006
|
+
hoveredPreview.type === 'team' ? 'Configure Team' : 'Configure Agent' })] }), _jsx(ChevronRight, { className: "w-3 h-3 text-zinc-500" })] }) })] }))] }), document.body)] }));
|
|
2985
4007
|
}
|
|
2986
4008
|
// =============================================================================
|
|
2987
4009
|
// AGENT RUNTIME SETTINGS
|
|
@@ -2992,7 +4014,8 @@ function AgentRuntimeSettings({ agent, workspace, team, onUpdateAgent, onClose }
|
|
|
2992
4014
|
const [terminalOutput, setTerminalOutput] = useState('');
|
|
2993
4015
|
const capabilities = agent.capabilities || { ...DEFAULT_AGENT_CAPABILITIES };
|
|
2994
4016
|
const allowedDirectories = agent.allowedDirectories || [];
|
|
2995
|
-
const teamAllowedDirectories = team
|
|
4017
|
+
const teamAllowedDirectories = resolveTeamDirectories(workspace, team);
|
|
4018
|
+
const effectiveAgentDirectories = resolveAgentDirectories(workspace, team, agent);
|
|
2996
4019
|
const toggleCapability = (key) => {
|
|
2997
4020
|
onUpdateAgent({
|
|
2998
4021
|
capabilities: {
|
|
@@ -3017,7 +4040,7 @@ function AgentRuntimeSettings({ agent, workspace, team, onUpdateAgent, onClose }
|
|
|
3017
4040
|
setTerminalOutput('Terminal capability is disabled for this agent.');
|
|
3018
4041
|
return;
|
|
3019
4042
|
}
|
|
3020
|
-
if (
|
|
4043
|
+
if (effectiveAgentDirectories.length === 0) {
|
|
3021
4044
|
setTerminalOutput('No allowed directories configured. Add one first.');
|
|
3022
4045
|
return;
|
|
3023
4046
|
}
|
|
@@ -3027,26 +4050,36 @@ function AgentRuntimeSettings({ agent, workspace, team, onUpdateAgent, onClose }
|
|
|
3027
4050
|
}
|
|
3028
4051
|
setIsRunning(true);
|
|
3029
4052
|
setTerminalOutput('Running...');
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
blocks
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
4053
|
+
try {
|
|
4054
|
+
const result = await getAgentPlatformBridge().workspace.runCommand({
|
|
4055
|
+
workspaceId: workspace.id,
|
|
4056
|
+
teamId: team.id,
|
|
4057
|
+
agentId: agent.id,
|
|
4058
|
+
command: trimmed,
|
|
4059
|
+
cwd: effectiveAgentDirectories[0],
|
|
4060
|
+
allowedDirs: effectiveAgentDirectories
|
|
4061
|
+
});
|
|
4062
|
+
const blocks = [];
|
|
4063
|
+
blocks.push(`$ ${trimmed}`);
|
|
4064
|
+
if (result.cwd)
|
|
4065
|
+
blocks.push(`cwd: ${result.cwd}`);
|
|
4066
|
+
if (result.stdout?.trim())
|
|
4067
|
+
blocks.push(result.stdout.trim());
|
|
4068
|
+
if (result.stderr?.trim())
|
|
4069
|
+
blocks.push(`[stderr]\n${result.stderr.trim()}`);
|
|
4070
|
+
if (result.error)
|
|
4071
|
+
blocks.push(`[error] ${result.error}`);
|
|
4072
|
+
blocks.push(`exit: ${result.exitCode ?? 'n/a'}`);
|
|
4073
|
+
setTerminalOutput(blocks.join('\n\n'));
|
|
4074
|
+
}
|
|
4075
|
+
catch (error) {
|
|
4076
|
+
setTerminalOutput(error instanceof Error ? error.message : 'Workspace command failed.');
|
|
4077
|
+
}
|
|
4078
|
+
finally {
|
|
4079
|
+
setIsRunning(false);
|
|
4080
|
+
}
|
|
4081
|
+
};
|
|
4082
|
+
return (_jsxs("div", { className: "flex-1 flex flex-col bg-[#0a0a0c]", children: [_jsx("div", { className: "flex-1 overflow-auto px-6 py-5", children: _jsxs("div", { className: "w-full max-w-[760px] mx-auto space-y-5", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-[15px] font-semibold text-white/90", children: "Agent Runtime Settings" }), _jsxs("p", { className: "text-[11px] text-white/35 mt-1", children: ["Configure capabilities and sandbox directory access for ", _jsx("span", { className: "text-white/55", children: agent.name }), " in ", _jsxs("span", { className: "text-white/55", children: [workspace.name, " / ", team.name] }), "."] })] }), _jsxs("div", { className: "rounded-lg border border-white/[0.08] bg-white/[0.02] p-4", children: [_jsx("p", { className: "text-[11px] text-white/45 uppercase tracking-wider mb-3", children: "Capabilities" }), _jsxs("div", { className: "space-y-2", children: [_jsxs("label", { className: "flex items-center justify-between py-1.5", children: [_jsx("span", { className: "text-[12px] text-white/75", children: "Terminal Commands (runs on this machine)" }), _jsx("input", { type: "checkbox", checked: capabilities.terminal, onChange: () => toggleCapability('terminal') })] }), _jsxs("label", { className: "flex items-center justify-between py-1.5", children: [_jsx("span", { className: "text-[12px] text-white/75", children: "Read Files" }), _jsx("input", { type: "checkbox", checked: capabilities.fileRead, onChange: () => toggleCapability('fileRead') })] }), _jsxs("label", { className: "flex items-center justify-between py-1.5", children: [_jsx("span", { className: "text-[12px] text-white/75", children: "Write Files" }), _jsx("input", { type: "checkbox", checked: capabilities.fileWrite, onChange: () => toggleCapability('fileWrite') })] })] })] }), _jsxs("div", { className: "rounded-lg border border-white/[0.08] bg-white/[0.02] p-4", children: [_jsx("p", { className: "text-[11px] text-white/45 uppercase tracking-wider mb-3", children: "Directory Access" }), allowedDirectories.length === 0 && _jsx("p", { className: "text-[11px] text-white/50 mb-2", children: "Inheriting available team directories. Select directories to restrict access." }), workspace.directories.length === 0 ? (_jsx("p", { className: "text-[11px] text-white/30", children: "No directories attached to this workspace yet. Add them in Workspace Settings." })) : teamAllowedDirectories.length === 0 ? (_jsx("p", { className: "text-[11px] text-white/30", children: "No valid project directories are available to this team." })) : (_jsx("div", { className: "space-y-1.5", children: teamAllowedDirectories.map((dir) => (_jsxs("label", { className: "flex items-center gap-2 py-1 px-2 rounded-md hover:bg-white/[0.03]", children: [_jsx("input", { type: "checkbox", checked: allowedDirectories.includes(dir), onChange: () => toggleDirectoryAccess(dir) }), _jsx("span", { className: "text-[11px] text-white/65 truncate", children: dir })] }, dir))) }))] }), _jsxs("div", { className: "rounded-lg border border-white/[0.08] bg-white/[0.02] p-4", children: [_jsx("p", { className: "text-[11px] text-white/45 uppercase tracking-wider mb-3", children: "Terminal Command Test" }), _jsxs("div", { className: "flex gap-2", children: [_jsx("input", { value: command, onChange: (e) => setCommand(e.target.value), placeholder: "e.g. pwd or Get-ChildItem", className: "flex-1 px-3 py-2 bg-black/30 border border-white/[0.1] rounded-md text-[12px] text-white focus:outline-none focus:border-white/[0.2]" }), _jsx("button", { onClick: () => { void runSandboxTest(); }, disabled: isRunning, className: "px-3 py-2 rounded-md bg-white/[0.08] hover:bg-white/[0.12] disabled:opacity-40 text-[11px] text-white/80", children: isRunning ? 'Running...' : 'Run' })] }), terminalOutput && (_jsx("pre", { className: "mt-3 p-3 bg-black/35 border border-white/[0.08] rounded-md text-[11px] text-white/65 overflow-auto whitespace-pre-wrap", children: terminalOutput }))] })] }) }), _jsxs("footer", { className: "px-6 h-[48px] border-t border-white/[0.06] bg-[#09090b] flex items-center justify-between", children: [_jsx("button", { onClick: onClose, className: "text-[11px] text-white/45 hover:text-white/70", children: "Back" }), _jsx("button", { onClick: onClose, className: "px-4 py-1.5 bg-white/[0.08] hover:bg-white/[0.12] text-white/70 text-[11px] font-medium rounded-md transition-colors", children: "Done" })] })] }));
|
|
3050
4083
|
}
|
|
3051
4084
|
// =============================================================================
|
|
3052
4085
|
// TEAM RUNTIME SETTINGS
|
|
@@ -3220,6 +4253,7 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
3220
4253
|
const [engineeringContextPressure, setEngineeringContextPressure] = useState(null);
|
|
3221
4254
|
const [cliControlPlaneLoading, setCliControlPlaneLoading] = useState(false);
|
|
3222
4255
|
const [cliControlPlaneError, setCliControlPlaneError] = useState(null);
|
|
4256
|
+
const [sessionResumeError, setSessionResumeError] = useState(null);
|
|
3223
4257
|
const [cliControlPlaneStatus, setCliControlPlaneStatus] = useState('idle');
|
|
3224
4258
|
const [cliControlPlaneCheckedAt, setCliControlPlaneCheckedAt] = useState(undefined);
|
|
3225
4259
|
const [cliControlPlaneManifest, setCliControlPlaneManifest] = useState(null);
|
|
@@ -3254,6 +4288,10 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
3254
4288
|
const [policyArtifacts, setPolicyArtifacts] = useState([]);
|
|
3255
4289
|
const [policyTaskBoards, setPolicyTaskBoards] = useState([]);
|
|
3256
4290
|
const [openEditorTabs, setOpenEditorTabs] = useState([]);
|
|
4291
|
+
const [editorTabsConversationId, setEditorTabsConversationId] = useState(null);
|
|
4292
|
+
const editorOperationsRef = useRef(new EditorOperationAuthority());
|
|
4293
|
+
const editorDraftVersionsRef = useRef(new Map());
|
|
4294
|
+
const codeMutationPendingRef = useRef(false);
|
|
3257
4295
|
const [activeEditorTabId, setActiveEditorTabId] = useState(null);
|
|
3258
4296
|
const [pendingEditorPath, setPendingEditorPath] = useState(null);
|
|
3259
4297
|
const [editorStatusMessage, setEditorStatusMessage] = useState(null);
|
|
@@ -3272,6 +4310,10 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
3272
4310
|
const codeAutoIndexKeyRef = useRef('');
|
|
3273
4311
|
const engineeringAutoLoadKeyRef = useRef('');
|
|
3274
4312
|
const workspaces = useWorkspaceStore(s => s.workspaces);
|
|
4313
|
+
const activeWorkspaceScope = useWorkspaceStore(s => s.activeWorkspaceScope);
|
|
4314
|
+
const setActiveWorkspaceScope = useWorkspaceStore(s => s.setActiveWorkspaceScope);
|
|
4315
|
+
const isWorkspaceWizardOpen = useWorkspaceStore(s => s.isWorkspaceWizardOpen);
|
|
4316
|
+
const closeWorkspaceWizard = useWorkspaceStore(s => s.closeWorkspaceWizard);
|
|
3275
4317
|
const setWorkspaces = useWorkspaceStore(s => s.setWorkspaces);
|
|
3276
4318
|
const loadWorkspaces = useWorkspaceStore(s => s.loadWorkspaces);
|
|
3277
4319
|
const updateTeam = useWorkspaceStore(s => s.updateTeam);
|
|
@@ -3282,7 +4324,7 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
3282
4324
|
const updateConversation = useAgentChatStore(s => s.updateConversation);
|
|
3283
4325
|
const activeRuntimeRequestId = useAgentChatStore(s => s.activeRequestId);
|
|
3284
4326
|
const activeRuntimeConversationId = useAgentChatStore(s => s.activeConversationId);
|
|
3285
|
-
const
|
|
4327
|
+
const storedCenterPaneMode = useAgentIdeStore(s => s.mode);
|
|
3286
4328
|
const setCenterPaneMode = useAgentIdeStore(s => s.setMode);
|
|
3287
4329
|
const setAgentIdeHasOpenFiles = useAgentIdeStore(s => s.setHasOpenFiles);
|
|
3288
4330
|
const authDisplayName = useAuthStore(s => s.user?.display_name);
|
|
@@ -3358,6 +4400,8 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
3358
4400
|
const activeConversation = activeConversationId
|
|
3359
4401
|
? conversations[activeConversationId]
|
|
3360
4402
|
: undefined;
|
|
4403
|
+
// Never paint the previous conversation's editor during scope hydration.
|
|
4404
|
+
const centerPaneMode = editorTabsConversationId === activeConversationId ? storedCenterPaneMode : 'agent';
|
|
3361
4405
|
// A CLI-resumed conversation has two identities: the renderer conversation that owns its
|
|
3362
4406
|
// presentation state, and the durable SDK coordination session that owns Goal/Loop/Handoff
|
|
3363
4407
|
// and delegated child runs. The workbench must query the latter when it is attached; otherwise
|
|
@@ -4346,12 +5390,17 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
4346
5390
|
};
|
|
4347
5391
|
}, [updateConversation]);
|
|
4348
5392
|
const activeEditorTab = useMemo(() => openEditorTabs.find((tab) => tab.id === activeEditorTabId) || null, [openEditorTabs, activeEditorTabId]);
|
|
5393
|
+
const editorOperationScope = activeConversationId ? JSON.stringify([activeConversationId, codeWorkbenchRootDirectory, activeConversationAllowedDirectories]) : null;
|
|
5394
|
+
editorOperationsRef.current.selectScope(editorOperationScope);
|
|
5395
|
+
const destructiveConfirmation = usePreparedConfirmation(JSON.stringify([editorOperationScope, viewMode, settingsPanel, workbenchPanelOpen, workbenchPanelTab, activeEditorTabId]));
|
|
5396
|
+
const editorTabsForConfirmationRef = useRef(openEditorTabs);
|
|
5397
|
+
editorTabsForConfirmationRef.current = openEditorTabs;
|
|
4349
5398
|
const activeEditorFile = useMemo(() => (activeEditorTab && activeEditorTab.type === 'file' ? activeEditorTab.file : null), [activeEditorTab]);
|
|
4350
5399
|
const activeEditorDiff = useMemo(() => (activeEditorTab && activeEditorTab.type === 'diff' ? activeEditorTab.diff : null), [activeEditorTab]);
|
|
4351
5400
|
const activeEditorFilePath = activeEditorFile?.path || null;
|
|
4352
5401
|
const openEditorFiles = useMemo(() => openEditorTabs.filter(isFileEditorTab).map((tab) => tab.file), [openEditorTabs]);
|
|
4353
5402
|
const persistedConversationEditorState = useMemo(() => buildConversationEditorState(normalizeEditorTabs(activeConversation?.editorState), activeConversation?.editorState?.activeTabId
|
|
4354
|
-
|| (activeConversation?.editorState?.activeFilePath ? createFileTabId(activeConversation.editorState.activeFilePath) : null)), [activeConversation?.editorState]);
|
|
5403
|
+
|| (activeConversation?.editorState?.activeFilePath ? createFileTabId(activeConversation.editorState.activeFilePath) : null), activeConversation?.editorState?.paneMode), [activeConversation?.editorState]);
|
|
4355
5404
|
const editorLayoutKey = useMemo(() => [
|
|
4356
5405
|
activeConversationId || 'none',
|
|
4357
5406
|
centerPaneMode,
|
|
@@ -4366,28 +5415,31 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
4366
5415
|
}
|
|
4367
5416
|
setEditorStatusMessage(null);
|
|
4368
5417
|
setPendingEditorPath(null);
|
|
4369
|
-
setCenterPaneMode('agent');
|
|
4370
5418
|
}, [activeConversationId]);
|
|
4371
5419
|
useEffect(() => {
|
|
4372
5420
|
const serialized = JSON.stringify(persistedConversationEditorState);
|
|
4373
|
-
if (serialized === lastPersistedEditorStateRef.current)
|
|
5421
|
+
if (editorTabsConversationId === activeConversationId && serialized === lastPersistedEditorStateRef.current)
|
|
4374
5422
|
return;
|
|
4375
5423
|
lastPersistedEditorStateRef.current = serialized;
|
|
4376
5424
|
setOpenEditorTabs(normalizeEditorTabs(persistedConversationEditorState));
|
|
5425
|
+
setCenterPaneMode(persistedConversationEditorState.paneMode || 'agent');
|
|
5426
|
+
setEditorTabsConversationId(activeConversationId);
|
|
4377
5427
|
setActiveEditorTabId(persistedConversationEditorState.activeTabId
|
|
4378
5428
|
|| (persistedConversationEditorState.activeFilePath ? createFileTabId(persistedConversationEditorState.activeFilePath) : null));
|
|
4379
|
-
}, [activeConversationId, persistedConversationEditorState]);
|
|
5429
|
+
}, [activeConversationId, editorTabsConversationId, persistedConversationEditorState, setCenterPaneMode]);
|
|
4380
5430
|
useEffect(() => {
|
|
4381
|
-
if (!activeConversationId)
|
|
5431
|
+
if (!activeConversationId || editorTabsConversationId !== activeConversationId)
|
|
4382
5432
|
return;
|
|
4383
|
-
const nextState = buildConversationEditorState(openEditorTabs, activeEditorTabId);
|
|
5433
|
+
const nextState = buildConversationEditorState(openEditorTabs, activeEditorTabId, centerPaneMode);
|
|
4384
5434
|
const serialized = JSON.stringify(nextState);
|
|
4385
5435
|
if (serialized === lastPersistedEditorStateRef.current)
|
|
4386
5436
|
return;
|
|
4387
5437
|
lastPersistedEditorStateRef.current = serialized;
|
|
4388
5438
|
updateConversation(activeConversationId, { editorState: nextState });
|
|
4389
|
-
}, [activeConversationId, activeEditorTabId, openEditorTabs, updateConversation]);
|
|
5439
|
+
}, [activeConversationId, editorTabsConversationId, activeEditorTabId, centerPaneMode, openEditorTabs, updateConversation]);
|
|
4390
5440
|
useEffect(() => {
|
|
5441
|
+
if (editorTabsConversationId !== activeConversationId)
|
|
5442
|
+
return;
|
|
4391
5443
|
if (openEditorTabs.length === 0) {
|
|
4392
5444
|
if (activeEditorTabId !== null) {
|
|
4393
5445
|
setActiveEditorTabId(null);
|
|
@@ -4398,8 +5450,10 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
4398
5450
|
return;
|
|
4399
5451
|
}
|
|
4400
5452
|
setActiveEditorTabId(openEditorTabs[openEditorTabs.length - 1]?.id || null);
|
|
4401
|
-
}, [activeEditorTabId, openEditorTabs]);
|
|
5453
|
+
}, [activeConversationId, editorTabsConversationId, activeEditorTabId, openEditorTabs]);
|
|
4402
5454
|
useEffect(() => {
|
|
5455
|
+
if (editorTabsConversationId !== activeConversationId)
|
|
5456
|
+
return;
|
|
4403
5457
|
setAgentIdeHasOpenFiles(openEditorTabs.length > 0);
|
|
4404
5458
|
if (openEditorTabs.length === 0 && !pendingEditorPath && centerPaneMode !== 'agent') {
|
|
4405
5459
|
setCenterPaneMode('agent');
|
|
@@ -4407,10 +5461,21 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
4407
5461
|
return () => {
|
|
4408
5462
|
setAgentIdeHasOpenFiles(false);
|
|
4409
5463
|
};
|
|
4410
|
-
}, [openEditorTabs.length, pendingEditorPath, centerPaneMode, setAgentIdeHasOpenFiles, setCenterPaneMode]);
|
|
5464
|
+
}, [activeConversationId, editorTabsConversationId, openEditorTabs.length, pendingEditorPath, centerPaneMode, setAgentIdeHasOpenFiles, setCenterPaneMode]);
|
|
4411
5465
|
useEffect(() => () => {
|
|
4412
5466
|
if (editorStatusTimerRef.current)
|
|
4413
5467
|
clearTimeout(editorStatusTimerRef.current);
|
|
5468
|
+
editorOperationsRef.current.selectScope(null);
|
|
5469
|
+
}, []);
|
|
5470
|
+
useEffect(() => {
|
|
5471
|
+
const protectPendingSave = (event) => {
|
|
5472
|
+
if (!editorOperationsRef.current.isSaving())
|
|
5473
|
+
return;
|
|
5474
|
+
event.preventDefault();
|
|
5475
|
+
event.returnValue = '';
|
|
5476
|
+
};
|
|
5477
|
+
window.addEventListener('beforeunload', protectPendingSave);
|
|
5478
|
+
return () => window.removeEventListener('beforeunload', protectPendingSave);
|
|
4414
5479
|
}, []);
|
|
4415
5480
|
// Load persisted workspaces and conversations on mount
|
|
4416
5481
|
useEffect(() => {
|
|
@@ -4489,6 +5554,7 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
4489
5554
|
sessionTab,
|
|
4490
5555
|
},
|
|
4491
5556
|
});
|
|
5557
|
+
useWorkspaceStore.getState().setActiveWorkspaceScope(resolveWorkspaceScope(useWorkspaceStore.getState().workspaces, conversation.agentId, conversation.workspaceId));
|
|
4492
5558
|
setSettingsPanel(null);
|
|
4493
5559
|
setCenterPaneMode('agent');
|
|
4494
5560
|
setActiveSessionTabId(conversationId);
|
|
@@ -4542,46 +5608,49 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
4542
5608
|
const openSdkSession = async () => {
|
|
4543
5609
|
const state = useAgentChatStore.getState();
|
|
4544
5610
|
const existing = Object.values(state.conversations).find((conversation) => (conversation.sessionUi?.sdkSessionId === sessionId));
|
|
4545
|
-
const conversationId = existing?.id ||
|
|
4546
|
-
updateConversation(conversationId, {
|
|
4547
|
-
workspaceMode: initialLaunchMode === 'agent' && initialWorkspaceRoot ? 'workspace' : 'chat-only',
|
|
4548
|
-
rootDirectory: initialLaunchMode === 'agent' ? initialWorkspaceRoot : undefined,
|
|
4549
|
-
grantedDirectories: initialLaunchMode === 'agent' && initialWorkspaceRoot ? [initialWorkspaceRoot] : [],
|
|
4550
|
-
model: MAIN_ASSISTANT_MODEL,
|
|
4551
|
-
runtime: createConversationRuntimeBinding({
|
|
4552
|
-
selection: runtimeSelectionForSdk('user'),
|
|
4553
|
-
model: MAIN_ASSISTANT_MODEL,
|
|
4554
|
-
reasoningModel: MAIN_ASSISTANT_MODEL,
|
|
4555
|
-
inferenceMode: 'cloud',
|
|
4556
|
-
}),
|
|
4557
|
-
});
|
|
4558
|
-
activateSessionConversation(conversationId);
|
|
4559
|
-
const attach = getAgentPlatformBridge()?.agent?.attachSdkSession;
|
|
4560
|
-
if (!attach) {
|
|
4561
|
-
appendMessage(conversationId, {
|
|
4562
|
-
role: 'assistant',
|
|
4563
|
-
content: `Unable to resume SDK session ${sessionId}: the Agent host session bridge is unavailable.`,
|
|
4564
|
-
error: 'Agent host session bridge unavailable',
|
|
4565
|
-
hideToolbar: true,
|
|
4566
|
-
});
|
|
4567
|
-
return;
|
|
4568
|
-
}
|
|
5611
|
+
const conversationId = existing?.id || generateId();
|
|
4569
5612
|
try {
|
|
5613
|
+
setSessionResumeError(null);
|
|
5614
|
+
const bridge = getAgentPlatformBridge()?.agent;
|
|
5615
|
+
if (!bridge?.attachSdkSession)
|
|
5616
|
+
throw new Error('The Agent host session bridge is unavailable.');
|
|
5617
|
+
if (existing)
|
|
5618
|
+
assertResumeLaunchScope(existing, initialLaunchMode, initialWorkspaceRoot);
|
|
5619
|
+
else {
|
|
5620
|
+
if (!bridge.showSdkSession)
|
|
5621
|
+
throw new Error('Canonical SDK session metadata is unavailable for recovery.');
|
|
5622
|
+
const preview = await bridge.showSdkSession({ sessionId });
|
|
5623
|
+
if (cancelled)
|
|
5624
|
+
return;
|
|
5625
|
+
if (!preview.success)
|
|
5626
|
+
throw new Error(preview.error || 'SDK session recovery metadata could not be read.');
|
|
5627
|
+
const scope = scopeFromSdkSessionMetadata(preview.session);
|
|
5628
|
+
assertResumeLaunchScope(scope, initialLaunchMode, initialWorkspaceRoot);
|
|
5629
|
+
}
|
|
5630
|
+
// Explicit launch conflicts have been refused before changing either the
|
|
5631
|
+
// saved conversation or its native session attachment.
|
|
5632
|
+
const attach = bridge.attachSdkSession;
|
|
4570
5633
|
const result = await attach({ conversationId, sessionId });
|
|
4571
5634
|
if (cancelled)
|
|
4572
5635
|
return;
|
|
4573
|
-
if (!result.success)
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
5636
|
+
if (!result.success)
|
|
5637
|
+
throw new Error(result.error || 'SDK session attachment could not be confirmed.');
|
|
5638
|
+
if (!existing) {
|
|
5639
|
+
const scope = scopeFromSdkSessionMetadata(result.session);
|
|
5640
|
+
assertResumeLaunchScope(scope, initialLaunchMode, initialWorkspaceRoot);
|
|
5641
|
+
createConversation(MAIN_ASSISTANT_ID, conversationId);
|
|
5642
|
+
updateConversation(conversationId, {
|
|
5643
|
+
...scope,
|
|
5644
|
+
model: MAIN_ASSISTANT_MODEL,
|
|
5645
|
+
runtime: createConversationRuntimeBinding({
|
|
5646
|
+
selection: runtimeSelectionForSdk('user'), model: MAIN_ASSISTANT_MODEL,
|
|
5647
|
+
reasoningModel: MAIN_ASSISTANT_MODEL, inferenceMode: 'cloud',
|
|
5648
|
+
}),
|
|
4581
5649
|
});
|
|
4582
|
-
return;
|
|
4583
5650
|
}
|
|
4584
5651
|
const current = useAgentChatStore.getState().getConversation(conversationId);
|
|
5652
|
+
if (!current)
|
|
5653
|
+
throw new Error('The resumed conversation is no longer available.');
|
|
4585
5654
|
updateConversation(conversationId, {
|
|
4586
5655
|
sessionUi: {
|
|
4587
5656
|
...(current?.sessionUi || {}),
|
|
@@ -4591,25 +5660,19 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
4591
5660
|
coordinationSessionId: result.coordinationSessionId,
|
|
4592
5661
|
},
|
|
4593
5662
|
});
|
|
5663
|
+
activateSessionConversation(conversationId);
|
|
4594
5664
|
}
|
|
4595
5665
|
catch (error) {
|
|
4596
5666
|
if (cancelled)
|
|
4597
5667
|
return;
|
|
4598
|
-
const message = error instanceof Error ? error.message : '
|
|
4599
|
-
|
|
4600
|
-
appendMessage(conversationId, {
|
|
4601
|
-
role: 'assistant',
|
|
4602
|
-
content: `Unable to resume SDK session ${sessionId}: ${message}`,
|
|
4603
|
-
error: message,
|
|
4604
|
-
hideToolbar: true,
|
|
4605
|
-
});
|
|
5668
|
+
const message = error instanceof Error ? error.message : 'SDK session recovery could not be verified.';
|
|
5669
|
+
setSessionResumeError(`Unable to resume SDK session: ${message}`);
|
|
4606
5670
|
}
|
|
4607
5671
|
};
|
|
4608
5672
|
void openSdkSession();
|
|
4609
5673
|
return () => { cancelled = true; };
|
|
4610
5674
|
}, [
|
|
4611
5675
|
activateSessionConversation,
|
|
4612
|
-
appendMessage,
|
|
4613
5676
|
createConversation,
|
|
4614
5677
|
initialLaunchMode,
|
|
4615
5678
|
initialSdkSessionId,
|
|
@@ -4619,24 +5682,9 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
4619
5682
|
]);
|
|
4620
5683
|
const createSessionConversation = useCallback(() => {
|
|
4621
5684
|
const conversationId = createConversation(MAIN_ASSISTANT_ID);
|
|
4622
|
-
|
|
4623
|
-
? useAgentChatStore.getState().getConversation(activeSessionTabId)
|
|
4624
|
-
: undefined;
|
|
4625
|
-
const inheritWorkspace = current?.workspaceMode === 'workspace' && Boolean(current.rootDirectory);
|
|
4626
|
-
const launchWorkspace = initialLaunchMode === 'agent' && Boolean(initialWorkspaceRoot);
|
|
4627
|
-
if (inheritWorkspace || launchWorkspace) {
|
|
4628
|
-
const rootDirectory = inheritWorkspace ? current.rootDirectory : initialWorkspaceRoot;
|
|
4629
|
-
updateConversation(conversationId, {
|
|
4630
|
-
schemaVersion: 3,
|
|
4631
|
-
workspaceMode: 'workspace',
|
|
4632
|
-
rootDirectory,
|
|
4633
|
-
grantedDirectories: inheritWorkspace
|
|
4634
|
-
? (current.grantedDirectories?.length ? [...current.grantedDirectories] : [rootDirectory])
|
|
4635
|
-
: [rootDirectory],
|
|
4636
|
-
});
|
|
4637
|
-
}
|
|
5685
|
+
updateConversation(conversationId, personalConversationDefaults());
|
|
4638
5686
|
activateSessionConversation(conversationId);
|
|
4639
|
-
}, [activateSessionConversation,
|
|
5687
|
+
}, [activateSessionConversation, createConversation, updateConversation]);
|
|
4640
5688
|
const closeSessionConversation = useCallback((conversationId) => {
|
|
4641
5689
|
const state = useAgentChatStore.getState();
|
|
4642
5690
|
const conversation = state.getConversation(conversationId);
|
|
@@ -5032,15 +6080,13 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
5032
6080
|
if (!uniqueAgentName)
|
|
5033
6081
|
return { success: false, error: 'Agent name is empty.' };
|
|
5034
6082
|
const newAgent = {
|
|
6083
|
+
...agentCreationConfiguration(workspace, team, { systemPrompt: params.instructions?.trim() || undefined }),
|
|
5035
6084
|
id: generateId(),
|
|
5036
6085
|
name: uniqueAgentName,
|
|
5037
6086
|
isMainAssistant: team.agents.length === 0 || !team.agents.some(a => a.isMainAssistant),
|
|
5038
|
-
model: MAIN_ASSISTANT_MODEL,
|
|
5039
|
-
systemPrompt: params.instructions?.trim() || `You are ${uniqueAgentName}, an assistant in ${workspace.name}/${team.name}.`,
|
|
5040
6087
|
templateName: 'Custom',
|
|
5041
6088
|
workspaceName: workspace.name,
|
|
5042
6089
|
teamName: team.name,
|
|
5043
|
-
capabilities: { ...DEFAULT_AGENT_CAPABILITIES },
|
|
5044
6090
|
permissionProfile: 'standard',
|
|
5045
6091
|
allowedDirectories: [...(team.allowedDirectories || [])],
|
|
5046
6092
|
allowedApps: [...(team.allowedApps || [])],
|
|
@@ -5812,6 +6858,7 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
5812
6858
|
selectedConversationId,
|
|
5813
6859
|
selectedAgentId
|
|
5814
6860
|
});
|
|
6861
|
+
setActiveWorkspaceScope(null);
|
|
5815
6862
|
setViewMode('inbox');
|
|
5816
6863
|
setSelectedAgentId(null);
|
|
5817
6864
|
setSelectedConversationId(null);
|
|
@@ -5830,11 +6877,24 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
5830
6877
|
agentId: id
|
|
5831
6878
|
});
|
|
5832
6879
|
setViewMode(id ? 'agent' : 'inbox');
|
|
6880
|
+
setActiveWorkspaceScope(resolveWorkspaceScope(workspaces, id || undefined));
|
|
5833
6881
|
setSelectedAgentId(id);
|
|
5834
6882
|
setSelectedConversationId(null);
|
|
5835
6883
|
setSelectedInboxConversationId(null);
|
|
5836
6884
|
setActiveSessionTabId(null);
|
|
5837
6885
|
};
|
|
6886
|
+
// Synchronize active workspace scope: if user scopes to a workspace while on global inbox, switch to workspace's main agent
|
|
6887
|
+
useEffect(() => {
|
|
6888
|
+
if (activeWorkspaceScope && viewMode === 'inbox') {
|
|
6889
|
+
const ws = workspaces.find(w => w.id === activeWorkspaceScope);
|
|
6890
|
+
if (ws) {
|
|
6891
|
+
const main = ws.teams.flatMap(t => t.agents).find(a => a.isMainAssistant) || ws.teams[0]?.agents[0];
|
|
6892
|
+
if (main) {
|
|
6893
|
+
handleSelectAgent(main.id);
|
|
6894
|
+
}
|
|
6895
|
+
}
|
|
6896
|
+
}
|
|
6897
|
+
}, [activeWorkspaceScope, viewMode, workspaces]);
|
|
5838
6898
|
// Select a specific conversation
|
|
5839
6899
|
const handleSelectConversation = (agentId, conversationId) => {
|
|
5840
6900
|
logAgentInterfaceDebug('select agent conversation', {
|
|
@@ -5844,6 +6904,7 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
5844
6904
|
activateSessionConversation(conversationId);
|
|
5845
6905
|
};
|
|
5846
6906
|
const handleOpenSettings = (panel) => {
|
|
6907
|
+
setActiveWorkspaceScope(resolveWorkspaceScope(workspaces, panel.agentId, panel.workspaceId));
|
|
5847
6908
|
if (activeConversationId) {
|
|
5848
6909
|
updateConversation(activeConversationId, {
|
|
5849
6910
|
sessionUi: {
|
|
@@ -5884,6 +6945,19 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
5884
6945
|
const handleCloseSettings = () => {
|
|
5885
6946
|
setSettingsPanel(null);
|
|
5886
6947
|
};
|
|
6948
|
+
const handleOpenWorkspaceSettings = useCallback((workspaceId) => {
|
|
6949
|
+
const ws = workspaces.find(w => w.id === workspaceId);
|
|
6950
|
+
if (!ws)
|
|
6951
|
+
return;
|
|
6952
|
+
handleOpenSettings({
|
|
6953
|
+
type: 'workspace',
|
|
6954
|
+
workspaceId: ws.id,
|
|
6955
|
+
workspaceName: ws.name,
|
|
6956
|
+
teamCount: ws.teams.length,
|
|
6957
|
+
agentCount: ws.teams.reduce((acc, team) => acc + team.agents.length, 0),
|
|
6958
|
+
initialSection: 'general',
|
|
6959
|
+
});
|
|
6960
|
+
}, [workspaces]);
|
|
5887
6961
|
const handleDeleteFromSettings = () => {
|
|
5888
6962
|
setSettingsPanel(null);
|
|
5889
6963
|
};
|
|
@@ -6006,18 +7080,13 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
6006
7080
|
suffix += 1;
|
|
6007
7081
|
}
|
|
6008
7082
|
targetAgent = {
|
|
7083
|
+
...agentCreationConfiguration(workspace, targetTeam, { model: params.model }),
|
|
6009
7084
|
id: generateId(),
|
|
6010
7085
|
name: nextAgentName,
|
|
6011
7086
|
isMainAssistant: !hasAnyAgents,
|
|
6012
|
-
model: params.model || MAIN_ASSISTANT_MODEL,
|
|
6013
|
-
systemPrompt: MAIN_ASSISTANT_SYSTEM_PROMPT,
|
|
6014
7087
|
templateName: 'Workspace Assistant',
|
|
6015
7088
|
workspaceName: workspace.name,
|
|
6016
7089
|
teamName: targetTeam.name,
|
|
6017
|
-
capabilities: {
|
|
6018
|
-
...DEFAULT_AGENT_CAPABILITIES,
|
|
6019
|
-
fileWrite: true
|
|
6020
|
-
},
|
|
6021
7090
|
permissionProfile: 'standard',
|
|
6022
7091
|
allowedDirectories: [normalizedDirectory],
|
|
6023
7092
|
allowedApps: [...(targetTeam.allowedApps || [])],
|
|
@@ -6038,11 +7107,6 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
6038
7107
|
targetAgent.templateName = 'Workspace Assistant';
|
|
6039
7108
|
targetAgent.systemPrompt = targetAgent.systemPrompt || MAIN_ASSISTANT_SYSTEM_PROMPT;
|
|
6040
7109
|
targetAgent.model = targetAgent.model || params.model || MAIN_ASSISTANT_MODEL;
|
|
6041
|
-
targetAgent.capabilities = {
|
|
6042
|
-
...DEFAULT_AGENT_CAPABILITIES,
|
|
6043
|
-
...targetAgent.capabilities,
|
|
6044
|
-
fileWrite: true
|
|
6045
|
-
};
|
|
6046
7110
|
targetAgent.permissionProfile = targetAgent.permissionProfile || 'standard';
|
|
6047
7111
|
targetAgent.allowedDirectories = prioritizeDirectory(targetAgent.allowedDirectories, normalizedDirectory);
|
|
6048
7112
|
targetAgent.allowedApps = [...(targetAgent.allowedApps || [])];
|
|
@@ -6120,7 +7184,7 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
6120
7184
|
editorStatusTimerRef.current = null;
|
|
6121
7185
|
}
|
|
6122
7186
|
setEditorStatusMessage(message);
|
|
6123
|
-
if (!message)
|
|
7187
|
+
if (!message || durationMs <= 0)
|
|
6124
7188
|
return;
|
|
6125
7189
|
editorStatusTimerRef.current = setTimeout(() => {
|
|
6126
7190
|
setEditorStatusMessage(null);
|
|
@@ -6220,44 +7284,38 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
6220
7284
|
activateSessionConversation(targetConversationId);
|
|
6221
7285
|
}, [activateSessionConversation, selectedAgent?.id, subagentRuntimeEvents, updateConversation]);
|
|
6222
7286
|
const handleSubagentCancelRun = useCallback(async (run) => {
|
|
6223
|
-
if (!getAgentPlatformBridge()?.subagents?.cancelRun
|
|
6224
|
-
setSubagentError('Subagent
|
|
7287
|
+
if (!getAgentPlatformBridge()?.subagents?.cancelRun) {
|
|
7288
|
+
setSubagentError('Subagent cancellation settlement is not available. Update the host and retry.');
|
|
6225
7289
|
return;
|
|
6226
7290
|
}
|
|
6227
7291
|
setSubagentLoading(true);
|
|
6228
7292
|
setSubagentError(null);
|
|
6229
7293
|
try {
|
|
6230
|
-
|
|
6231
|
-
|
|
6232
|
-
|
|
6233
|
-
|
|
6234
|
-
|
|
6235
|
-
|
|
6236
|
-
|
|
6237
|
-
|
|
6238
|
-
|
|
6239
|
-
propagateToChild: !!run.childRequestId,
|
|
6240
|
-
propagatedAt: Date.now(),
|
|
6241
|
-
caller: policyCaller,
|
|
6242
|
-
})
|
|
6243
|
-
: await getAgentPlatformBridge().subagents.updateRun({
|
|
6244
|
-
id: run.id,
|
|
6245
|
-
status: 'cancelled',
|
|
6246
|
-
summary: 'Cancelled from the Agent workbench.',
|
|
6247
|
-
caller: policyCaller,
|
|
6248
|
-
});
|
|
6249
|
-
if (!result?.success) {
|
|
6250
|
-
setSubagentError(result?.error || 'Failed to cancel subagent run.');
|
|
6251
|
-
return;
|
|
6252
|
-
}
|
|
6253
|
-
const updatedRun = toSubagentWorkbenchRun(result.run);
|
|
7294
|
+
const result = await getAgentPlatformBridge().subagents.cancelRun({
|
|
7295
|
+
id: run.id,
|
|
7296
|
+
reason: 'Cancelled from the Agent workbench.',
|
|
7297
|
+
requestedBy: policyCaller.agentId,
|
|
7298
|
+
requestedFrom: 'parent',
|
|
7299
|
+
propagateToChild: true,
|
|
7300
|
+
caller: policyCaller,
|
|
7301
|
+
});
|
|
7302
|
+
const updatedRun = toSubagentWorkbenchRun(result?.run);
|
|
6254
7303
|
if (updatedRun) {
|
|
6255
7304
|
setSubagentRuns((current) => mergeSubagentWorkbenchRuns([updatedRun, ...current]).slice(0, 120));
|
|
6256
7305
|
}
|
|
7306
|
+
if (!result?.success) {
|
|
7307
|
+
await handleSubagentRefresh();
|
|
7308
|
+
setSubagentError(result?.error || 'Cancellation is pending; child execution is not confirmed stopped.');
|
|
7309
|
+
return;
|
|
7310
|
+
}
|
|
6257
7311
|
setTransientEditorStatus('Cancelled subagent run.', 2200);
|
|
6258
7312
|
void handleSubagentRefresh();
|
|
6259
7313
|
void refreshSubagentAvailability();
|
|
6260
7314
|
}
|
|
7315
|
+
catch {
|
|
7316
|
+
await handleSubagentRefresh().catch(() => undefined);
|
|
7317
|
+
setSubagentError('Cancellation acknowledgement was lost; child execution is not confirmed stopped. Refresh and retry.');
|
|
7318
|
+
}
|
|
6261
7319
|
finally {
|
|
6262
7320
|
setSubagentLoading(false);
|
|
6263
7321
|
}
|
|
@@ -6293,6 +7351,7 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
6293
7351
|
viewMode,
|
|
6294
7352
|
]);
|
|
6295
7353
|
const handleEditorContentChange = useCallback((path, content) => {
|
|
7354
|
+
editorDraftVersionsRef.current.set(path, (editorDraftVersionsRef.current.get(path) ?? 0) + 1);
|
|
6296
7355
|
setOpenEditorTabs((prev) => prev.map((tab) => (tab.type === 'file' && tab.file.path === path
|
|
6297
7356
|
? { ...tab, file: { ...tab.file, content, isDirty: content !== tab.file.savedContent } }
|
|
6298
7357
|
: tab)));
|
|
@@ -6315,11 +7374,15 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
6315
7374
|
}
|
|
6316
7375
|
setPendingEditorPath(entry.path);
|
|
6317
7376
|
setEditorStatusMessage(`Opening ${entry.name}...`);
|
|
6318
|
-
|
|
6319
|
-
|
|
6320
|
-
allowedDirs: activeConversationAllowedDirectories,
|
|
6321
|
-
});
|
|
7377
|
+
editorOperationsRef.current.invalidate(entry.path);
|
|
7378
|
+
const current = editorOperationsRef.current.capture(entry.path);
|
|
6322
7379
|
try {
|
|
7380
|
+
const result = await getAgentPlatformBridge().workspace.readFile({
|
|
7381
|
+
conversationId: activeConversationId || undefined,
|
|
7382
|
+
path: entry.path, allowedDirs: activeConversationAllowedDirectories,
|
|
7383
|
+
});
|
|
7384
|
+
if (!current())
|
|
7385
|
+
return;
|
|
6323
7386
|
if (!result?.success || !result.path) {
|
|
6324
7387
|
logAgentInterfaceDebug('editor file open failed', {
|
|
6325
7388
|
conversationId: activeConversationId,
|
|
@@ -6343,12 +7406,17 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
6343
7406
|
type: 'file',
|
|
6344
7407
|
file: openedFile
|
|
6345
7408
|
};
|
|
6346
|
-
setOpenEditorTabs((
|
|
7409
|
+
setOpenEditorTabs(prev => !current() || prev.some(tab => tab.id === openedTab.id) ? prev : [...prev, openedTab]);
|
|
6347
7410
|
setActiveEditorTabId(openedTab.id);
|
|
6348
7411
|
setEditorStatusMessage(null);
|
|
6349
7412
|
}
|
|
7413
|
+
catch (error) {
|
|
7414
|
+
if (current())
|
|
7415
|
+
setTransientEditorStatus(error instanceof Error ? error.message : `Failed to open ${entry.name}.`, 0);
|
|
7416
|
+
}
|
|
6350
7417
|
finally {
|
|
6351
|
-
|
|
7418
|
+
if (current())
|
|
7419
|
+
setPendingEditorPath(value => value === entry.path ? null : value);
|
|
6352
7420
|
}
|
|
6353
7421
|
}, [activeConversationAllowedDirectories, activeConversationId, centerPaneMode, openEditorTabs, setCenterPaneMode, setTransientEditorStatus]);
|
|
6354
7422
|
const handleOpenEditorFile = useCallback(async (entry) => {
|
|
@@ -6367,7 +7435,11 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
6367
7435
|
allowedDirectories: activeConversationAllowedDirectories,
|
|
6368
7436
|
caller: policyCaller,
|
|
6369
7437
|
}), [activeConversationAllowedDirectories, codeWorkbenchRootDirectory, policyCaller]);
|
|
7438
|
+
const engineeringConfirmationTargetsRef = useRef({ patches: engineeringPatchReviews, checkpoints: engineeringCheckpoints });
|
|
7439
|
+
const engineeringConfirmationRefreshRef = useRef(0);
|
|
7440
|
+
engineeringConfirmationTargetsRef.current = { patches: engineeringPatchReviews, checkpoints: engineeringCheckpoints };
|
|
6370
7441
|
useEffect(() => {
|
|
7442
|
+
setCodeWorkbenchLoading(false);
|
|
6371
7443
|
setCodeWorkbenchError(null);
|
|
6372
7444
|
setCodeWorkbenchStats(null);
|
|
6373
7445
|
setCodeWorkbenchFiles([]);
|
|
@@ -6399,8 +7471,11 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
6399
7471
|
setEngineeringSessions([]);
|
|
6400
7472
|
setEngineeringRuntimeEvents([]);
|
|
6401
7473
|
setEngineeringContextPressure(null);
|
|
6402
|
-
}, [
|
|
7474
|
+
}, [editorOperationScope]);
|
|
6403
7475
|
const handleEngineeringRefresh = useCallback(async () => {
|
|
7476
|
+
const viewCurrent = destructiveConfirmation.capture();
|
|
7477
|
+
const refreshVersion = ++engineeringConfirmationRefreshRef.current;
|
|
7478
|
+
const current = () => viewCurrent() && engineeringConfirmationRefreshRef.current === refreshVersion;
|
|
6404
7479
|
if (!codeWorkbenchRootDirectory) {
|
|
6405
7480
|
setEngineeringError('Open a folder before loading engineering tools.');
|
|
6406
7481
|
return;
|
|
@@ -6438,6 +7513,8 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
6438
7513
|
getAgentPlatformBridge().engineering.listSessions?.(engineeringRequestBase),
|
|
6439
7514
|
]);
|
|
6440
7515
|
const runtimeTimelineResult = await runtimeTimelinePromise;
|
|
7516
|
+
if (!current())
|
|
7517
|
+
return;
|
|
6441
7518
|
const git = toEngineeringGitStatus(gitResult);
|
|
6442
7519
|
if (git) {
|
|
6443
7520
|
setEngineeringGit(git);
|
|
@@ -6506,9 +7583,10 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
6506
7583
|
}
|
|
6507
7584
|
}
|
|
6508
7585
|
finally {
|
|
6509
|
-
|
|
7586
|
+
if (current())
|
|
7587
|
+
setEngineeringLoading(false);
|
|
6510
7588
|
}
|
|
6511
|
-
}, [activeConversationId, codeWorkbenchRootDirectory, engineeringRequestBase]);
|
|
7589
|
+
}, [activeConversationId, codeWorkbenchRootDirectory, engineeringRequestBase, destructiveConfirmation.capture]);
|
|
6512
7590
|
const handleEngineeringTogglePath = useCallback((path) => {
|
|
6513
7591
|
setEngineeringSelectedPaths((current) => (current.includes(path)
|
|
6514
7592
|
? current.filter((item) => item !== path)
|
|
@@ -6621,78 +7699,47 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
6621
7699
|
setEngineeringLoading(false);
|
|
6622
7700
|
}
|
|
6623
7701
|
}, [codeWorkbenchRootDirectory, engineeringRequestBase]);
|
|
6624
|
-
const
|
|
6625
|
-
|
|
6626
|
-
|
|
6627
|
-
|
|
6628
|
-
|
|
6629
|
-
|
|
7702
|
+
const engineeringDestructiveActions = engineeringConfirmationActions({
|
|
7703
|
+
gate: destructiveConfirmation,
|
|
7704
|
+
service: () => getAgentPlatformBridge()?.engineering,
|
|
7705
|
+
requestBase: engineeringRequestBase,
|
|
7706
|
+
conversationId: activeConversationId || undefined,
|
|
7707
|
+
targetVersion: (kind, id) => {
|
|
7708
|
+
const targets = engineeringConfirmationTargetsRef.current;
|
|
7709
|
+
const item = kind === 'patch' ? targets.patches.find(entry => entry.id === id) : targets.checkpoints.find(entry => entry.checkpointId === id);
|
|
7710
|
+
return item ? JSON.stringify(item) : undefined;
|
|
7711
|
+
},
|
|
7712
|
+
applyItem: value => {
|
|
7713
|
+
const item = toPatchReviewItem(value);
|
|
7714
|
+
if (item)
|
|
7715
|
+
setEngineeringPatchReviews(current => current.map(entry => entry.id === item.id ? item : entry));
|
|
7716
|
+
},
|
|
7717
|
+
status: setTransientEditorStatus,
|
|
7718
|
+
refresh: handleEngineeringRefresh,
|
|
7719
|
+
});
|
|
7720
|
+
const handleEngineeringReviewPatchSelection = async (request) => {
|
|
7721
|
+
if (request.action !== 'comment')
|
|
7722
|
+
return engineeringDestructiveActions.review(request);
|
|
7723
|
+
const current = editorOperationsRef.current.capture('');
|
|
6630
7724
|
setEngineeringError(null);
|
|
6631
7725
|
try {
|
|
6632
|
-
const
|
|
6633
|
-
|
|
6634
|
-
if (item)
|
|
6635
|
-
setEngineeringPatchReviews((current) => current.map((entry) => entry.id === item.id ? item : entry));
|
|
6636
|
-
};
|
|
6637
|
-
if (request.action === 'comment') {
|
|
6638
|
-
const result = await getAgentPlatformBridge().engineering.reviewPatchSelection({
|
|
6639
|
-
...engineeringRequestBase,
|
|
6640
|
-
...request,
|
|
6641
|
-
});
|
|
6642
|
-
if (!result?.success) {
|
|
6643
|
-
setEngineeringError(result?.error || 'Failed to save the patch review comment.');
|
|
6644
|
-
return;
|
|
6645
|
-
}
|
|
6646
|
-
applyItem(result.item);
|
|
6647
|
-
setTransientEditorStatus('Saved patch review comment.', 2200);
|
|
6648
|
-
return;
|
|
6649
|
-
}
|
|
6650
|
-
const preview = await getAgentPlatformBridge().engineering.reviewPatchSelection({
|
|
6651
|
-
...engineeringRequestBase,
|
|
6652
|
-
...request,
|
|
6653
|
-
});
|
|
6654
|
-
if (!preview?.success) {
|
|
6655
|
-
setEngineeringError(preview?.error || 'Failed to preview the patch review decision.');
|
|
6656
|
-
return;
|
|
6657
|
-
}
|
|
6658
|
-
const conflicts = Array.isArray(preview.conflicts) ? preview.conflicts : [];
|
|
6659
|
-
if (conflicts.length > 0) {
|
|
6660
|
-
setEngineeringError(conflicts.map((conflict) => `${conflict.relativePath}: ${conflict.detail || conflict.reason}`).join('\n'));
|
|
6661
|
-
return;
|
|
6662
|
-
}
|
|
6663
|
-
if (!preview.previewToken) {
|
|
6664
|
-
setEngineeringError('Selective patch review did not return a transactional preview token.');
|
|
6665
|
-
return;
|
|
6666
|
-
}
|
|
6667
|
-
const scope = request.hunkId ? 'this hunk' : `all unresolved hunks in ${request.relativePath}`;
|
|
6668
|
-
const mutation = preview.wouldChangeFiles?.length
|
|
6669
|
-
? ' This will transactionally update the workspace file.'
|
|
6670
|
-
: '';
|
|
6671
|
-
if (!window.confirm(`${request.action === 'accept' ? 'Accept' : 'Reject'} ${scope}?${mutation}`))
|
|
7726
|
+
const result = await getAgentPlatformBridge().engineering.reviewPatchSelection({ ...engineeringRequestBase, ...request });
|
|
7727
|
+
if (!current())
|
|
6672
7728
|
return;
|
|
6673
|
-
|
|
6674
|
-
|
|
6675
|
-
...request,
|
|
6676
|
-
confirmed: true,
|
|
6677
|
-
previewToken: preview.previewToken,
|
|
6678
|
-
});
|
|
6679
|
-
if (!result?.success || !result.applied) {
|
|
6680
|
-
setEngineeringError(result?.error || 'Failed to apply the patch review decision.');
|
|
7729
|
+
if (!result?.success) {
|
|
7730
|
+
setEngineeringError(result?.error || 'Failed to save the patch review comment.');
|
|
6681
7731
|
return;
|
|
6682
7732
|
}
|
|
6683
|
-
|
|
6684
|
-
|
|
6685
|
-
|
|
7733
|
+
const item = toPatchReviewItem(result.item);
|
|
7734
|
+
if (item)
|
|
7735
|
+
setEngineeringPatchReviews(entries => entries.map(entry => entry.id === item.id ? item : entry));
|
|
7736
|
+
setTransientEditorStatus('Saved patch review comment.', 2200);
|
|
6686
7737
|
}
|
|
6687
|
-
|
|
6688
|
-
|
|
7738
|
+
catch (error) {
|
|
7739
|
+
if (current())
|
|
7740
|
+
setEngineeringError(error instanceof Error ? error.message : 'Failed to save the patch review comment.');
|
|
6689
7741
|
}
|
|
6690
|
-
}
|
|
6691
|
-
codeWorkbenchRootDirectory,
|
|
6692
|
-
engineeringRequestBase,
|
|
6693
|
-
handleEngineeringRefresh,
|
|
6694
|
-
setTransientEditorStatus,
|
|
6695
|
-
]);
|
|
7742
|
+
};
|
|
6696
7743
|
const handleEngineeringCompareCheckpoints = useCallback(async (fromCheckpointId, toCheckpointId) => {
|
|
6697
7744
|
if (!codeWorkbenchRootDirectory || !getAgentPlatformBridge()?.engineering?.compareCheckpoints) {
|
|
6698
7745
|
setEngineeringError('Checkpoint compare bridge is not available.');
|
|
@@ -6717,69 +7764,7 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
6717
7764
|
setEngineeringLoading(false);
|
|
6718
7765
|
}
|
|
6719
7766
|
}, [codeWorkbenchRootDirectory, engineeringRequestBase, setTransientEditorStatus]);
|
|
6720
|
-
const handleEngineeringRestoreCheckpoint =
|
|
6721
|
-
if (!codeWorkbenchRootDirectory || !getAgentPlatformBridge()?.engineering?.restoreCheckpoint) {
|
|
6722
|
-
setEngineeringError('Checkpoint restore bridge is not available.');
|
|
6723
|
-
return;
|
|
6724
|
-
}
|
|
6725
|
-
setEngineeringLoading(true);
|
|
6726
|
-
setEngineeringError(null);
|
|
6727
|
-
try {
|
|
6728
|
-
const preview = await getAgentPlatformBridge().engineering.restoreCheckpoint({
|
|
6729
|
-
...engineeringRequestBase,
|
|
6730
|
-
checkpointId,
|
|
6731
|
-
conversationId: activeConversationId,
|
|
6732
|
-
});
|
|
6733
|
-
if (!preview?.success) {
|
|
6734
|
-
setEngineeringError(preview?.error || 'Failed to create checkpoint restore preview.');
|
|
6735
|
-
return;
|
|
6736
|
-
}
|
|
6737
|
-
if (!preview.previewToken) {
|
|
6738
|
-
setEngineeringError('Checkpoint restore did not return a transactional preview token.');
|
|
6739
|
-
return;
|
|
6740
|
-
}
|
|
6741
|
-
const conflicts = Array.isArray(preview.conflicts) ? preview.conflicts : [];
|
|
6742
|
-
const nonOverridableConflicts = conflicts.filter((conflict) => conflict.reason !== 'current_state_changed');
|
|
6743
|
-
if (nonOverridableConflicts.length > 0) {
|
|
6744
|
-
setEngineeringError(nonOverridableConflicts.map((conflict) => (`${conflict.relativePath}: ${conflict.detail || conflict.reason}`)).join('\n'));
|
|
6745
|
-
return;
|
|
6746
|
-
}
|
|
6747
|
-
const conflictWarning = conflicts.length > 0
|
|
6748
|
-
? `\n\nWARNING: ${conflicts.length} file${conflicts.length === 1 ? '' : 's'} changed since this checkpoint. Continuing will overwrite the current version:\n${conflicts.map((conflict) => conflict.relativePath).join('\n')}`
|
|
6749
|
-
: '';
|
|
6750
|
-
const confirmed = window.confirm(`Restore checkpoint ${checkpointId}? This will transactionally restore the affected files:\n\n${(preview.wouldRestoreFiles || []).join('\n') || 'No files listed.'}${conflictWarning}`);
|
|
6751
|
-
if (!confirmed)
|
|
6752
|
-
return;
|
|
6753
|
-
const result = await getAgentPlatformBridge().engineering.restoreCheckpoint({
|
|
6754
|
-
...engineeringRequestBase,
|
|
6755
|
-
checkpointId,
|
|
6756
|
-
conversationId: activeConversationId,
|
|
6757
|
-
confirmed: true,
|
|
6758
|
-
previewToken: preview.previewToken,
|
|
6759
|
-
conflictStrategy: conflicts.length > 0 ? 'overwrite' : 'abort',
|
|
6760
|
-
});
|
|
6761
|
-
if (!result?.success) {
|
|
6762
|
-
setEngineeringError(result?.error || 'Failed to confirm checkpoint restore.');
|
|
6763
|
-
return;
|
|
6764
|
-
}
|
|
6765
|
-
if (!result.restored) {
|
|
6766
|
-
setEngineeringError('Checkpoint restore completed without confirming any restored files.');
|
|
6767
|
-
return;
|
|
6768
|
-
}
|
|
6769
|
-
const restoredCount = result.restoredFiles?.length || 0;
|
|
6770
|
-
setTransientEditorStatus(`Restored ${restoredCount} file${restoredCount === 1 ? '' : 's'} from ${checkpointId}.`, 3000);
|
|
6771
|
-
void handleEngineeringRefresh();
|
|
6772
|
-
}
|
|
6773
|
-
finally {
|
|
6774
|
-
setEngineeringLoading(false);
|
|
6775
|
-
}
|
|
6776
|
-
}, [
|
|
6777
|
-
activeConversationId,
|
|
6778
|
-
codeWorkbenchRootDirectory,
|
|
6779
|
-
engineeringRequestBase,
|
|
6780
|
-
handleEngineeringRefresh,
|
|
6781
|
-
setTransientEditorStatus,
|
|
6782
|
-
]);
|
|
7767
|
+
const handleEngineeringRestoreCheckpoint = engineeringDestructiveActions.restore;
|
|
6783
7768
|
const handleEngineeringStage = useCallback(async (paths) => {
|
|
6784
7769
|
if (!codeWorkbenchRootDirectory || !getAgentPlatformBridge()?.engineering?.gitStage) {
|
|
6785
7770
|
setEngineeringError('Engineering stage bridge is not available.');
|
|
@@ -7155,41 +8140,62 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
7155
8140
|
const targets = Array.from(new Set(paths.filter(Boolean)));
|
|
7156
8141
|
if (targets.length === 0 || !getAgentPlatformBridge()?.workspace?.readFile)
|
|
7157
8142
|
return;
|
|
8143
|
+
const snapshots = new Map(openEditorTabs.filter(isFileEditorTab).map(tab => [tab.file.path, tab.file]));
|
|
8144
|
+
const currentScope = editorOperationsRef.current.capture('');
|
|
8145
|
+
const failed = [];
|
|
8146
|
+
const retained = [];
|
|
7158
8147
|
const refreshed = await Promise.all(targets.map(async (path) => {
|
|
7159
|
-
const
|
|
7160
|
-
|
|
7161
|
-
|
|
7162
|
-
|
|
7163
|
-
|
|
7164
|
-
|
|
7165
|
-
|
|
8148
|
+
const snapshot = snapshots.get(path);
|
|
8149
|
+
if (!snapshot)
|
|
8150
|
+
return null;
|
|
8151
|
+
if (snapshot.isDirty) {
|
|
8152
|
+
retained.push(path);
|
|
8153
|
+
return null;
|
|
8154
|
+
}
|
|
8155
|
+
const current = editorOperationsRef.current.capture(path);
|
|
8156
|
+
try {
|
|
8157
|
+
const result = await getAgentPlatformBridge().workspace.readFile({ conversationId: activeConversationId || undefined, path, allowedDirs: activeConversationAllowedDirectories });
|
|
8158
|
+
if (!result?.success && current())
|
|
8159
|
+
failed.push(path);
|
|
8160
|
+
return result?.success && result.path && current()
|
|
8161
|
+
? { path, content: result.content || '', current, snapshot }
|
|
8162
|
+
: null;
|
|
8163
|
+
}
|
|
8164
|
+
catch {
|
|
8165
|
+
if (current())
|
|
8166
|
+
failed.push(path);
|
|
8167
|
+
return null;
|
|
8168
|
+
}
|
|
7166
8169
|
}));
|
|
7167
|
-
|
|
7168
|
-
|
|
8170
|
+
if (!currentScope())
|
|
8171
|
+
return;
|
|
8172
|
+
if (failed.length)
|
|
8173
|
+
setCodeWorkbenchError('Code changes were applied, but some open files could not be refreshed. Their editor contents were retained; reopen them before saving.');
|
|
8174
|
+
else if (retained.length)
|
|
8175
|
+
setCodeWorkbenchError('Code changes were applied on disk. Unsaved editor drafts were retained; review the disk changes before saving over them.');
|
|
8176
|
+
const byPath = new Map(refreshed.flatMap((entry) => entry ? [[entry.path, entry]] : []));
|
|
8177
|
+
if (byPath.size === 0 || !currentScope())
|
|
7169
8178
|
return;
|
|
7170
8179
|
setOpenEditorTabs((prev) => prev.map((tab) => {
|
|
7171
8180
|
if (tab.type !== 'file')
|
|
7172
8181
|
return tab;
|
|
7173
|
-
const
|
|
7174
|
-
if (
|
|
8182
|
+
const result = byPath.get(tab.file.path);
|
|
8183
|
+
if (!result || !result.current())
|
|
7175
8184
|
return tab;
|
|
7176
|
-
return {
|
|
7177
|
-
...tab,
|
|
7178
|
-
file: {
|
|
7179
|
-
...tab.file,
|
|
7180
|
-
content,
|
|
7181
|
-
savedContent: content,
|
|
7182
|
-
isDirty: false,
|
|
7183
|
-
lastSavedAt: Date.now(),
|
|
7184
|
-
}
|
|
7185
|
-
};
|
|
8185
|
+
return { ...tab, file: reconcileEditorRefresh(tab.file, result.snapshot, result.content, Date.now()) };
|
|
7186
8186
|
}));
|
|
7187
|
-
}, [activeConversationAllowedDirectories]);
|
|
8187
|
+
}, [activeConversationAllowedDirectories, activeConversationId, openEditorTabs]);
|
|
7188
8188
|
const handleCodeApplyAction = useCallback(async (action) => {
|
|
8189
|
+
if (codeMutationPendingRef.current) {
|
|
8190
|
+
setCodeWorkbenchError('A code change is still completing. Wait before starting another.');
|
|
8191
|
+
return;
|
|
8192
|
+
}
|
|
7189
8193
|
if (!codeWorkbenchRootDirectory || !getAgentPlatformBridge()?.codeIndex?.applyCodeAction) {
|
|
7190
8194
|
setCodeWorkbenchError('Code action apply bridge is not available. Restart Hub.');
|
|
7191
8195
|
return;
|
|
7192
8196
|
}
|
|
8197
|
+
codeMutationPendingRef.current = true;
|
|
8198
|
+
const current = editorOperationsRef.current.capture('');
|
|
7193
8199
|
setCodeWorkbenchLoading(true);
|
|
7194
8200
|
setCodeWorkbenchError(null);
|
|
7195
8201
|
try {
|
|
@@ -7203,6 +8209,8 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
7203
8209
|
kind: action.kind,
|
|
7204
8210
|
diagnosticCode: action.diagnosticCode,
|
|
7205
8211
|
});
|
|
8212
|
+
if (!current())
|
|
8213
|
+
return;
|
|
7206
8214
|
if (!result?.success) {
|
|
7207
8215
|
setCodeWorkbenchError(result?.error || 'Failed to apply code action.');
|
|
7208
8216
|
return;
|
|
@@ -7211,12 +8219,20 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
7211
8219
|
.flatMap((edit) => isPlainRecord(edit) ? [readString(edit, 'filePath')] : [])
|
|
7212
8220
|
.filter((path) => !!path);
|
|
7213
8221
|
await refreshOpenEditorFilesFromDisk(editedPaths);
|
|
8222
|
+
if (!current())
|
|
8223
|
+
return;
|
|
7214
8224
|
setTransientEditorStatus(result.applied ? `Applied code action: ${action.title}` : 'Code action produced no file changes.', 2600);
|
|
7215
8225
|
void handleCodeRefreshActions();
|
|
7216
8226
|
void handleCodeRefreshChanges();
|
|
7217
8227
|
}
|
|
8228
|
+
catch (error) {
|
|
8229
|
+
if (current())
|
|
8230
|
+
setCodeWorkbenchError(error instanceof Error ? error.message : 'Code action failed. Verify disk state before retrying.');
|
|
8231
|
+
}
|
|
7218
8232
|
finally {
|
|
7219
|
-
|
|
8233
|
+
codeMutationPendingRef.current = false;
|
|
8234
|
+
if (current())
|
|
8235
|
+
setCodeWorkbenchLoading(false);
|
|
7220
8236
|
}
|
|
7221
8237
|
}, [
|
|
7222
8238
|
codeIndexRequestBase,
|
|
@@ -7227,6 +8243,10 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
7227
8243
|
setTransientEditorStatus,
|
|
7228
8244
|
]);
|
|
7229
8245
|
const handleCodeOrganizeImports = useCallback(async () => {
|
|
8246
|
+
if (codeMutationPendingRef.current) {
|
|
8247
|
+
setCodeWorkbenchError('A code change is still completing. Wait before starting another.');
|
|
8248
|
+
return;
|
|
8249
|
+
}
|
|
7230
8250
|
if (!codeWorkbenchRootDirectory || !getAgentPlatformBridge()?.codeIndex?.organizeImports) {
|
|
7231
8251
|
setCodeWorkbenchError('Organize imports bridge is not available. Restart Hub.');
|
|
7232
8252
|
return;
|
|
@@ -7237,6 +8257,8 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
7237
8257
|
setCodeWorkbenchError('Select a TypeScript or JavaScript file/symbol before organizing imports.');
|
|
7238
8258
|
return;
|
|
7239
8259
|
}
|
|
8260
|
+
codeMutationPendingRef.current = true;
|
|
8261
|
+
const current = editorOperationsRef.current.capture('');
|
|
7240
8262
|
setCodeWorkbenchLoading(true);
|
|
7241
8263
|
setCodeWorkbenchError(null);
|
|
7242
8264
|
try {
|
|
@@ -7244,6 +8266,8 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
7244
8266
|
...codeIndexRequestBase,
|
|
7245
8267
|
filePath: targetPath,
|
|
7246
8268
|
});
|
|
8269
|
+
if (!current())
|
|
8270
|
+
return;
|
|
7247
8271
|
if (!result?.success) {
|
|
7248
8272
|
setCodeWorkbenchError(result?.error || 'Failed to organize imports.');
|
|
7249
8273
|
return;
|
|
@@ -7252,12 +8276,20 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
7252
8276
|
.flatMap((edit) => isPlainRecord(edit) ? [readString(edit, 'filePath')] : [])
|
|
7253
8277
|
.filter((path) => !!path);
|
|
7254
8278
|
await refreshOpenEditorFilesFromDisk(editedPaths);
|
|
8279
|
+
if (!current())
|
|
8280
|
+
return;
|
|
7255
8281
|
setTransientEditorStatus(result.applied ? 'Organized imports.' : 'Imports were already organized.', 2200);
|
|
7256
8282
|
void handleCodeRefreshActions();
|
|
7257
8283
|
void handleCodeRefreshChanges();
|
|
7258
8284
|
}
|
|
8285
|
+
catch (error) {
|
|
8286
|
+
if (current())
|
|
8287
|
+
setCodeWorkbenchError(error instanceof Error ? error.message : 'Organize imports failed. Verify disk state before retrying.');
|
|
8288
|
+
}
|
|
7259
8289
|
finally {
|
|
7260
|
-
|
|
8290
|
+
codeMutationPendingRef.current = false;
|
|
8291
|
+
if (current())
|
|
8292
|
+
setCodeWorkbenchLoading(false);
|
|
7261
8293
|
}
|
|
7262
8294
|
}, [
|
|
7263
8295
|
codeIndexRequestBase,
|
|
@@ -7271,6 +8303,10 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
7271
8303
|
setTransientEditorStatus,
|
|
7272
8304
|
]);
|
|
7273
8305
|
const handleCodeRenameSymbol = useCallback(async () => {
|
|
8306
|
+
if (codeMutationPendingRef.current) {
|
|
8307
|
+
setCodeWorkbenchError('A code change is still completing. Wait before starting another.');
|
|
8308
|
+
return;
|
|
8309
|
+
}
|
|
7274
8310
|
if (!codeWorkbenchRootDirectory || !getAgentPlatformBridge()?.codeIndex?.renameSymbol) {
|
|
7275
8311
|
setCodeWorkbenchError('Rename bridge is not available. Restart Hub.');
|
|
7276
8312
|
return;
|
|
@@ -7285,6 +8321,8 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
7285
8321
|
const nextName = window.prompt('Rename symbol to:', currentName);
|
|
7286
8322
|
if (!nextName || nextName.trim() === currentName)
|
|
7287
8323
|
return;
|
|
8324
|
+
codeMutationPendingRef.current = true;
|
|
8325
|
+
const current = editorOperationsRef.current.capture('');
|
|
7288
8326
|
setCodeWorkbenchLoading(true);
|
|
7289
8327
|
setCodeWorkbenchError(null);
|
|
7290
8328
|
try {
|
|
@@ -7295,6 +8333,8 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
7295
8333
|
column: selectedSymbol?.column || 1,
|
|
7296
8334
|
newName: nextName.trim(),
|
|
7297
8335
|
});
|
|
8336
|
+
if (!current())
|
|
8337
|
+
return;
|
|
7298
8338
|
if (!result?.success) {
|
|
7299
8339
|
setCodeWorkbenchError(result?.error || 'Failed to rename symbol.');
|
|
7300
8340
|
return;
|
|
@@ -7303,12 +8343,20 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
7303
8343
|
.flatMap((edit) => isPlainRecord(edit) ? [readString(edit, 'filePath')] : [])
|
|
7304
8344
|
.filter((path) => !!path);
|
|
7305
8345
|
await refreshOpenEditorFilesFromDisk(editedPaths);
|
|
8346
|
+
if (!current())
|
|
8347
|
+
return;
|
|
7306
8348
|
setTransientEditorStatus(result.applied ? `Renamed symbol to ${nextName.trim()}.` : 'Rename produced no file changes.', 2600);
|
|
7307
8349
|
void handleCodeIndex();
|
|
7308
8350
|
void handleCodeRefreshChanges();
|
|
7309
8351
|
}
|
|
8352
|
+
catch (error) {
|
|
8353
|
+
if (current())
|
|
8354
|
+
setCodeWorkbenchError(error instanceof Error ? error.message : 'Rename failed. Verify disk state before retrying.');
|
|
8355
|
+
}
|
|
7310
8356
|
finally {
|
|
7311
|
-
|
|
8357
|
+
codeMutationPendingRef.current = false;
|
|
8358
|
+
if (current())
|
|
8359
|
+
setCodeWorkbenchLoading(false);
|
|
7312
8360
|
}
|
|
7313
8361
|
}, [
|
|
7314
8362
|
codeIndexRequestBase,
|
|
@@ -7830,55 +8878,80 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
7830
8878
|
}
|
|
7831
8879
|
}, [centerPaneMode, setCenterPaneMode]);
|
|
7832
8880
|
const handleCloseEditorTab = useCallback((tabId) => {
|
|
7833
|
-
|
|
7834
|
-
|
|
7835
|
-
|
|
7836
|
-
|
|
7837
|
-
|
|
8881
|
+
const target = editorTabsForConfirmationRef.current.find(tab => tab.id === tabId);
|
|
8882
|
+
if (!target)
|
|
8883
|
+
return;
|
|
8884
|
+
const path = target.type === 'file' ? target.file.path : '';
|
|
8885
|
+
const guard = editorCloseGuard({ authority: editorOperationsRef.current, target,
|
|
8886
|
+
readTabs: () => editorTabsForConfirmationRef.current, readDraftVersion: path => editorDraftVersionsRef.current.get(path) ?? 0 });
|
|
8887
|
+
if (target.type === 'file' && editorOperationsRef.current.isSaving(path)) {
|
|
8888
|
+
setTransientEditorStatus('Wait for the file save to finish before closing this tab.', 4000);
|
|
8889
|
+
return;
|
|
8890
|
+
}
|
|
8891
|
+
const close = () => {
|
|
8892
|
+
if (!guard.valid())
|
|
8893
|
+
return;
|
|
8894
|
+
if (target.type === 'file')
|
|
8895
|
+
editorOperationsRef.current.invalidate(path);
|
|
8896
|
+
setOpenEditorTabs(prev => {
|
|
8897
|
+
// Recheck inside the state update: a keystroke may already be queued but
|
|
8898
|
+
// not rendered when consent was consumed. Never remove that newer draft.
|
|
8899
|
+
if (!guard.acceptsTabs(prev))
|
|
7838
8900
|
return prev;
|
|
7839
|
-
|
|
7840
|
-
|
|
7841
|
-
|
|
7842
|
-
|
|
7843
|
-
|
|
7844
|
-
return next[next.length - 1]?.id || null;
|
|
8901
|
+
const next = prev.filter(tab => tab.id !== tabId);
|
|
8902
|
+
setActiveEditorTabId(selected => selected === tabId ? next[next.length - 1]?.id || null : selected);
|
|
8903
|
+
if (next.length === 0)
|
|
8904
|
+
setCenterPaneMode('agent');
|
|
8905
|
+
return next;
|
|
7845
8906
|
});
|
|
7846
|
-
|
|
7847
|
-
|
|
7848
|
-
}
|
|
7849
|
-
|
|
7850
|
-
|
|
7851
|
-
|
|
8907
|
+
};
|
|
8908
|
+
if (target.type === 'file' && target.file.isDirty) {
|
|
8909
|
+
void confirmEditorDiscard(destructiveConfirmation, { name: target.file.name, valid: guard.valid, close });
|
|
8910
|
+
}
|
|
8911
|
+
else
|
|
8912
|
+
close();
|
|
8913
|
+
}, [destructiveConfirmation, setTransientEditorStatus]);
|
|
7852
8914
|
const handleSaveEditorFile = useCallback(async (path) => {
|
|
7853
8915
|
if (!activeConversationId)
|
|
7854
8916
|
return;
|
|
7855
8917
|
const file = openEditorTabs.find((entry) => entry.type === 'file' && entry.file.path === path)?.file;
|
|
7856
8918
|
if (!file)
|
|
7857
8919
|
return;
|
|
7858
|
-
|
|
7859
|
-
|
|
7860
|
-
path: file.path,
|
|
7861
|
-
content: file.content,
|
|
7862
|
-
allowedDirs: activeConversationAllowedDirectories,
|
|
7863
|
-
});
|
|
7864
|
-
if (!result?.success) {
|
|
7865
|
-
setTransientEditorStatus(result?.error || `Failed to save ${file.name}.`, 4000);
|
|
8920
|
+
const operation = editorOperationsRef.current.beginSave(path);
|
|
8921
|
+
if (!operation)
|
|
7866
8922
|
return;
|
|
7867
|
-
|
|
7868
|
-
|
|
7869
|
-
|
|
7870
|
-
|
|
7871
|
-
|
|
7872
|
-
|
|
7873
|
-
|
|
7874
|
-
|
|
7875
|
-
|
|
7876
|
-
|
|
8923
|
+
const current = editorOperationsRef.current.capture(path);
|
|
8924
|
+
setTransientEditorStatus(`Saving ${file.name}...`, 0);
|
|
8925
|
+
try {
|
|
8926
|
+
const result = await getAgentPlatformBridge().workspace.writeFile({
|
|
8927
|
+
conversationId: activeConversationId,
|
|
8928
|
+
path: file.path, content: file.content, allowedDirs: activeConversationAllowedDirectories,
|
|
8929
|
+
expectedContent: file.savedContent,
|
|
8930
|
+
});
|
|
8931
|
+
if (!operation.current())
|
|
8932
|
+
return;
|
|
8933
|
+
const failure = editorSaveFailure(result, file.name);
|
|
8934
|
+
if (failure) {
|
|
8935
|
+
setTransientEditorStatus(failure, 0);
|
|
8936
|
+
return;
|
|
7877
8937
|
}
|
|
7878
|
-
|
|
7879
|
-
|
|
8938
|
+
// A later keystroke was NOT part of this request. ACK exactly the submitted
|
|
8939
|
+
// snapshot, retaining subsequent edits as dirty, never current-content ACK.
|
|
8940
|
+
setOpenEditorTabs(prev => !current() ? prev : prev.map(entry => entry.type === 'file' && entry.file.path === path
|
|
8941
|
+
? { ...entry, file: acknowledgeEditorSave(entry.file, file.content, Date.now()) } : entry));
|
|
8942
|
+
const recovery = editorRecoveryFiles(result);
|
|
8943
|
+
setTransientEditorStatus(`Saved submitted version of ${file.name}. Newer edits, if any, remain unsaved.${recovery}`, recovery ? 0 : 4000);
|
|
8944
|
+
}
|
|
8945
|
+
catch (error) {
|
|
8946
|
+
if (operation.current())
|
|
8947
|
+
setTransientEditorStatus(error instanceof Error ? error.message : `Failed to save ${file.name}.`, 0);
|
|
8948
|
+
}
|
|
8949
|
+
finally {
|
|
8950
|
+
operation.finish();
|
|
8951
|
+
}
|
|
7880
8952
|
}, [activeConversationAllowedDirectories, activeConversationId, openEditorTabs, setTransientEditorStatus]);
|
|
7881
8953
|
const handleRevertEditorFile = useCallback((path) => {
|
|
8954
|
+
editorDraftVersionsRef.current.set(path, (editorDraftVersionsRef.current.get(path) ?? 0) + 1);
|
|
7882
8955
|
setOpenEditorTabs((prev) => prev.map((entry) => (entry.type === 'file' && entry.file.path === path
|
|
7883
8956
|
? {
|
|
7884
8957
|
...entry,
|
|
@@ -8076,85 +9149,100 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
8076
9149
|
terminalDraftInput,
|
|
8077
9150
|
updateConversation,
|
|
8078
9151
|
]);
|
|
8079
|
-
const
|
|
8080
|
-
|
|
8081
|
-
|
|
8082
|
-
|
|
8083
|
-
|
|
8084
|
-
|
|
8085
|
-
|
|
8086
|
-
|
|
8087
|
-
|
|
8088
|
-
|
|
8089
|
-
|
|
8090
|
-
|
|
8091
|
-
|
|
8092
|
-
|
|
8093
|
-
|
|
8094
|
-
|
|
8095
|
-
|
|
8096
|
-
|
|
8097
|
-
|
|
8098
|
-
|
|
8099
|
-
|
|
8100
|
-
|
|
8101
|
-
|
|
9152
|
+
const onboardingAttempt = useRef(null);
|
|
9153
|
+
const handleAgentDeployed = async (data) => {
|
|
9154
|
+
if (onboardingAttempt.current?.key !== data.submissionId)
|
|
9155
|
+
onboardingAttempt.current = { key: data.submissionId, attempt: new WorkspaceCreationAttempt() };
|
|
9156
|
+
let createdScope;
|
|
9157
|
+
const persistedAgentId = await onboardingAttempt.current.attempt.run(() => {
|
|
9158
|
+
const agentId = generateId();
|
|
9159
|
+
// Resolve display names for identity
|
|
9160
|
+
const resolvedWsName = data.workspace === 'new'
|
|
9161
|
+
? (data.workspaceName || 'New Workspace')
|
|
9162
|
+
: (workspaces.find(w => w.id === data.workspace)?.name || 'Workspace');
|
|
9163
|
+
const resolvedTmName = data.team === 'new'
|
|
9164
|
+
? (data.teamName || 'New Team')
|
|
9165
|
+
: (workspaces.flatMap(w => w.teams).find(t => t.id === data.team)?.name || 'Team');
|
|
9166
|
+
const resolvedTemplateName = data.template === 'custom' ? 'Custom' : (data.template || 'Custom')
|
|
9167
|
+
.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');
|
|
9168
|
+
setWorkspaces(prev => {
|
|
9169
|
+
if (!data.name.trim() || !validateOnboardingPlacement(prev, data.workspace, data.team, data.workspaceName || '', data.teamName || '')) {
|
|
9170
|
+
throw new Error('Agent placement changed. Select an active workspace and team before creating the agent.');
|
|
9171
|
+
}
|
|
9172
|
+
let updated = [...prev];
|
|
9173
|
+
// Resolve or create workspace
|
|
9174
|
+
let wsId = data.workspace;
|
|
9175
|
+
if (wsId === 'new') {
|
|
9176
|
+
wsId = generateId();
|
|
9177
|
+
updated.push({
|
|
9178
|
+
id: wsId,
|
|
9179
|
+
name: data.workspaceName || 'New Workspace',
|
|
9180
|
+
directories: [],
|
|
9181
|
+
apps: [],
|
|
9182
|
+
teams: [],
|
|
9183
|
+
isExpanded: true,
|
|
9184
|
+
createdAt: Date.now(),
|
|
9185
|
+
});
|
|
9186
|
+
}
|
|
9187
|
+
// Resolve or create team within workspace
|
|
9188
|
+
let tmId = data.team;
|
|
9189
|
+
if (tmId === 'new') {
|
|
9190
|
+
tmId = generateId();
|
|
9191
|
+
updated = updated.map(w => w.id === wsId
|
|
9192
|
+
? {
|
|
9193
|
+
...w,
|
|
9194
|
+
teams: [...w.teams, {
|
|
9195
|
+
id: tmId,
|
|
9196
|
+
name: data.teamName || 'New Team',
|
|
9197
|
+
allowedDirectories: [],
|
|
9198
|
+
allowedApps: [],
|
|
9199
|
+
agents: [],
|
|
9200
|
+
isExpanded: true
|
|
9201
|
+
}]
|
|
9202
|
+
}
|
|
9203
|
+
: w);
|
|
9204
|
+
}
|
|
9205
|
+
const targetTeam = updated
|
|
9206
|
+
.find(w => w.id === wsId)
|
|
9207
|
+
?.teams.find(t => t.id === tmId);
|
|
9208
|
+
if (!targetTeam)
|
|
9209
|
+
throw new Error('Agent team could not be resolved.');
|
|
9210
|
+
createdScope = { workspaceId: wsId, teamId: tmId };
|
|
9211
|
+
const resolvedTeamDirs = targetTeam?.allowedDirectories || [];
|
|
9212
|
+
const resolvedTeamApps = targetTeam?.allowedApps || [];
|
|
9213
|
+
// Add agent to team
|
|
9214
|
+
const agent = {
|
|
9215
|
+
...agentCreationConfiguration(updated.find(w => w.id === wsId), targetTeam, { model: data.model, systemPrompt: data.customInstructions || undefined }),
|
|
9216
|
+
...(data.runtimeSelection ? { runtimeSelection: data.runtimeSelection } : {}),
|
|
9217
|
+
id: agentId,
|
|
9218
|
+
name: data.name,
|
|
9219
|
+
isMainAssistant: (targetTeam?.agents.length || 0) === 0 || !targetTeam?.agents.some(a => a.isMainAssistant),
|
|
9220
|
+
templateName: resolvedTemplateName,
|
|
9221
|
+
workspaceName: resolvedWsName,
|
|
9222
|
+
teamName: resolvedTmName,
|
|
9223
|
+
permissionProfile: 'standard',
|
|
9224
|
+
allowedDirectories: [...resolvedTeamDirs],
|
|
9225
|
+
allowedApps: [...resolvedTeamApps],
|
|
9226
|
+
conversations: [],
|
|
8102
9227
|
isExpanded: true,
|
|
8103
|
-
|
|
8104
|
-
});
|
|
8105
|
-
}
|
|
8106
|
-
// Resolve or create team within workspace
|
|
8107
|
-
let tmId = data.team;
|
|
8108
|
-
if (tmId === 'new') {
|
|
8109
|
-
tmId = generateId();
|
|
9228
|
+
};
|
|
8110
9229
|
updated = updated.map(w => w.id === wsId
|
|
8111
9230
|
? {
|
|
8112
9231
|
...w,
|
|
8113
|
-
|
|
8114
|
-
|
|
8115
|
-
|
|
8116
|
-
|
|
8117
|
-
allowedApps: [],
|
|
8118
|
-
agents: [],
|
|
8119
|
-
isExpanded: true
|
|
8120
|
-
}]
|
|
9232
|
+
isExpanded: true,
|
|
9233
|
+
teams: w.teams.map(t => t.id === tmId
|
|
9234
|
+
? { ...t, isExpanded: true, agents: [...t.agents, agent] }
|
|
9235
|
+
: t),
|
|
8121
9236
|
}
|
|
8122
9237
|
: w);
|
|
8123
|
-
|
|
8124
|
-
|
|
8125
|
-
|
|
8126
|
-
|
|
8127
|
-
|
|
8128
|
-
|
|
8129
|
-
|
|
8130
|
-
|
|
8131
|
-
id: agentId,
|
|
8132
|
-
name: data.name,
|
|
8133
|
-
isMainAssistant: (targetTeam?.agents.length || 0) === 0 || !targetTeam?.agents.some(a => a.isMainAssistant),
|
|
8134
|
-
model: data.model,
|
|
8135
|
-
systemPrompt: data.customInstructions,
|
|
8136
|
-
templateName: resolvedTemplateName,
|
|
8137
|
-
workspaceName: resolvedWsName,
|
|
8138
|
-
teamName: resolvedTmName,
|
|
8139
|
-
capabilities: { ...DEFAULT_AGENT_CAPABILITIES },
|
|
8140
|
-
permissionProfile: 'standard',
|
|
8141
|
-
allowedDirectories: [...resolvedTeamDirs],
|
|
8142
|
-
allowedApps: [...resolvedTeamApps],
|
|
8143
|
-
conversations: [],
|
|
8144
|
-
isExpanded: true,
|
|
8145
|
-
};
|
|
8146
|
-
updated = updated.map(w => w.id === wsId
|
|
8147
|
-
? {
|
|
8148
|
-
...w,
|
|
8149
|
-
isExpanded: true,
|
|
8150
|
-
teams: w.teams.map(t => t.id === tmId
|
|
8151
|
-
? { ...t, isExpanded: true, agents: [...t.agents, agent] }
|
|
8152
|
-
: t),
|
|
8153
|
-
}
|
|
8154
|
-
: w);
|
|
8155
|
-
return updated;
|
|
8156
|
-
});
|
|
8157
|
-
setSelectedAgentId(agentId);
|
|
9238
|
+
return updated;
|
|
9239
|
+
});
|
|
9240
|
+
return agentId;
|
|
9241
|
+
}, (persisted, id) => !!createdScope && persisted.some(w => w.id === createdScope.workspaceId && !w.isArchived && w.teams.some(t => t.id === createdScope.teamId && !t.isArchived && t.agents.some(a => a.id === id))));
|
|
9242
|
+
return persistedAgentId;
|
|
9243
|
+
};
|
|
9244
|
+
const handleCreatedAgentSelected = (persistedAgentId) => {
|
|
9245
|
+
setSelectedAgentId(persistedAgentId);
|
|
8158
9246
|
setSelectedConversationId(null);
|
|
8159
9247
|
setSelectedInboxConversationId(null);
|
|
8160
9248
|
setActiveSessionTabId(null);
|
|
@@ -8187,7 +9275,7 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
8187
9275
|
: settingsPanel.type === 'team'
|
|
8188
9276
|
? (teamForSettings?.name || settingsPanel.teamName || 'Team')
|
|
8189
9277
|
: (workspaceForSettings?.name || settingsPanel.workspaceName || 'Workspace');
|
|
8190
|
-
return (_jsx(EntitySettingsLayout, { entityType: settingsPanel.type, entityId: entityId, entityName: entityName, chromeTitle: settingsPanel.chromeTitle, workspaceId: settingsPanel.workspaceId, workspaceName: workspaceForSettings?.name || settingsPanel.workspaceName, initialSection: settingsPanel.initialSection, workspaceDirectories: workspaceForSettings?.directories || [], workspaceApps: workspaceForSettings?.apps || [], currentDirectories: currentDirectories, teamDirectories: teamForSettings
|
|
9278
|
+
return (_jsx(EntitySettingsLayout, { entityType: settingsPanel.type, entityId: entityId, entityName: entityName, chromeTitle: settingsPanel.chromeTitle, workspaceId: settingsPanel.workspaceId, workspaceName: workspaceForSettings?.name || settingsPanel.workspaceName, initialSection: settingsPanel.initialSection, workspaceDirectories: workspaceForSettings?.directories || [], workspaceApps: workspaceForSettings?.apps || [], currentDirectories: currentDirectories, teamDirectories: workspaceForSettings && teamForSettings ? resolveTeamDirectories(workspaceForSettings, teamForSettings) : [], currentAppIds: currentAppIds, teamAppIds: teamForSettings?.allowedApps || [], teamAgentPolicy: teamForSettings?.teamAgentPolicy, teamAgents: (teamForSettings?.agents || []).map((agent, index) => ({
|
|
8191
9279
|
id: agent.id,
|
|
8192
9280
|
name: agent.name,
|
|
8193
9281
|
templateName: agent.templateName,
|
|
@@ -8268,7 +9356,7 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
8268
9356
|
sp += `\n\nInstalled XENO apps: ${runtimeContext.installedApps.join(', ')}`;
|
|
8269
9357
|
}
|
|
8270
9358
|
return sp || undefined;
|
|
8271
|
-
})()), templateName: selectedAgent.templateName, workspaceName: selectedAgent.workspaceName, teamName: selectedAgent.teamName, capabilities: selectedAgent.capabilities, permissionProfile: selectedAgent.permissionProfile || 'standard', runtimeSelection: selectedAgent.runtimeSelection, externalInputLockReason: providerSessionTuiInputLockReason, onSendToNativeTui: activeProviderSessionTerminalId ? sendTextToActiveProviderTui : undefined, allowedDirectories:
|
|
9359
|
+
})()), templateName: selectedAgent.templateName, workspaceName: selectedAgent.workspaceName, teamName: selectedAgent.teamName, capabilities: selectedAgent.capabilities, permissionProfile: selectedAgent.permissionProfile || 'standard', runtimeSelection: selectedAgent.runtimeSelection, externalInputLockReason: providerSessionTuiInputLockReason, onSendToNativeTui: activeProviderSessionTerminalId ? sendTextToActiveProviderTui : undefined, allowedDirectories: resolveAgentDirectories(selectedAgentHierarchy.workspace, selectedAgentHierarchy.team, selectedAgent), approvalRules: selectedAgent.approvalRules || [], onAddApprovalRule: (rule) => {
|
|
8272
9360
|
addAgentApprovalRule(selectedAgentHierarchy.workspace.id, selectedAgentHierarchy.team.id, selectedAgent.id, rule);
|
|
8273
9361
|
}, allowedApps: resolvedAllowedApps, teamAgents: teamAgents, onCreateAgent: handleCreateAgentFromAgent, onAskAgent: handleAskAgentFromAgent, onEnableFileWrite: enableSelectedAgentFileWrite, onOpenEditorPath: handleOpenEditorPath, onOpenEditorDiff: handleOpenEditorDiff, onPeekEditorPath: handlePeekEditorPath, onPeekEditorDiff: handlePeekEditorDiff, onOpenRuntimeSettings: () => {
|
|
8274
9362
|
handleOpenSettings({
|
|
@@ -8304,40 +9392,125 @@ export default function AgentInterface({ surface = 'embedded', initialSdkSession
|
|
|
8304
9392
|
});
|
|
8305
9393
|
}, renderWorkbenchPanel: false, onOpenConversationSettings: handleSelectSidebarSettings, onConversationCreated: activateSessionConversation, onNavigateConversation: activateSessionConversation }) }));
|
|
8306
9394
|
}
|
|
9395
|
+
// Projects Workspace Hub view (rendered on the right side)
|
|
9396
|
+
if (viewMode === 'projects') {
|
|
9397
|
+
return (_jsx(ProjectsWorkspaceView, { workspaces: workspaces, activeWorkspaceScope: activeWorkspaceScope, onSelectWorkspaceScope: (wsId) => setActiveWorkspaceScope(wsId), onSelectAgent: (agentId) => {
|
|
9398
|
+
handleSelectAgent(agentId);
|
|
9399
|
+
}, onSelectConversation: (agentId, convId) => {
|
|
9400
|
+
handleSelectConversation(agentId, convId);
|
|
9401
|
+
setViewMode('agent');
|
|
9402
|
+
}, onStartProjectChat: (agentId, dir) => handleStartProjectChat(agentId, dir), onOpenExplorer: (path) => handleOpenPathInExplorer(path), onBackToChat: () => setViewMode('inbox') }));
|
|
9403
|
+
}
|
|
9404
|
+
// Teams Workspace Hub view (rendered on the right side)
|
|
9405
|
+
if (viewMode === 'teams') {
|
|
9406
|
+
if (!activeWorkspaceScope)
|
|
9407
|
+
return _jsx(OwnedWorkforceView, { kind: "team", onBackToChat: () => setViewMode('inbox') }, "owned-teams");
|
|
9408
|
+
return (_jsx(TeamsWorkspaceView, { workspaces: workspaces, activeWorkspaceScope: activeWorkspaceScope, onSelectAgent: (agentId) => {
|
|
9409
|
+
handleSelectAgent(agentId);
|
|
9410
|
+
}, onSelectConversation: (agentId, convId) => {
|
|
9411
|
+
handleSelectConversation(agentId, convId);
|
|
9412
|
+
setViewMode('agent');
|
|
9413
|
+
}, onOpenTeamSettings: (teamId) => {
|
|
9414
|
+
const ws = workspaces.find((w) => w.id === activeWorkspaceScope) || workspaces[0];
|
|
9415
|
+
if (ws) {
|
|
9416
|
+
handleOpenSettings({
|
|
9417
|
+
type: 'team',
|
|
9418
|
+
workspaceId: ws.id,
|
|
9419
|
+
workspaceName: ws.name,
|
|
9420
|
+
teamId,
|
|
9421
|
+
});
|
|
9422
|
+
}
|
|
9423
|
+
}, onBackToChat: () => setViewMode('inbox') }));
|
|
9424
|
+
}
|
|
9425
|
+
// Agents Workspace Hub view (rendered on the right side)
|
|
9426
|
+
if (viewMode === 'agents') {
|
|
9427
|
+
if (!activeWorkspaceScope)
|
|
9428
|
+
return _jsx(OwnedWorkforceView, { kind: "agent", onBackToChat: () => setViewMode('inbox') }, "owned-agents");
|
|
9429
|
+
return (_jsx(AgentsWorkspaceView, { workspaces: workspaces, activeWorkspaceScope: activeWorkspaceScope, onSelectAgent: (agentId) => {
|
|
9430
|
+
handleSelectAgent(agentId);
|
|
9431
|
+
}, onSelectConversation: (agentId, convId) => {
|
|
9432
|
+
handleSelectConversation(agentId, convId);
|
|
9433
|
+
setViewMode('agent');
|
|
9434
|
+
}, onOpenAgentSettings: (agentId, teamId) => {
|
|
9435
|
+
const ws = workspaces.find((w) => w.id === activeWorkspaceScope) || workspaces[0];
|
|
9436
|
+
if (ws) {
|
|
9437
|
+
handleOpenSettings({
|
|
9438
|
+
type: 'agent',
|
|
9439
|
+
workspaceId: ws.id,
|
|
9440
|
+
workspaceName: ws.name,
|
|
9441
|
+
teamId,
|
|
9442
|
+
agentId,
|
|
9443
|
+
});
|
|
9444
|
+
}
|
|
9445
|
+
}, onBackToChat: () => setViewMode('inbox') }));
|
|
9446
|
+
}
|
|
9447
|
+
// Scheduled Tasks Hub view (rendered on the right side)
|
|
9448
|
+
if (viewMode === 'scheduled') {
|
|
9449
|
+
return (_jsx(ScheduledWorkspaceView, { workspaces: workspaces, activeWorkspaceScope: activeWorkspaceScope, onBackToChat: () => setViewMode('inbox') }));
|
|
9450
|
+
}
|
|
8307
9451
|
// Plugins view
|
|
8308
9452
|
if (viewMode === 'plugins') {
|
|
8309
9453
|
return (_jsx(React.Suspense, { fallback: _jsx(WorkbenchLoadingSkeleton, { title: "Loading plugins", subtitle: "Preparing Plugin/MCP controls." }), children: _jsx(PluginManager, { className: "h-full", caller: policyCaller }) }));
|
|
8310
9454
|
}
|
|
8311
9455
|
// Default: onboarding wizard
|
|
8312
|
-
return _jsx(AgentOnboarding, { onComplete: handleAgentDeployed, workspaces: workspaces });
|
|
9456
|
+
return _jsx(AgentOnboarding, { onComplete: handleAgentDeployed, onCreated: handleCreatedAgentSelected, workspaces: workspaces });
|
|
9457
|
+
};
|
|
9458
|
+
const handleStartProjectChat = (agentId, directory) => {
|
|
9459
|
+
const workspace = workspaces.find(ws => !ws.isArchived && ws.id === activeWorkspaceScope)
|
|
9460
|
+
|| (!activeWorkspaceScope ? workspaces.find(ws => !ws.isArchived && ws.teams.some(t => t.agents.some(a => a.id === agentId))) : undefined);
|
|
9461
|
+
if (!workspace || !workspace.directories.includes(directory)
|
|
9462
|
+
|| !projectAssignment(workspace, directory).agents.some(agent => agent.id === agentId))
|
|
9463
|
+
return;
|
|
9464
|
+
// 1. Create a new conversation for this agent
|
|
9465
|
+
const newConvId = createConversation(agentId);
|
|
9466
|
+
updateConversation(newConvId, { workspaceId: workspace.id });
|
|
9467
|
+
// 2. Grant and bind the project codebase directory to the conversation
|
|
9468
|
+
useAgentChatStore.getState().grantConversationDirectory(newConvId, directory);
|
|
9469
|
+
// 3. Ensure active workspace scope is pinned
|
|
9470
|
+
for (const ws of workspaces) {
|
|
9471
|
+
if (!ws.isArchived && ws.teams.some(t => t.agents.some(a => a.id === agentId))) {
|
|
9472
|
+
setActiveWorkspaceScope(ws.id);
|
|
9473
|
+
break;
|
|
9474
|
+
}
|
|
9475
|
+
}
|
|
9476
|
+
// 4. Navigate into the chat
|
|
9477
|
+
handleSelectConversation(agentId, newConvId);
|
|
9478
|
+
setViewMode('agent');
|
|
9479
|
+
};
|
|
9480
|
+
const handleOpenPathInExplorer = async (dirPath) => {
|
|
9481
|
+
const result = await getAgentPlatformBridge().workspace.openFileWith({
|
|
9482
|
+
path: dirPath, target: 'explorer', allowedDirs: [dirPath],
|
|
9483
|
+
});
|
|
9484
|
+
if (!result.success)
|
|
9485
|
+
throw new Error(result.error || 'Unable to open Explorer.');
|
|
8313
9486
|
};
|
|
8314
9487
|
// Permission dialog state
|
|
8315
9488
|
const pendingPermission = usePermissionStore(s => s.pending);
|
|
8316
9489
|
const resolvePermission = usePermissionStore(s => s.resolvePermission);
|
|
8317
9490
|
const sessionTabsNode = (_jsx(XenoAgentSessionTabs, { tabs: sessionTabs, activeConversationId: activeSessionTabId, placement: surface === 'standalone-desktop' ? 'titlebar' : 'embedded', onActivate: activateSessionConversation, onClose: closeSessionConversation, onCloseMany: closeSessionConversations, onCreate: createSessionConversation, onReorder: reorderSessionConversations }));
|
|
8318
|
-
const agentWorkspace = (_jsxs("div", { className: "xeno-app-shell flex h-full w-full", "data-xeno-agent-interface-owner": "shared", "data-xeno-agent-interface-contract": "1", "data-xeno-agent-interface-surface": surface, children: [_jsx(Sidebar, { collapsed: sidebarCollapsed, onToggleCollapse: () => setSidebarCollapsed(c => !c), onOpenSettings: handleOpenSettings, workspaces: workspaces, setWorkspaces: setWorkspaces, inboxAgentId: MAIN_ASSISTANT_ID, isInboxSelected: viewMode === 'inbox', selectedInboxConversationId: selectedInboxConversationId, onSelectInbox: handleSelectInbox, onSelectInboxConversation: handleSelectInboxConversation, selectedAgentId: selectedAgentId, onSelectAgent: handleSelectAgent, selectedConversationId: selectedConversationId, onSelectConversation: handleSelectConversation, agentRunAvailability: activeSubagentRunCounts, onOpenSearchResultInEditor: handleOpenEditorPath, onSelectPlugins: () => {
|
|
9491
|
+
const agentWorkspace = (_jsxs("div", { className: "xeno-app-shell flex h-full w-full", "data-xeno-agent-interface-owner": "shared", "data-xeno-agent-interface-contract": "1", "data-xeno-agent-interface-surface": surface, children: [destructiveConfirmation.confirmation, _jsx(Sidebar, { collapsed: sidebarCollapsed, onToggleCollapse: () => setSidebarCollapsed(c => !c), onOpenSettings: handleOpenSettings, workspaces: workspaces, setWorkspaces: setWorkspaces, inboxAgentId: MAIN_ASSISTANT_ID, isInboxSelected: viewMode === 'inbox', selectedInboxConversationId: selectedInboxConversationId, onSelectInbox: handleSelectInbox, onSelectInboxConversation: handleSelectInboxConversation, selectedAgentId: selectedAgentId, onSelectAgent: handleSelectAgent, selectedConversationId: selectedConversationId, onSelectConversation: handleSelectConversation, agentRunAvailability: activeSubagentRunCounts, onOpenSearchResultInEditor: handleOpenEditorPath, onSelectPlugins: () => {
|
|
8319
9492
|
if (activeConversationId) {
|
|
8320
9493
|
handleSelectWorkbenchTab('plugins');
|
|
8321
9494
|
return;
|
|
8322
9495
|
}
|
|
8323
9496
|
handleOpenPluginManager();
|
|
8324
|
-
}, onSelectKnowledge: () => handleSelectWorkbenchTab('knowledge'), onSelectSettings: handleSelectSidebarSettings }), _jsxs("div", { className: "relative flex-1 min-w-0 flex flex-col overflow-hidden", children: [_jsx(RightSidebarControls, { folderPanelOpen: folderPanelOpen, onOpenFolderPanel: () => setFolderPanelOpen(true) }), centerPaneMode === 'editor' && (_jsxs("div", { className: "xeno-chrome-shell xeno-border-subtle h-10 pr-[120px] border-b flex items-center justify-between gap-2", children: [_jsx("div", { className: "h-full min-w-0 flex-1", children: openEditorTabs.length > 0 && (_jsx(EditorTabs, { tabs: openEditorTabs, activeTabId: activeEditorTabId, onSelectTab: handleSelectEditorTab, onCloseTab: handleCloseEditorTab })) }), _jsx("div", { className: "flex items-center gap-2 pr-2", children: _jsx("button", { onClick: handleToggleWorkbenchPanel, className: `h-7 px-2.5 rounded-[5px] text-[10px] transition-colors ${workbenchPanelOpen
|
|
9497
|
+
}, onSelectKnowledge: () => handleSelectWorkbenchTab('knowledge'), onSelectProjects: () => setViewMode('projects'), onSelectTeams: () => setViewMode('teams'), onSelectAgents: () => setViewMode('agents'), onSelectScheduled: () => setViewMode('scheduled'), onStartProjectChat: handleStartProjectChat, onSelectSettings: handleSelectSidebarSettings, viewMode: viewMode, isSettingsOpen: Boolean(settingsPanel) }), _jsxs("div", { className: "relative flex-1 min-w-0 flex flex-col overflow-hidden", children: [_jsx(RightSidebarControls, { folderPanelOpen: folderPanelOpen, onOpenFolderPanel: () => setFolderPanelOpen(true), visible: !settingsPanel && !['projects', 'teams', 'agents', 'scheduled'].includes(viewMode || '') }), centerPaneMode === 'editor' && (_jsxs("div", { className: "xeno-chrome-shell xeno-border-subtle h-10 pr-[120px] border-b flex items-center justify-between gap-2", children: [_jsx("div", { className: "h-full min-w-0 flex-1", children: openEditorTabs.length > 0 && (_jsx(EditorTabs, { tabs: openEditorTabs, activeTabId: activeEditorTabId, onSelectTab: handleSelectEditorTab, onCloseTab: handleCloseEditorTab })) }), _jsx("div", { className: "flex items-center gap-2 pr-2", children: _jsx("button", { onClick: handleToggleWorkbenchPanel, className: `h-7 px-2.5 rounded-[5px] text-[10px] transition-colors ${workbenchPanelOpen
|
|
8325
9498
|
? 'bg-white/[0.075] text-white/72'
|
|
8326
|
-
: 'bg-transparent hover:bg-white/[0.055] text-white/35 hover:text-white/60'}`, children: "Panel" }) })] })), _jsxs("div", { className: "flex-1 min-h-0 flex flex-col overflow-hidden", children: [
|
|
8327
|
-
|
|
8328
|
-
|
|
8329
|
-
|
|
8330
|
-
|
|
8331
|
-
|
|
8332
|
-
|
|
9499
|
+
: 'bg-transparent hover:bg-white/[0.055] text-white/35 hover:text-white/60'}`, children: "Panel" }) })] })), _jsxs("div", { className: "flex-1 min-h-0 flex flex-col overflow-hidden", children: [_jsxs("main", { className: "flex-1 min-w-0 flex flex-col overflow-hidden", children: [sessionResumeError && _jsx("div", { role: "alert", className: "px-3 py-2 text-[12px] text-red-300", children: sessionResumeError }), centerPaneMode === 'split'
|
|
9500
|
+
? (_jsxs("div", { className: "flex-1 min-h-0 grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)] overflow-hidden", children: [_jsx("section", { className: "min-w-0 min-h-0 flex flex-col border-r xeno-border-subtle overflow-hidden", children: renderContent() }), _jsxs("section", { className: "min-w-0 min-h-0 flex flex-col overflow-hidden", children: [_jsxs("div", { className: "xeno-chrome-shell xeno-border-subtle h-10 border-b flex items-center justify-between gap-2 pr-[120px]", children: [_jsx("div", { className: "h-full min-w-0 flex-1", children: openEditorTabs.length > 0 && (_jsx(EditorTabs, { tabs: openEditorTabs, activeTabId: activeEditorTabId, onSelectTab: handleSelectEditorTab, onCloseTab: handleCloseEditorTab })) }), _jsx("div", { className: "flex items-center gap-2 pr-2", children: _jsx("button", { onClick: handleToggleWorkbenchPanel, className: `h-7 px-2.5 rounded-[5px] text-[10px] transition-colors ${workbenchPanelOpen
|
|
9501
|
+
? 'bg-white/[0.075] text-white/72'
|
|
9502
|
+
: 'bg-transparent hover:bg-white/[0.055] text-white/35 hover:text-white/60'}`, children: "Panel" }) })] }), _jsx("div", { className: "flex-1 min-h-0 flex flex-col overflow-hidden", children: _jsx(React.Suspense, { fallback: _jsx(WorkbenchLoadingSkeleton, { title: "Loading editor", subtitle: "Preparing editor workbench." }), children: activeEditorDiff ? (_jsx(MonacoDiffWorkbenchEditor, { diff: activeEditorDiff, rootDirectory: activeConversation?.rootDirectory || null, layoutKey: editorLayoutKey, statusMessage: editorStatusMessage, onOpenFile: handleOpenEditorPath })) : (_jsx(MonacoWorkbenchEditor, { file: activeEditorFile, pendingFilePath: pendingEditorPath, rootDirectory: activeConversation?.rootDirectory || null, openFilePaths: openEditorFiles.map((file) => file.path), layoutKey: editorLayoutKey, statusMessage: editorStatusMessage, onChangeFile: handleEditorContentChange, onSaveFile: handleSaveEditorFile, onRevertFile: handleRevertEditorFile })) }) })] })] }))
|
|
9503
|
+
: centerPaneMode === 'editor'
|
|
9504
|
+
? (_jsx(React.Suspense, { fallback: _jsx(WorkbenchLoadingSkeleton, { title: "Loading editor", subtitle: "Preparing editor workbench." }), children: activeEditorDiff ? (_jsx(MonacoDiffWorkbenchEditor, { diff: activeEditorDiff, rootDirectory: activeConversation?.rootDirectory || null, layoutKey: editorLayoutKey, statusMessage: editorStatusMessage, onOpenFile: handleOpenEditorPath })) : (_jsx(MonacoWorkbenchEditor, { file: activeEditorFile, pendingFilePath: pendingEditorPath, rootDirectory: activeConversation?.rootDirectory || null, openFilePaths: openEditorFiles.map((file) => file.path), layoutKey: editorLayoutKey, statusMessage: editorStatusMessage, onChangeFile: handleEditorContentChange, onSaveFile: handleSaveEditorFile, onRevertFile: handleRevertEditorFile })) }))
|
|
9505
|
+
: renderContent()] }), activeConversationId && workbenchPanelOpen && !settingsPanel && (_jsx("div", { className: "px-6 pb-5", children: _jsx("div", { className: `w-full mx-auto ${isWideWorkbenchTab(workbenchPanelTab) ? 'max-w-[1120px]' : 'max-w-[820px]'}`, children: _jsx(React.Suspense, { fallback: _jsx(WorkbenchLoadingSkeleton, { title: "Loading workbench", subtitle: "Preparing trace and support panels." }), children: _jsx(AgentWorkbenchPanel, { knowledgeWorkspaceId: activeConversation?.workspaceId, tab: workbenchPanelTab,
|
|
8333
9506
|
/* The host's default `resolveRunId` is
|
|
8334
9507
|
`subagentRunId ?? conversationId`, so the conversation id
|
|
8335
9508
|
IS the run id here. Passing anything else would ask the
|
|
8336
9509
|
host about a run it has never heard of. */
|
|
8337
|
-
reviewRunId: activeConversationId, coordinationSessionId: activeConversation?.sessionUi?.coordinationSessionId || activeConversationId, traceMessages: traceMessages, selectedTraceMessage: selectedTraceMessage, outputEntries: outputEntries, problemEntries: problemEntries, onSelectTab: handleSelectWorkbenchTab, onClose: handleCloseWorkbenchPanel, onSelectTraceMessage: handleSelectWorkbenchTraceMessage, onOpenChatSettings: handleOpenActiveConversationSettings, onOpenChatAcpAgents: handleOpenActiveConversationAcpAgents, onOpenChatPlugins: handleOpenPluginManager, onOpenChatKnowledge: handleOpenActiveConversationKnowledge, onOpenEditorPath: handleOpenEditorPath, onOpenEditorDiff: handleOpenEditorDiff, terminalCapabilityEnabled: terminalCapabilityEnabled, terminalReady: terminalReady, resolvedTerminalCwd: resolvedTerminalCwd, terminalDraftCwd: terminalDraftCwd, terminalDraftInput: terminalDraftInput, onChangeTerminalCwd: setTerminalDraftCwd, onChangeTerminalInput: setTerminalDraftInput, onResetTerminalCwd: handleResetWorkbenchTerminalCwd, onClearTerminalHistory: handleClearWorkbenchTerminalHistory, onRunTerminalCommand: () => { void handleRunWorkbenchTerminalCommand(); }, terminalHistory: terminalHistory, liveTerminalRuns: liveTerminalRunsForConversation, onReuseTerminalEntry: handleReuseWorkbenchTerminalEntry, onStopTerminalRun: (terminalId) => { void handleStopWorkbenchTerminalRun(terminalId); }, codeWorkbench: codeWorkbenchState, onCodeQueryChange: setCodeWorkbenchQuery, onCodeModeChange: handleCodeModeChange, onCodeIndex: handleCodeIndex, onCodeSearch: handleCodeSearch, onCodeOpenPath: handleCodeOpenPath, onCodeToggleFile: handleCodeToggleFile, onCodeToggleSymbol: handleCodeToggleSymbol, onCodeCreateContextPack: () => { void handleCodeCreateContextPack(); }, onCodeMaterializeContextPack: (packId) => { void handleCodeMaterializeContextPack(packId); }, onCodeAttachContextPack: (packId) => { void handleCodeAttachContextPack(packId); }, onCodeRefreshContextPacks: () => { void handleCodeRefreshContextPacks(); }, onCodeRefreshChanges: () => { void handleCodeRefreshChanges(); }, onCodeRefreshActions: () => { void handleCodeRefreshActions(); }, onCodeApplyAction: (action) => { void handleCodeApplyAction(action); }, onCodeOrganizeImports: () => { void handleCodeOrganizeImports(); }, onCodeRenameSymbol: () => { void handleCodeRenameSymbol(); }, onCodeRefreshLanguageServices: () => { void handleCodeRefreshLanguageServices(); }, onCodeControlLanguageService: (serviceId, action) => { void handleCodeControlLanguageService(serviceId, action); }, onCodeRepairIndex: () => { void handleCodeRepairIndex(); }, engineeringWorkbench: engineeringWorkbenchState, onEngineeringRefresh: () => { void handleEngineeringRefresh(); }, onEngineeringTogglePath: handleEngineeringTogglePath, onEngineeringOpenPath: handleEngineeringOpenPath, onEngineeringPreviewDiff: (paths) => { void handleEngineeringPreviewDiff(paths); }, onEngineeringStage: (paths) => { void handleEngineeringStage(paths); }, onEngineeringUnstage: (paths) => { void handleEngineeringUnstage(paths); }, onEngineeringRunCheck: (checkId) => { void handleEngineeringRunCheck(checkId); }, onEngineeringStartBackgroundCheck: (checkId) => { void handleEngineeringStartBackgroundCheck(checkId); }, onEngineeringStopBackgroundRun: (runId) => { void handleEngineeringStopBackgroundRun(runId); }, onEngineeringReadBackgroundRunOutput: (runId) => { void handleEngineeringReadBackgroundRunOutput(runId); }, onEngineeringCommitMessageChange: setEngineeringCommitMessage, onEngineeringCommit: () => { void handleEngineeringCommit(); }, onEngineeringQueuePatchReview: () => { void handleEngineeringQueuePatchReview(); }, onEngineeringUpdatePatchReview: (id, status) => { void handleEngineeringUpdatePatchReview(id, status); }, onEngineeringReviewPatchSelection: (request) => { void handleEngineeringReviewPatchSelection(request); }, onEngineeringCompareCheckpoints: (fromCheckpointId, toCheckpointId) => { void handleEngineeringCompareCheckpoints(fromCheckpointId, toCheckpointId); }, onEngineeringRestoreCheckpoint: (checkpointId) => { void handleEngineeringRestoreCheckpoint(checkpointId); }, cliControlPlane: cliControlPlaneState, cliControlPlaneCaller: policyCaller, cliControlPlaneConversationId: activeConversationId, cliControlPlaneRemoteBackendId: selectedAgent?.runtimeSelection?.remoteBackendId || '', onCliControlPlaneInspect: () => { void handleCliControlPlaneInspect(); }, onCliControlPlaneInspectOperation: (operation) => { void handleCliControlPlaneInspectOperation(operation); }, onCliControlPlaneRemoteRunOperation: (action, runId) => { void handleCliControlPlaneRemoteRunOperation(action, runId); }, subagentWorkbench: subagentWorkbenchState, subagentDelegationTargets: subagentDelegationTargets, subagentDelegationSourceName: selectedAgent?.name, subagentDelegationDisabledReason: subagentDelegationDisabledReason, onSubagentRefresh: () => { void handleSubagentRefresh(); }, onSubagentRecoverRuns: () => { void handleSubagentRecoverRuns(); }, onSubagentSelectRun: handleSubagentSelectRun, onSubagentOpenConversation: handleSubagentOpenConversation, onSubagentCancelRun: (run) => { void handleSubagentCancelRun(run); }, onCreateSubagentDelegation: handleWorkbenchSubagentDelegation, policyWorkbench: policyWorkbenchState, onPolicyRefresh: () => { void handlePolicyRefresh(); } }) }) }) }))] })] }), folderPanelOpen && (_jsx(FolderSidebar, { conversationId: activeConversationId, rootDirectory: activeConversation?.rootDirectory || null, allowedDirectories: activeConversationAllowedDirectories, onOpenFolder: handleOpenFolderForConversation, onClose: () => setFolderPanelOpen(false), onOpenFile: handleOpenEditorFile, activeFilePath: activeEditorFilePath, terminalCapabilityEnabled: terminalCapabilityEnabled, terminalReady: terminalReady, xenoTuiReady: xenoTuiReady, xenoTuiUnavailableReason: xenoTuiUnavailableReason, providerSessionTuiReady: providerSessionTuiReady, providerSessionTuiUnavailableReason: providerSessionTuiUnavailableReason, providerSessionTuiLabel: providerSessionTuiLabel, resolvedTerminalCwd: resolvedTerminalCwd, terminalTabs: rightPanelTerminalsForConversation, onPtyInput: handleRightPanelPtyInput, onPtyResize: handleRightPanelPtyResize, onCreateTerminal: handleCreateRightPanelTerminal, onCreateXenoTui: handleCreateXenoTui, onCreateProviderTui: handleCreateProviderSessionTui, onCloseTerminal: handleCloseRightPanelTerminal, onClearTerminal: handleClearRightPanelTerminal, onRestartTerminal: handleRestartRightPanelTerminal, onStopTerminal: handleStopRightPanelTerminal, width: rightPanelWidth, onResizeStart: handleRightPanelResizeStart })), rightPanelResizing && (_jsx("div", { className: "fixed inset-0 z-[9999] cursor-col-resize bg-transparent", "aria-hidden": "true" })), pendingPermission && (_jsx(PermissionDialog, { request: pendingPermission, onDecision: resolvePermission }))] }));
|
|
9510
|
+
reviewRunId: activeConversationId, coordinationSessionId: activeConversation?.sessionUi?.coordinationSessionId || activeConversationId, traceMessages: traceMessages, selectedTraceMessage: selectedTraceMessage, outputEntries: outputEntries, problemEntries: problemEntries, onSelectTab: handleSelectWorkbenchTab, onClose: handleCloseWorkbenchPanel, onSelectTraceMessage: handleSelectWorkbenchTraceMessage, onOpenChatSettings: handleOpenActiveConversationSettings, onOpenChatAcpAgents: handleOpenActiveConversationAcpAgents, onOpenChatPlugins: handleOpenPluginManager, onOpenChatKnowledge: handleOpenActiveConversationKnowledge, onOpenEditorPath: handleOpenEditorPath, onOpenEditorDiff: handleOpenEditorDiff, terminalCapabilityEnabled: terminalCapabilityEnabled, terminalReady: terminalReady, resolvedTerminalCwd: resolvedTerminalCwd, terminalDraftCwd: terminalDraftCwd, terminalDraftInput: terminalDraftInput, onChangeTerminalCwd: setTerminalDraftCwd, onChangeTerminalInput: setTerminalDraftInput, onResetTerminalCwd: handleResetWorkbenchTerminalCwd, onClearTerminalHistory: handleClearWorkbenchTerminalHistory, onRunTerminalCommand: () => { void handleRunWorkbenchTerminalCommand(); }, terminalHistory: terminalHistory, liveTerminalRuns: liveTerminalRunsForConversation, onReuseTerminalEntry: handleReuseWorkbenchTerminalEntry, onStopTerminalRun: (terminalId) => { void handleStopWorkbenchTerminalRun(terminalId); }, codeWorkbench: codeWorkbenchState, onCodeQueryChange: setCodeWorkbenchQuery, onCodeModeChange: handleCodeModeChange, onCodeIndex: handleCodeIndex, onCodeSearch: handleCodeSearch, onCodeOpenPath: handleCodeOpenPath, onCodeToggleFile: handleCodeToggleFile, onCodeToggleSymbol: handleCodeToggleSymbol, onCodeCreateContextPack: () => { void handleCodeCreateContextPack(); }, onCodeMaterializeContextPack: (packId) => { void handleCodeMaterializeContextPack(packId); }, onCodeAttachContextPack: (packId) => { void handleCodeAttachContextPack(packId); }, onCodeRefreshContextPacks: () => { void handleCodeRefreshContextPacks(); }, onCodeRefreshChanges: () => { void handleCodeRefreshChanges(); }, onCodeRefreshActions: () => { void handleCodeRefreshActions(); }, onCodeApplyAction: (action) => { void handleCodeApplyAction(action); }, onCodeOrganizeImports: () => { void handleCodeOrganizeImports(); }, onCodeRenameSymbol: () => { void handleCodeRenameSymbol(); }, onCodeRefreshLanguageServices: () => { void handleCodeRefreshLanguageServices(); }, onCodeControlLanguageService: (serviceId, action) => { void handleCodeControlLanguageService(serviceId, action); }, onCodeRepairIndex: () => { void handleCodeRepairIndex(); }, engineeringWorkbench: engineeringWorkbenchState, onEngineeringRefresh: () => { void handleEngineeringRefresh(); }, onEngineeringTogglePath: handleEngineeringTogglePath, onEngineeringOpenPath: handleEngineeringOpenPath, onEngineeringPreviewDiff: (paths) => { void handleEngineeringPreviewDiff(paths); }, onEngineeringStage: (paths) => { void handleEngineeringStage(paths); }, onEngineeringUnstage: (paths) => { void handleEngineeringUnstage(paths); }, onEngineeringRunCheck: (checkId) => { void handleEngineeringRunCheck(checkId); }, onEngineeringStartBackgroundCheck: (checkId) => { void handleEngineeringStartBackgroundCheck(checkId); }, onEngineeringStopBackgroundRun: (runId) => { void handleEngineeringStopBackgroundRun(runId); }, onEngineeringReadBackgroundRunOutput: (runId) => { void handleEngineeringReadBackgroundRunOutput(runId); }, onEngineeringCommitMessageChange: setEngineeringCommitMessage, onEngineeringCommit: () => { void handleEngineeringCommit(); }, onEngineeringQueuePatchReview: () => { void handleEngineeringQueuePatchReview(); }, onEngineeringUpdatePatchReview: (id, status) => { void handleEngineeringUpdatePatchReview(id, status); }, onEngineeringReviewPatchSelection: (request) => { void handleEngineeringReviewPatchSelection(request); }, onEngineeringCompareCheckpoints: (fromCheckpointId, toCheckpointId) => { void handleEngineeringCompareCheckpoints(fromCheckpointId, toCheckpointId); }, onEngineeringRestoreCheckpoint: (checkpointId) => { void handleEngineeringRestoreCheckpoint(checkpointId); }, cliControlPlane: cliControlPlaneState, cliControlPlaneCaller: policyCaller, cliControlPlaneConversationId: activeConversationId, cliControlPlaneRemoteBackendId: selectedAgent?.runtimeSelection?.remoteBackendId || '', onCliControlPlaneInspect: () => { void handleCliControlPlaneInspect(); }, onCliControlPlaneInspectOperation: (operation) => { void handleCliControlPlaneInspectOperation(operation); }, onCliControlPlaneRemoteRunOperation: (action, runId) => { void handleCliControlPlaneRemoteRunOperation(action, runId); }, subagentWorkbench: subagentWorkbenchState, subagentDelegationTargets: subagentDelegationTargets, subagentDelegationSourceName: selectedAgent?.name, subagentDelegationDisabledReason: subagentDelegationDisabledReason, onSubagentRefresh: () => { void handleSubagentRefresh(); }, onSubagentRecoverRuns: () => { void handleSubagentRecoverRuns(); }, onSubagentSelectRun: handleSubagentSelectRun, onSubagentOpenConversation: handleSubagentOpenConversation, onSubagentCancelRun: (run) => { void handleSubagentCancelRun(run); }, onCreateSubagentDelegation: handleWorkbenchSubagentDelegation, policyWorkbench: policyWorkbenchState, onPolicyRefresh: () => { void handlePolicyRefresh(); } }) }) }) }))] })] }), folderPanelOpen && !settingsPanel && !['projects', 'teams', 'agents', 'scheduled'].includes(viewMode || '') && (_jsx(FolderSidebar, { conversationId: activeConversationId, workspaceId: activeConversation?.workspaceId || null, rootDirectory: activeConversation?.rootDirectory || null, allowedDirectories: activeConversationAllowedDirectories, onOpenFolder: handleOpenFolderForConversation, onClose: () => setFolderPanelOpen(false), onOpenFile: handleOpenEditorFile, activeFilePath: activeEditorFilePath, terminalCapabilityEnabled: terminalCapabilityEnabled, terminalReady: terminalReady, xenoTuiReady: xenoTuiReady, xenoTuiUnavailableReason: xenoTuiUnavailableReason, providerSessionTuiReady: providerSessionTuiReady, providerSessionTuiUnavailableReason: providerSessionTuiUnavailableReason, providerSessionTuiLabel: providerSessionTuiLabel, resolvedTerminalCwd: resolvedTerminalCwd, terminalTabs: rightPanelTerminalsForConversation, onPtyInput: handleRightPanelPtyInput, onPtyResize: handleRightPanelPtyResize, onCreateTerminal: handleCreateRightPanelTerminal, onCreateXenoTui: handleCreateXenoTui, onCreateProviderTui: handleCreateProviderSessionTui, onCloseTerminal: handleCloseRightPanelTerminal, onClearTerminal: handleClearRightPanelTerminal, onRestartTerminal: handleRestartRightPanelTerminal, onStopTerminal: handleStopRightPanelTerminal, width: rightPanelWidth, onResizeStart: handleRightPanelResizeStart })), rightPanelResizing && (_jsx("div", { className: "fixed inset-0 z-[9999] cursor-col-resize bg-transparent", "aria-hidden": "true" })), pendingPermission && (_jsx(PermissionDialog, { request: pendingPermission, onDecision: resolvePermission }))] }));
|
|
8338
9511
|
if (surface !== 'standalone-desktop') {
|
|
8339
|
-
return (_jsxs("div", { className: "flex h-full w-full flex-col overflow-hidden", "data-xeno-agent-embedded-shell": "true", children: [_jsx("header", { className: "xeno-chrome-shell xeno-border-subtle h-10 flex-shrink-0 border-b", "data-xeno-agent-session-header": "embedded", "data-xeno-hub-header-style": "true", children: sessionTabsNode }), _jsx("div", { className: "min-h-0 min-w-0 flex-1", children: agentWorkspace })] }));
|
|
9512
|
+
return (_jsxs("div", { className: "flex h-full w-full flex-col overflow-hidden", "data-xeno-agent-embedded-shell": "true", children: [_jsx("header", { className: "xeno-chrome-shell xeno-border-subtle h-10 flex-shrink-0 border-b", "data-xeno-agent-session-header": "embedded", "data-xeno-hub-header-style": "true", children: sessionTabsNode }), _jsx(WorkspacePersistenceNotice, {}), _jsx(SidebarLayoutNotice, {}), _jsx("div", { className: "min-h-0 min-w-0 flex-1", children: agentWorkspace })] }));
|
|
8340
9513
|
}
|
|
8341
|
-
return (_jsxs("div", { className: "flex h-full w-full flex-col overflow-hidden", "data-xeno-agent-standalone-shell": "true", "data-xeno-agent-launch-mode": initialLaunchMode || 'default', children: [_jsx(XenoAgentProductHeader, { title: initialLaunchMode === 'chat' ? 'XENO Chat' : 'XENO Agent', centerContent: sessionTabsNode, onMinimize: windowControls?.onMinimize, onMaximize: windowControls?.onMaximize, onClose: windowControls?.onClose }), _jsx("div", { className: "min-h-0 min-w-0 flex-1", children: agentWorkspace })] }));
|
|
9514
|
+
return (_jsxs("div", { className: "flex h-full w-full flex-col overflow-hidden", "data-xeno-agent-standalone-shell": "true", "data-xeno-agent-launch-mode": initialLaunchMode || 'default', children: [_jsx(XenoAgentProductHeader, { title: initialLaunchMode === 'chat' ? 'XENO Chat' : 'XENO Agent', workspaceSelector: _jsx(XenoAgentWorkspaceSelector, { onOpenWorkspaceSettings: handleOpenWorkspaceSettings }), centerContent: sessionTabsNode, onMinimize: windowControls?.onMinimize, onNewWindow: windowControls?.onNewWindow, onMaximize: windowControls?.onMaximize, onClose: windowControls?.onClose }), _jsx(WorkspacePersistenceNotice, {}), _jsx(SidebarLayoutNotice, {}), _jsx("div", { className: "min-h-0 min-w-0 flex-1", children: agentWorkspace }), isWorkspaceWizardOpen && (_jsx(WorkspaceCreationWizard, { onClose: closeWorkspaceWizard }))] }));
|
|
8342
9515
|
}
|
|
8343
9516
|
//# sourceMappingURL=AgentInterface.js.map
|