mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-06-03 19:15:37 +08:00
fix: cursor projects fetching
This commit is contained in:
@@ -150,7 +150,6 @@ async function spawnCursor(command, options = {}, ws) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const response = JSON.parse(line);
|
const response = JSON.parse(line);
|
||||||
console.log('Parsed JSON response:', response);
|
|
||||||
|
|
||||||
// Handle different message types
|
// Handle different message types
|
||||||
switch (response.type) {
|
switch (response.type) {
|
||||||
@@ -159,7 +158,6 @@ async function spawnCursor(command, options = {}, ws) {
|
|||||||
// Capture session ID
|
// Capture session ID
|
||||||
if (response.session_id && !capturedSessionId) {
|
if (response.session_id && !capturedSessionId) {
|
||||||
capturedSessionId = response.session_id;
|
capturedSessionId = response.session_id;
|
||||||
console.log('Captured session ID:', capturedSessionId);
|
|
||||||
|
|
||||||
// Update process key with captured session ID
|
// Update process key with captured session ID
|
||||||
if (processKey !== capturedSessionId) {
|
if (processKey !== capturedSessionId) {
|
||||||
@@ -197,7 +195,6 @@ async function spawnCursor(command, options = {}, ws) {
|
|||||||
|
|
||||||
case 'result': {
|
case 'result': {
|
||||||
// Session complete — send stream end + lifecycle complete with result payload
|
// Session complete — send stream end + lifecycle complete with result payload
|
||||||
console.log('Cursor session result:', response);
|
|
||||||
const resultText = typeof response.result === 'string' ? response.result : '';
|
const resultText = typeof response.result === 'string' ? response.result : '';
|
||||||
ws.send(createNormalizedMessage({
|
ws.send(createNormalizedMessage({
|
||||||
kind: 'complete',
|
kind: 'complete',
|
||||||
@@ -213,8 +210,6 @@ async function spawnCursor(command, options = {}, ws) {
|
|||||||
// Unknown message types — ignore.
|
// Unknown message types — ignore.
|
||||||
}
|
}
|
||||||
} catch (parseError) {
|
} catch (parseError) {
|
||||||
console.log('Non-JSON response:', line);
|
|
||||||
|
|
||||||
if (shouldSuppressForTrustRetry(line)) {
|
if (shouldSuppressForTrustRetry(line)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -228,7 +223,6 @@ async function spawnCursor(command, options = {}, ws) {
|
|||||||
// Handle stdout (streaming JSON responses)
|
// Handle stdout (streaming JSON responses)
|
||||||
cursorProcess.stdout.on('data', (data) => {
|
cursorProcess.stdout.on('data', (data) => {
|
||||||
const rawOutput = data.toString();
|
const rawOutput = data.toString();
|
||||||
console.log('Cursor CLI stdout:', rawOutput);
|
|
||||||
|
|
||||||
// Stream chunks can split JSON objects across packets; keep trailing partial line.
|
// Stream chunks can split JSON objects across packets; keep trailing partial line.
|
||||||
stdoutLineBuffer += rawOutput;
|
stdoutLineBuffer += rawOutput;
|
||||||
@@ -254,8 +248,6 @@ async function spawnCursor(command, options = {}, ws) {
|
|||||||
|
|
||||||
// Handle process completion
|
// Handle process completion
|
||||||
cursorProcess.on('close', async (code) => {
|
cursorProcess.on('close', async (code) => {
|
||||||
console.log(`Cursor CLI process exited with code ${code}`);
|
|
||||||
|
|
||||||
const finalSessionId = capturedSessionId || sessionId || processKey;
|
const finalSessionId = capturedSessionId || sessionId || processKey;
|
||||||
activeCursorProcesses.delete(finalSessionId);
|
activeCursorProcesses.delete(finalSessionId);
|
||||||
|
|
||||||
|
|||||||
@@ -45,44 +45,28 @@ export class CursorSessionSynchronizer implements IProviderSessionSynchronizer {
|
|||||||
*/
|
*/
|
||||||
async synchronize(since?: Date): Promise<number> {
|
async synchronize(since?: Date): Promise<number> {
|
||||||
const projectsDir = path.join(this.cursorHome, 'projects');
|
const projectsDir = path.join(this.cursorHome, 'projects');
|
||||||
const projectEntries = await listDirectoryEntriesSafe(projectsDir);
|
|
||||||
const seenProjectPaths = new Set<string>();
|
|
||||||
|
|
||||||
let processed = 0;
|
let processed = 0;
|
||||||
for (const entry of projectEntries) {
|
|
||||||
if (!entry.isDirectory()) {
|
const files = await findFilesRecursivelyCreatedAfter(projectsDir, '.jsonl', since ?? null);
|
||||||
|
|
||||||
|
for (const filePath of files) {
|
||||||
|
const parsed = await this.processSessionFile(filePath);
|
||||||
|
if (!parsed) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const workerLogPath = path.join(projectsDir, entry.name, 'worker.log');
|
const timestamps = await readFileTimestamps(filePath);
|
||||||
const projectPath = await this.extractProjectPathFromWorkerLog(workerLogPath);
|
sessionsDb.createSession(
|
||||||
if (!projectPath || seenProjectPaths.has(projectPath)) {
|
parsed.sessionId,
|
||||||
continue;
|
this.provider,
|
||||||
}
|
parsed.projectPath,
|
||||||
|
parsed.sessionName,
|
||||||
seenProjectPaths.add(projectPath);
|
timestamps.createdAt,
|
||||||
const projectHash = this.md5(projectPath);
|
timestamps.updatedAt,
|
||||||
const chatsDir = path.join(this.cursorHome, 'chats', projectHash);
|
filePath
|
||||||
const files = await findFilesRecursivelyCreatedAfter(chatsDir, '.jsonl', since ?? null);
|
);
|
||||||
|
processed += 1;
|
||||||
for (const filePath of files) {
|
|
||||||
const parsed = await this.processSessionFile(filePath);
|
|
||||||
if (!parsed) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const timestamps = await readFileTimestamps(filePath);
|
|
||||||
sessionsDb.createSession(
|
|
||||||
parsed.sessionId,
|
|
||||||
this.provider,
|
|
||||||
parsed.projectPath,
|
|
||||||
parsed.sessionName,
|
|
||||||
timestamps.createdAt,
|
|
||||||
timestamps.updatedAt,
|
|
||||||
filePath
|
|
||||||
);
|
|
||||||
processed += 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return processed;
|
return processed;
|
||||||
@@ -113,13 +97,6 @@ export class CursorSessionSynchronizer implements IProviderSessionSynchronizer {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Produces the same project hash Cursor uses in chat directory names.
|
|
||||||
*/
|
|
||||||
private md5(input: string): string {
|
|
||||||
return crypto.createHash('md5').update(input).digest('hex');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts project path from Cursor worker.log.
|
* Extracts project path from Cursor worker.log.
|
||||||
*/
|
*/
|
||||||
@@ -149,7 +126,7 @@ export class CursorSessionSynchronizer implements IProviderSessionSynchronizer {
|
|||||||
*/
|
*/
|
||||||
private async processSessionFile(filePath: string): Promise<ParsedSession | null> {
|
private async processSessionFile(filePath: string): Promise<ParsedSession | null> {
|
||||||
const sessionId = path.basename(filePath, '.jsonl');
|
const sessionId = path.basename(filePath, '.jsonl');
|
||||||
const grandparentDir = path.dirname(path.dirname(filePath));
|
const grandparentDir = path.dirname(path.dirname(path.dirname(filePath)));
|
||||||
const workerLogPath = path.join(grandparentDir, 'worker.log');
|
const workerLogPath = path.join(grandparentDir, 'worker.log');
|
||||||
const projectPath = await this.extractProjectPathFromWorkerLog(workerLogPath);
|
const projectPath = await this.extractProjectPathFromWorkerLog(workerLogPath);
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ const PROVIDER_WATCH_PATHS: Array<{ provider: LLMProvider; rootPath: string }> =
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
provider: 'cursor',
|
provider: 'cursor',
|
||||||
rootPath: path.join(os.homedir(), '.cursor', 'chats'),
|
rootPath: path.join(os.homedir(), '.cursor', 'projects'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provider: 'codex',
|
provider: 'codex',
|
||||||
|
|||||||
Reference in New Issue
Block a user