feat: Enhance session management and tool settings for Claude and Cursor

- Updated ClaudeStatus component to accept a provider prop for better flexibility.
- Added CursorLogo component for displaying cursor sessions.
- Modified MainContent to conditionally display session names based on provider.
- Updated Shell component to show session names and summaries based on provider.
- Enhanced Sidebar to handle both Claude and Cursor sessions, including sorting and displaying session icons.
- Introduced new ToolsSettings functionality to manage tools for both Claude and Cursor, including allowed and disallowed commands.
- Implemented fetching and saving of Cursor-specific settings and commands.
- Added UI elements for managing Cursor tools, including permission settings and command lists.
This commit is contained in:
simos
2025-08-12 10:49:04 +03:00
parent ece52adac2
commit cf6f0e7321
15 changed files with 3146 additions and 94 deletions

View File

@@ -31,7 +31,7 @@ import { ThemeProvider } from './contexts/ThemeContext';
import { AuthProvider } from './contexts/AuthContext';
import ProtectedRoute from './components/ProtectedRoute';
import { useVersionCheck } from './hooks/useVersionCheck';
import { api } from './utils/api';
import { api, authenticatedFetch } from './utils/api';
// Main App component with routing
@@ -192,6 +192,27 @@ function AppContent() {
const response = await api.projects();
const data = await response.json();
// Always fetch Cursor sessions for each project so we can combine views
for (let project of data) {
try {
const url = `/api/cursor/sessions?projectPath=${encodeURIComponent(project.fullPath || project.path)}`;
const cursorResponse = await authenticatedFetch(url);
if (cursorResponse.ok) {
const cursorData = await cursorResponse.json();
if (cursorData.success && cursorData.sessions) {
project.cursorSessions = cursorData.sessions;
} else {
project.cursorSessions = [];
}
} else {
project.cursorSessions = [];
}
} catch (error) {
console.error(`Error fetching Cursor sessions for project ${project.name}:`, error);
project.cursorSessions = [];
}
}
// Optimize to preserve object references when data hasn't changed
setProjects(prevProjects => {
// If no previous projects, just set the new data
@@ -210,7 +231,8 @@ function AppContent() {
newProject.displayName !== prevProject.displayName ||
newProject.fullPath !== prevProject.fullPath ||
JSON.stringify(newProject.sessionMeta) !== JSON.stringify(prevProject.sessionMeta) ||
JSON.stringify(newProject.sessions) !== JSON.stringify(prevProject.sessions)
JSON.stringify(newProject.sessions) !== JSON.stringify(prevProject.sessions) ||
JSON.stringify(newProject.cursorSessions) !== JSON.stringify(prevProject.cursorSessions)
);
}) || data.length !== prevProjects.length;
@@ -236,16 +258,26 @@ function AppContent() {
const shouldSwitchTab = !selectedSession || selectedSession.id !== sessionId;
// Find the session across all projects
for (const project of projects) {
const session = project.sessions?.find(s => s.id === sessionId);
let session = project.sessions?.find(s => s.id === sessionId);
if (session) {
setSelectedProject(project);
setSelectedSession(session);
setSelectedSession({ ...session, __provider: 'claude' });
// Only switch to chat tab if we're loading a different session
if (shouldSwitchTab) {
setActiveTab('chat');
}
return;
}
// Also check Cursor sessions
const cSession = project.cursorSessions?.find(s => s.id === sessionId);
if (cSession) {
setSelectedProject(project);
setSelectedSession({ ...cSession, __provider: 'cursor' });
if (shouldSwitchTab) {
setActiveTab('chat');
}
return;
}
}
// If session not found, it might be a newly created session
@@ -270,6 +302,15 @@ function AppContent() {
if (activeTab !== 'git' && activeTab !== 'preview') {
setActiveTab('chat');
}
// For Cursor sessions, we need to set the session ID differently
// since they're persistent and not created by Claude
const provider = localStorage.getItem('selected-provider') || 'claude';
if (provider === 'cursor') {
// Cursor sessions have persistent IDs
sessionStorage.setItem('cursorSessionId', session.id);
}
if (isMobile) {
setSidebarOpen(false);
}