94 lines · 3.4 KB · TypeScript
RawDownload
import * as fs from 'fs';import * as os from 'os';import * as path from 'path';import { afterEach, describe, expect, it } from 'vitest'; import { ProjectPathResolver } from '../../../../src/main/services/discovery/ProjectPathResolver'; function createSessionLine(cwd: string): string {  return JSON.stringify({    uuid: 'test-uuid',    type: 'user',    cwd,    message: { role: 'user', content: 'hello' },    timestamp: new Date().toISOString(),  });} describe('ProjectPathResolver', () => {  const tempDirs: string[] = [];   afterEach(async () => {    // Allow Windows file handles from readline/streams to be released    await new Promise((resolve) => setTimeout(resolve, 50));    for (const tempDir of tempDirs) {      try {        fs.rmSync(tempDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 });      } catch {        // Ignore cleanup failures to prevent cascading test errors on Windows      }    }    tempDirs.length = 0;  });   it('prefers absolute cwd hint', async () => {    const projectsDir = fs.mkdtempSync(path.join(os.tmpdir(), 'resolver-projects-'));    tempDirs.push(projectsDir);     const resolver = new ProjectPathResolver(projectsDir);    const resolved = await resolver.resolveProjectPath('-Users-test-proj', {      cwdHint: '/Users/test/proj',    });     expect(resolved).toBe('/Users/test/proj');  });   it('extracts cwd from session file when available', async () => {    const projectsDir = fs.mkdtempSync(path.join(os.tmpdir(), 'resolver-projects-'));    tempDirs.push(projectsDir);     const projectId = '-Users-test-my-repo';    const projectDir = path.join(projectsDir, projectId);    fs.mkdirSync(projectDir, { recursive: true });     const sessionPath = path.join(projectDir, 'session-1.jsonl');    fs.writeFileSync(sessionPath, `${createSessionLine('/Users/test/my-repo')}\n`, 'utf8');     const resolver = new ProjectPathResolver(projectsDir);    const resolved = await resolver.resolveProjectPath(projectId);     expect(resolved).toBe('/Users/test/my-repo');  });   it('falls back to decoded project ID when no cwd is available', async () => {    const projectsDir = fs.mkdtempSync(path.join(os.tmpdir(), 'resolver-projects-'));    tempDirs.push(projectsDir);     const resolver = new ProjectPathResolver(projectsDir);    const resolved = await resolver.resolveProjectPath('-C:-Users-test-my-repo');     expect(resolved).toBe('C:/Users/test/my/repo');  });   it('invalidates cached paths by project', async () => {    const projectsDir = fs.mkdtempSync(path.join(os.tmpdir(), 'resolver-projects-'));    tempDirs.push(projectsDir);     const projectId = '-Users-test-my-repo';    const projectDir = path.join(projectsDir, projectId);    fs.mkdirSync(projectDir, { recursive: true });     const sessionPath = path.join(projectDir, 'session-1.jsonl');    fs.writeFileSync(sessionPath, `${createSessionLine('/Users/test/my-repo-v1')}\n`, 'utf8');     const resolver = new ProjectPathResolver(projectsDir);    const firstResolved = await resolver.resolveProjectPath(projectId);    expect(firstResolved).toBe('/Users/test/my-repo-v1');     fs.writeFileSync(sessionPath, `${createSessionLine('/Users/test/my-repo-v2')}\n`, 'utf8');    resolver.invalidateProject(projectId);     const secondResolved = await resolver.resolveProjectPath(projectId);    expect(secondResolved).toBe('/Users/test/my-repo-v2');  });});