diff --git a/src/core/vscode-workspace.ts b/src/core/vscode-workspace.ts index a68098d..2571afe 100644 --- a/src/core/vscode-workspace.ts +++ b/src/core/vscode-workspace.ts @@ -32,6 +32,21 @@ const DEFAULT_SETTINGS: Record = { */ export type PathPlaceholderMap = Map; +function normalizeWorkspacePath(path: string): string { + return path.replace(/\\/g, '/'); +} + +function resolveFolderAbsolutePath(workspacePath: string, folderPath: string): string { + return (isAbsolute(folderPath) + ? folderPath + : resolve(workspacePath, folderPath) + ).replace(/\\/g, '/'); +} + +function resolveFolderDisplayPath(folderPath: string): string { + return normalizeWorkspacePath(folderPath); +} + /** * Build a placeholder map from repositories using path as the lookup key. * @@ -127,8 +142,8 @@ export function generateVscodeWorkspace( // 1. Repository folders (from workspace.yaml) for (const repo of repositories) { - const absolutePath = resolve(workspacePath, repo.path).replace(/\\/g, '/'); - const entry: WorkspaceFolder = { path: absolutePath }; + const absolutePath = resolveFolderAbsolutePath(workspacePath, repo.path); + const entry: WorkspaceFolder = { path: resolveFolderDisplayPath(repo.path) }; if (repo.name) entry.name = repo.name; folders.push(entry); seenPaths.add(absolutePath); @@ -138,11 +153,9 @@ export function generateVscodeWorkspace( if (resolvedTemplate && Array.isArray(resolvedTemplate.folders)) { for (const folder of resolvedTemplate.folders as WorkspaceFolder[]) { const rawPath = folder.path as string; - const normalizedPath = (typeof rawPath === 'string' && !isAbsolute(rawPath) - ? resolve(workspacePath, rawPath) - : rawPath).replace(/\\/g, '/'); + const normalizedPath = resolveFolderAbsolutePath(workspacePath, rawPath); if (!seenPaths.has(normalizedPath)) { - const entry: WorkspaceFolder = { path: normalizedPath }; + const entry: WorkspaceFolder = { path: resolveFolderDisplayPath(rawPath) }; if (folder.name) entry.name = folder.name; folders.push(entry); seenPaths.add(normalizedPath); diff --git a/tests/e2e/vscode-workspace-reconcile.test.ts b/tests/e2e/vscode-workspace-reconcile.test.ts index d260204..5ffcce2 100644 --- a/tests/e2e/vscode-workspace-reconcile.test.ts +++ b/tests/e2e/vscode-workspace-reconcile.test.ts @@ -19,7 +19,7 @@ describe('vscode workspace folder reconciliation e2e', () => { }); test('removes repo from workspace.yaml when folder removed from .code-workspace', async () => { - const repoBPath = resolve(testDir, '../repoB').replace(/\\/g, '/'); + const repoBPath = '../repoB'; writeFileSync( join(testDir, '.allagents', 'workspace.yaml'), diff --git a/tests/e2e/vscode-workspace-setup.test.ts b/tests/e2e/vscode-workspace-setup.test.ts index f6f4fc6..1aa53d8 100644 --- a/tests/e2e/vscode-workspace-setup.test.ts +++ b/tests/e2e/vscode-workspace-setup.test.ts @@ -35,6 +35,7 @@ clients: const content = JSON.parse(readFileSync(expectedPath, 'utf-8')); expect(content.folders).toHaveLength(2); expect(content.folders[0].path).toBe('.'); + expect(content.folders[1].path).toBe('../myrepo'); expect(content.settings).toEqual({ 'chat.agent.maxRequests': 999 }); }); diff --git a/tests/unit/cli/workspace-setup.test.ts b/tests/unit/cli/workspace-setup.test.ts index 75e508b..67d5491 100644 --- a/tests/unit/cli/workspace-setup.test.ts +++ b/tests/unit/cli/workspace-setup.test.ts @@ -39,11 +39,10 @@ clients: const folders = result.folders as Array<{ path: string }>; expect(folders[0].path).toBe('.'); - // On Windows paths are absolute (C:\...) not starting with / - // Just verify they are not relative (don't start with . or ..) - for (const folder of folders.slice(1)) { - expect(folder.path.startsWith('.')).toBe(false); - } + expect(folders.slice(1)).toEqual([ + { path: '../backend' }, + { path: '../frontend' }, + ]); expect(result.settings).toEqual({ 'chat.agent.maxRequests': 999 }); }); diff --git a/tests/unit/core/vscode-workspace.test.ts b/tests/unit/core/vscode-workspace.test.ts index c6e83fd..9bf4c9c 100644 --- a/tests/unit/core/vscode-workspace.test.ts +++ b/tests/unit/core/vscode-workspace.test.ts @@ -14,7 +14,7 @@ import { const testBase = join(tmpdir(), 'allagents-test'); describe('generateVscodeWorkspace', () => { - test('generates workspace with repository folders resolved to absolute paths', () => { + test('generates workspace with repository folders preserving relative paths from workspace.yaml', () => { const workspacePath = join(testBase, 'myapp'); const result = generateVscodeWorkspace({ workspacePath, @@ -27,8 +27,8 @@ describe('generateVscodeWorkspace', () => { expect(result.folders).toEqual([ { path: '.' }, - { path: resolve(workspacePath, '../backend').replace(/\\/g, '/') }, - { path: resolve(workspacePath, '../frontend').replace(/\\/g, '/') }, + { path: '../backend' }, + { path: '../frontend' }, ]); }); @@ -45,8 +45,8 @@ describe('generateVscodeWorkspace', () => { expect(result.folders).toEqual([ { path: '.' }, - { path: resolve(workspacePath, '../backend').replace(/\\/g, '/'), name: 'API Server' }, - { path: resolve(workspacePath, '../frontend').replace(/\\/g, '/') }, + { path: '../backend', name: 'API Server' }, + { path: '../frontend' }, ]); }); @@ -85,8 +85,8 @@ describe('generateVscodeWorkspace', () => { // extra is not a duplicate, so it's kept with its name expect(result.folders).toEqual([ { path: '.' }, - { path: resolve(workspacePath, '../backend').replace(/\\/g, '/') }, - { path: sharedPath }, + { path: '../backend' }, + { path: '../shared' }, { path: extraPath, name: 'ExtraLib' }, ]); });