@@ -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