iter(g319): ua info 支持逗号分隔批量查询,一次拿全多个组件

This commit is contained in:
HIsheR
2026-10-27 01:03:33 +08:00
parent 77d1c72e1e
commit dcf470c0c7
5 changed files with 58 additions and 24 deletions
+9
View File
@@ -3257,6 +3257,15 @@
"motivation": "多步向导是后台最高频的表单形态之一,现有 19 条配方没有覆盖「步进条 + 分步字段 + 步间校验 + 回跳」的组合:stepper 的 active 双向绑定与 formItem 句柄的 validate() 恰好能拼出这个场景,缺一条示范怎么把校验拦在步与步之间,而不是最后一步集体报错。",
"acceptance": "① recipes.md 新增配方 20(编号连续、含代码块与要点,代码块能被 ua recipes 认出 stepper / formItem / button / card / toast 组件);② 配方代码与真实签名一致(FormRule.message、button disabled 收 Signal、formItem 句柄 validate);③ ua recipes 20 与 ua search 均能命中;④ npm run check 通过。",
"notes": ""
},
{
"id": "g319",
"domain": "tooling",
"status": "open",
"title": "ua info 支持逗号分隔批量查询多个组件",
"motivation": "Agent 拼一个界面通常要 3–5 个组件的参数,现在只能 `ua info button`、`ua info select` 一条条查(MCP get_component 同样单查),每轮多花好几次往返;逗号分隔批量一次拿全,文本 / --md / --json 三种模式都覆盖。",
"acceptance": "① `ua info button,select --md` 一次输出两个组件的 Markdown 片段(片段间以分隔线隔开);② `--json` 多值时输出数组、单值保持对象(不破坏现有脚本消费);③ 不存在的 id 报错并指明是第几个;④ manifest usage 串同步更新;⑤ npm run check 通过。",
"notes": ""
}
]
}
+1 -1
View File
@@ -52,7 +52,7 @@
可用工具:`list_components` / `get_component`(传 `format: "md"` 直接拿 Markdown 片段,等同 `ua info --md`)/ `search_components` / `get_tokens`(返回 --ua-* 令牌清单,避免硬编码颜色间距)/ `list_recipes` / `get_recipe`(取跨组件组合配方:骨架代码 + 要点 + 用到的组件 id,配好再逐个 `get_component` 查参数)。
2. **CLI**:`node packages/tools/cli/bin/ua.js loop [--json](迭代循环诊断:锁心跳 / 上次留痕 / 待办数) | iter done <id> <commit> <summary>(迭代收尾:置 done + 写留痕,ts 由本机时钟生成) | iter add <条目json>(补自选题) | list [--json|--components] | search <关键词> | info <name> [--json|--md](--md 出可粘贴的 Markdown 片段:标题 + 参数表 + 用法 + 示例) | recipes [编号] [--json] | index | docs | style | verify | changelog`(`--json` 给脚本与 Agent 用,不必解析文本);`search` 覆盖 id / 标题 / 参数名 / 参数说明 / 步骤五层 + 配方三层(标题 / 配方组件 / 要点,命中行直接给 `ua recipes <编号>` 指路),命中非 id 标题时会标出命中字段(如「← 参数说明含『处理中』」),`--json` 输出 `{ components, recipes }` 两数组、各项带 `matched` 字段
2. **CLI**:`node packages/tools/cli/bin/ua.js loop [--json](迭代循环诊断:锁心跳 / 上次留痕 / 待办数) | iter done <id> <commit> <summary>(迭代收尾:置 done + 写留痕,ts 由本机时钟生成) | iter add <条目json>(补自选题) | list [--json|--components] | search <关键词> | info <name[,name…]> [--json|--md](name 支持逗号分隔一次查多个;--md 出可粘贴的 Markdown 片段:标题 + 参数表 + 用法 + 示例,批量片段以水平线分隔;--json 单值为对象、多值为数组) | recipes [编号] [--json] | index | docs | style | verify | changelog`(`--json` 给脚本与 Agent 用,不必解析文本);`search` 覆盖 id / 标题 / 参数名 / 参数说明 / 步骤五层 + 配方三层(标题 / 配方组件 / 要点,命中行直接给 `ua recipes <编号>` 指路),命中非 id 标题时会标出命中字段(如「← 参数说明含『处理中』」),`--json` 输出 `{ components, recipes }` 两数组、各项带 `matched` 字段
3. **静态索引**:`.ua/index.json`(机器可读索引)、`llms.txt`(速览)或 **`llms-full.txt`(全量 Agent 文档:逐组件参数 / 回调 / 手把手步骤 / 令牌 / 组合配方,无图形纯文本,喂给 Agent 首选)**。
+2 -2
View File
@@ -1,6 +1,6 @@
# @ui-arch 组件库 Agent 文档(无图形版)
> 自动生成于 2026-10-26T16:55:18.044Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
> 自动生成于 2026-10-26T17:03:14.418Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
> 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。
## 快速上手
@@ -2764,7 +2764,7 @@ API 速览:
一行用法:
```
node packages/tools/cli/bin/ua.js <index|list|info <包名|组件id> [--json|--md]|docs|tokens [--json|--unused]|style|verify|commit-lint|audit:visual|audit:contrast|audit:motion|doctor|mcp>;仓库内等价于 npm run index / docs / style / verify / audit:visual / audit:contrast / audit:motion / doctor
node packages/tools/cli/bin/ua.js <index|list|info <包名|组件id[,组件id…]> [--json|--md]|docs|tokens [--json|--unused]|style|verify|commit-lint|audit:visual|audit:contrast|audit:motion|doctor|mcp>;仓库内等价于 npm run index / docs / style / verify / audit:visual / audit:contrast / audit:motion / doctor
```
约定:
+43 -18
View File
@@ -315,31 +315,56 @@ function cmdSearch(words = [], args = []) {
console.log(`\n共 ${parts.join('、')}命中;查参数:ua info <组件id>,看骨架:ua recipes <编号>`);
}
/*** 输出单包或单组件信息:默认人读摘要,--json 输出原始 JSON ***/
/*** 输出包或组件信息:默认人读摘要,--json 输出原始 JSON;name 支持逗号分隔一次查多个(单值保持原输出结构不破坏脚本) ***/
function cmdInfo(name, args = []) {
const { packages } = loadIndex();
const asJson = args.includes('--json');
const pkg = packages.find((x) => x.name === name || x.name === `@ui-arch/${name}`);
if (pkg) {
if (asJson) return console.log(JSON.stringify(pkg, null, 2));
return console.log(
`${pkg.name} v${pkg.version} [${pkg.type}] ${pkg.description}\n(--json 看完整清单;按组件查:ua info <组件id>)`,
);
}
const hit = collectComponents(packages).find((x) => x.comp.id === name);
if (!hit) {
const near = nearIds(name);
console.error(`not found: ${name}(包名与组件 id 都没命中)${near.length ? `;相近:${near.join(' / ')}` : ''}`);
const asMd = args.includes('--md');
const names = name.split(',').map((s) => s.trim()).filter(Boolean); // 批量:逗号分隔多组件一次拿全,省 Agent 往返
const comps = collectComponents(packages);
const resolve = (n) => { // 单个名字 → 包或组件条目;都没命中返回 null 交由调用方报错
const pkg = packages.find((x) => x.name === n || x.name === `@ui-arch/${n}`);
if (pkg) return { kind: 'pkg', pkg };
const hit = comps.find((x) => x.comp.id === n);
return hit ? { kind: 'comp', hit } : null;
};
if (names.length === 1) {
const r = resolve(names[0]);
if (!r) {
const near = nearIds(names[0]);
console.error(`not found: ${names[0]}(包名与组件 id 都没命中)${near.length ? `;相近:${near.join(' / ')}` : ''}`);
return process.exit(1);
}
if (r.kind === 'pkg') {
if (asJson) return console.log(JSON.stringify(r.pkg, null, 2));
return console.log(
`${r.pkg.name} v${r.pkg.version} [${r.pkg.type}] ${r.pkg.description}\n(--json 看完整清单;按组件查:ua info <组件id>)`,
);
}
const { hit } = r;
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 recipeTail = related.length ? `\n\n出现在配方:${related.map((r) => `${r.id}(${r.title})`).join('、')}(ua mcp 的 get_recipe 可取骨架)` : '';
if (args.includes('--md')) {
// Markdown 片段:贴进文档 / issue / 回复时不用手抄参数表;配方清单压成一行尾注
return console.log(formatComponentMd(hit.pkg, hit.comp) + recipeTail);
const recipeTail = related.length ? `\n\n出现在配方:${related.map((x) => `${x.id}(${x.title})`).join('、')}(ua mcp 的 get_recipe 可取骨架)` : '';
if (asMd) return console.log(formatComponentMd(hit.pkg, hit.comp) + recipeTail); // Markdown 片段:贴进文档 / issue / 回复时不用手抄参数表
return console.log(formatComponent(hit.pkg, hit.comp) + recipeTail);
}
console.log(formatComponent(hit.pkg, hit.comp) + recipeTail);
const resolved = names.map((n) => resolve(n)); // 批量路径:先全量解析,任一失败整条拒绝(输出一半再报错会让脚本误判成功)
const bad = names.filter((n, i) => !resolved[i]);
if (bad.length) {
const near = nearIds(bad[0]);
console.error(`not found: ${bad.join(' / ')}(第 ${names.indexOf(bad[0]) + 1} 个,包名与组件 id 都没命中)${near.length ? `;相近:${near.join(' / ')}` : ''}`);
return process.exit(1);
}
const compMd = (r) => { // 批量输出统一用组件片段格式:包条目退化为标题行
if (r.kind === 'pkg') return `## ${r.pkg.name}(${r.pkg.type})\n\n${r.pkg.description}`;
const related = recipesFor(r.hit.comp.id);
const tail = related.length ? `\n\n> 出现在配方:${related.map((x) => `${x.id}(${x.title})`).join('、')}` : '';
return formatComponentMd(r.hit.pkg, r.hit.comp) + tail;
};
if (asJson) {
return console.log(JSON.stringify(resolved.map((r) => (r.kind === 'pkg' ? r.pkg : { package: r.hit.pkg.name, ...r.hit.comp, recipes: recipesFor(r.hit.comp.id) })), null, 2));
}
console.log(resolved.map(compMd).join('\n\n---\n\n')); // 片段间以水平线分隔,方便人读与脚本按线切块
}
// ---- 静态文档站生成 ----
@@ -2033,6 +2058,6 @@ switch (cmd) {
cmdMcp();
break;
default:
console.log('usage: ua <index|list|search <kw>|info <name> [--json|--md]|recipes [编号] [--json]|docs|tokens [--json|--unused]|style|sync-counts|verify|doctor|commit-lint|lint-iterations|iter|audit:visual [--json|--baseline]|audit:contrast [--json|--list]|audit:motion [--json]|audit:surface [--json|--list]|loop [--json]|changelog|mcp>');
console.log('usage: ua <index|list|search <kw>|info <name[,name…]> [--json|--md]|recipes [编号] [--json]|docs|tokens [--json|--unused]|style|sync-counts|verify|doctor|commit-lint|lint-iterations|iter|audit:visual [--json|--baseline]|audit:contrast [--json|--list]|audit:motion [--json]|audit:surface [--json|--list]|loop [--json]|changelog|mcp>');
process.exit(cmd ? 1 : 0);
}
+1 -1
View File
@@ -34,7 +34,7 @@
"MCP tool 入参 schema"
]
},
"usage": "node packages/tools/cli/bin/ua.js <index|list|info <包名|组件id> [--json|--md]|docs|tokens [--json|--unused]|style|verify|commit-lint|audit:visual|audit:contrast|audit:motion|doctor|mcp>;仓库内等价于 npm run index / docs / style / verify / audit:visual / audit:contrast / audit:motion / doctor",
"usage": "node packages/tools/cli/bin/ua.js <index|list|info <包名|组件id[,组件id…]> [--json|--md]|docs|tokens [--json|--unused]|style|verify|commit-lint|audit:visual|audit:contrast|audit:motion|doctor|mcp>;仓库内等价于 npm run index / docs / style / verify / audit:visual / audit:contrast / audit:motion / doctor",
"conventions": [
"零依赖:只用 node 标准库,Node >= 18",
"清单是单一来源:代码注释、文档站、llms-full.txt、MCP 全部从 ua.manifest.json 派生",