mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-05-04 14:40:45 +00:00
feat: support skills in .agents directory and other provider config directories
This commit is contained in:
parent
f3b56f5a31
commit
ef772feea2
2 changed files with 51 additions and 22 deletions
|
|
@ -504,17 +504,35 @@ Skill 3 content`);
|
|||
});
|
||||
});
|
||||
|
||||
describe('getSkillsBaseDir', () => {
|
||||
it('should return project-level base dir', () => {
|
||||
const baseDir = manager.getSkillsBaseDir('project');
|
||||
describe('getSkillsBaseDirs', () => {
|
||||
it('should return all project-level base dirs', () => {
|
||||
const baseDirs = manager.getSkillsBaseDirs('project');
|
||||
|
||||
expect(baseDir).toBe(path.join('/test/project', '.qwen', 'skills'));
|
||||
expect(baseDirs).toHaveLength(5);
|
||||
expect(baseDirs).toContain(path.join('/test/project', '.qwen', 'skills'));
|
||||
expect(baseDirs).toContain(
|
||||
path.join('/test/project', '.agent', 'skills'),
|
||||
);
|
||||
expect(baseDirs).toContain(
|
||||
path.join('/test/project', '.cursor', 'skills'),
|
||||
);
|
||||
expect(baseDirs).toContain(
|
||||
path.join('/test/project', '.codex', 'skills'),
|
||||
);
|
||||
expect(baseDirs).toContain(
|
||||
path.join('/test/project', '.claude', 'skills'),
|
||||
);
|
||||
});
|
||||
|
||||
it('should return user-level base dir', () => {
|
||||
const baseDir = manager.getSkillsBaseDir('user');
|
||||
it('should return all user-level base dirs', () => {
|
||||
const baseDirs = manager.getSkillsBaseDirs('user');
|
||||
|
||||
expect(baseDir).toBe(path.join('/home/user', '.qwen', 'skills'));
|
||||
expect(baseDirs).toHaveLength(5);
|
||||
expect(baseDirs).toContain(path.join('/home/user', '.qwen', 'skills'));
|
||||
expect(baseDirs).toContain(path.join('/home/user', '.agent', 'skills'));
|
||||
expect(baseDirs).toContain(path.join('/home/user', '.cursor', 'skills'));
|
||||
expect(baseDirs).toContain(path.join('/home/user', '.codex', 'skills'));
|
||||
expect(baseDirs).toContain(path.join('/home/user', '.claude', 'skills'));
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,13 @@ import { normalizeContent } from '../utils/textUtils.js';
|
|||
const debugLogger = createDebugLogger('SKILL_MANAGER');
|
||||
|
||||
const QWEN_CONFIG_DIR = '.qwen';
|
||||
const PROVIDER_CONFIG_DIRS = [
|
||||
'.qwen',
|
||||
'.agent',
|
||||
'.cursor',
|
||||
'.codex',
|
||||
'.claude',
|
||||
];
|
||||
const SKILLS_CONFIG_DIR = 'skills';
|
||||
const SKILL_MANIFEST_FILE = 'SKILL.md';
|
||||
|
||||
|
|
@ -412,19 +419,18 @@ export class SkillManager {
|
|||
* Gets the base directory for skills at a specific level.
|
||||
*
|
||||
* @param level - Storage level
|
||||
* @returns Absolute directory path
|
||||
* @returns Absolute directory paths
|
||||
*/
|
||||
getSkillsBaseDir(level: SkillLevel): string {
|
||||
const baseDir =
|
||||
getSkillsBaseDirs(level: SkillLevel): string[] {
|
||||
const baseDirs =
|
||||
level === 'project'
|
||||
? path.join(
|
||||
this.config.getProjectRoot(),
|
||||
QWEN_CONFIG_DIR,
|
||||
SKILLS_CONFIG_DIR,
|
||||
? PROVIDER_CONFIG_DIRS.map((v) =>
|
||||
path.join(this.config.getProjectRoot(), v, SKILLS_CONFIG_DIR),
|
||||
)
|
||||
: path.join(os.homedir(), QWEN_CONFIG_DIR, SKILLS_CONFIG_DIR);
|
||||
|
||||
return baseDir;
|
||||
: PROVIDER_CONFIG_DIRS.map((v) =>
|
||||
path.join(os.homedir(), v, SKILLS_CONFIG_DIR),
|
||||
);
|
||||
return baseDirs;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -461,9 +467,13 @@ export class SkillManager {
|
|||
return skills;
|
||||
}
|
||||
|
||||
const baseDir = this.getSkillsBaseDir(level);
|
||||
debugLogger.debug(`Loading ${level} level skills from: ${baseDir}`);
|
||||
const skills = await this.loadSkillsFromDir(baseDir, level);
|
||||
const baseDirs = this.getSkillsBaseDirs(level);
|
||||
const skills: SkillConfig[] = [];
|
||||
for (let i = 0; i < baseDirs.length; i++) {
|
||||
debugLogger.debug(`Loading ${level} level skills from: ${baseDirs[i]}`);
|
||||
const skillsFromDir = await this.loadSkillsFromDir(baseDirs[i], level);
|
||||
skills.push(...skillsFromDir);
|
||||
}
|
||||
debugLogger.debug(`Loaded ${skills.length} ${level} level skills`);
|
||||
return skills;
|
||||
}
|
||||
|
|
@ -583,7 +593,8 @@ export class SkillManager {
|
|||
private updateWatchersFromCache(): void {
|
||||
const watchTargets = new Set<string>(
|
||||
(['project', 'user'] as const)
|
||||
.map((level) => this.getSkillsBaseDir(level))
|
||||
.map((level) => this.getSkillsBaseDirs(level))
|
||||
.reduce((acc, baseDirs) => acc.concat(baseDirs), [])
|
||||
.filter((baseDir) => fsSync.existsSync(baseDir)),
|
||||
);
|
||||
|
||||
|
|
@ -639,7 +650,7 @@ export class SkillManager {
|
|||
}
|
||||
|
||||
private async ensureUserSkillsDir(): Promise<void> {
|
||||
const baseDir = this.getSkillsBaseDir('user');
|
||||
const baseDir = path.join(os.homedir(), QWEN_CONFIG_DIR, SKILLS_CONFIG_DIR);
|
||||
try {
|
||||
await fs.mkdir(baseDir, { recursive: true });
|
||||
} catch (error) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue