From cc9ec02c94cdd32245afeb63f200b4fb6930efc3 Mon Sep 17 00:00:00 2001 From: HIsheR Date: Mon, 26 Oct 2026 16:26:53 +0800 Subject: [PATCH] =?UTF-8?q?iter(g176):=20=E6=94=AF=E6=8C=81=E6=8C=89?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E8=AF=B4=E6=98=8E=E6=A3=80=E7=B4=A2=E7=BB=84?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .ua/index.json | 4 +- AGENTS.md | 2 +- llms-full.txt | 4 +- packages/tools/cli/bin/ua.js | 57 +++++++++++++++++++---------- packages/tools/cli/ua.manifest.json | 4 +- 5 files changed, 44 insertions(+), 27 deletions(-) diff --git a/.ua/index.json b/.ua/index.json index 965a436..dd1adc4 100644 --- a/.ua/index.json +++ b/.ua/index.json @@ -1,6 +1,6 @@ { "$schema": "ui-arch-registry-index/0.1", - "generatedAt": "2026-10-26T08:22:46.231Z", + "generatedAt": "2026-10-26T08:26:18.408Z", "repoRoot": ".", "packages": [ { @@ -3680,7 +3680,7 @@ "intro": "工程层工具包(private,不发布)。所有 Agent 与人都通过它读取组件库:清单驱动索引、文档、MCP 三件套,外加 style / verify 两道门禁。", "steps": [ "装好依赖后先跑 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 输出结构化数组;写样式前先查,禁止硬编码", "改完清单跑 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" diff --git a/AGENTS.md b/AGENTS.md index 71f4bb0..20a742c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -50,7 +50,7 @@ 可用工具:`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 [--json] | index | docs | style | verify | changelog`(`--json` 给脚本与 Agent 用,不必解析文本) +2. **CLI**:`node packages/tools/cli/bin/ua.js list [--json|--components] | search <关键词> | info [--json] | index | docs | style | verify | changelog`(`--json` 给脚本与 Agent 用,不必解析文本);`search` 覆盖 id / 标题 / 参数名 / 参数说明 / 步骤五层,命中非 id 标题时会标出命中字段(如「← 参数说明含『处理中』」),`--json` 附带 `matched` 字段 3. **静态索引**:`.ua/index.json`(机器可读索引)、`llms.txt`(速览)或 **`llms-full.txt`(全量 Agent 文档:逐组件参数 / 回调 / 手把手步骤 / 令牌 / 组合配方,无图形纯文本,喂给 Agent 首选)**。 diff --git a/llms-full.txt b/llms-full.txt index 4c02ada..03d1d6c 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -1,6 +1,6 @@ # @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)。 ## 快速上手 @@ -41,7 +41,7 @@ ### @ui-arch/cli 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 输出结构化数组;写样式前先查,禁止硬编码 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 diff --git a/packages/tools/cli/bin/ua.js b/packages/tools/cli/bin/ua.js index f3b3879..52825d0 100644 --- a/packages/tools/cli/bin/ua.js +++ b/packages/tools/cli/bin/ua.js @@ -203,25 +203,39 @@ function nearIds(name) { .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 = []) { const kws = [...new Set(words.map((w) => String(w).toLowerCase().trim()).filter(Boolean))]; 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() .map(({ pkg, comp }) => { - const scores = kws.map((kw) => scoreOf(kw, comp)); - return scores.every((s) => s > 0) ? { pkg, comp, score: Math.min(...scores) } : null; // 任一词不中即淘汰 + const ms = kws.map((kw) => ({ kw, ...matchOf(kw, comp) })); + 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) .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); } 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>`); } @@ -583,7 +602,7 @@ function cmdMcp() { }, { 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: { type: 'object', properties: { query: { type: 'string' } }, @@ -647,9 +666,7 @@ function cmdMcp() { ) .map((p) => ({ name: p.name, version: p.version, type: p.type, description: p.description })); const comps = collectComponents(packages) // 组件级命中:包级 exports 只给出包名,Agent 还得再查一次 - .filter(({ comp }) => - [comp.id, comp.title, ...(comp.props ?? []).map((p) => p.n)].join(' ').toLowerCase().includes(q), - ) + .filter(({ comp }) => searchFields(comp).some((f) => f.text.includes(q))) // 与 CLI search 同一份字段表 .map(({ pkg, comp }) => ({ package: pkg.name, id: comp.id, title: comp.title })); if (!pkgs.length && !comps.length) throw new Error(`no match: ${args.query}`); return { packages: pkgs, components: comps }; diff --git a/packages/tools/cli/ua.manifest.json b/packages/tools/cli/ua.manifest.json index b3b9c08..8ea0c87 100644 --- a/packages/tools/cli/ua.manifest.json +++ b/packages/tools/cli/ua.manifest.json @@ -36,11 +36,11 @@ "intro": "工程层工具包(private,不发布)。所有 Agent 与人都通过它读取组件库:清单驱动索引、文档、MCP 三件套,外加 style / verify 两道门禁。", "steps": [ "装好依赖后先跑 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 输出结构化数组;写样式前先查,禁止硬编码", "改完清单跑 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" ], "components": [] } -} \ No newline at end of file +}