Skip to content

Commit 9e636e6

Browse files
author
yangbiao@cmcm.com
committed
Merge branch 'fix/dvcode-cli' into 'master'
fix:修复skill的MarketplaceLoader 的加载逻辑 See merge request ai_native/DeepVCode/DeepVcodeClient!335
2 parents 6c24bae + 4a516bc commit 9e636e6

1 file changed

Lines changed: 94 additions & 65 deletions

File tree

packages/core/src/skills/loaders/marketplace-loader.ts

Lines changed: 94 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -194,75 +194,59 @@ export class MarketplaceLoader implements IPluginLoader {
194194
return path.isAbsolute(targetPath) ? targetPath : path.join(pluginDir, targetPath);
195195
};
196196

197-
// Commands
197+
// 🔧 新增:处理 marketplace.json 中的显式定义(ui-ux-pro-max 情景)
198+
if (pluginDef.skills && (Array.isArray(pluginDef.skills) || typeof pluginDef.skills === 'string')) {
199+
const skillItems = Array.isArray(pluginDef.skills) ? pluginDef.skills : [pluginDef.skills];
200+
for (const skillItem of skillItems) {
201+
const skillPath = typeof skillItem === 'string' ? skillItem : skillItem?.path;
202+
if (skillPath) {
203+
const fullPath = getFullPath(skillPath);
204+
const component = await this.componentParser.parse(fullPath, ComponentType.SKILL, id, marketplaceId, pluginDir);
205+
if (component) components.push(component);
206+
}
207+
}
208+
}
209+
198210
if (pluginDef.commands && (Array.isArray(pluginDef.commands) || typeof pluginDef.commands === 'string')) {
199211
const cmdItems = Array.isArray(pluginDef.commands) ? pluginDef.commands : [pluginDef.commands];
200212
for (const cmdItem of cmdItems) {
201-
// 支持字符串或对象格式:{ path: "commands/foo.md" }
202213
const cmdPath = typeof cmdItem === 'string' ? cmdItem : cmdItem?.path;
203-
if (!cmdPath || typeof cmdPath !== 'string') {
204-
console.warn(`Invalid command path in plugin ${id}:`, cmdItem);
205-
continue;
206-
}
207-
const fullPath = getFullPath(cmdPath);
208-
const component = await this.componentParser.parse(
209-
fullPath,
210-
ComponentType.COMMAND,
211-
id,
212-
marketplaceId,
213-
pluginDir
214-
);
215-
if (component) {
216-
components.push(component);
214+
if (cmdPath) {
215+
const fullPath = getFullPath(cmdPath);
216+
const component = await this.componentParser.parse(fullPath, ComponentType.COMMAND, id, marketplaceId, pluginDir);
217+
if (component) components.push(component);
217218
}
218219
}
219220
}
220221

221-
// Agents
222222
if (pluginDef.agents && (Array.isArray(pluginDef.agents) || typeof pluginDef.agents === 'string')) {
223223
const agentItems = Array.isArray(pluginDef.agents) ? pluginDef.agents : [pluginDef.agents];
224224
for (const agentItem of agentItems) {
225-
// 支持字符串或对象格式:{ path: "agents/foo.md" }
226225
const agentPath = typeof agentItem === 'string' ? agentItem : agentItem?.path;
227-
if (!agentPath || typeof agentPath !== 'string') {
228-
console.warn(`Invalid agent path in plugin ${id}:`, agentItem);
229-
continue;
230-
}
231-
const fullPath = getFullPath(agentPath);
232-
const component = await this.componentParser.parse(
233-
fullPath,
234-
ComponentType.AGENT,
235-
id,
236-
marketplaceId,
237-
pluginDir
238-
);
239-
if (component) {
240-
components.push(component);
226+
if (agentPath) {
227+
const fullPath = getFullPath(agentPath);
228+
const component = await this.componentParser.parse(fullPath, ComponentType.AGENT, id, marketplaceId, pluginDir);
229+
if (component) components.push(component);
241230
}
242231
}
243232
}
244233

245-
// Skills (如果显式定义了)
246-
if (pluginDef.skills && (Array.isArray(pluginDef.skills) || typeof pluginDef.skills === 'string')) {
247-
const skillItems = Array.isArray(pluginDef.skills) ? pluginDef.skills : [pluginDef.skills];
248-
for (const skillItem of skillItems) {
249-
// 支持字符串或对象格式:{ path: "skills/foo.md" }
250-
const skillPath = typeof skillItem === 'string' ? skillItem : skillItem?.path;
251-
if (!skillPath || typeof skillPath !== 'string') {
252-
console.warn(`Invalid skill path in plugin ${id}:`, skillItem);
253-
continue;
254-
}
255-
const fullPath = getFullPath(skillPath);
256-
const component = await this.componentParser.parse(
257-
fullPath,
258-
ComponentType.SKILL,
259-
id,
260-
marketplaceId,
261-
pluginDir
262-
);
263-
if (component) {
264-
components.push(component);
265-
}
234+
// 🔧 尝试加载 plugin.json 进行补充 (如果有的话)
235+
const pluginJsonPath = path.join(pluginDir, 'plugin.json');
236+
const claudePluginJsonPath = path.join(pluginDir, '.claude-plugin', 'plugin.json');
237+
let metadata: any = {};
238+
if (await fs.pathExists(pluginJsonPath)) {
239+
metadata = await fs.readJson(pluginJsonPath);
240+
} else if (await fs.pathExists(claudePluginJsonPath)) {
241+
metadata = await fs.readJson(claudePluginJsonPath);
242+
}
243+
244+
if (metadata.skills && !pluginDef.skills) {
245+
const skillPaths = Array.isArray(metadata.skills) ? metadata.skills : [metadata.skills];
246+
for (const sp of skillPaths) {
247+
const fullPath = getFullPath(sp);
248+
const component = await this.componentParser.parse(fullPath, ComponentType.SKILL, id, marketplaceId, pluginDir);
249+
if (component) components.push(component);
266250
}
267251
}
268252

@@ -389,22 +373,66 @@ export class MarketplaceLoader implements IPluginLoader {
389373

390374
// 2. 读取元数据 (plugin.json)
391375
let metadata: any = { name: pluginName, description: '', version: 'unknown' };
376+
const pluginJsonPath = path.join(pluginDir, 'plugin.json');
377+
const claudePluginJsonPath = path.join(pluginDir, '.claude-plugin', 'plugin.json');
378+
392379
if (structure.hasPluginJson) {
393-
metadata = await fs.readJson(path.join(pluginDir, 'plugin.json'));
394-
} else if (structure.hasClaudePluginDir) {
395-
metadata = await fs.readJson(path.join(pluginDir, '.claude-plugin', 'plugin.json'));
380+
metadata = await fs.readJson(pluginJsonPath);
381+
} else if (structure.hasClaudePluginDir && await fs.pathExists(claudePluginJsonPath)) {
382+
metadata = await fs.readJson(claudePluginJsonPath);
396383
}
397384

398385
// 3. 发现组件 (使用 ComponentParser)
399386
const components: UnifiedComponent[] = [];
400387

388+
// 优先处理显式定义的组件 (如果有 plugin.json)
389+
const getMetadataPath = (p: string) => path.isAbsolute(p) ? p : path.join(pluginDir, p);
390+
391+
if (metadata.skills && (Array.isArray(metadata.skills) || typeof metadata.skills === 'string')) {
392+
const skillPaths = Array.isArray(metadata.skills) ? metadata.skills : [metadata.skills];
393+
for (const sp of skillPaths) {
394+
const fullPath = getMetadataPath(sp);
395+
const component = await this.componentParser.parse(fullPath, ComponentType.SKILL, id, marketplaceId, pluginDir);
396+
if (component) components.push(component);
397+
}
398+
}
399+
400+
if (metadata.commands && (Array.isArray(metadata.commands) || typeof metadata.commands === 'string')) {
401+
const cmdPaths = Array.isArray(metadata.commands) ? metadata.commands : [metadata.commands];
402+
for (const cp of cmdPaths) {
403+
const fullPath = getMetadataPath(cp);
404+
const component = await this.componentParser.parse(fullPath, ComponentType.COMMAND, id, marketplaceId, pluginDir);
405+
if (component) components.push(component);
406+
}
407+
}
408+
409+
if (metadata.agents && (Array.isArray(metadata.agents) || typeof metadata.agents === 'string')) {
410+
const agentPaths = Array.isArray(metadata.agents) ? metadata.agents : [metadata.agents];
411+
for (const ap of agentPaths) {
412+
const fullPath = getMetadataPath(ap);
413+
const component = await this.componentParser.parse(fullPath, ComponentType.AGENT, id, marketplaceId, pluginDir);
414+
if (component) components.push(component);
415+
}
416+
}
417+
418+
// 自动发现组件(去重)
419+
const existingIds = new Set(components.map(c => c.id));
420+
const addComponent = (c: any) => {
421+
if (c && !existingIds.has(c.id)) {
422+
components.push(c);
423+
existingIds.add(c.id);
424+
}
425+
};
426+
401427
// Agents
402428
if (structure.directories.agents) {
403429
if (await fs.pathExists(path.join(pluginDir, 'agents'))) {
404-
components.push(...await this.scanComponents(pluginDir, 'agents', ComponentType.AGENT, id, marketplaceId));
430+
const found = await this.scanComponents(pluginDir, 'agents', ComponentType.AGENT, id, marketplaceId);
431+
found.forEach(addComponent);
405432
}
406433
if (await fs.pathExists(path.join(pluginDir, '.claude/agents'))) {
407-
components.push(...await this.scanComponents(pluginDir, '.claude/agents', ComponentType.AGENT, id, marketplaceId));
434+
const found = await this.scanComponents(pluginDir, '.claude/agents', ComponentType.AGENT, id, marketplaceId);
435+
found.forEach(addComponent);
408436
}
409437
}
410438

@@ -413,28 +441,29 @@ export class MarketplaceLoader implements IPluginLoader {
413441
const commandDirs = ['commands', '.claude/commands', '.cursor/commands', '.roo/commands'];
414442
for (const dir of commandDirs) {
415443
if (await fs.pathExists(path.join(pluginDir, dir))) {
416-
components.push(...await this.scanComponents(pluginDir, dir, ComponentType.COMMAND, id, marketplaceId));
444+
const found = await this.scanComponents(pluginDir, dir, ComponentType.COMMAND, id, marketplaceId);
445+
found.forEach(addComponent);
417446
}
418447
}
419448
}
420449

421450
// Skills
422451
if (structure.directories.skills) {
423452
if (await fs.pathExists(path.join(pluginDir, 'skills'))) {
424-
components.push(...await this.scanComponents(pluginDir, 'skills', ComponentType.SKILL, id, marketplaceId));
453+
const found = await this.scanComponents(pluginDir, 'skills', ComponentType.SKILL, id, marketplaceId);
454+
found.forEach(addComponent);
425455
}
426456
if (await fs.pathExists(path.join(pluginDir, '.claude/skills'))) {
427-
components.push(...await this.scanComponents(pluginDir, '.claude/skills', ComponentType.SKILL, id, marketplaceId));
457+
const found = await this.scanComponents(pluginDir, '.claude/skills', ComponentType.SKILL, id, marketplaceId);
458+
found.forEach(addComponent);
428459
}
429460
} else {
430461
// 尝试扫描根目录下的 Skills (DeepV Code 扁平结构)
431-
// 这种结构常见于旧的 DeepV Code 插件,如 document-skills
462+
// 这种结构常见于旧性 DeepV Code 插件,如 document-skills
432463
const skills = await this.scanComponents(
433464
pluginDir, '.', ComponentType.SKILL, id, marketplaceId
434465
);
435-
if (skills.length > 0) {
436-
components.push(...skills);
437-
}
466+
skills.forEach(addComponent);
438467
}
439468

440469
// 4. 构建 UnifiedPlugin

0 commit comments

Comments
 (0)