iter(g176): 支持按参数说明检索组件
This commit is contained in:
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "ui-arch-registry-index/0.1",
|
"$schema": "ui-arch-registry-index/0.1",
|
||||||
"generatedAt": "2026-10-26T08:22:46.231Z",
|
"generatedAt": "2026-10-26T08:26:18.408Z",
|
||||||
"repoRoot": ".",
|
"repoRoot": ".",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
@@ -3680,7 +3680,7 @@
|
|||||||
"intro": "工程层工具包(private,不发布)。所有 Agent 与人都通过它读取组件库:清单驱动索引、文档、MCP 三件套,外加 style / verify 两道门禁。",
|
"intro": "工程层工具包(private,不发布)。所有 Agent 与人都通过它读取组件库:清单驱动索引、文档、MCP 三件套,外加 style / verify 两道门禁。",
|
||||||
"steps": [
|
"steps": [
|
||||||
"装好依赖后先跑 npm run check 确认基线全绿(build → demo → style → typecheck → smoke → index → verify)",
|
"装好依赖后先跑 npm run check 确认基线全绿(build → demo → style → typecheck → smoke → index → verify)",
|
||||||
"查组件:ua list 看全量,ua search <关键词> 按 id/标题/props/步骤模糊找(拼错会回相近 id),ua info <组件id> 看 props/步骤/示例(ua info <包名> 看单包 api 与约定,加 --json 出原始清单)",
|
"查组件:ua list 看全量,ua search <关键词> 按 id/标题/参数名/参数说明/步骤模糊找(「处理中」这类说明里的词也能搜到,命中非 id 标题时会标出命中字段;拼错会回相近 id),ua info <组件id> 看 props/步骤/示例(ua info <包名> 看单包 api 与约定,加 --json 出原始清单)",
|
||||||
"查令牌:ua tokens 打印全部 --ua-* 变量(颜色带暗色值),--json 输出结构化数组;写样式前先查,禁止硬编码",
|
"查令牌:ua tokens 打印全部 --ua-* 变量(颜色带暗色值),--json 输出结构化数组;写样式前先查,禁止硬编码",
|
||||||
"改完清单跑 npm run docs:同时刷新人类文档站与 llms-full.txt(Agent 首选喂料)",
|
"改完清单跑 npm run docs:同时刷新人类文档站与 llms-full.txt(Agent 首选喂料)",
|
||||||
"在 ~/.workbuddy/mcp.json 注册 ua mcp 后,Agent 可直接调 list_components / get_component / search_components / get_tokens / list_recipes / get_recipe"
|
"在 ~/.workbuddy/mcp.json 注册 ua mcp 后,Agent 可直接调 list_components / get_component / search_components / get_tokens / list_recipes / get_recipe"
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
|
|
||||||
可用工具:`list_components` / `get_component` / `search_components` / `get_tokens`(返回 --ua-* 令牌清单,避免硬编码颜色间距)/ `list_recipes` / `get_recipe`(取跨组件组合配方:骨架代码 + 要点 + 用到的组件 id,配好再逐个 `get_component` 查参数)。
|
可用工具:`list_components` / `get_component` / `search_components` / `get_tokens`(返回 --ua-* 令牌清单,避免硬编码颜色间距)/ `list_recipes` / `get_recipe`(取跨组件组合配方:骨架代码 + 要点 + 用到的组件 id,配好再逐个 `get_component` 查参数)。
|
||||||
|
|
||||||
2. **CLI**:`node packages/tools/cli/bin/ua.js list [--json|--components] | search <关键词> | info <name> [--json] | index | docs | style | verify | changelog`(`--json` 给脚本与 Agent 用,不必解析文本)
|
2. **CLI**:`node packages/tools/cli/bin/ua.js list [--json|--components] | search <关键词> | info <name> [--json] | index | docs | style | verify | changelog`(`--json` 给脚本与 Agent 用,不必解析文本);`search` 覆盖 id / 标题 / 参数名 / 参数说明 / 步骤五层,命中非 id 标题时会标出命中字段(如「← 参数说明含『处理中』」),`--json` 附带 `matched` 字段
|
||||||
|
|
||||||
3. **静态索引**:`.ua/index.json`(机器可读索引)、`llms.txt`(速览)或 **`llms-full.txt`(全量 Agent 文档:逐组件参数 / 回调 / 手把手步骤 / 令牌 / 组合配方,无图形纯文本,喂给 Agent 首选)**。
|
3. **静态索引**:`.ua/index.json`(机器可读索引)、`llms.txt`(速览)或 **`llms-full.txt`(全量 Agent 文档:逐组件参数 / 回调 / 手把手步骤 / 令牌 / 组合配方,无图形纯文本,喂给 Agent 首选)**。
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
# @ui-arch 组件库 Agent 文档(无图形版)
|
# @ui-arch 组件库 Agent 文档(无图形版)
|
||||||
|
|
||||||
> 自动生成于 2026-10-26T08:22:46.231Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
|
> 自动生成于 2026-10-26T08:26:18.408Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
|
||||||
> 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。
|
> 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。
|
||||||
|
|
||||||
## 快速上手
|
## 快速上手
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
### @ui-arch/cli
|
### @ui-arch/cli
|
||||||
|
|
||||||
1. 装好依赖后先跑 npm run check 确认基线全绿(build → demo → style → typecheck → smoke → index → verify)
|
1. 装好依赖后先跑 npm run check 确认基线全绿(build → demo → style → typecheck → smoke → index → verify)
|
||||||
2. 查组件:ua list 看全量,ua search <关键词> 按 id/标题/props/步骤模糊找(拼错会回相近 id),ua info <组件id> 看 props/步骤/示例(ua info <包名> 看单包 api 与约定,加 --json 出原始清单)
|
2. 查组件:ua list 看全量,ua search <关键词> 按 id/标题/参数名/参数说明/步骤模糊找(「处理中」这类说明里的词也能搜到,命中非 id 标题时会标出命中字段;拼错会回相近 id),ua info <组件id> 看 props/步骤/示例(ua info <包名> 看单包 api 与约定,加 --json 出原始清单)
|
||||||
3. 查令牌:ua tokens 打印全部 --ua-* 变量(颜色带暗色值),--json 输出结构化数组;写样式前先查,禁止硬编码
|
3. 查令牌:ua tokens 打印全部 --ua-* 变量(颜色带暗色值),--json 输出结构化数组;写样式前先查,禁止硬编码
|
||||||
4. 改完清单跑 npm run docs:同时刷新人类文档站与 llms-full.txt(Agent 首选喂料)
|
4. 改完清单跑 npm run docs:同时刷新人类文档站与 llms-full.txt(Agent 首选喂料)
|
||||||
5. 在 ~/.workbuddy/mcp.json 注册 ua mcp 后,Agent 可直接调 list_components / get_component / search_components / get_tokens / list_recipes / get_recipe
|
5. 在 ~/.workbuddy/mcp.json 注册 ua mcp 后,Agent 可直接调 list_components / get_component / search_components / get_tokens / list_recipes / get_recipe
|
||||||
|
|||||||
@@ -203,25 +203,39 @@ function nearIds(name) {
|
|||||||
.map(([id]) => id);
|
.map(([id]) => id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*** 按关键词搜组件:多词取最弱命中(AND 语义),id 命中优先于 title,其次 props 名与步骤文案;未命中退出码 1 ***/
|
/*** 组件的可检索字段:权重从高到低(id > 标题 > 参数名 > 参数说明 > 步骤),search 与 MCP 共用一份 ***/
|
||||||
|
function searchFields(comp) {
|
||||||
|
const props = comp.props ?? [];
|
||||||
|
return [
|
||||||
|
{ label: 'id', weight: 3, text: String(comp.id ?? '') },
|
||||||
|
{ label: '标题', weight: 2, text: String(comp.title ?? '') },
|
||||||
|
{ label: '参数', weight: 1, text: props.map((p) => String(p.n ?? '')).join(' ') },
|
||||||
|
{ label: '参数说明', weight: 0.8, text: props.map((p) => String(p.d ?? '')).join(' ') },
|
||||||
|
{ label: '步骤', weight: 0.5, text: (comp.steps ?? []).join(' ') },
|
||||||
|
].map((f) => ({ label: f.label, weight: f.weight, text: f.text.toLowerCase() }));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** 单个关键词在组件上的最佳命中:返回最高档字段(id 全等额外抬到最前),未命中 score 为 0 ***/
|
||||||
|
function matchOf(kw, comp) {
|
||||||
|
let best = { score: 0, label: '' };
|
||||||
|
for (const f of searchFields(comp)) {
|
||||||
|
if (!f.text.includes(kw)) continue;
|
||||||
|
const score = f.label === 'id' && f.text === kw ? 4 : f.weight; // id 全等单独一档,避免被 id 含稀释
|
||||||
|
if (score > best.score) best = { score, label: f.label };
|
||||||
|
}
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** 按关键词搜组件:多词取最弱命中(AND 语义),并标出该词命中的字段,便于判断为何被召回 ***/
|
||||||
function cmdSearch(words = [], args = []) {
|
function cmdSearch(words = [], args = []) {
|
||||||
const kws = [...new Set(words.map((w) => String(w).toLowerCase().trim()).filter(Boolean))];
|
const kws = [...new Set(words.map((w) => String(w).toLowerCase().trim()).filter(Boolean))];
|
||||||
if (!kws.length) return console.error('usage: ua search <关键词...> [--json]');
|
if (!kws.length) return console.error('usage: ua search <关键词...> [--json]');
|
||||||
const scoreOf = (kw, comp) => {
|
|
||||||
const id = String(comp.id ?? '').toLowerCase();
|
|
||||||
const title = String(comp.title ?? '').toLowerCase();
|
|
||||||
const props = (comp.props ?? []).map((p) => String(p.n ?? '').toLowerCase()).join(' ');
|
|
||||||
const steps = (comp.steps ?? []).join(' ').toLowerCase();
|
|
||||||
if (id === kw) return 4; // 分档只用于排序:id 全等 > id 含 > 标题 > props 名 > 步骤
|
|
||||||
if (id.includes(kw)) return 3;
|
|
||||||
if (title.includes(kw)) return 2;
|
|
||||||
if (props.includes(kw)) return 1;
|
|
||||||
return steps.includes(kw) ? 0.5 : 0;
|
|
||||||
};
|
|
||||||
const hits = collectComponents()
|
const hits = collectComponents()
|
||||||
.map(({ pkg, comp }) => {
|
.map(({ pkg, comp }) => {
|
||||||
const scores = kws.map((kw) => scoreOf(kw, comp));
|
const ms = kws.map((kw) => ({ kw, ...matchOf(kw, comp) }));
|
||||||
return scores.every((s) => s > 0) ? { pkg, comp, score: Math.min(...scores) } : null; // 任一词不中即淘汰
|
if (ms.some((m) => !m.score)) return null; // 任一词不中即淘汰
|
||||||
|
const weakest = ms.reduce((a, b) => (b.score < a.score ? b : a)); // 排序与提示都看最弱那一词
|
||||||
|
return { pkg, comp, score: weakest.score, field: weakest.label, keyword: weakest.kw };
|
||||||
})
|
})
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.sort((a, b) => b.score - a.score || String(a.comp.id).localeCompare(String(b.comp.id)));
|
.sort((a, b) => b.score - a.score || String(a.comp.id).localeCompare(String(b.comp.id)));
|
||||||
@@ -231,9 +245,14 @@ function cmdSearch(words = [], args = []) {
|
|||||||
return process.exit(1);
|
return process.exit(1);
|
||||||
}
|
}
|
||||||
if (args.includes('--json')) {
|
if (args.includes('--json')) {
|
||||||
return console.log(JSON.stringify(hits.map((h) => ({ package: h.pkg.name, ...h.comp })), null, 2));
|
return console.log(
|
||||||
|
JSON.stringify(hits.map((h) => ({ package: h.pkg.name, ...h.comp, matched: { field: h.field, keyword: h.keyword } })), null, 2),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for (const h of hits) {
|
||||||
|
const why = h.field === 'id' || h.field === '标题' ? '' : ` ← ${h.field}含「${h.keyword}」`;
|
||||||
|
console.log(`${String(h.comp.id).padEnd(16)} ${h.comp.title ?? ''} (${h.pkg.name})${why}`);
|
||||||
}
|
}
|
||||||
for (const h of hits) console.log(`${String(h.comp.id).padEnd(16)} ${h.comp.title ?? ''} (${h.pkg.name})`);
|
|
||||||
console.log(`\n共 ${hits.length} 个组件命中;查参数:ua info <组件id>`);
|
console.log(`\n共 ${hits.length} 个组件命中;查参数:ua info <组件id>`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -583,7 +602,7 @@ function cmdMcp() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'search_components',
|
name: 'search_components',
|
||||||
description: 'Search by keyword: returns matched packages plus matched components (id/title/props)',
|
description: 'Search by keyword: returns matched packages plus matched components (id/title/prop names/prop descriptions/steps)',
|
||||||
inputSchema: {
|
inputSchema: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: { query: { type: 'string' } },
|
properties: { query: { type: 'string' } },
|
||||||
@@ -647,9 +666,7 @@ function cmdMcp() {
|
|||||||
)
|
)
|
||||||
.map((p) => ({ name: p.name, version: p.version, type: p.type, description: p.description }));
|
.map((p) => ({ name: p.name, version: p.version, type: p.type, description: p.description }));
|
||||||
const comps = collectComponents(packages) // 组件级命中:包级 exports 只给出包名,Agent 还得再查一次
|
const comps = collectComponents(packages) // 组件级命中:包级 exports 只给出包名,Agent 还得再查一次
|
||||||
.filter(({ comp }) =>
|
.filter(({ comp }) => searchFields(comp).some((f) => f.text.includes(q))) // 与 CLI search 同一份字段表
|
||||||
[comp.id, comp.title, ...(comp.props ?? []).map((p) => p.n)].join(' ').toLowerCase().includes(q),
|
|
||||||
)
|
|
||||||
.map(({ pkg, comp }) => ({ package: pkg.name, id: comp.id, title: comp.title }));
|
.map(({ pkg, comp }) => ({ package: pkg.name, id: comp.id, title: comp.title }));
|
||||||
if (!pkgs.length && !comps.length) throw new Error(`no match: ${args.query}`);
|
if (!pkgs.length && !comps.length) throw new Error(`no match: ${args.query}`);
|
||||||
return { packages: pkgs, components: comps };
|
return { packages: pkgs, components: comps };
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
"intro": "工程层工具包(private,不发布)。所有 Agent 与人都通过它读取组件库:清单驱动索引、文档、MCP 三件套,外加 style / verify 两道门禁。",
|
"intro": "工程层工具包(private,不发布)。所有 Agent 与人都通过它读取组件库:清单驱动索引、文档、MCP 三件套,外加 style / verify 两道门禁。",
|
||||||
"steps": [
|
"steps": [
|
||||||
"装好依赖后先跑 npm run check 确认基线全绿(build → demo → style → typecheck → smoke → index → verify)",
|
"装好依赖后先跑 npm run check 确认基线全绿(build → demo → style → typecheck → smoke → index → verify)",
|
||||||
"查组件:ua list 看全量,ua search <关键词> 按 id/标题/props/步骤模糊找(拼错会回相近 id),ua info <组件id> 看 props/步骤/示例(ua info <包名> 看单包 api 与约定,加 --json 出原始清单)",
|
"查组件:ua list 看全量,ua search <关键词> 按 id/标题/参数名/参数说明/步骤模糊找(「处理中」这类说明里的词也能搜到,命中非 id 标题时会标出命中字段;拼错会回相近 id),ua info <组件id> 看 props/步骤/示例(ua info <包名> 看单包 api 与约定,加 --json 出原始清单)",
|
||||||
"查令牌:ua tokens 打印全部 --ua-* 变量(颜色带暗色值),--json 输出结构化数组;写样式前先查,禁止硬编码",
|
"查令牌:ua tokens 打印全部 --ua-* 变量(颜色带暗色值),--json 输出结构化数组;写样式前先查,禁止硬编码",
|
||||||
"改完清单跑 npm run docs:同时刷新人类文档站与 llms-full.txt(Agent 首选喂料)",
|
"改完清单跑 npm run docs:同时刷新人类文档站与 llms-full.txt(Agent 首选喂料)",
|
||||||
"在 ~/.workbuddy/mcp.json 注册 ua mcp 后,Agent 可直接调 list_components / get_component / search_components / get_tokens / list_recipes / get_recipe"
|
"在 ~/.workbuddy/mcp.json 注册 ua mcp 后,Agent 可直接调 list_components / get_component / search_components / get_tokens / list_recipes / get_recipe"
|
||||||
|
|||||||
Reference in New Issue
Block a user