mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-02 08:15:56 +01:00
Merge pull request #301257 from microsoft/connor4312/301252
chat: support root-level SKILL.md as fallback for plugins
This commit is contained in:
@@ -510,7 +510,7 @@ export abstract class AbstractAgentPluginDiscovery extends Disposable implements
|
||||
};
|
||||
|
||||
const commands = observeComponent('commands', d => this._readMarkdownComponents(d));
|
||||
const skills = observeComponent('skills', d => this._readSkills(d));
|
||||
const skills = observeComponent('skills', d => this._readSkills(uri, d));
|
||||
const agents = observeComponent('agents', d => this._readMarkdownComponents(d));
|
||||
const instructions = observeComponent('rules', d => this._readRules(d));
|
||||
const hooks = observeComponent(
|
||||
@@ -699,7 +699,7 @@ export abstract class AbstractAgentPluginDiscovery extends Disposable implements
|
||||
}
|
||||
}
|
||||
|
||||
private async _readSkills(dirs: readonly URI[]): Promise<readonly IAgentPluginSkill[]> {
|
||||
private async _readSkills(pluginRoot: URI, dirs: readonly URI[]): Promise<readonly IAgentPluginSkill[]> {
|
||||
const seen = new Set<string>();
|
||||
const skills: IAgentPluginSkill[] = [];
|
||||
|
||||
@@ -738,6 +738,14 @@ export abstract class AbstractAgentPluginDiscovery extends Disposable implements
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: support single-skill plugins with SKILL.md at the plugin root
|
||||
if (skills.length === 0) {
|
||||
const rootSkillMd = URI.joinPath(pluginRoot, 'SKILL.md');
|
||||
if (await this._pathExists(rootSkillMd)) {
|
||||
addSkill(basename(pluginRoot), rootSkillMd);
|
||||
}
|
||||
}
|
||||
|
||||
skills.sort((a, b) => a.name.localeCompare(b.name));
|
||||
return skills;
|
||||
}
|
||||
|
||||
@@ -242,6 +242,45 @@ suite('AgentPlugin format detection', () => {
|
||||
assert.deepStrictEqual(skillNames, ['deploy', 'lint']);
|
||||
}));
|
||||
|
||||
test('reads root-level SKILL.md as a fallback skill', () => runWithFakedTimers({ useFakeTimers: true }, async () => {
|
||||
const uri = pluginUri('/plugins/root-skill');
|
||||
await writeFile('/plugins/root-skill/.plugin/plugin.json', JSON.stringify({ name: 'root-skill' }));
|
||||
await writeFile('/plugins/root-skill/SKILL.md', '# Visual Explainer');
|
||||
|
||||
const discovery = createDiscovery();
|
||||
discovery.start(mockEnablementModel);
|
||||
await discovery.setSourcesAndRefresh([uri]);
|
||||
|
||||
const plugins = discovery.plugins.get();
|
||||
assert.strictEqual(plugins.length, 1);
|
||||
|
||||
await waitForState(plugins[0].skills, s => s.length > 0);
|
||||
assert.deepStrictEqual(
|
||||
plugins[0].skills.get().map(s => s.name),
|
||||
['root-skill'],
|
||||
);
|
||||
}));
|
||||
|
||||
test('root-level SKILL.md is ignored when skills/ has content', () => runWithFakedTimers({ useFakeTimers: true }, async () => {
|
||||
const uri = pluginUri('/plugins/root-skill-ignored');
|
||||
await writeFile('/plugins/root-skill-ignored/.plugin/plugin.json', JSON.stringify({ name: 'root-skill-ignored' }));
|
||||
await writeFile('/plugins/root-skill-ignored/SKILL.md', '# Root skill');
|
||||
await writeFile('/plugins/root-skill-ignored/skills/real/SKILL.md', '# Real skill');
|
||||
|
||||
const discovery = createDiscovery();
|
||||
discovery.start(mockEnablementModel);
|
||||
await discovery.setSourcesAndRefresh([uri]);
|
||||
|
||||
const plugins = discovery.plugins.get();
|
||||
assert.strictEqual(plugins.length, 1);
|
||||
|
||||
await waitForState(plugins[0].skills, s => s.length > 0);
|
||||
assert.deepStrictEqual(
|
||||
plugins[0].skills.get().map(s => s.name),
|
||||
['real'],
|
||||
);
|
||||
}));
|
||||
|
||||
test('reads agents from agents/ directory', () => runWithFakedTimers({ useFakeTimers: true }, async () => {
|
||||
const uri = pluginUri('/plugins/agents-plugin');
|
||||
await writeFile('/plugins/agents-plugin/.plugin/plugin.json', JSON.stringify({ name: 'agents-plugin' }));
|
||||
|
||||
Reference in New Issue
Block a user