iter(g25): 新增 ua tokens 命令与 MCP get_tokens 工具
This commit is contained in:
@@ -329,15 +329,16 @@ function renderAgentDocs(index, tokens) {
|
||||
}
|
||||
if (tokens?.color) {
|
||||
lines.push('## 设计令牌(--ua-*)', '');
|
||||
const kebab = (s) => s.replace(/[A-Z]/g, (c) => '-' + c.toLowerCase()); // textMuted → text-muted,与 ui.css 实际变量名一致
|
||||
for (const [k, v] of Object.entries(tokens.color)) {
|
||||
const light = typeof v === 'string' ? v : v.light;
|
||||
const dark = typeof v === 'string' ? v : v.dark;
|
||||
lines.push(`- --ua-color-${k}: ${light}${dark !== light ? `(暗色 ${dark})` : ''}`);
|
||||
lines.push(`- --ua-color-${kebab(k)}: ${light}${dark !== light ? `(暗色 ${dark})` : ''}`);
|
||||
}
|
||||
for (const [g, vals] of Object.entries(tokens)) {
|
||||
if (g === 'color' || g === '$schema') continue;
|
||||
lines.push('', `### ${g}`, '');
|
||||
for (const [k, v] of Object.entries(vals)) lines.push(`- --ua-${g}-${k}: ${v}`);
|
||||
for (const [k, v] of Object.entries(vals)) lines.push(`- --ua-${g}-${kebab(k)}: ${v}`);
|
||||
}
|
||||
lines.push('');
|
||||
}
|
||||
@@ -365,9 +366,44 @@ function cmdDocs() {
|
||||
);
|
||||
}
|
||||
|
||||
// ---- 令牌查询:CLI 与 MCP 共用同一份拍平结果 ----
|
||||
|
||||
/*** 读取 tokens.json 拍平为 CSS 变量清单(颜色区分亮/暗两态,其余单值;名字统一 kebab-case 与 ui.css 对齐) ***/
|
||||
function loadTokenList() {
|
||||
const p = path.join(ROOT, 'packages', 'design', 'tokens', 'tokens.json');
|
||||
if (!fs.existsSync(p)) return [];
|
||||
const tokens = JSON.parse(fs.readFileSync(p, 'utf8'));
|
||||
const kebab = (s) => s.replace(/[A-Z]/g, (c) => '-' + c.toLowerCase()); // camelCase 键转 kebab-case
|
||||
const out = [];
|
||||
for (const [k, v] of Object.entries(tokens.color ?? {})) {
|
||||
if (typeof v === 'string') out.push({ cssVar: `--ua-color-${kebab(k)}`, value: v });
|
||||
else out.push({ cssVar: `--ua-color-${kebab(k)}`, value: v.light, dark: v.dark });
|
||||
}
|
||||
for (const [group, vals] of Object.entries(tokens)) {
|
||||
if (group === 'color' || group.startsWith('$')) continue;
|
||||
for (const [k, v] of Object.entries(vals)) out.push({ cssVar: `--ua-${group}-${kebab(k)}`, value: String(v) });
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/*** ua tokens:打印令牌清单;--json 输出结构化数组供脚本消费 ***/
|
||||
function cmdTokens(args) {
|
||||
const list = loadTokenList();
|
||||
if (!list.length) {
|
||||
console.error('未找到 packages/design/tokens/tokens.json');
|
||||
process.exit(1);
|
||||
}
|
||||
if (args.includes('--json')) {
|
||||
console.log(JSON.stringify(list, null, 2));
|
||||
return;
|
||||
}
|
||||
for (const t of list) console.log(`${t.cssVar.padEnd(26)} ${t.value}${t.dark && t.dark !== t.value ? ' / 暗色 ' + t.dark : ''}`);
|
||||
console.log(`共 ${list.length} 个令牌`);
|
||||
}
|
||||
|
||||
// ---- 内置 stdio MCP server(JSON-RPC 2.0,按行分帧) ----
|
||||
|
||||
/*** 启动 MCP server:向 Agent 暴露 list / get / search 三个查询工具 ***/
|
||||
/*** 启动 MCP server:向 Agent 暴露 list / get / search / tokens 四个查询工具 ***/
|
||||
function cmdMcp() {
|
||||
if (!fs.existsSync(INDEX_FILE)) cmdIndex();
|
||||
const { packages } = loadIndex();
|
||||
@@ -396,6 +432,11 @@ function cmdMcp() {
|
||||
required: ['query'],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'get_tokens',
|
||||
description: 'Get the --ua-* design token list (cssVar / value / dark), so styles never hardcode colors or spacing',
|
||||
inputSchema: { type: 'object', properties: {} },
|
||||
},
|
||||
];
|
||||
|
||||
const send = (obj) => process.stdout.write(JSON.stringify(obj) + '\n');
|
||||
@@ -421,6 +462,11 @@ function cmdMcp() {
|
||||
)
|
||||
.map((p) => ({ name: p.name, version: p.version, type: p.type, description: p.description }));
|
||||
}
|
||||
if (name === 'get_tokens') {
|
||||
const list = loadTokenList();
|
||||
if (!list.length) throw new Error('tokens.json not found');
|
||||
return list;
|
||||
}
|
||||
throw new Error(`unknown tool: ${name}`);
|
||||
}
|
||||
|
||||
@@ -851,6 +897,9 @@ switch (cmd) {
|
||||
case 'changelog':
|
||||
cmdChangelog(args);
|
||||
break;
|
||||
case 'tokens':
|
||||
cmdTokens(args);
|
||||
break;
|
||||
case 'lint-iterations':
|
||||
cmdLintIterations();
|
||||
break;
|
||||
@@ -858,6 +907,6 @@ switch (cmd) {
|
||||
cmdMcp();
|
||||
break;
|
||||
default:
|
||||
console.log('usage: ua <index|list|info <name>|docs|style|verify|commit-lint|lint-iterations|changelog|mcp>');
|
||||
console.log('usage: ua <index|list|info <name>|docs|tokens [--json]|style|verify|commit-lint|lint-iterations|changelog|mcp>');
|
||||
process.exit(cmd ? 1 : 0);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
"name": "@ui-arch/cli",
|
||||
"type": "tooling",
|
||||
"description": "ua 命令行与 MCP 注册表服务:把各包 ua.manifest.json 汇总成机器可读索引(.ua/index.json)、Agent 全量文档(llms-full.txt)与人类文档站,并提供清单一致性门禁。",
|
||||
"tags": ["cli", "tooling", "mcp", "docs", "gate"],
|
||||
"tags": [
|
||||
"cli",
|
||||
"tooling",
|
||||
"mcp",
|
||||
"docs",
|
||||
"gate"
|
||||
],
|
||||
"api": {
|
||||
"entry": "bin/ua.js",
|
||||
"exports": [
|
||||
@@ -15,9 +21,12 @@
|
||||
"ua commit-lint <文件|message>:提交信息门禁(type 枚举 / scope 规则 / subject 中文祈使 ≤50 字符),规范见 COMMITTING.md,违规退出码 1",
|
||||
"ua mcp:零依赖 stdio MCP server,暴露 list_components / get_component / search_components"
|
||||
],
|
||||
"keyTypes": ["ua.manifest.json 清单结构", "MCP tool 入参 schema"]
|
||||
"keyTypes": [
|
||||
"ua.manifest.json 清单结构",
|
||||
"MCP tool 入参 schema"
|
||||
]
|
||||
},
|
||||
"usage": "node packages/tools/cli/bin/ua.js <index|list|info <name>|docs|style|verify|commit-lint|mcp>;仓库内等价于 npm run index / docs / style / verify",
|
||||
"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",
|
||||
"conventions": [
|
||||
"零依赖:只用 node 标准库,Node >= 18",
|
||||
"清单是单一来源:代码注释、文档站、llms-full.txt、MCP 全部从 ua.manifest.json 派生",
|
||||
@@ -28,8 +37,9 @@
|
||||
"steps": [
|
||||
"装好依赖后先跑 npm run check 确认基线全绿(build → style → typecheck → smoke → index → verify)",
|
||||
"查组件:ua list 看全量,ua info <包名> 看单包 api 与约定",
|
||||
"查令牌:ua tokens 打印全部 --ua-* 变量(颜色带暗色值),--json 输出结构化数组;写样式前先查,禁止硬编码",
|
||||
"改完清单跑 npm run docs:同时刷新人类文档站与 llms-full.txt(Agent 首选喂料)",
|
||||
"提交前 npm run check:style 查注释规范,verify 查清单 ↔ 文档 ↔ 演示锚点是否一致",
|
||||
"在 ~/.workbuddy/mcp.json 注册 ua mcp 后,Agent 可直接调 list_components / get_component / search_components / get_tokens",
|
||||
"在 ~/.workbuddy/mcp.json 注册 ua mcp 后,Agent 可直接调 list_components / get_component / search_components"
|
||||
],
|
||||
"components": []
|
||||
|
||||
Reference in New Issue
Block a user