Skip to content

Commit 4ec6c57

Browse files
authored
Merge pull request #36 from bazokhan/fix/windows-cursor-cwd-slug
fix: resolve Windows Cursor cwd slug path conversion
2 parents 081d549 + debac39 commit 4ec6c57

2 files changed

Lines changed: 65 additions & 3 deletions

File tree

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import * as fs from 'fs';
2+
import * as os from 'os';
3+
import * as path from 'path';
4+
import { describe, expect, it } from 'vitest';
5+
import { cwdFromSlug } from '../utils/slug.js';
6+
7+
describe('cwdFromSlug', () => {
8+
const itWindows = process.platform === 'win32' ? it : it.skip;
9+
10+
itWindows('resolves Windows drive-letter slugs using existing path', () => {
11+
const base = fs.mkdtempSync(path.join(os.tmpdir(), 'continues-slug-'));
12+
const target = path.join(base, 'project-alpha');
13+
fs.mkdirSync(target, { recursive: true });
14+
15+
const normalized = target.replace(/\\/g, '/');
16+
const slug = normalized.replace(':', '').replace(/[/.]/g, '-');
17+
const resolved = cwdFromSlug(slug).replace(/\\/g, '/');
18+
19+
expect(resolved.toLowerCase()).toBe(normalized.toLowerCase());
20+
21+
fs.rmSync(base, { recursive: true, force: true });
22+
});
23+
24+
itWindows('falls back to drive-letter path format when no candidate exists', () => {
25+
expect(cwdFromSlug('D-Workspace-project-alpha')).toBe('D:/Workspace/project/alpha');
26+
});
27+
28+
it('falls back to Unix path format for drive-letter-like slugs on non-Windows', () => {
29+
if (process.platform === 'win32') return;
30+
expect(cwdFromSlug('D-Workspace-project-alpha')).toBe('/D/Workspace/project/alpha');
31+
});
32+
33+
it('keeps Unix fallback behavior for non-drive slugs', () => {
34+
expect(cwdFromSlug('Users-alice-my-project')).toBe('/Users/alice/my/project');
35+
});
36+
});

src/utils/slug.ts

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as fs from 'fs';
2+
import { IS_WINDOWS } from './platform.js';
23

34
/**
45
* Derive cwd from a slug directory name using recursive backtracking.
@@ -11,13 +12,30 @@ import * as fs from 'fs';
1112
export function cwdFromSlug(slug: string): string {
1213
const parts = slug.split('-');
1314
let best: string | null = null;
15+
const isDriveSlug = parts.length > 0 && /^[A-Za-z]$/.test(parts[0] || '');
16+
17+
function candidatePaths(segments: string[]): string[] {
18+
const unixPath = '/' + segments.join('/');
19+
if (segments.length > 0 && /^[A-Za-z]$/.test(segments[0] || '')) {
20+
const drive = segments[0].toUpperCase();
21+
const rest = segments.slice(1).join('/');
22+
const winPath = rest ? `${drive}:/${rest}` : `${drive}:/`;
23+
// On Windows prefer drive-letter paths; on Unix keep legacy order.
24+
return IS_WINDOWS ? [winPath, unixPath] : [unixPath, winPath];
25+
}
26+
return [unixPath];
27+
}
1428

1529
function resolve(idx: number, segments: string[]): void {
1630
if (best) return; // already found a match
1731

1832
if (idx >= parts.length) {
19-
const p = '/' + segments.join('/');
20-
if (fs.existsSync(p)) best = p;
33+
for (const p of candidatePaths(segments)) {
34+
if (fs.existsSync(p)) {
35+
best = p;
36+
break;
37+
}
38+
}
2139
return;
2240
}
2341

@@ -41,7 +59,15 @@ export function cwdFromSlug(slug: string): string {
4159
}
4260

4361
resolve(0, []);
44-
return best || '/' + slug.replace(/-/g, '/');
62+
if (best) return best;
63+
64+
if (isDriveSlug && IS_WINDOWS) {
65+
const drive = parts[0].toUpperCase();
66+
const rest = parts.slice(1).join('/');
67+
return rest ? `${drive}:/${rest}` : `${drive}:/`;
68+
}
69+
70+
return '/' + slug.replace(/-/g, '/');
4571
}
4672

4773
/**

0 commit comments

Comments
 (0)