mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-05-04 22:51:08 +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', () => {
|
describe('getSkillsBaseDirs', () => {
|
||||||
it('should return project-level base dir', () => {
|
it('should return all project-level base dirs', () => {
|
||||||
const baseDir = manager.getSkillsBaseDir('project');
|
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', () => {
|
it('should return all user-level base dirs', () => {
|
||||||
const baseDir = manager.getSkillsBaseDir('user');
|
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 debugLogger = createDebugLogger('SKILL_MANAGER');
|
||||||
|
|
||||||
const QWEN_CONFIG_DIR = '.qwen';
|
const QWEN_CONFIG_DIR = '.qwen';
|
||||||
|
const PROVIDER_CONFIG_DIRS = [
|
||||||
|
'.qwen',
|
||||||
|
'.agent',
|
||||||
|
'.cursor',
|
||||||
|
'.codex',
|
||||||
|
'.claude',
|
||||||
|
];
|
||||||
const SKILLS_CONFIG_DIR = 'skills';
|
const SKILLS_CONFIG_DIR = 'skills';
|
||||||
const SKILL_MANIFEST_FILE = 'SKILL.md';
|
const SKILL_MANIFEST_FILE = 'SKILL.md';
|
||||||
|
|
||||||
|
|
@ -412,19 +419,18 @@ export class SkillManager {
|
||||||
* Gets the base directory for skills at a specific level.
|
* Gets the base directory for skills at a specific level.
|
||||||
*
|
*
|
||||||
* @param level - Storage level
|
* @param level - Storage level
|
||||||
* @returns Absolute directory path
|
* @returns Absolute directory paths
|
||||||
*/
|
*/
|
||||||
getSkillsBaseDir(level: SkillLevel): string {
|
getSkillsBaseDirs(level: SkillLevel): string[] {
|
||||||
const baseDir =
|
const baseDirs =
|
||||||
level === 'project'
|
level === 'project'
|
||||||
? path.join(
|
? PROVIDER_CONFIG_DIRS.map((v) =>
|
||||||
this.config.getProjectRoot(),
|
path.join(this.config.getProjectRoot(), v, SKILLS_CONFIG_DIR),
|
||||||
QWEN_CONFIG_DIR,
|
|
||||||
SKILLS_CONFIG_DIR,
|
|
||||||
)
|
)
|
||||||
: path.join(os.homedir(), QWEN_CONFIG_DIR, SKILLS_CONFIG_DIR);
|
: PROVIDER_CONFIG_DIRS.map((v) =>
|
||||||
|
path.join(os.homedir(), v, SKILLS_CONFIG_DIR),
|
||||||
return baseDir;
|
);
|
||||||
|
return baseDirs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -461,9 +467,13 @@ export class SkillManager {
|
||||||
return skills;
|
return skills;
|
||||||
}
|
}
|
||||||
|
|
||||||
const baseDir = this.getSkillsBaseDir(level);
|
const baseDirs = this.getSkillsBaseDirs(level);
|
||||||
debugLogger.debug(`Loading ${level} level skills from: ${baseDir}`);
|
const skills: SkillConfig[] = [];
|
||||||
const skills = await this.loadSkillsFromDir(baseDir, level);
|
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`);
|
debugLogger.debug(`Loaded ${skills.length} ${level} level skills`);
|
||||||
return skills;
|
return skills;
|
||||||
}
|
}
|
||||||
|
|
@ -583,7 +593,8 @@ export class SkillManager {
|
||||||
private updateWatchersFromCache(): void {
|
private updateWatchersFromCache(): void {
|
||||||
const watchTargets = new Set<string>(
|
const watchTargets = new Set<string>(
|
||||||
(['project', 'user'] as const)
|
(['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)),
|
.filter((baseDir) => fsSync.existsSync(baseDir)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -639,7 +650,7 @@ export class SkillManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async ensureUserSkillsDir(): Promise<void> {
|
private async ensureUserSkillsDir(): Promise<void> {
|
||||||
const baseDir = this.getSkillsBaseDir('user');
|
const baseDir = path.join(os.homedir(), QWEN_CONFIG_DIR, SKILLS_CONFIG_DIR);
|
||||||
try {
|
try {
|
||||||
await fs.mkdir(baseDir, { recursive: true });
|
await fs.mkdir(baseDir, { recursive: true });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue