diff --git a/src/utils/skill-metadata.ts b/src/utils/skill-metadata.ts index bf720b3..11164a7 100644 --- a/src/utils/skill-metadata.ts +++ b/src/utils/skill-metadata.ts @@ -1,6 +1,10 @@ import { existsSync, readFileSync, writeFileSync } from 'fs'; import { join } from 'path'; +function normalizePathSeparators(path: string): string { + return path.replace(/\\/g, '/'); +} + export const SKILL_METADATA_FILE = '.openskills.json'; export type SkillSourceType = 'git' | 'github' | 'local'; @@ -30,6 +34,8 @@ export function writeSkillMetadata(skillDir: string, metadata: SkillSourceMetada const metadataPath = join(skillDir, SKILL_METADATA_FILE); const payload = { ...metadata, + subpath: metadata.subpath ? normalizePathSeparators(metadata.subpath) : undefined, + localPath: metadata.localPath ? normalizePathSeparators(metadata.localPath) : undefined, installedAt: metadata.installedAt || new Date().toISOString(), }; writeFileSync(metadataPath, JSON.stringify(payload, null, 2)); diff --git a/tests/utils/skill-metadata.test.ts b/tests/utils/skill-metadata.test.ts index 57cf036..be965b4 100644 --- a/tests/utils/skill-metadata.test.ts +++ b/tests/utils/skill-metadata.test.ts @@ -38,4 +38,33 @@ describe('skill-metadata', () => { writeFileSync(join(tempDir, SKILL_METADATA_FILE), '{not-json'); expect(readSkillMetadata(tempDir)).toBeNull(); }); + + it('normalizes Windows backslashes to forward slashes in subpath', () => { + const payload = { + source: 'owner/repo', + sourceType: 'git' as const, + repoUrl: 'https://github.com/owner/repo', + subpath: 'skills\\nested\\skill', + installedAt: '2026-01-01T00:00:00.000Z', + }; + + writeSkillMetadata(tempDir, payload); + const read = readSkillMetadata(tempDir); + + expect(read?.subpath).toBe('skills/nested/skill'); + }); + + it('normalizes Windows backslashes to forward slashes in localPath', () => { + const payload = { + source: '/path/to/skill', + sourceType: 'local' as const, + localPath: 'C:\\Users\\test\\skills\\my-skill', + installedAt: '2026-01-01T00:00:00.000Z', + }; + + writeSkillMetadata(tempDir, payload); + const read = readSkillMetadata(tempDir); + + expect(read?.localPath).toBe('C:/Users/test/skills/my-skill'); + }); });