agent-ecosystem/test/main/services/extensions/SkillsMutationService.test.ts
iliya d53999ba45 feat: add Radix UI Alert Dialog component and enhance SkillImportService
- Integrated the @radix-ui/react-alert-dialog package for improved alert dialog functionality.
- Updated SkillImportService to include a new inspectSourceDir method for enhanced file inspection and warning generation during skill imports.
- Refactored existing methods to streamline file reading and directory walking processes, improving overall performance and error handling.
- Added new SkillPlanService to manage skill upsert plans, enhancing the skills mutation workflow.
- Updated UI components to support new features and improve user experience in the skills management interface.
2026-03-12 11:53:40 +02:00

107 lines
3.8 KiB
TypeScript

import * as fs from 'node:fs/promises';
import * as os from 'node:os';
import * as path from 'node:path';
import { afterEach, describe, expect, it } from 'vitest';
import { SkillPlanService } from '@main/services/extensions/skills/SkillPlanService';
import { SkillScaffoldService } from '@main/services/extensions/skills/SkillScaffoldService';
import { SkillsCatalogService } from '@main/services/extensions/skills/SkillsCatalogService';
import { SkillsMutationService } from '@main/services/extensions/skills/SkillsMutationService';
import type { ResolvedSkillRoot } from '@main/services/extensions/skills/SkillRootsResolver';
function createResolver(rootPath: string) {
return {
resolve(projectPath?: string): ResolvedSkillRoot[] {
return [
{
scope: 'project',
rootKind: 'claude',
projectRoot: projectPath ?? rootPath,
rootPath,
},
];
},
};
}
describe('SkillsMutationService', () => {
const createdDirs: string[] = [];
afterEach(async () => {
await Promise.all(createdDirs.splice(0).map((dir) => fs.rm(dir, { recursive: true, force: true })));
});
it('applies the reviewed plan and deletes obsolete managed files', async () => {
const projectRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'skill-mutation-'));
createdDirs.push(projectRoot);
const skillsRoot = path.join(projectRoot, '.claude', 'skills');
const skillDir = path.join(skillsRoot, 'demo');
await fs.mkdir(path.join(skillDir, 'scripts'), { recursive: true });
await fs.writeFile(path.join(skillDir, 'SKILL.md'), '# old', 'utf8');
await fs.writeFile(path.join(skillDir, 'scripts', 'README.md'), 'old script', 'utf8');
const resolver = createResolver(skillsRoot);
const mutationService = new SkillsMutationService(
resolver as any,
new SkillsCatalogService(resolver as any),
new SkillScaffoldService(resolver as any),
undefined,
new SkillPlanService()
);
const request = {
scope: 'project' as const,
rootKind: 'claude' as const,
projectPath: projectRoot,
folderName: 'demo',
existingSkillId: skillDir,
files: [{ relativePath: 'SKILL.md', content: '# updated' }],
};
const preview = await mutationService.previewUpsert(request);
await mutationService.applyUpsert({ ...request, reviewPlanId: preview.planId });
await expect(fs.readFile(path.join(skillDir, 'SKILL.md'), 'utf8')).resolves.toBe('# updated');
await expect(fs.stat(path.join(skillDir, 'scripts', 'README.md'))).rejects.toMatchObject({
code: 'ENOENT',
});
});
it('rejects apply when the reviewed plan is stale', async () => {
const projectRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'skill-mutation-'));
createdDirs.push(projectRoot);
const skillsRoot = path.join(projectRoot, '.claude', 'skills');
const skillDir = path.join(skillsRoot, 'demo');
await fs.mkdir(skillDir, { recursive: true });
await fs.writeFile(path.join(skillDir, 'SKILL.md'), '# old', 'utf8');
const resolver = createResolver(skillsRoot);
const mutationService = new SkillsMutationService(
resolver as any,
new SkillsCatalogService(resolver as any),
new SkillScaffoldService(resolver as any),
undefined,
new SkillPlanService()
);
const request = {
scope: 'project' as const,
rootKind: 'claude' as const,
projectPath: projectRoot,
folderName: 'demo',
existingSkillId: skillDir,
files: [{ relativePath: 'SKILL.md', content: '# updated' }],
};
const preview = await mutationService.previewUpsert(request);
await fs.writeFile(path.join(skillDir, 'SKILL.md'), '# changed after review', 'utf8');
await expect(
mutationService.applyUpsert({ ...request, reviewPlanId: preview.planId })
).rejects.toThrow('changed after review');
});
});