diff --git a/.ua/backlog.json b/.ua/backlog.json index 131db37..3e8d141 100644 --- a/.ua/backlog.json +++ b/.ua/backlog.json @@ -1556,6 +1556,14 @@ "acceptance": "ua search <关键词> 按 id/标题/props 名/步骤匹配并排序输出,支持 --json;ua info 与 search 未命中时给出编辑距离 ≤3 的相近 id;usage 与 CLI 清单 steps、README、AGENTS 同步。", "notes": "", "status": "done" + }, + { + "id": "g150", + "title": "ua info 反查组件出现在哪些配方", + "motivation": "配方与组件是两套入口:查完 props 往往还要自己判断「这组件平时和谁一起用」,而 recipes.md 里已有答案却没接上。", + "acceptance": "ua info <组件id> 末尾列出包含该组件的配方 id 与标题(无命中不追加空行);--json 输出增加 recipes 字段;MCP get_component 组件级返回同步带 recipes。", + "notes": "", + "status": "open" } ] } diff --git a/packages/tools/cli/bin/ua.js b/packages/tools/cli/bin/ua.js index f6167d5..60f3377 100644 --- a/packages/tools/cli/bin/ua.js +++ b/packages/tools/cli/bin/ua.js @@ -146,6 +146,14 @@ function formatComponent(pkg, comp) { return lines.join('\n'); } +/*** 反查某组件出现在哪些配方里:查参数时顺带给出「它通常和谁一起用」的组合线索 ***/ +function recipesFor(compId) { + const re = new RegExp(`\\b${compId}\\b`); + return parseRecipes() + .filter((r) => re.test(`${r.code}\n${r.text}`)) + .map((r) => ({ id: r.id, title: r.title })); +} + /*** 编辑距离(截断版):只用来给拼错的名字找相近候选,超过 3 直接当无建议 ***/ function editDistance(a, b) { const prev = Array.from({ length: b.length + 1 }, (_, j) => j); @@ -219,7 +227,10 @@ function cmdInfo(name, args = []) { console.error(`not found: ${name}(包名与组件 id 都没命中)${near.length ? `;相近:${near.join(' / ')}` : ''}`); return process.exit(1); } - console.log(asJson ? JSON.stringify({ package: hit.pkg.name, ...hit.comp }, null, 2) : formatComponent(hit.pkg, hit.comp)); + if (asJson) return console.log(JSON.stringify({ package: hit.pkg.name, ...hit.comp, recipes: recipesFor(hit.comp.id) }, null, 2)); + const related = recipesFor(hit.comp.id); + const tail = related.length ? `\n\n出现在配方:${related.map((r) => `${r.id}(${r.title})`).join('、')}(ua mcp 的 get_recipe 可取骨架)` : ''; + console.log(formatComponent(hit.pkg, hit.comp) + tail); } // ---- 静态文档站生成 ---- @@ -586,7 +597,7 @@ function cmdMcp() { if (p) return p; const hit = collectComponents(packages).find((x) => x.comp.id === args.name); // 退化到组件级查询 if (!hit) throw new Error(`not found: ${args.name}`); - return { package: hit.pkg.name, ...hit.comp }; + return { package: hit.pkg.name, ...hit.comp, recipes: recipesFor(hit.comp.id) }; } if (name === 'search_components') { const q = String(args.query ?? '').toLowerCase();