@xenosystem/agent-interface-ui 0.1.25 → 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.
Files changed (380) hide show
  1. package/dist/adapters/agentHostPlatformBridge.d.ts.map +1 -1
  2. package/dist/adapters/agentHostPlatformBridge.js +96 -16
  3. package/dist/adapters/agentHostPlatformBridge.js.map +1 -1
  4. package/dist/adapters/hubAgentPlatformBridge.d.ts.map +1 -1
  5. package/dist/adapters/hubAgentPlatformBridge.js +2 -0
  6. package/dist/adapters/hubAgentPlatformBridge.js.map +1 -1
  7. package/dist/adapters/scopedBackupBridge.d.ts +4 -0
  8. package/dist/adapters/scopedBackupBridge.d.ts.map +1 -0
  9. package/dist/adapters/scopedBackupBridge.js +49 -0
  10. package/dist/adapters/scopedBackupBridge.js.map +1 -0
  11. package/dist/adapters/xenoAgentCompatibilityBridge.d.ts.map +1 -1
  12. package/dist/adapters/xenoAgentCompatibilityBridge.js +9 -1
  13. package/dist/adapters/xenoAgentCompatibilityBridge.js.map +1 -1
  14. package/dist/agent.css +13227 -0
  15. package/dist/components/agent/AgentIdentityGenerator.d.ts +16 -0
  16. package/dist/components/agent/AgentIdentityGenerator.d.ts.map +1 -0
  17. package/dist/components/agent/AgentIdentityGenerator.js +80 -0
  18. package/dist/components/agent/AgentIdentityGenerator.js.map +1 -0
  19. package/dist/components/agent/AgentInterface.d.ts +1 -0
  20. package/dist/components/agent/AgentInterface.d.ts.map +1 -1
  21. package/dist/components/agent/AgentInterface.js +1816 -643
  22. package/dist/components/agent/AgentInterface.js.map +1 -1
  23. package/dist/components/agent/AgentNotificationBanner.d.ts +10 -0
  24. package/dist/components/agent/AgentNotificationBanner.d.ts.map +1 -0
  25. package/dist/components/agent/AgentNotificationBanner.js +28 -0
  26. package/dist/components/agent/AgentNotificationBanner.js.map +1 -0
  27. package/dist/components/agent/AgentOnboarding.d.ts +16 -2
  28. package/dist/components/agent/AgentOnboarding.d.ts.map +1 -1
  29. package/dist/components/agent/AgentOnboarding.js +93 -201
  30. package/dist/components/agent/AgentOnboarding.js.map +1 -1
  31. package/dist/components/agent/AgentView.d.ts.map +1 -1
  32. package/dist/components/agent/AgentView.js +533 -308
  33. package/dist/components/agent/AgentView.js.map +1 -1
  34. package/dist/components/agent/AgentWorkbenchPanel.d.ts +3 -1
  35. package/dist/components/agent/AgentWorkbenchPanel.d.ts.map +1 -1
  36. package/dist/components/agent/AgentWorkbenchPanel.js +3 -2
  37. package/dist/components/agent/AgentWorkbenchPanel.js.map +1 -1
  38. package/dist/components/agent/AgentWorkspaceBrowserPanel.d.ts +4 -1
  39. package/dist/components/agent/AgentWorkspaceBrowserPanel.d.ts.map +1 -1
  40. package/dist/components/agent/AgentWorkspaceBrowserPanel.js +23 -195
  41. package/dist/components/agent/AgentWorkspaceBrowserPanel.js.map +1 -1
  42. package/dist/components/agent/AgentsWorkspaceView.d.ts +12 -0
  43. package/dist/components/agent/AgentsWorkspaceView.d.ts.map +1 -0
  44. package/dist/components/agent/AgentsWorkspaceView.js +129 -0
  45. package/dist/components/agent/AgentsWorkspaceView.js.map +1 -0
  46. package/dist/components/agent/DevelopmentCoordinationPanel.d.ts +7 -0
  47. package/dist/components/agent/DevelopmentCoordinationPanel.d.ts.map +1 -1
  48. package/dist/components/agent/DevelopmentCoordinationPanel.js +57 -49
  49. package/dist/components/agent/DevelopmentCoordinationPanel.js.map +1 -1
  50. package/dist/components/agent/KnowledgePanel.d.ts.map +1 -1
  51. package/dist/components/agent/KnowledgePanel.js +17 -67
  52. package/dist/components/agent/KnowledgePanel.js.map +1 -1
  53. package/dist/components/agent/LiveConversationCollaboration.d.ts +27 -0
  54. package/dist/components/agent/LiveConversationCollaboration.d.ts.map +1 -0
  55. package/dist/components/agent/LiveConversationCollaboration.js +127 -0
  56. package/dist/components/agent/LiveConversationCollaboration.js.map +1 -0
  57. package/dist/components/agent/MonacoDiffWorkbenchEditor.d.ts.map +1 -1
  58. package/dist/components/agent/MonacoDiffWorkbenchEditor.js +1 -1
  59. package/dist/components/agent/MonacoDiffWorkbenchEditor.js.map +1 -1
  60. package/dist/components/agent/MonacoWorkbenchEditor.d.ts.map +1 -1
  61. package/dist/components/agent/MonacoWorkbenchEditor.js +3 -3
  62. package/dist/components/agent/MonacoWorkbenchEditor.js.map +1 -1
  63. package/dist/components/agent/OwnedBrowserController.d.ts +55 -0
  64. package/dist/components/agent/OwnedBrowserController.d.ts.map +1 -0
  65. package/dist/components/agent/OwnedBrowserController.js +166 -0
  66. package/dist/components/agent/OwnedBrowserController.js.map +1 -0
  67. package/dist/components/agent/OwnedWorkforceView.d.ts +10 -0
  68. package/dist/components/agent/OwnedWorkforceView.d.ts.map +1 -0
  69. package/dist/components/agent/OwnedWorkforceView.js +256 -0
  70. package/dist/components/agent/OwnedWorkforceView.js.map +1 -0
  71. package/dist/components/agent/PluginManager.d.ts +34 -0
  72. package/dist/components/agent/PluginManager.d.ts.map +1 -1
  73. package/dist/components/agent/PluginManager.js +187 -126
  74. package/dist/components/agent/PluginManager.js.map +1 -1
  75. package/dist/components/agent/ProjectsWorkspaceView.d.ts +14 -0
  76. package/dist/components/agent/ProjectsWorkspaceView.d.ts.map +1 -0
  77. package/dist/components/agent/ProjectsWorkspaceView.js +176 -0
  78. package/dist/components/agent/ProjectsWorkspaceView.js.map +1 -0
  79. package/dist/components/agent/RunReviewPanel.d.ts +8 -13
  80. package/dist/components/agent/RunReviewPanel.d.ts.map +1 -1
  81. package/dist/components/agent/RunReviewPanel.js +120 -106
  82. package/dist/components/agent/RunReviewPanel.js.map +1 -1
  83. package/dist/components/agent/ScheduledWorkspaceView.d.ts +19 -0
  84. package/dist/components/agent/ScheduledWorkspaceView.d.ts.map +1 -0
  85. package/dist/components/agent/ScheduledWorkspaceView.js +150 -0
  86. package/dist/components/agent/ScheduledWorkspaceView.js.map +1 -0
  87. package/dist/components/agent/SdkSessionPanel.d.ts +25 -0
  88. package/dist/components/agent/SdkSessionPanel.d.ts.map +1 -0
  89. package/dist/components/agent/SdkSessionPanel.js +15 -0
  90. package/dist/components/agent/SdkSessionPanel.js.map +1 -0
  91. package/dist/components/agent/SlashCommandAutocomplete.d.ts +12 -0
  92. package/dist/components/agent/SlashCommandAutocomplete.d.ts.map +1 -0
  93. package/dist/components/agent/SlashCommandAutocomplete.js +33 -0
  94. package/dist/components/agent/SlashCommandAutocomplete.js.map +1 -0
  95. package/dist/components/agent/TeamsWorkspaceView.d.ts +12 -0
  96. package/dist/components/agent/TeamsWorkspaceView.d.ts.map +1 -0
  97. package/dist/components/agent/TeamsWorkspaceView.js +127 -0
  98. package/dist/components/agent/TeamsWorkspaceView.js.map +1 -0
  99. package/dist/components/agent/WorkspacePersistenceNotice.d.ts +3 -0
  100. package/dist/components/agent/WorkspacePersistenceNotice.d.ts.map +1 -0
  101. package/dist/components/agent/WorkspacePersistenceNotice.js +23 -0
  102. package/dist/components/agent/WorkspacePersistenceNotice.js.map +1 -0
  103. package/dist/components/agent/acp/AcpAgentConfigForm.d.ts +1 -0
  104. package/dist/components/agent/acp/AcpAgentConfigForm.d.ts.map +1 -1
  105. package/dist/components/agent/acp/AcpAgentConfigForm.js +47 -14
  106. package/dist/components/agent/acp/AcpAgentConfigForm.js.map +1 -1
  107. package/dist/components/agent/acp/AcpAgentDiagnosticsPanel.js +1 -1
  108. package/dist/components/agent/acp/AcpAgentDiagnosticsPanel.js.map +1 -1
  109. package/dist/components/agent/acp/AcpAgentManager.d.ts.map +1 -1
  110. package/dist/components/agent/acp/AcpAgentManager.js +18 -18
  111. package/dist/components/agent/acp/AcpAgentManager.js.map +1 -1
  112. package/dist/components/agent/acp/AcpAgentTestResultPanel.js +1 -1
  113. package/dist/components/agent/acp/AcpAgentTestResultPanel.js.map +1 -1
  114. package/dist/components/agent/acp/AcpApprovalPanel.js +2 -2
  115. package/dist/components/agent/acp/AcpApprovalPanel.js.map +1 -1
  116. package/dist/components/agent/acp/AcpCertificationPanel.js +1 -1
  117. package/dist/components/agent/acp/AcpCertificationPanel.js.map +1 -1
  118. package/dist/components/agent/acp/AcpLiveProviderWorkflowPanel.js +1 -1
  119. package/dist/components/agent/acp/AcpLiveProviderWorkflowPanel.js.map +1 -1
  120. package/dist/components/agent/acp/AcpProviderManagerPanel.js +1 -1
  121. package/dist/components/agent/acp/AcpProviderManagerPanel.js.map +1 -1
  122. package/dist/components/agent/acp/AcpProviderModelsPanel.js +1 -1
  123. package/dist/components/agent/acp/AcpProviderModelsPanel.js.map +1 -1
  124. package/dist/components/agent/acp/AcpSupportBundlePanel.js +1 -1
  125. package/dist/components/agent/acp/AcpSupportBundlePanel.js.map +1 -1
  126. package/dist/components/agent/collaborationWindow.d.ts +11 -0
  127. package/dist/components/agent/collaborationWindow.d.ts.map +1 -0
  128. package/dist/components/agent/collaborationWindow.js +10 -0
  129. package/dist/components/agent/collaborationWindow.js.map +1 -0
  130. package/dist/components/agent/conversationCollaborationAppendJournal.d.ts +25 -0
  131. package/dist/components/agent/conversationCollaborationAppendJournal.d.ts.map +1 -0
  132. package/dist/components/agent/conversationCollaborationAppendJournal.js +118 -0
  133. package/dist/components/agent/conversationCollaborationAppendJournal.js.map +1 -0
  134. package/dist/components/agent/conversationCollaborationController.d.ts +96 -0
  135. package/dist/components/agent/conversationCollaborationController.d.ts.map +1 -0
  136. package/dist/components/agent/conversationCollaborationController.js +597 -0
  137. package/dist/components/agent/conversationCollaborationController.js.map +1 -0
  138. package/dist/components/agent/destructiveConfirmation.d.ts +76 -0
  139. package/dist/components/agent/destructiveConfirmation.d.ts.map +1 -0
  140. package/dist/components/agent/destructiveConfirmation.js +231 -0
  141. package/dist/components/agent/destructiveConfirmation.js.map +1 -0
  142. package/dist/components/agent/developmentCoordinationController.d.ts +43 -0
  143. package/dist/components/agent/developmentCoordinationController.d.ts.map +1 -0
  144. package/dist/components/agent/developmentCoordinationController.js +94 -0
  145. package/dist/components/agent/developmentCoordinationController.js.map +1 -0
  146. package/dist/components/agent/developmentCoordinationProjection.d.ts +24 -0
  147. package/dist/components/agent/developmentCoordinationProjection.d.ts.map +1 -1
  148. package/dist/components/agent/developmentCoordinationProjection.js +34 -5
  149. package/dist/components/agent/developmentCoordinationProjection.js.map +1 -1
  150. package/dist/components/agent/editorOperationAuthority.d.ts +29 -0
  151. package/dist/components/agent/editorOperationAuthority.d.ts.map +1 -0
  152. package/dist/components/agent/editorOperationAuthority.js +73 -0
  153. package/dist/components/agent/editorOperationAuthority.js.map +1 -0
  154. package/dist/components/agent/knowledgePagination.d.ts +7 -0
  155. package/dist/components/agent/knowledgePagination.d.ts.map +1 -0
  156. package/dist/components/agent/knowledgePagination.js +7 -0
  157. package/dist/components/agent/knowledgePagination.js.map +1 -0
  158. package/dist/components/agent/knowledgePanelController.d.ts +32 -0
  159. package/dist/components/agent/knowledgePanelController.d.ts.map +1 -0
  160. package/dist/components/agent/knowledgePanelController.js +119 -0
  161. package/dist/components/agent/knowledgePanelController.js.map +1 -0
  162. package/dist/components/agent/monacoWorkbenchShared.js +1 -1
  163. package/dist/components/agent/onboardingModels.d.ts +31 -0
  164. package/dist/components/agent/onboardingModels.d.ts.map +1 -0
  165. package/dist/components/agent/onboardingModels.js +107 -0
  166. package/dist/components/agent/onboardingModels.js.map +1 -0
  167. package/dist/components/agent/personalConversationScope.d.ts +26 -0
  168. package/dist/components/agent/personalConversationScope.d.ts.map +1 -0
  169. package/dist/components/agent/personalConversationScope.js +43 -0
  170. package/dist/components/agent/personalConversationScope.js.map +1 -0
  171. package/dist/components/agent/reviewRequestScope.d.ts +16 -0
  172. package/dist/components/agent/reviewRequestScope.d.ts.map +1 -0
  173. package/dist/components/agent/reviewRequestScope.js +101 -0
  174. package/dist/components/agent/reviewRequestScope.js.map +1 -0
  175. package/dist/components/agent/scheduleCreationAttempt.d.ts +12 -0
  176. package/dist/components/agent/scheduleCreationAttempt.d.ts.map +1 -0
  177. package/dist/components/agent/scheduleCreationAttempt.js +30 -0
  178. package/dist/components/agent/scheduleCreationAttempt.js.map +1 -0
  179. package/dist/components/agent/settings/EntitySettingsLayout.d.ts +1 -1
  180. package/dist/components/agent/settings/EntitySettingsLayout.d.ts.map +1 -1
  181. package/dist/components/agent/settings/EntitySettingsLayout.js +64 -44
  182. package/dist/components/agent/settings/EntitySettingsLayout.js.map +1 -1
  183. package/dist/components/agent/settings/SettingsNavigation.d.ts.map +1 -1
  184. package/dist/components/agent/settings/SettingsNavigation.js +17 -17
  185. package/dist/components/agent/settings/SettingsNavigation.js.map +1 -1
  186. package/dist/components/agent/settings/entityArchiveState.d.ts +24 -0
  187. package/dist/components/agent/settings/entityArchiveState.d.ts.map +1 -0
  188. package/dist/components/agent/settings/entityArchiveState.js +12 -0
  189. package/dist/components/agent/settings/entityArchiveState.js.map +1 -0
  190. package/dist/components/agent/settings/sections/AccessMembersSection.d.ts.map +1 -1
  191. package/dist/components/agent/settings/sections/AccessMembersSection.js +10 -25
  192. package/dist/components/agent/settings/sections/AccessMembersSection.js.map +1 -1
  193. package/dist/components/agent/settings/sections/AccountWorkspacePanel.d.ts +16 -0
  194. package/dist/components/agent/settings/sections/AccountWorkspacePanel.d.ts.map +1 -0
  195. package/dist/components/agent/settings/sections/AccountWorkspacePanel.js +265 -0
  196. package/dist/components/agent/settings/sections/AccountWorkspacePanel.js.map +1 -0
  197. package/dist/components/agent/settings/sections/AgentPermissionRulesPanel.d.ts.map +1 -1
  198. package/dist/components/agent/settings/sections/AgentPermissionRulesPanel.js +47 -32
  199. package/dist/components/agent/settings/sections/AgentPermissionRulesPanel.js.map +1 -1
  200. package/dist/components/agent/settings/sections/DangerZoneSection.d.ts.map +1 -1
  201. package/dist/components/agent/settings/sections/DangerZoneSection.js +30 -6
  202. package/dist/components/agent/settings/sections/DangerZoneSection.js.map +1 -1
  203. package/dist/components/agent/settings/sections/DefaultAgentConfigSection.d.ts.map +1 -1
  204. package/dist/components/agent/settings/sections/DefaultAgentConfigSection.js +47 -37
  205. package/dist/components/agent/settings/sections/DefaultAgentConfigSection.js.map +1 -1
  206. package/dist/components/agent/settings/sections/EnvironmentSecretsSection.d.ts.map +1 -1
  207. package/dist/components/agent/settings/sections/EnvironmentSecretsSection.js +30 -43
  208. package/dist/components/agent/settings/sections/EnvironmentSecretsSection.js.map +1 -1
  209. package/dist/components/agent/settings/sections/ExportBackupSection.d.ts +3 -1
  210. package/dist/components/agent/settings/sections/ExportBackupSection.d.ts.map +1 -1
  211. package/dist/components/agent/settings/sections/ExportBackupSection.js +14 -12
  212. package/dist/components/agent/settings/sections/ExportBackupSection.js.map +1 -1
  213. package/dist/components/agent/settings/sections/GeneralSection.d.ts.map +1 -1
  214. package/dist/components/agent/settings/sections/GeneralSection.js +47 -4
  215. package/dist/components/agent/settings/sections/GeneralSection.js.map +1 -1
  216. package/dist/components/agent/settings/sections/IntegrationsSection.d.ts.map +1 -1
  217. package/dist/components/agent/settings/sections/IntegrationsSection.js +14 -21
  218. package/dist/components/agent/settings/sections/IntegrationsSection.js.map +1 -1
  219. package/dist/components/agent/settings/sections/NotificationsSection.d.ts.map +1 -1
  220. package/dist/components/agent/settings/sections/NotificationsSection.js +125 -20
  221. package/dist/components/agent/settings/sections/NotificationsSection.js.map +1 -1
  222. package/dist/components/agent/settings/sections/ResourceLimitsSection.d.ts.map +1 -1
  223. package/dist/components/agent/settings/sections/ResourceLimitsSection.js +7 -7
  224. package/dist/components/agent/settings/sections/ResourceLimitsSection.js.map +1 -1
  225. package/dist/components/agent/settings/sections/SecurityComplianceSection.d.ts.map +1 -1
  226. package/dist/components/agent/settings/sections/SecurityComplianceSection.js +5 -4
  227. package/dist/components/agent/settings/sections/SecurityComplianceSection.js.map +1 -1
  228. package/dist/components/agent/settings/sections/UsageAnalyticsSection.d.ts.map +1 -1
  229. package/dist/components/agent/settings/sections/UsageAnalyticsSection.js +2 -3
  230. package/dist/components/agent/settings/sections/UsageAnalyticsSection.js.map +1 -1
  231. package/dist/components/agent/settings/sections/WorkspaceDirectoryAccessSection.d.ts.map +1 -1
  232. package/dist/components/agent/settings/sections/WorkspaceDirectoryAccessSection.js +39 -26
  233. package/dist/components/agent/settings/sections/WorkspaceDirectoryAccessSection.js.map +1 -1
  234. package/dist/components/agent/settings/sections/WorkspaceKeysPanel.d.ts +6 -0
  235. package/dist/components/agent/settings/sections/WorkspaceKeysPanel.d.ts.map +1 -0
  236. package/dist/components/agent/settings/sections/WorkspaceKeysPanel.js +205 -0
  237. package/dist/components/agent/settings/sections/WorkspaceKeysPanel.js.map +1 -0
  238. package/dist/components/agent/settings/sections/environmentDraftAction.d.ts +3 -0
  239. package/dist/components/agent/settings/sections/environmentDraftAction.d.ts.map +1 -0
  240. package/dist/components/agent/settings/sections/environmentDraftAction.js +6 -0
  241. package/dist/components/agent/settings/sections/environmentDraftAction.js.map +1 -0
  242. package/dist/components/agent/settings/sections/membershipOperationProjection.d.ts +3 -0
  243. package/dist/components/agent/settings/sections/membershipOperationProjection.d.ts.map +1 -0
  244. package/dist/components/agent/settings/sections/membershipOperationProjection.js +9 -0
  245. package/dist/components/agent/settings/sections/membershipOperationProjection.js.map +1 -0
  246. package/dist/components/agent/settings/sections/workspaceKeyOperationProjection.d.ts +6 -0
  247. package/dist/components/agent/settings/sections/workspaceKeyOperationProjection.d.ts.map +1 -0
  248. package/dist/components/agent/settings/sections/workspaceKeyOperationProjection.js +8 -0
  249. package/dist/components/agent/settings/sections/workspaceKeyOperationProjection.js.map +1 -0
  250. package/dist/components/agent/settings/shared/InAppConfirmationDialog.d.ts +25 -0
  251. package/dist/components/agent/settings/shared/InAppConfirmationDialog.d.ts.map +1 -0
  252. package/dist/components/agent/settings/shared/InAppConfirmationDialog.js +89 -0
  253. package/dist/components/agent/settings/shared/InAppConfirmationDialog.js.map +1 -0
  254. package/dist/components/agent/settings/shared/InputField.d.ts +1 -1
  255. package/dist/components/agent/settings/shared/InputField.d.ts.map +1 -1
  256. package/dist/components/agent/settings/shared/InputField.js +4 -3
  257. package/dist/components/agent/settings/shared/InputField.js.map +1 -1
  258. package/dist/components/agent/settings/shared/MembersTable.d.ts +3 -3
  259. package/dist/components/agent/settings/shared/MembersTable.d.ts.map +1 -1
  260. package/dist/components/agent/settings/shared/MembersTable.js +1 -1
  261. package/dist/components/agent/settings/shared/MembersTable.js.map +1 -1
  262. package/dist/components/agent/settings/shared/ScopedAuditPanel.d.ts +5 -0
  263. package/dist/components/agent/settings/shared/ScopedAuditPanel.d.ts.map +1 -0
  264. package/dist/components/agent/settings/shared/ScopedAuditPanel.js +70 -0
  265. package/dist/components/agent/settings/shared/ScopedAuditPanel.js.map +1 -0
  266. package/dist/components/agent/settings/shared/SettingsCard.d.ts +2 -1
  267. package/dist/components/agent/settings/shared/SettingsCard.d.ts.map +1 -1
  268. package/dist/components/agent/settings/shared/SettingsCard.js +2 -2
  269. package/dist/components/agent/settings/shared/SettingsCard.js.map +1 -1
  270. package/dist/components/agent/settings/shared/ToggleSwitch.d.ts.map +1 -1
  271. package/dist/components/agent/settings/shared/ToggleSwitch.js +1 -1
  272. package/dist/components/agent/settings/shared/ToggleSwitch.js.map +1 -1
  273. package/dist/components/agent/settings/shared/UsageChart.d.ts +10 -0
  274. package/dist/components/agent/settings/shared/UsageChart.d.ts.map +1 -1
  275. package/dist/components/agent/settings/shared/UsageChart.js +16 -10
  276. package/dist/components/agent/settings/shared/UsageChart.js.map +1 -1
  277. package/dist/components/agent/settings/shared/WorkspaceRulesControl.d.ts +8 -0
  278. package/dist/components/agent/settings/shared/WorkspaceRulesControl.d.ts.map +1 -0
  279. package/dist/components/agent/settings/shared/WorkspaceRulesControl.js +26 -0
  280. package/dist/components/agent/settings/shared/WorkspaceRulesControl.js.map +1 -0
  281. package/dist/components/agent/settings/shared/useScopedConfirmation.d.ts +8 -0
  282. package/dist/components/agent/settings/shared/useScopedConfirmation.d.ts.map +1 -0
  283. package/dist/components/agent/settings/shared/useScopedConfirmation.js +53 -0
  284. package/dist/components/agent/settings/shared/useScopedConfirmation.js.map +1 -0
  285. package/dist/components/agent/settings/shared/useSettingsConfirmation.d.ts +8 -0
  286. package/dist/components/agent/settings/shared/useSettingsConfirmation.d.ts.map +1 -0
  287. package/dist/components/agent/settings/shared/useSettingsConfirmation.js +51 -0
  288. package/dist/components/agent/settings/shared/useSettingsConfirmation.js.map +1 -0
  289. package/dist/components/agent/settings/shared/workspaceRulesController.d.ts +28 -0
  290. package/dist/components/agent/settings/shared/workspaceRulesController.d.ts.map +1 -0
  291. package/dist/components/agent/settings/shared/workspaceRulesController.js +82 -0
  292. package/dist/components/agent/settings/shared/workspaceRulesController.js.map +1 -0
  293. package/dist/components/agent/sidebarEntityPins.d.ts +11 -0
  294. package/dist/components/agent/sidebarEntityPins.d.ts.map +1 -0
  295. package/dist/components/agent/sidebarEntityPins.js +37 -0
  296. package/dist/components/agent/sidebarEntityPins.js.map +1 -0
  297. package/dist/components/agent/workspaceHierarchy.d.ts +24 -0
  298. package/dist/components/agent/workspaceHierarchy.d.ts.map +1 -0
  299. package/dist/components/agent/workspaceHierarchy.js +50 -0
  300. package/dist/components/agent/workspaceHierarchy.js.map +1 -0
  301. package/dist/components/product/XenoAgentProductHeader.d.ts +4 -2
  302. package/dist/components/product/XenoAgentProductHeader.d.ts.map +1 -1
  303. package/dist/components/product/XenoAgentProductHeader.js +22 -4
  304. package/dist/components/product/XenoAgentProductHeader.js.map +1 -1
  305. package/dist/components/product/XenoAgentSessionTabs.js +1 -1
  306. package/dist/components/product/XenoAgentSessionTabs.js.map +1 -1
  307. package/dist/components/product/XenoAgentWorkspaceSelector.d.ts +7 -0
  308. package/dist/components/product/XenoAgentWorkspaceSelector.d.ts.map +1 -0
  309. package/dist/components/product/XenoAgentWorkspaceSelector.js +237 -0
  310. package/dist/components/product/XenoAgentWorkspaceSelector.js.map +1 -0
  311. package/dist/components/workspace/WorkspaceCreationWizard.d.ts +6 -0
  312. package/dist/components/workspace/WorkspaceCreationWizard.d.ts.map +1 -0
  313. package/dist/components/workspace/WorkspaceCreationWizard.js +48 -0
  314. package/dist/components/workspace/WorkspaceCreationWizard.js.map +1 -0
  315. package/dist/hooks/useSidebarLayoutPreference.d.ts +29 -0
  316. package/dist/hooks/useSidebarLayoutPreference.d.ts.map +1 -0
  317. package/dist/hooks/useSidebarLayoutPreference.js +83 -0
  318. package/dist/hooks/useSidebarLayoutPreference.js.map +1 -0
  319. package/dist/hooks/useWorkspaceCreation.d.ts +8 -0
  320. package/dist/hooks/useWorkspaceCreation.d.ts.map +1 -0
  321. package/dist/hooks/useWorkspaceCreation.js +40 -0
  322. package/dist/hooks/useWorkspaceCreation.js.map +1 -0
  323. package/dist/index.d.ts +3 -0
  324. package/dist/index.d.ts.map +1 -1
  325. package/dist/index.js +3 -0
  326. package/dist/index.js.map +1 -1
  327. package/dist/platformApiTypes.d.ts +77 -36
  328. package/dist/platformApiTypes.d.ts.map +1 -1
  329. package/dist/platformBridge.d.ts +4 -0
  330. package/dist/platformBridge.d.ts.map +1 -1
  331. package/dist/platformBridge.js +10 -0
  332. package/dist/platformBridge.js.map +1 -1
  333. package/dist/stores/agentChatStore.d.ts +120 -2
  334. package/dist/stores/agentChatStore.d.ts.map +1 -1
  335. package/dist/stores/agentChatStore.js +329 -35
  336. package/dist/stores/agentChatStore.js.map +1 -1
  337. package/dist/stores/agentCreationDefaults.d.ts +25 -0
  338. package/dist/stores/agentCreationDefaults.d.ts.map +1 -0
  339. package/dist/stores/agentCreationDefaults.js +11 -0
  340. package/dist/stores/agentCreationDefaults.js.map +1 -0
  341. package/dist/stores/entitySettingsStore.d.ts +37 -12
  342. package/dist/stores/entitySettingsStore.d.ts.map +1 -1
  343. package/dist/stores/entitySettingsStore.js +558 -585
  344. package/dist/stores/entitySettingsStore.js.map +1 -1
  345. package/dist/stores/suggestionStore.d.ts +9 -2
  346. package/dist/stores/suggestionStore.d.ts.map +1 -1
  347. package/dist/stores/suggestionStore.js +51 -24
  348. package/dist/stores/suggestionStore.js.map +1 -1
  349. package/dist/stores/workspaceCreationAttempt.d.ts +14 -0
  350. package/dist/stores/workspaceCreationAttempt.d.ts.map +1 -0
  351. package/dist/stores/workspaceCreationAttempt.js +35 -0
  352. package/dist/stores/workspaceCreationAttempt.js.map +1 -0
  353. package/dist/stores/workspaceReconciliation.d.ts +6 -0
  354. package/dist/stores/workspaceReconciliation.d.ts.map +1 -0
  355. package/dist/stores/workspaceReconciliation.js +33 -0
  356. package/dist/stores/workspaceReconciliation.js.map +1 -0
  357. package/dist/stores/workspaceStore.d.ts +44 -9
  358. package/dist/stores/workspaceStore.d.ts.map +1 -1
  359. package/dist/stores/workspaceStore.js +238 -99
  360. package/dist/stores/workspaceStore.js.map +1 -1
  361. package/dist/types/agentEditor.d.ts +1 -0
  362. package/dist/types/agentEditor.d.ts.map +1 -1
  363. package/dist/utils/advertisedReasoning.d.ts +25 -0
  364. package/dist/utils/advertisedReasoning.d.ts.map +1 -0
  365. package/dist/utils/advertisedReasoning.js +62 -0
  366. package/dist/utils/advertisedReasoning.js.map +1 -0
  367. package/dist/utils/clipboardCopy.d.ts +4 -0
  368. package/dist/utils/clipboardCopy.d.ts.map +1 -0
  369. package/dist/utils/clipboardCopy.js +27 -0
  370. package/dist/utils/clipboardCopy.js.map +1 -0
  371. package/dist/utils/providerCommandArgs.d.ts +11 -0
  372. package/dist/utils/providerCommandArgs.d.ts.map +1 -0
  373. package/dist/utils/providerCommandArgs.js +18 -0
  374. package/dist/utils/providerCommandArgs.js.map +1 -0
  375. package/dist/utils/rendererTeardown.d.ts +6 -0
  376. package/dist/utils/rendererTeardown.d.ts.map +1 -0
  377. package/dist/utils/rendererTeardown.js +18 -0
  378. package/dist/utils/rendererTeardown.js.map +1 -0
  379. package/package.json +20 -8
  380. 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, Package, Terminal, X } from 'lucide-react';
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
- return (_jsxs("div", { className: "absolute top-2 right-3 z-20 flex items-center gap-1.5", children: [_jsx("button", { className: "h-[34px] w-[34px] inline-flex items-center justify-center text-white/35 hover:text-white/60 transition-colors", title: "Sidebar options", "aria-label": "Sidebar options", type: "button", children: _jsx(MoreHorizontal, { className: "w-4 h-4", strokeWidth: 1.8 }) }), !folderPanelOpen && (_jsx("button", { onClick: onOpenFolderPanel, className: "h-[34px] w-[34px] inline-flex items-center justify-center transition-colors text-white/45 hover:text-white/75", title: "Open right sidebar", "aria-label": "Open right sidebar", type: "button", children: _jsx(PanelRightOpen, { className: "w-4 h-4", strokeWidth: 1.8 }) }))] }));
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 [showMoveSubmenu, setShowMoveSubmenu] = useState(false);
1942
- React.useEffect(() => {
1943
- const handleClickOutside = (e) => {
1944
- if (menuRef.current && !menuRef.current.contains(e.target)) {
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
- const MenuItem = ({ label, onClick, danger = false }) => (_jsx("button", { onClick: onClick, className: `w-full px-2.5 py-1 text-left text-[11px] transition-colors ${danger
1975
- ? 'text-red-400/70 hover:bg-red-500/10 hover:text-red-400'
1976
- : 'text-white/60 hover:bg-white/[0.06] hover:text-white'}`, children: label }));
1977
- return (_jsxs("div", { ref: menuRef, className: "fixed z-[100] py-1 bg-[#18181a] border border-white/[0.08] rounded-md shadow-2xl", style: { left: menu.x, top: menu.y }, children: [menu.type === 'workspace' && (_jsxs(_Fragment, { children: [_jsx(MenuItem, { label: "Rename", onClick: () => { onAction('rename'); onClose(); } }), _jsx(MenuItem, { label: "Duplicate", onClick: () => { onAction('duplicate'); onClose(); } }), _jsx(MenuItem, { label: "Add folder", onClick: () => { onAction('add-folder'); onClose(); } }), _jsx(MenuItem, { label: "Collapse all", onClick: () => { onAction('collapse'); onClose(); } }), _jsx(MenuItem, { label: "Expand all", onClick: () => { onAction('expand'); onClose(); } }), _jsx("div", { className: "my-1 mx-2 border-t border-white/[0.06]" }), _jsx(MenuItem, { label: "Settings", onClick: () => { onAction('settings'); onClose(); } }), _jsx("div", { className: "my-1 mx-2 border-t border-white/[0.06]" }), _jsx(MenuItem, { label: "Delete", onClick: () => { onAction('delete'); onClose(); }, danger: true })] })), menu.type === 'team' && (_jsxs(_Fragment, { children: [_jsx(MenuItem, { label: "Rename", onClick: () => { onAction('rename'); onClose(); } }), _jsx(MenuItem, { label: "Duplicate", onClick: () => { onAction('duplicate'); onClose(); } }), moveTargets.length > 0 && (_jsxs("div", { className: "relative", onMouseLeave: () => setShowMoveSubmenu(false), children: [_jsxs("div", { onMouseEnter: () => setShowMoveSubmenu(true), className: "w-full px-2.5 py-1 text-left text-[11px] text-white/60 hover:bg-white/[0.06] hover:text-white transition-colors flex items-center justify-between cursor-pointer", children: ["Move to workspace", _jsx("span", { className: "text-[9px] text-white/30 ml-3", children: ">" })] }), showMoveSubmenu && (_jsx("div", { className: "absolute left-full top-0 ml-0.5 py-1 bg-[#18181a] border border-white/[0.08] rounded-md shadow-2xl", children: moveTargets.map((target) => (_jsx("button", { onClick: () => { onAction('move', target.workspaceId); onClose(); }, className: "w-full px-2.5 py-1 text-left text-[11px] text-white/60 hover:bg-white/[0.06] hover:text-white transition-colors whitespace-nowrap", children: target.workspaceName }, target.workspaceId))) }))] })), _jsx("div", { className: "my-1 mx-2 border-t border-white/[0.06]" }), _jsx(MenuItem, { label: "Settings", onClick: () => { onAction('settings'); onClose(); } }), _jsx("div", { className: "my-1 mx-2 border-t border-white/[0.06]" }), _jsx(MenuItem, { label: "Delete", onClick: () => { onAction('delete'); onClose(); }, danger: true })] })), menu.type === 'agent' && (_jsxs(_Fragment, { children: [_jsx(MenuItem, { label: "Rename", onClick: () => { onAction('rename'); onClose(); } }), _jsx(MenuItem, { label: "Duplicate", onClick: () => { onAction('duplicate'); onClose(); } }), moveTargets.length > 0 && (_jsxs("div", { className: "relative", onMouseLeave: () => setShowMoveSubmenu(false), children: [_jsxs("div", { onMouseEnter: () => setShowMoveSubmenu(true), className: "w-full px-2.5 py-1 text-left text-[11px] text-white/60 hover:bg-white/[0.06] hover:text-white transition-colors flex items-center justify-between cursor-pointer", children: ["Move to team", _jsx("span", { className: "text-[9px] text-white/30 ml-3", children: ">" })] }), showMoveSubmenu && (_jsx("div", { className: "absolute left-full top-0 ml-0.5 max-h-[200px] overflow-auto py-1 bg-[#18181a] border border-white/[0.08] rounded-md shadow-2xl", children: moveTargets.map((target) => (_jsxs("button", { onClick: () => { onAction('move', target.workspaceId, target.teamId); onClose(); }, className: "w-full px-2.5 py-1 text-left text-[11px] text-white/60 hover:bg-white/[0.06] hover:text-white transition-colors whitespace-nowrap", children: [_jsxs("span", { className: "text-white/30", children: [target.workspaceName, " /"] }), " ", target.teamName] }, `${target.workspaceId}-${target.teamId}`))) }))] })), _jsx("div", { className: "my-1 mx-2 border-t border-white/[0.06]" }), _jsx(MenuItem, { label: "Settings", onClick: () => { onAction('settings'); onClose(); } }), _jsx("div", { className: "my-1 mx-2 border-t border-white/[0.06]" }), _jsx(MenuItem, { label: "Delete", onClick: () => { onAction('delete'); onClose(); }, danger: true })] })), menu.type === 'conversation' && (_jsxs(_Fragment, { children: [_jsx(MenuItem, { label: "Rename", onClick: () => { onAction('rename'); onClose(); } }), _jsx("div", { className: "my-1 mx-2 border-t border-white/[0.06]" }), _jsx(MenuItem, { label: "Delete", onClick: () => { onAction('delete'); onClose(); }, danger: true })] }))] }));
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 < 30)
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
- ? inboxConversations.filter((conv) => (conv.title || 'New conversation').toLowerCase().includes(normalizedInboxSearchQuery))
2067
- : inboxConversations;
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
- return (_jsxs("aside", { className: "flex-shrink-0 bg-[#0c0c0e] border-r border-white/[0.06] flex flex-col items-center py-2 gap-2 w-[48px]", children: [_jsx("button", { onClick: onToggleCollapse, className: "p-1.5 rounded-md text-white/30 bg-white/[0.04] hover:text-white/50 hover:bg-white/[0.08] transition-colors", title: "Expand sidebar", children: _jsx(PanelLeftOpen, { className: "w-4 h-4" }) }), _jsx("button", { onClick: onSelectInbox, className: `p-1.5 rounded-md transition-colors ${isInboxSelected
2770
- ? 'text-white bg-white/[0.08]'
2771
- : 'text-white/45 hover:text-white hover:bg-white/[0.04]'}`, title: "Inbox", children: _jsx(InboxIcon, {}) }), _jsx("div", { className: "flex-1" }), _jsx("button", { onClick: onSelectKnowledge, className: "p-1.5 rounded-md text-white/45 hover:text-white/70 hover:bg-white/[0.04] transition-colors", title: "Knowledge", children: _jsx(BookIcon, {}) }), _jsx("button", { onClick: onSelectSettings, className: "p-1.5 rounded-md text-white/45 hover:text-white/70 hover:bg-white/[0.04] transition-colors", title: "Settings", children: _jsx(SettingsIcon, {}) })] }));
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: "flex items-center gap-1", children: [inboxSearchMode ? (_jsxs("div", { className: "flex-1 min-w-0 h-[34px] flex items-center gap-2 px-2 py-1.5 rounded-md bg-white/[0.08] border border-white/[0.08]", children: [_jsx(InboxIcon, {}), _jsx("input", { ref: inboxSearchInputRef, value: inboxSearchQuery, onChange: (e) => setInboxSearchQuery(e.target.value), onKeyDown: (e) => {
2780
- if (e.key === 'Escape') {
2781
- e.preventDefault();
2782
- clearInboxSearch();
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
- }, onBlur: () => {
2785
- if (!inboxSearchQuery.trim())
2786
- clearInboxSearch();
2787
- }, placeholder: "Search all conversations", className: "flex-1 min-w-0 bg-transparent text-[14px] text-white placeholder:text-white/25 focus:outline-none" })] })) : (_jsxs("button", { onClick: onSelectInbox, onContextMenu: (e) => {
2788
- e.preventDefault();
2789
- setInboxMenuPos({ x: e.clientX, y: e.clientY });
2790
- }, className: `flex-1 min-w-0 h-[34px] flex items-center gap-2 px-2 py-1.5 rounded-md transition-colors ${isInboxSelected
2791
- ? 'text-white bg-white/[0.08]'
2792
- : 'text-white/70 hover:text-white hover:bg-white/[0.04]'}`, children: [_jsx(InboxIcon, {}), _jsx("span", { className: "text-[14px]", children: "Inbox" })] })), _jsx("button", { onClick: onToggleCollapse, className: "p-1.5 rounded-md text-white/30 bg-white/[0.04] hover:text-white/50 hover:bg-white/[0.08] transition-colors flex-shrink-0", title: "Collapse sidebar", children: _jsx(PanelLeftClose, { className: "w-4 h-4" }) })] }), showGlobalSearchResults && (_jsxs("div", { className: "ml-3 mt-1 max-h-[320px] overflow-y-auto border-l pl-2 xeno-border-subtle [&::-webkit-scrollbar]:hidden", children: [_jsxs("div", { className: "mb-1 flex items-center justify-between px-2 py-1", children: [_jsx("span", { className: "text-[10px] font-medium uppercase tracking-[0.16em] text-[color:var(--xeno-ink-faint)]", children: "Global Search" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-[10px] tabular-nums text-[color:var(--xeno-ink-faint)]", children: searchLoading ? 'indexing...' : `${searchTotal} hit${searchTotal === 1 ? '' : 's'}` }), _jsx("button", { type: "button", disabled: searchRepairing, onClick: (event) => {
2793
- event.preventDefault();
2794
- event.stopPropagation();
2795
- void repairAgentSearch();
2796
- }, className: "rounded border border-white/[0.07] px-1.5 py-0.5 text-[9px] uppercase tracking-[0.12em] text-white/32 transition-colors hover:border-white/[0.16] hover:text-white/62 disabled:opacity-30", title: "Repair and rebuild the local conversation search index", children: searchRepairing ? 'repairing' : 'repair' })] })] }), _jsxs("div", { className: "mb-1 rounded-md border border-white/[0.045] bg-black/15 px-2 py-1.5", children: [_jsxs("div", { className: "flex items-center justify-between gap-2 text-[10px] text-[color:var(--xeno-ink-faint)]", children: [_jsxs("span", { className: "truncate", children: [(searchStats?.backend || 'index'), " / ", searchStats?.documentCount ?? 0, " docs", typeof searchStats?.lastQueryMs === 'number' ? ` / ${searchStats.lastQueryMs}ms` : '', typeof searchProfile?.p95QueryMs === 'number' ? ` / p95 ${searchProfile.p95QueryMs}ms` : ''] }), searchHealth && (_jsx("span", { className: `flex-shrink-0 ${searchHealth.healthy ? 'text-[#96e59d]/70' : 'text-[#ffd38a]/80'}`, children: searchHealth.healthy ? 'healthy' : `${searchHealth.issues.length} issue${searchHealth.issues.length === 1 ? '' : 's'}` }))] }), searchHealth?.issues?.[0] && (_jsx("p", { className: "mt-1 truncate text-[10px] text-[#ffd38a]/70", children: searchHealth.issues[0].message })), searchProfile?.slowQueries?.[0] && (_jsxs("p", { className: "mt-1 truncate text-[10px] text-white/28", children: ["Slowest recent: ", searchProfile.slowQueries[0].durationMs, "ms / ", searchProfile.slowQueries[0].query] })), searchWatcherStatus && (_jsxs("p", { className: "mt-1 truncate text-[10px] text-white/24", children: ["Watcher: ", searchWatcherStatus.running ? `${searchWatcherStatus.watchedPathCount} paths` : 'offline', searchWatcherStatus.pendingReindex ? ' / reindex pending' : '', searchWatcherStatus.lastReindexError ? ` / ${searchWatcherStatus.lastReindexError}` : ''] }))] }), searchAttachNotice && (_jsx("p", { className: "mb-1 rounded-md border border-white/[0.06] bg-white/[0.04] px-2 py-1 text-[11px] text-[color:var(--xeno-ink-muted)]", children: searchAttachNotice })), searchRepairNotice && (_jsx("p", { className: "mb-1 rounded-md border border-[#96e59d]/15 bg-[#96e59d]/10 px-2 py-1 text-[11px] text-[#bdf1c2]/85", children: searchRepairNotice })), searchError && (_jsx("p", { className: "rounded-md border border-red-400/15 bg-red-400/10 px-2 py-1.5 text-[11px] text-red-200/80", children: searchError })), !searchError && searchResults.length > 0 && (_jsx("div", { className: "space-y-1", children: searchResults.slice(0, 12).map((result) => {
2797
- const canAttach = !!activeAttachTargetConversationId
2798
- && !!result.scope.conversationId
2799
- && result.scope.conversationId !== activeAttachTargetConversationId;
2800
- const canCopyReference = result.actions.includes('copy-reference');
2801
- const canOpenInEditor = result.actions.includes('open-in-editor') && !!result.sourceRef?.filePath;
2802
- const canOpenTrace = result.actions.includes('open-trace') && !!result.sourceRef?.runtimeEventId;
2803
- const canSummarize = result.actions.includes('summarize');
2804
- return (_jsxs("div", { role: "button", tabIndex: 0, onClick: () => openSearchResult(result), onKeyDown: (event) => {
2805
- if (event.key !== 'Enter' && event.key !== ' ')
2806
- return;
2807
- event.preventDefault();
2808
- openSearchResult(result);
2809
- }, className: "group/search w-full rounded-lg border border-white/[0.05] bg-white/[0.025] px-2 py-2 text-left transition-colors hover:border-white/[0.12] hover:bg-white/[0.06]", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("p", { className: "min-w-0 truncate text-[12px] font-medium text-[color:var(--xeno-ink-secondary)]", children: result.title || result.type }), _jsxs("div", { className: "flex flex-shrink-0 items-center gap-1", children: [canCopyReference && (_jsx("button", { type: "button", onClick: (event) => { void copySearchReference(event, result); }, onKeyDown: (event) => {
2810
- if (event.key !== 'Enter' && event.key !== ' ')
2811
- return;
2812
- event.preventDefault();
2813
- void copySearchReference(event, result);
2814
- }, 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: "Copy" })), canOpenInEditor && (_jsx("button", { type: "button", onClick: (event) => { void openSearchResultInEditor(event, result); }, onKeyDown: (event) => {
2815
- if (event.key !== 'Enter' && event.key !== ' ')
2816
- return;
2817
- event.preventDefault();
2818
- void openSearchResultInEditor(event, result);
2819
- }, 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: "Open" })), canOpenTrace && (_jsx("button", { type: "button", onClick: (event) => openSearchResultTrace(event, result), onKeyDown: (event) => {
2820
- if (event.key !== 'Enter' && event.key !== ' ')
2821
- return;
2822
- event.preventDefault();
2823
- openSearchResultTrace(event, result);
2824
- }, 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: "Trace" })), canSummarize && (_jsx("button", { type: "button", onClick: (event) => { void summarizeSearchResult(event, result); }, onKeyDown: (event) => {
2825
- if (event.key !== 'Enter' && event.key !== ' ')
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
- next.add(conv.id);
2859
- return next;
2860
- });
2861
- }, className: "flex-shrink-0 w-4 h-4 ml-1 mr-1 rounded-[3px] border flex items-center justify-center transition-all duration-100", style: {
2862
- background: selectedConvIds.has(conv.id) ? 'rgba(255,255,255,0.85)' : 'rgba(0,0,0,0.35)',
2863
- borderColor: selectedConvIds.has(conv.id) ? 'rgba(255,255,255,0.85)' : 'rgba(255,255,255,0.2)',
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
- if (e.key === 'Escape')
2871
- setEditingConvId(null);
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
- }, onBlur: handleRename, className: "w-full rounded border border-white/[0.15] bg-black/40 px-2 py-1 text-[11px] text-[color:var(--xeno-ink-primary)] focus:outline-none", autoFocus: true }) })) : (_jsxs("button", { onClick: () => toggleWorkspace(workspace.id), onContextMenu: (e) => handleContextMenu(e, 'workspace', workspace.id), className: "group flex w-full items-center gap-2 rounded-md px-2 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(ChevronDownIcon, { className: `w-3 h-3 transition-transform ${workspace.isExpanded ? '' : '-rotate-90'}` }), _jsx("span", { className: "text-[11px] font-medium flex-1 text-left truncate", children: workspace.name }), workspace.directories.length > 0 && (_jsxs("span", { className: "text-[9px] text-[color:var(--xeno-ink-faint)]", children: [workspace.directories.length, " dirs"] }))] })), workspace.isExpanded && (_jsxs("div", { className: "ml-3 mt-1 space-y-0.5 border-l pl-2 xeno-border-subtle", children: [workspace.teams.map((team) => (_jsxs("div", { children: [isRenaming('team', team.id) ? (_jsx("div", { className: "px-1 py-0.5", children: _jsx("input", { type: "text", value: renameValue, onChange: (e) => setRenameValue(e.target.value), onKeyDown: (e) => {
2895
- if (e.key === 'Enter')
2896
- handleRename();
2897
- if (e.key === 'Escape') {
2898
- setRenamingItem(null);
2899
- setRenameValue('');
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
- }, onBlur: handleRename, className: "w-full rounded border border-white/[0.15] bg-black/40 px-2 py-1 text-[10px] text-[color:var(--xeno-ink-primary)] focus:outline-none", autoFocus: true }) })) : (_jsxs("button", { onClick: () => toggleTeam(workspace.id, team.id), onContextMenu: (e) => handleContextMenu(e, 'team', workspace.id, team.id), className: "group flex w-full items-center gap-2 rounded-md px-2 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(ChevronDownIcon, { className: `w-3 h-3 transition-transform ${team.isExpanded ? '' : '-rotate-90'}` }), _jsx("span", { className: "text-[11px] flex-1 text-left truncate", children: team.name })] })), team.isExpanded && (_jsxs("div", { className: "ml-3 mt-0.5 space-y-0.5 border-l pl-2 xeno-border-subtle", children: [sortedAgents(team.agents).map((agent, index) => {
2902
- const agentConversations = conversationsByAgent[agent.id] || [];
2903
- const teamHasMainAssistant = team.agents.some(a => a.isMainAssistant);
2904
- const showAsMainAssistant = teamHasMainAssistant ? !!agent.isMainAssistant : index === 0;
2905
- const activeRunCount = agentRunAvailability[agent.id] || 0;
2906
- return (_jsxs("div", { children: [isRenaming('agent', agent.id) ? (_jsx("div", { className: "px-1 py-0.5", children: _jsx("input", { type: "text", value: renameValue, onChange: (e) => setRenameValue(e.target.value), onKeyDown: (e) => {
2907
- if (e.key === 'Enter')
2908
- handleRename();
2909
- if (e.key === 'Escape') {
2910
- setRenamingItem(null);
2911
- setRenameValue('');
2912
- }
2913
- }, onBlur: handleRename, className: "w-full rounded border border-white/[0.15] bg-black/40 px-2 py-1 text-[10px] text-[color:var(--xeno-ink-primary)] focus:outline-none", autoFocus: true }) })) : (_jsx("div", { className: `rounded-md transition-colors ${selectedAgentId === agent.id && !selectedConversationId ? 'bg-white/[0.04]' : ''}`, children: _jsxs("button", { onClick: () => onSelectAgent(agent.id), onContextMenu: (e) => handleContextMenu(e, 'agent', workspace.id, team.id, agent.id), className: `w-full flex items-center gap-2 px-2 py-1.5 rounded-md transition-colors ${selectedAgentId === agent.id && !selectedConversationId
2914
- ? 'text-[color:var(--xeno-ink-primary)]'
2915
- : 'text-[color:var(--xeno-ink-muted)] hover:bg-white/[0.02] hover:text-[color:var(--xeno-ink-secondary)]'}`, children: [_jsx("span", { role: "button", tabIndex: 0, onClick: (e) => {
2916
- e.stopPropagation();
2917
- toggleAgent(workspace.id, team.id, agent.id);
2918
- }, onKeyDown: (e) => {
2919
- if (e.key === 'Enter' || e.key === ' ') {
2920
- e.preventDefault();
2921
- e.stopPropagation();
2922
- toggleAgent(workspace.id, team.id, agent.id);
2923
- }
2924
- }, className: "rounded p-0.5 -ml-0.5 transition-colors hover:bg-white/[0.06]", children: _jsx(ChevronDownIcon, { className: `w-3 h-3 transition-transform ${agent.isExpanded ? '' : '-rotate-90'}` }) }), _jsx("span", { className: "text-[12px] truncate", children: agent.name }), _jsxs("span", { title: activeRunCount > 0 ? `${activeRunCount} active subagent run${activeRunCount === 1 ? '' : 's'}` : 'Idle', className: "inline-flex items-center gap-1", children: [_jsx("span", { className: `h-1.5 w-1.5 rounded-[2px] ${activeRunCount > 0 ? 'bg-[#8ad7ff] animate-pulse' : 'bg-white/14'}` }), activeRunCount > 0 && (_jsx("span", { className: "text-[8px] tabular-nums text-[#8ad7ff]/80", children: activeRunCount }))] }), showAsMainAssistant && (_jsx("span", { className: "rounded bg-white/[0.08] px-1 py-0.5 text-[8px] uppercase tracking-wide text-[color:var(--xeno-ink-faint)]", children: "Main" })), _jsx("span", { className: "ml-auto text-[9px] text-[color:var(--xeno-ink-faint)]", children: "+" })] }) })), agent.isExpanded && agentConversations.length > 0 && (_jsx("div", { className: "ml-4 mt-0.5 space-y-0.5 border-l pl-2 xeno-border-subtle", children: agentConversations.map((conv) => {
2925
- const isDeleting = deletingConvIds.has(conv.id);
2926
- return (isRenaming('conversation', conv.id) ? (_jsx("div", { className: "px-1 py-0.5", children: _jsx("input", { type: "text", value: renameValue, onChange: (e) => setRenameValue(e.target.value), onKeyDown: (e) => {
2927
- if (e.key === 'Enter')
2928
- handleRename();
2929
- if (e.key === 'Escape') {
2930
- setRenamingItem(null);
2931
- setRenameValue('');
2932
- }
2933
- }, onBlur: handleRename, className: "w-full rounded border border-white/[0.15] bg-black/40 px-2 py-1 text-[9px] text-[color:var(--xeno-ink-primary)] focus:outline-none", autoFocus: true }) }, conv.id)) : (_jsxs("div", { className: `relative overflow-hidden rounded-md transition-all duration-300 ease-[cubic-bezier(0.22,1,0.36,1)] ${isDeleting
2934
- ? 'max-h-0 opacity-0 -translate-y-2 scale-y-75 pointer-events-none'
2935
- : 'max-h-14 opacity-100 translate-y-0 scale-y-100'}`, style: { transformOrigin: 'top left' }, children: [_jsx("button", { onClick: () => { if (!isDeleting)
2936
- onSelectConversation(agent.id, conv.id); }, onContextMenu: (e) => {
2937
- if (isDeleting)
2938
- return;
2939
- handleContextMenu(e, 'conversation', workspace.id, team.id, agent.id, conv.id);
2940
- }, className: `relative w-full text-left px-2 py-1.5 rounded-md transition-all duration-300 ${selectedAgentId === agent.id && selectedConversationId === conv.id
2941
- ? 'bg-white/[0.06] text-[color:var(--xeno-ink-secondary)]'
2942
- : 'text-[color:var(--xeno-ink-muted)] hover:bg-white/[0.02] hover:text-[color:var(--xeno-ink-secondary)]'} ${isDeleting ? 'translate-x-3 scale-[0.985] saturate-50' : 'translate-x-0 scale-100'}`, children: _jsx("p", { className: "text-[12px] truncate", children: conv.title || 'New conversation' }) }), 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-3 top-1/2 h-1 w-1 rounded-[1px] bg-red-300/80", style: { animation: 'conversationDeleteParticle 320ms ease-out forwards', ['--dx']: '12px', ['--dy']: '-12px' } }), _jsx("span", { className: "absolute left-8 top-1/2 h-1 w-1 rounded-[1px] bg-orange-200/80", style: { animation: 'conversationDeleteParticle 320ms ease-out forwards', animationDelay: '22ms', ['--dx']: '22px', ['--dy']: '-4px' } }), _jsx("span", { className: "absolute left-14 top-1/2 h-1.5 w-1.5 rounded-[2px] bg-white/70", style: { animation: 'conversationDeleteParticle 320ms ease-out forwards', animationDelay: '36ms', ['--dx']: '18px', ['--dy']: '10px' } })] }))] }, conv.id)));
2943
- }) }))] }, agent.id));
2944
- }), addingAgentToTeam === team.id && (_jsx("div", { className: "px-1 py-1", children: _jsx("input", { type: "text", value: newAgentName, onChange: (e) => setNewAgentName(e.target.value), onKeyDown: (e) => {
2945
- if (e.key === 'Enter')
2946
- handleAddAgent(workspace.id, team.id);
2947
- if (e.key === 'Escape') {
2948
- setAddingAgentToTeam(null);
2949
- setNewAgentName('');
2950
- }
2951
- }, onBlur: () => { setAddingAgentToTeam(null); setNewAgentName(''); }, placeholder: "Agent name...", className: "w-full rounded border border-white/[0.1] bg-black/40 px-2 py-1 text-[10px] text-[color:var(--xeno-ink-primary)] placeholder:text-[color:var(--xeno-ink-faint)] focus:outline-none focus:border-white/[0.2]", autoFocus: true }) })), addingAgentToTeam !== team.id && (_jsxs("button", { onClick: () => setAddingAgentToTeam(team.id), className: "flex w-full items-center gap-1.5 rounded-md px-2 py-1 text-[color:var(--xeno-ink-faint)] transition-colors hover:bg-white/[0.03] hover:text-[color:var(--xeno-ink-muted)]", children: [_jsx(PlusIcon, {}), _jsx("span", { className: "text-[9px]", children: "Add agent" })] }))] }))] }, team.id))), addingTeamToWorkspace === workspace.id ? (_jsx("div", { className: "px-1 py-1", children: _jsx("input", { type: "text", value: newTeamName, onChange: (e) => setNewTeamName(e.target.value), onKeyDown: (e) => {
2952
- if (e.key === 'Enter')
2953
- handleAddTeam(workspace.id);
2954
- if (e.key === 'Escape') {
2955
- setAddingTeamToWorkspace(null);
2956
- setNewTeamName('');
2957
- }
2958
- }, onBlur: () => { setAddingTeamToWorkspace(null); setNewTeamName(''); }, placeholder: "Team name...", className: "w-full rounded border border-white/[0.1] bg-black/40 px-2 py-1 text-[10px] text-[color:var(--xeno-ink-primary)] placeholder:text-[color:var(--xeno-ink-faint)] focus:outline-none focus:border-white/[0.2]", autoFocus: true }) })) : (_jsxs("button", { onClick: () => setAddingTeamToWorkspace(workspace.id), className: "flex w-full items-center gap-1.5 rounded-md px-2 py-1 text-[color:var(--xeno-ink-faint)] transition-colors hover:bg-white/[0.03] hover:text-[color:var(--xeno-ink-muted)]", children: [_jsx(PlusIcon, {}), _jsx("span", { className: "text-[9px]", children: "Add team" })] }))] }))] }, workspace.id))), isAddingWorkspace ? (_jsx("div", { className: "px-1 py-1", children: _jsx("input", { type: "text", value: newWorkspaceName, onChange: (e) => setNewWorkspaceName(e.target.value), onKeyDown: (e) => {
2959
- if (e.key === 'Enter')
2960
- handleAddWorkspace();
2961
- if (e.key === 'Escape') {
2962
- setIsAddingWorkspace(false);
2963
- setNewWorkspaceName('');
2964
- }
2965
- }, onBlur: () => { setIsAddingWorkspace(false); setNewWorkspaceName(''); }, placeholder: "Workspace name...", className: "w-full rounded border border-white/[0.1] bg-black/40 px-2 py-1.5 text-[11px] text-[color:var(--xeno-ink-primary)] placeholder:text-[color:var(--xeno-ink-faint)] focus:outline-none focus:border-white/[0.2]", autoFocus: true }) })) : (_jsxs("button", { onClick: () => setIsAddingWorkspace(true), className: "flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-[color:var(--xeno-ink-faint)] transition-colors hover:bg-white/[0.04] hover:text-[color:var(--xeno-ink-muted)]", children: [_jsx(PlusIcon, {}), _jsx("span", { className: "text-[11px]", children: "Add workspace" })] }))] })] })] }), _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-[200]", onClick: () => setInboxMenuPos(null), onContextMenu: (e) => {
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-[201] w-[156px] rounded-[4px] border py-1 xeno-border-subtle xeno-elevated-shell", style: { left: Math.min(inboxMenuPos.x, window.innerWidth - 166), top: Math.min(inboxMenuPos.y, window.innerHeight - 92) }, children: [_jsxs("button", { onClick: handleInboxSelectAll, className: "flex h-7 w-full items-center gap-2 px-3 text-left text-[11px] text-[color:var(--xeno-ink-muted)] transition-colors duration-75 hover:bg-white/[0.06] hover:text-[color:var(--xeno-ink-secondary)]", children: [_jsxs("svg", { className: "w-3.5 h-3.5 flex-shrink-0", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", strokeWidth: 1.5, children: [_jsx("rect", { x: "3", y: "3", width: "18", height: "18", rx: "4" }), _jsx("path", { d: "M8 12l2.5 2.5L16 9" })] }), areAllVisibleInboxConversationsSelected ? 'Unselect all' : 'Select all'] }), _jsxs("button", { onClick: handleInboxSearchStart, className: "flex h-7 w-full items-center gap-2 px-3 text-left text-[11px] text-[color:var(--xeno-ink-muted)] transition-colors duration-75 hover:bg-white/[0.06] hover:text-[color:var(--xeno-ink-secondary)]", children: [_jsxs("svg", { className: "w-3.5 h-3.5 flex-shrink-0", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", strokeWidth: 1.5, children: [_jsx("circle", { cx: "11", cy: "11", r: "7" }), _jsx("path", { d: "m20 20-3.5-3.5" })] }), "Search"] })] })] }), document.body), convMenuId && createPortal(_jsxs(_Fragment, { children: [_jsx("div", { className: "fixed inset-0 z-[200]", onClick: () => { setConvMenuId(null); setHoveredConvId(null); }, onContextMenu: (e) => { e.preventDefault(); setConvMenuId(null); setHoveredConvId(null); } }), _jsxs("div", { className: "fixed z-[201] w-[140px] rounded-[4px] border py-1 xeno-border-subtle xeno-elevated-shell", style: { left: Math.min(convMenuPos.x, window.innerWidth - 150), top: Math.min(convMenuPos.y, window.innerHeight - 80) }, children: [_jsxs("button", { onClick: () => {
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: "flex h-7 w-full items-center gap-2 px-3 text-left text-[11px] text-[color:var(--xeno-ink-muted)] transition-colors duration-75 hover:bg-white/[0.06] hover:text-[color:var(--xeno-ink-secondary)]", children: [_jsxs("svg", { className: "w-3.5 h-3.5 flex-shrink-0", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", strokeWidth: 1.5, children: [_jsx("path", { d: "M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7" }), _jsx("path", { d: "M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z" })] }), "Rename"] }), _jsxs("button", { onClick: () => {
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: "flex h-7 w-full items-center gap-2 px-3 text-left text-[11px] text-[color:var(--xeno-ink-muted)] transition-colors duration-75 hover:bg-white/[0.06] hover:text-[color:var(--xeno-ink-secondary)]", children: [_jsxs("svg", { className: "w-3.5 h-3.5 flex-shrink-0", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", strokeWidth: 1.5, children: [_jsx("rect", { x: "3", y: "3", width: "18", height: "18", rx: "4" }), _jsx("polyline", { points: "20 6 9 17 4 12" })] }), "Select"] }), _jsx("div", { className: "mx-2 my-0.5 h-px bg-[var(--xeno-border-subtle)]" }), _jsxs("button", { onClick: () => {
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 text-left px-3 h-7 flex items-center gap-2 text-[11px] text-red-400/50 hover:text-red-400 hover:bg-white/[0.06] transition-colors duration-75", children: [_jsx("svg", { className: "w-3.5 h-3.5 flex-shrink-0", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", strokeWidth: 1.5, children: _jsx("path", { d: "M3 6h18M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2" }) }), "Delete"] })] })] }), document.body)] }));
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.allowedDirectories || [];
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 (allowedDirectories.length === 0) {
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
- const result = await getAgentPlatformBridge().workspace.runCommand({
3031
- command: trimmed,
3032
- cwd: allowedDirectories[0],
3033
- allowedDirs: allowedDirectories
3034
- });
3035
- setIsRunning(false);
3036
- const blocks = [];
3037
- blocks.push(`$ ${trimmed}`);
3038
- if (result.cwd)
3039
- blocks.push(`cwd: ${result.cwd}`);
3040
- if (result.stdout?.trim())
3041
- blocks.push(result.stdout.trim());
3042
- if (result.stderr?.trim())
3043
- blocks.push(`[stderr]\n${result.stderr.trim()}`);
3044
- if (result.error)
3045
- blocks.push(`[error] ${result.error}`);
3046
- blocks.push(`exit: ${result.exitCode ?? 'n/a'}`);
3047
- setTerminalOutput(blocks.join('\n\n'));
3048
- };
3049
- 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" }), 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 directories are allowed for this team. Configure Team Settings first." })) : (_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" })] })] }));
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 centerPaneMode = useAgentIdeStore(s => s.mode);
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 || createConversation(MAIN_ASSISTANT_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
- const message = result.error || 'unknown host error';
4575
- console.error(`[agent-interface] Unable to attach SDK session ${sessionId}: ${message}`);
4576
- appendMessage(conversationId, {
4577
- role: 'assistant',
4578
- content: `Unable to resume SDK session ${sessionId}: ${message}`,
4579
- error: message,
4580
- hideToolbar: true,
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 : 'unknown host error';
4599
- console.error(`[agent-interface] Unable to attach SDK session ${sessionId}: ${message}`);
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
- const current = activeSessionTabId
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, activeSessionTabId, createConversation, initialLaunchMode, initialWorkspaceRoot, updateConversation]);
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 && !getAgentPlatformBridge()?.subagents?.updateRun) {
6224
- setSubagentError('Subagent run bridge is not available. Restart Hub.');
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
- if (run.childRequestId && getAgentPlatformBridge()?.agent?.cancel) {
6231
- await getAgentPlatformBridge().agent.cancel(run.childRequestId);
6232
- }
6233
- const result = getAgentPlatformBridge().subagents.cancelRun
6234
- ? await getAgentPlatformBridge().subagents.cancelRun({
6235
- id: run.id,
6236
- reason: 'Cancelled from the Agent workbench.',
6237
- requestedBy: policyCaller.agentId,
6238
- requestedFrom: 'parent',
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
- const result = await getAgentPlatformBridge().workspace.readFile({
6319
- path: entry.path,
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((prev) => [...prev, openedTab]);
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
- setPendingEditorPath((current) => (current === entry.path ? null : current));
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
- }, [activeConversationId, codeWorkbenchRootDirectory]);
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
- setEngineeringLoading(false);
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 handleEngineeringReviewPatchSelection = useCallback(async (request) => {
6625
- if (!codeWorkbenchRootDirectory || !getAgentPlatformBridge()?.engineering?.reviewPatchSelection) {
6626
- setEngineeringError('Selective patch review bridge is not available.');
6627
- return;
6628
- }
6629
- setEngineeringLoading(true);
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 applyItem = (value) => {
6633
- const item = toPatchReviewItem(value);
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
- const result = await getAgentPlatformBridge().engineering.reviewPatchSelection({
6674
- ...engineeringRequestBase,
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
- applyItem(result.item);
6684
- setTransientEditorStatus(`${request.action === 'accept' ? 'Accepted' : 'Rejected'} ${result.selectedHunkIds.length} hunk${result.selectedHunkIds.length === 1 ? '' : 's'}.`, 2600);
6685
- void handleEngineeringRefresh();
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
- finally {
6688
- setEngineeringLoading(false);
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 = useCallback(async (checkpointId) => {
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 result = await getAgentPlatformBridge().workspace.readFile({
7160
- path,
7161
- allowedDirs: activeConversationAllowedDirectories,
7162
- });
7163
- return result?.success && result.path
7164
- ? { path: result.path, content: result.content || '' }
7165
- : null;
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
- const byPath = new Map(refreshed.flatMap((entry) => entry ? [[entry.path, entry.content]] : []));
7168
- if (byPath.size === 0)
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 content = byPath.get(tab.file.path);
7174
- if (content === undefined)
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
- setCodeWorkbenchLoading(false);
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
- setCodeWorkbenchLoading(false);
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
- setCodeWorkbenchLoading(false);
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
- setOpenEditorTabs((prev) => {
7834
- const target = prev.find((tab) => tab.id === tabId);
7835
- if (target?.type === 'file' && target.file.isDirty) {
7836
- const shouldDiscard = window.confirm(`Discard unsaved changes in ${target.file.name}?`);
7837
- if (!shouldDiscard)
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
- const next = prev.filter((tab) => tab.id !== tabId);
7841
- setActiveEditorTabId((current) => {
7842
- if (current !== tabId)
7843
- return current;
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
- if (next.length === 0) {
7847
- setCenterPaneMode('agent');
7848
- }
7849
- return next;
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
- setTransientEditorStatus(`Saving ${file.name}...`, 1200);
7859
- const result = await getAgentPlatformBridge().workspace.writeFile({
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
- setOpenEditorTabs((prev) => prev.map((entry) => (entry.type === 'file' && entry.file.path === path
7869
- ? {
7870
- ...entry,
7871
- file: {
7872
- ...entry.file,
7873
- savedContent: entry.file.content,
7874
- isDirty: false,
7875
- lastSavedAt: Date.now(),
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
- : entry)));
7879
- setTransientEditorStatus(`Saved ${file.name}`, 2000);
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 handleAgentDeployed = (data) => {
8080
- const agentId = generateId();
8081
- // Resolve display names for identity
8082
- const resolvedWsName = data.workspace === 'new'
8083
- ? (data.workspaceName || 'New Workspace')
8084
- : (workspaces.find(w => w.id === data.workspace)?.name || 'Workspace');
8085
- const resolvedTmName = data.team === 'new'
8086
- ? (data.teamName || 'New Team')
8087
- : (workspaces.flatMap(w => w.teams).find(t => t.id === data.team)?.name || 'Team');
8088
- const resolvedTemplateName = data.template === 'custom' ? 'Custom' : (data.template || 'Custom')
8089
- .split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');
8090
- setWorkspaces(prev => {
8091
- let updated = [...prev];
8092
- // Resolve or create workspace
8093
- let wsId = data.workspace;
8094
- if (wsId === 'new') {
8095
- wsId = generateId();
8096
- updated.push({
8097
- id: wsId,
8098
- name: data.workspaceName || 'New Workspace',
8099
- directories: [],
8100
- apps: [],
8101
- teams: [],
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
- createdAt: Date.now(),
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
- teams: [...w.teams, {
8114
- id: tmId,
8115
- name: data.teamName || 'New Team',
8116
- allowedDirectories: [],
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
- const targetTeam = updated
8125
- .find(w => w.id === wsId)
8126
- ?.teams.find(t => t.id === tmId);
8127
- const resolvedTeamDirs = targetTeam?.allowedDirectories || [];
8128
- const resolvedTeamApps = targetTeam?.allowedApps || [];
8129
- // Add agent to team
8130
- const agent = {
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?.allowedDirectories || [], currentAppIds: currentAppIds, teamAppIds: teamForSettings?.allowedApps || [], teamAgentPolicy: teamForSettings?.teamAgentPolicy, teamAgents: (teamForSettings?.agents || []).map((agent, index) => ({
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: selectedAgent.allowedDirectories, approvalRules: selectedAgent.approvalRules || [], onAddApprovalRule: (rule) => {
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: [_jsx("main", { className: "flex-1 min-w-0 flex flex-col overflow-hidden", children: centerPaneMode === 'split'
8327
- ? (_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
8328
- ? 'bg-white/[0.075] text-white/72'
8329
- : '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 })) }) })] })] }))
8330
- : centerPaneMode === 'editor'
8331
- ? (_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 })) }))
8332
- : 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, { tab: workbenchPanelTab,
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