mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-05-02 13:40:46 +00:00
Merge branch 'main' into feature/support-agents-directory-skills
This commit is contained in:
commit
6f362a89ae
304 changed files with 17148 additions and 9229 deletions
|
|
@ -621,6 +621,118 @@ Skill 3 content`);
|
|||
expect(baseDirs).toContain(path.join('/home/user', '.codex', 'skills'));
|
||||
expect(baseDirs).toContain(path.join('/home/user', '.claude', 'skills'));
|
||||
});
|
||||
|
||||
it('should return bundled-level base dir', () => {
|
||||
const baseDir = manager.getSkillsBaseDir('bundled');
|
||||
|
||||
expect(baseDir).toMatch(/skills[/\\]bundled$/);
|
||||
});
|
||||
|
||||
it('should throw for extension level', () => {
|
||||
expect(() => manager.getSkillsBaseDir('extension')).toThrow(
|
||||
'Extension skills do not have a base directory',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('bundled skills', () => {
|
||||
const bundledDirSegment = path.join('skills', 'bundled');
|
||||
const projectDirSegment = path.join('.qwen', 'skills');
|
||||
const userDirSegment = path.join('.qwen', 'skills');
|
||||
const projectPrefix = path.join('/test/project');
|
||||
const userPrefix = path.join('/home/user');
|
||||
|
||||
const reviewDirEntry = {
|
||||
name: 'review',
|
||||
isDirectory: () => true,
|
||||
isFile: () => false,
|
||||
isSymbolicLink: () => false,
|
||||
};
|
||||
|
||||
const emptyDir = [] as unknown as Awaited<ReturnType<typeof fs.readdir>>;
|
||||
|
||||
function mockReaddirForLevels(levels: Set<string>) {
|
||||
vi.mocked(fs.readdir).mockImplementation((dirPath) => {
|
||||
const pathStr = String(dirPath);
|
||||
const isBundled =
|
||||
pathStr.endsWith(bundledDirSegment) && !pathStr.includes('.qwen');
|
||||
const isProject =
|
||||
pathStr.includes(projectDirSegment) &&
|
||||
pathStr.startsWith(projectPrefix);
|
||||
const isUser =
|
||||
pathStr.includes(userDirSegment) && pathStr.startsWith(userPrefix);
|
||||
|
||||
if (
|
||||
(levels.has('bundled') && isBundled) ||
|
||||
(levels.has('project') && isProject) ||
|
||||
(levels.has('user') && isUser)
|
||||
) {
|
||||
return Promise.resolve([reviewDirEntry] as unknown as Awaited<
|
||||
ReturnType<typeof fs.readdir>
|
||||
>);
|
||||
}
|
||||
return Promise.resolve(emptyDir);
|
||||
});
|
||||
}
|
||||
|
||||
function setupReviewSkillMocks() {
|
||||
vi.mocked(fs.access).mockResolvedValue(undefined);
|
||||
vi.mocked(fs.readFile).mockResolvedValue(`---
|
||||
name: review
|
||||
description: Review code changes
|
||||
---
|
||||
Review content`);
|
||||
|
||||
mockParseYaml.mockReturnValue({
|
||||
name: 'review',
|
||||
description: 'Review code changes',
|
||||
});
|
||||
}
|
||||
|
||||
it('should load bundled skills in listSkills', async () => {
|
||||
mockReaddirForLevels(new Set(['bundled']));
|
||||
setupReviewSkillMocks();
|
||||
|
||||
const skills = await manager.listSkills({ force: true });
|
||||
|
||||
expect(skills.some((s) => s.name === 'review')).toBe(true);
|
||||
const reviewSkill = skills.find((s) => s.name === 'review');
|
||||
expect(reviewSkill!.level).toBe('bundled');
|
||||
});
|
||||
|
||||
it('should prioritize project-level over bundled skills with same name', async () => {
|
||||
mockReaddirForLevels(new Set(['project', 'bundled']));
|
||||
setupReviewSkillMocks();
|
||||
|
||||
const skills = await manager.listSkills({ force: true });
|
||||
|
||||
const reviewSkills = skills.filter((s) => s.name === 'review');
|
||||
expect(reviewSkills).toHaveLength(1);
|
||||
expect(reviewSkills[0].level).toBe('project');
|
||||
});
|
||||
|
||||
it('should prioritize user-level over bundled skills with same name', async () => {
|
||||
mockReaddirForLevels(new Set(['user', 'bundled']));
|
||||
setupReviewSkillMocks();
|
||||
|
||||
const skills = await manager.listSkills({ force: true });
|
||||
|
||||
const reviewSkills = skills.filter((s) => s.name === 'review');
|
||||
expect(reviewSkills).toHaveLength(1);
|
||||
expect(reviewSkills[0].level).toBe('user');
|
||||
});
|
||||
|
||||
it('should fall back to bundled level in loadSkill', async () => {
|
||||
// Project, user, extension all empty; bundled has the skill
|
||||
mockReaddirForLevels(new Set(['bundled']));
|
||||
setupReviewSkillMocks();
|
||||
|
||||
const skill = await manager.loadSkill('review');
|
||||
|
||||
expect(skill).toBeDefined();
|
||||
expect(skill!.name).toBe('review');
|
||||
expect(skill!.level).toBe('bundled');
|
||||
});
|
||||
});
|
||||
|
||||
describe('change listeners', () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue