iter(g34): ua info 支持组件 id 查询并输出可读 props 表

This commit is contained in:
HIsheR
2026-10-26 11:45:46 +08:00
parent fe165a3cba
commit d461a3ed33
9 changed files with 71 additions and 29 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@ui-arch/ui",
"type": "skin-dom",
"description": "DOM 皮肤组件库:button / textField / textarea / slider / checkbox / switch / select / menu / radioGroup / accordion / breadcrumb / card / badge / image / tag / avatar / alert / toast / tooltip / popover / skeleton / spinner / progress / tabs / pagination / modal / drawer / form / formItem / dataTable,构建在 @ui-arch/frame 与 @ui-arch/table-core 之上,样式只消费 --ua-* 令牌。",
"description": "DOM 皮肤组件库:表单 / 反馈 / 浮层 / 导航 / 数据展示,构建在 @ui-arch/frame 与 @ui-arch/table-core 之上,样式只消费 --ua-* 令牌(组件全量见 api.exports 或刚体清单)",
"tags": [
"components",
"dom",
+45 -11
View File
@@ -121,15 +121,47 @@ function cmdList() {
}
}
/*** 输出单包完整元数据 ***/
function cmdInfo(name) {
/*** 摊平组件清单(带所属包),供 info / MCP 按组件 id 查询 ***/
function collectComponents(packages) {
const list = packages ?? loadIndex().packages;
return list.flatMap((pkg) => (pkg.docs?.components ?? []).map((comp) => ({ pkg, comp })));
}
/*** 渲染组件的人类可读说明:props 表 + 步骤 + 示例,便于直接抄进代码 ***/
function formatComponent(pkg, comp) {
const lines = [`${comp.id} — ${comp.title ?? ''} (${pkg.name}${comp.demo ? `, demo: ${comp.demo}` : ''})`, ''];
if ((comp.props ?? []).length) {
lines.push('props:');
const width = Math.max(...comp.props.map((x) => (x.n ?? '').length));
for (const x of comp.props) lines.push(` ${(x.n ?? '').padEnd(width)} ${(x.t ?? '').padEnd(30)} ${x.r ? '必填 ' : ' '}${x.d ?? ''}`);
lines.push('');
}
if ((comp.steps ?? []).length) {
lines.push('steps:');
comp.steps.forEach((t, i) => lines.push(` ${i + 1}. ${t}`));
lines.push('');
}
if (comp.example) lines.push('example:', ` ${comp.example}`);
return lines.join('\n');
}
/*** 输出单包或单组件信息:默认人读摘要,--json 输出原始 JSON ***/
function cmdInfo(name, args = []) {
const { packages } = loadIndex();
const p = packages.find((x) => x.name === name || x.name === `@ui-arch/${name}`);
if (!p) {
console.error(`not found: ${name}`);
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) {
console.error(`not found: ${name}(包名与组件 id 都没命中)`);
process.exit(1);
}
console.log(JSON.stringify(p, null, 2));
console.log(asJson ? JSON.stringify({ package: hit.pkg.name, ...hit.comp }, null, 2) : formatComponent(hit.pkg, hit.comp));
}
// ---- 静态文档站生成 ----
@@ -407,7 +439,7 @@ function cmdMcp() {
},
{
name: 'get_component',
description: 'Get full metadata (API, usage, conventions) of one component',
description: 'Get one package by name, or one component by its id (returns props/steps/example)',
inputSchema: {
type: 'object',
properties: { name: { type: 'string', description: 'package name, e.g. @ui-arch/table-core or table-core' } },
@@ -439,8 +471,10 @@ function cmdMcp() {
}
if (name === 'get_component') {
const p = packages.find((x) => x.name === args.name || x.name === `@ui-arch/${args.name}`);
if (!p) throw new Error(`not found: ${args.name}`);
return p;
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 };
}
if (name === 'search_components') {
const q = String(args.query ?? '').toLowerCase();
@@ -910,10 +944,10 @@ switch (cmd) {
break;
case 'info':
if (!args[0]) {
console.error('usage: ua info <package-name>');
console.error('usage: ua info <包名|组件id> [--json]');
process.exit(1);
}
cmdInfo(args[0]);
cmdInfo(args[0], args.slice(1));
break;
case 'docs':
cmdDocs();
+3 -3
View File
@@ -14,7 +14,7 @@
"exports": [
"ua index:扫描 packages/ 两层目录的 ua.manifest.json,生成 .ua/index.json 与 llms.txt",
"ua list:列出注册表内所有包与组件数",
"ua info <name>:查看单个包的清单详情(api / 约定 / 文档步骤)",
"ua info <包名|组件id>:包名返回摘要,组件 id 返回 props 表 + 步骤 + 示例;--json 输出原始清单",
"ua docs:生成人类文档站 apps/docs/index.html + demo.html 与 Agent 全量文档 llms-full.txt",
"ua style:注释规范门禁(导出必须 /*** ***/、接口字段行尾注释、行注释中文),违规退出码 1",
"ua verify:清单一致性门禁(id 唯一 / exports 对应 / props 必带 n t d / steps≥3 / demo 锚点存在)",
@@ -26,7 +26,7 @@
"MCP tool 入参 schema"
]
},
"usage": "node packages/tools/cli/bin/ua.js <index|list|info <name>|docs|tokens|style|verify|commit-lint|mcp>;仓库内等价于 npm run index / docs / style / verify",
"usage": "node packages/tools/cli/bin/ua.js <index|list|info <包名|组件id>|docs|tokens|style|verify|commit-lint|mcp>;仓库内等价于 npm run index / docs / style / verify",
"conventions": [
"零依赖:只用 node 标准库,Node >= 18",
"清单是单一来源:代码注释、文档站、llms-full.txt、MCP 全部从 ua.manifest.json 派生",
@@ -36,7 +36,7 @@
"intro": "工程层工具包(private,不发布)。所有 Agent 与人都通过它读取组件库:清单驱动索引、文档、MCP 三件套,外加 style / verify 两道门禁。",
"steps": [
"装好依赖后先跑 npm run check 确认基线全绿(build → demo → style → typecheck → smoke → index → verify)",
"查组件:ua list 看全量,ua info <包名> 看单包 api 与约定",
"查组件:ua list 看全量,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",