@wot-ui/cli 0.0.1-beta.3 → 0.0.1-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026-PRESENT Wot UI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,13 +1,20 @@
1
- # @wot-ui/cli
1
+ # open-wot
2
2
 
3
- `@wot-ui/cli` 是面向 wot-ui 的命令行工具包,提供组件知识查询、项目分析、MCP Server 与离线数据提取能力。
3
+ open-wot 是 wot-ui 的 AI 工具链仓库,当前对外发布的核心包为 `@wot-ui/cli`。它提供命令行工具、MCP Server、离线组件知识库与数据提取脚本,用于把 wot-ui v2 的组件知识接入编辑器、AI Agent 和本地工程分析流程。
4
4
 
5
- ## 能力概览
5
+ ## 仓库定位
6
6
 
7
- - 组件查询:`list`、`info`、`doc`、`demo`、`token`、`changelog`
7
+ - 面向 wot-ui v2 的组件知识查询工具
8
+ - 面向本地项目的组件使用分析与 lint 工具
9
+ - 面向 AI 客户端的 MCP stdio 服务
10
+ - 面向仓库维护者的数据提取与同步工作流
11
+
12
+ ## 核心能力
13
+
14
+ - 组件知识查询:`list`、`info`、`doc`、`demo`、`token`、`changelog`
8
15
  - 项目分析:`doctor`、`usage`、`lint`
9
- - MCP 集成:`wot mcp`
10
- - 数据提取:从 `wot-ui/wot-ui` 源码生成 `data/v2.json`
16
+ - MCP Server:`wot mcp`
17
+ - 元数据提取:从 `wot-ui/wot-ui` 源码生成本地 `v2.json`
11
18
 
12
19
  ## 安装
13
20
 
@@ -15,37 +22,49 @@
15
22
  npm install -g @wot-ui/cli
16
23
  ```
17
24
 
18
- ## 常用命令
25
+ 安装完成后可直接使用 `wot` 命令。
26
+
27
+ 如果你在仓库内本地调试,推荐直接运行源码入口,而不是依赖全局命令:
28
+
29
+ ```bash
30
+ pnpm exec tsx src/index.ts list
31
+ ```
32
+
33
+ ## 快速开始
19
34
 
20
35
  ```bash
21
36
  wot list
22
37
  wot info Button
23
- wot doc Button
24
38
  wot demo Button basic
39
+ wot doc Button
25
40
  wot token Button
26
41
  wot changelog
27
- wot doctor ./my-app
28
- wot usage ./my-app
29
- wot lint ./my-app
42
+ wot doctor ./my-project
43
+ wot usage ./my-project
44
+ wot lint ./my-project
30
45
  wot mcp
31
46
  ```
32
47
 
33
48
  ## 命令说明
34
49
 
35
- - `wot list`:列出所有可用组件
36
- - `wot info <Component>`:查看组件基础信息
50
+ ### 组件知识
51
+
52
+ - `wot list`:列出可用的 wot-ui 组件
53
+ - `wot info <Component>`:查看组件 props、events、slots、CSS 变量
37
54
  - `wot doc <Component>`:输出组件 markdown 文档
38
- - `wot demo <Component> [name]`:查看示例列表或示例源码
39
- - `wot token [Component]`:查看 CSS 变量与默认值
55
+ - `wot demo <Component> [name]`:查看 demo 列表或指定 demo 源码
56
+ - `wot token [Component]`:查看组件 CSS 变量与默认值
40
57
  - `wot changelog [version] [component]`:查看版本更新记录
41
- - `wot doctor [dir]`:检查工程环境与依赖
42
- - `wot usage [dir]`:统计 `.vue` 中的 `wd-*` 使用情况
43
- - `wot lint [dir]`:运行 wot-ui 相关规则检查
44
- - `wot mcp`:启动 MCP stdio Server
45
58
 
46
- ## 输出格式
59
+ ### 项目分析
60
+
61
+ - `wot doctor [dir]`:检查项目依赖、运行环境与基础集成情况
62
+ - `wot usage [dir]`:统计 `.vue` 文件中的 `wd-*` 使用情况
63
+ - `wot lint [dir]`:检查未知组件、空按钮等规则
47
64
 
48
- 部分命令支持:
65
+ ### 通用参数
66
+
67
+ 多数查询命令支持以下参数:
49
68
 
50
69
  - `--format text`
51
70
  - `--format json`
@@ -53,41 +72,120 @@ wot mcp
53
72
  - `--lang en`
54
73
  - `--version v2`
55
74
 
56
- ## 提取数据
75
+ ## MCP 集成
76
+
77
+ 将以下配置加入支持 MCP 的客户端:
78
+
79
+ ```json
80
+ {
81
+ "mcpServers": {
82
+ "wot-ui": {
83
+ "command": "wot",
84
+ "args": ["mcp"]
85
+ }
86
+ }
87
+ }
88
+ ```
89
+
90
+ 当前 MCP Server 提供以下 tools:
91
+
92
+ - `wot_list`
93
+ - `wot_info`
94
+ - `wot_doc`
95
+ - `wot_demo`
96
+ - `wot_token`
97
+ - `wot_changelog`
98
+ - `wot_lint`
99
+
100
+ ## 数据来源
101
+
102
+ 当前版本聚焦 `wot-ui v2`。仓库内的离线数据来自 `wot-ui/wot-ui` 源码,主要提取自:
103
+
104
+ - `docs/component/*.md`
105
+ - `docs/guide/changelog.md`
106
+ - `src/uni_modules/wot-ui/components/*/index.scss`
107
+
108
+ 重新生成本地数据有两种方式。
57
109
 
58
110
  使用本地已有的 wot-ui 仓库:
59
111
 
60
112
  ```bash
61
- pnpm extract --wot-dir ../wot-ui --output ./data/v2.json
113
+ pnpm extract:cli --wot-dir ../wot-ui --output data/v2.json
62
114
  ```
63
115
 
64
- 如果希望直接克隆上游仓库并提取,建议在仓库根目录执行:
116
+ 直接克隆最新的 wot-ui 仓库并提取:
65
117
 
66
118
  ```bash
67
119
  pnpm extract:clone
68
120
  ```
69
121
 
70
- 提取脚本会输出当前处理阶段,包括数据源路径、扫描到的组件文档数量、解析结果与文件写入位置。
122
+ ## 开发本仓库
123
+
124
+ 当前根目录就是主发布包,核心源码位于 `src`,离线数据位于 `data`,提取脚本位于 `scripts`。
71
125
 
72
- ## 开发调试
126
+ ### 环境要求
73
127
 
74
- `packages/cli` 内开发时,最方便的方式是直接运行源码:
128
+ - Node.js `>= 20`
129
+ - pnpm `10.x`
130
+
131
+ ### 安装依赖
132
+
133
+ ```bash
134
+ pnpm install
135
+ ```
136
+
137
+ ### 常用开发命令
75
138
 
76
139
  ```bash
77
- pnpm --filter @wot-ui/cli exec tsx src/index.ts list
78
- pnpm --filter @wot-ui/cli exec tsx src/index.ts mcp
140
+ pnpm lint
141
+ pnpm test:all
142
+ pnpm build:all
143
+ pnpm typecheck:all
144
+ pnpm build:cli
145
+ pnpm test:cli
146
+ pnpm typecheck:cli
79
147
  ```
80
148
 
81
- 构建与测试命令:
149
+ ### 本地调试 CLI
150
+
151
+ 直接运行源码入口最方便:
82
152
 
83
153
  ```bash
84
- pnpm --filter @wot-ui/cli build
85
- pnpm --filter @wot-ui/cli test
86
- pnpm --filter @wot-ui/cli typecheck
154
+ pnpm exec tsx src/index.ts list
155
+ pnpm exec tsx src/index.ts info Button
87
156
  ```
88
157
 
158
+ 如果要调试构建产物:
159
+
160
+ ```bash
161
+ pnpm build:cli
162
+ node dist/index.mjs list
163
+ ```
164
+
165
+ ### 本地调试 MCP
166
+
167
+ ```bash
168
+ pnpm exec tsx src/index.ts mcp
169
+ ```
170
+
171
+ MCP 走 stdio,终端无交互输出属于正常现象。若要查看 tools 与 prompts 的调用过程,建议配合 MCP Inspector 或编辑器内置 MCP 客户端调试。
172
+
173
+ ## 自动化流程
174
+
175
+ - `.github/workflows/ci.yml`:执行主包的 lint、typecheck、build、test
176
+ - `.github/workflows/release.yml`:在 `v*` tag 上通过 reusable workflow 发布 `@wot-ui/cli`
177
+ - `.github/workflows/sync.yml`:拉取上游 `wot-ui/wot-ui`,提取最新元数据,并自动创建同步 PR
178
+
89
179
  ## 当前边界
90
180
 
91
181
  - 当前仅支持 `wot-ui v2`
92
- - `usage` `lint` 当前聚焦 `.vue` 文件
93
- - CSS 变量优先从组件 SCSS 源码提取
182
+ - `usage` `lint` 当前聚焦 `.vue` 文件中的 `<wd-*>` 标签及相关 import
183
+ - 提取脚本优先从 SCSS 源码解析 CSS 变量,并在必要时回退到 markdown 表格
184
+
185
+ ## 相关文档
186
+
187
+ - [CONTRIBUTING.md](CONTRIBUTING.md):贡献与开发流程
188
+
189
+ ## License
190
+
191
+ [MIT](./LICENSE) License © wot-ui
package/dist/index.mjs CHANGED
@@ -1,10 +1,22 @@
1
1
  #!/usr/bin/env node
2
- import { a as resolveVersion, i as listComponents, n as lintProject, o as loadMetadataFile, r as findComponent, t as analyzeUsage } from "./scanner-BFHnD5iE.mjs";
2
+ import { a as resolveVersion, i as listComponents, n as lintProject, o as loadMetadataFile, r as findComponent, s as version, t as analyzeUsage } from "./scanner-D0vLA-5K.mjs";
3
3
  import process from "node:process";
4
4
  import { Command } from "commander";
5
5
  import { existsSync, readFileSync } from "node:fs";
6
6
  import { join, resolve } from "node:path";
7
7
 
8
+ //#region src/utils/output.ts
9
+ function writeStdout(message) {
10
+ process.stdout.write(message);
11
+ }
12
+ function writeLine(message = "") {
13
+ writeStdout(`${message}\n`);
14
+ }
15
+ function writeJson(value) {
16
+ writeLine(JSON.stringify(value, null, 2));
17
+ }
18
+
19
+ //#endregion
8
20
  //#region src/commands/shared.ts
9
21
  function addQueryOptions(command) {
10
22
  return command.option("--format <format>", "output format: text, json, markdown", "text").option("--lang <lang>", "output language: zh, en", "zh").option("--version <version>", "target wot-ui version");
@@ -17,10 +29,10 @@ function normalizeQueryOptions(options) {
17
29
  };
18
30
  }
19
31
  function printError(message, format) {
20
- if (format === "json") console.log(JSON.stringify({
32
+ if (format === "json") writeJson({
21
33
  error: true,
22
34
  message
23
- }, null, 2));
35
+ });
24
36
  else console.error(message);
25
37
  }
26
38
  function getComponentLabel(component, lang) {
@@ -55,16 +67,15 @@ function registerChangelogCommand(program) {
55
67
  return versionMatches && componentMatches;
56
68
  });
57
69
  if (query.format === "json") {
58
- console.log(JSON.stringify({ entries }, null, 2));
70
+ writeJson({ entries });
59
71
  return;
60
72
  }
61
- const lines = entries.flatMap((entry) => [
73
+ writeLine(entries.flatMap((entry) => [
62
74
  `${entry.version}${entry.date ? ` (${entry.date})` : ""}`,
63
75
  entry.summary,
64
76
  ...entry.highlights.map((item) => `- ${item}`),
65
77
  ""
66
- ]);
67
- console.log(lines.join("\n").trim());
78
+ ]).join("\n").trim());
68
79
  } catch (error) {
69
80
  printError(error instanceof Error ? error.message : "Failed to load changelog", query.format);
70
81
  process.exitCode = 1;
@@ -87,13 +98,13 @@ function registerDemoCommand(program) {
87
98
  const demos = component.demos ?? [];
88
99
  if (!demoName) {
89
100
  if (query.format === "json") {
90
- console.log(JSON.stringify({
101
+ writeJson({
91
102
  component: component.name,
92
103
  demos
93
- }, null, 2));
104
+ });
94
105
  return;
95
106
  }
96
- console.log(demos.map((demo$1) => `- ${demo$1.name}: ${demo$1.title}`).join("\n"));
107
+ writeLine(demos.map((demo$1) => `- ${demo$1.name}: ${demo$1.title}`).join("\n"));
97
108
  return;
98
109
  }
99
110
  const demo = demos.find((item) => item.name.toLowerCase() === demoName.toLowerCase());
@@ -103,13 +114,13 @@ function registerDemoCommand(program) {
103
114
  return;
104
115
  }
105
116
  if (query.format === "json") {
106
- console.log(JSON.stringify({
117
+ writeJson({
107
118
  component: component.name,
108
119
  demo
109
- }, null, 2));
120
+ });
110
121
  return;
111
122
  }
112
- console.log(demo.code);
123
+ writeLine(demo.code);
113
124
  } catch (error) {
114
125
  printError(error instanceof Error ? error.message : "Failed to load demo", query.format);
115
126
  process.exitCode = 1;
@@ -130,13 +141,13 @@ function registerDocCommand(program) {
130
141
  return;
131
142
  }
132
143
  if (query.format === "json") {
133
- console.log(JSON.stringify({
144
+ writeJson({
134
145
  name: component.name,
135
146
  doc: component.doc
136
- }, null, 2));
147
+ });
137
148
  return;
138
149
  }
139
- console.log(component.doc);
150
+ writeLine(component.doc);
140
151
  } catch (error) {
141
152
  printError(error instanceof Error ? error.message : "Failed to load documentation", query.format);
142
153
  process.exitCode = 1;
@@ -156,8 +167,8 @@ function getDependencyVersion(pkg, name) {
156
167
  }
157
168
  function detectWotDependency(pkg) {
158
169
  for (const name of ["wot-design-uni", "wot-ui"]) {
159
- const version = getDependencyVersion(pkg, name);
160
- if (version) return `${name}@${version}`;
170
+ const version$1 = getDependencyVersion(pkg, name);
171
+ if (version$1) return `${name}@${version$1}`;
161
172
  }
162
173
  if (pkg?.dependencies) {
163
174
  const scoped = Object.keys(pkg.dependencies).find((name) => name.includes("wot"));
@@ -218,11 +229,10 @@ function registerDoctorCommand(program) {
218
229
  try {
219
230
  const report = diagnoseProject(resolve(dir));
220
231
  if (query.format === "json") {
221
- console.log(JSON.stringify(report, null, 2));
232
+ writeJson(report);
222
233
  return;
223
234
  }
224
- const lines = [`Directory: ${report.dir}`, ...report.checks.map((check) => `${check.status.toUpperCase()} ${check.name}: ${check.message}${check.suggestion ? ` | ${check.suggestion}` : ""}`)];
225
- console.log(lines.join("\n"));
235
+ writeLine([`Directory: ${report.dir}`, ...report.checks.map((check) => `${check.status.toUpperCase()} ${check.name}: ${check.message}${check.suggestion ? ` | ${check.suggestion}` : ""}`)].join("\n"));
226
236
  } catch (error) {
227
237
  printError(error instanceof Error ? error.message : "Failed to diagnose project", query.format);
228
238
  process.exitCode = 1;
@@ -243,10 +253,10 @@ function registerInfoCommand(program) {
243
253
  return;
244
254
  }
245
255
  if (query.format === "json") {
246
- console.log(JSON.stringify(component, null, 2));
256
+ writeJson(component);
247
257
  return;
248
258
  }
249
- const lines = [
259
+ writeLine([
250
260
  `${getComponentLabel(component, query.lang)} (${component.tag})`,
251
261
  getComponentDescription(component, query.lang),
252
262
  "",
@@ -264,8 +274,7 @@ function registerInfoCommand(program) {
264
274
  const defaultValue = cssVar.defaultValue ?? cssVar.token;
265
275
  return `- ${cssVar.name}${defaultValue ? ` = ${defaultValue}` : ""}: ${cssVar.description}`;
266
276
  })
267
- ];
268
- console.log(lines.join("\n"));
277
+ ].join("\n"));
269
278
  } catch (error) {
270
279
  printError(error instanceof Error ? error.message : "Failed to load component info", query.format);
271
280
  process.exitCode = 1;
@@ -281,15 +290,14 @@ function registerLintCommand(program) {
281
290
  try {
282
291
  const report = lintProject(resolve(dir), query.version);
283
292
  if (query.format === "json") {
284
- console.log(JSON.stringify(report, null, 2));
293
+ writeJson(report);
285
294
  return;
286
295
  }
287
296
  if (!report.issues.length) {
288
- console.log(`No lint issues found. Scanned files: ${report.scannedFiles}`);
297
+ writeLine(`No lint issues found. Scanned files: ${report.scannedFiles}`);
289
298
  return;
290
299
  }
291
- const lines = [`Scanned files: ${report.scannedFiles}`, ...report.issues.map((issue) => `${issue.severity.toUpperCase()} ${issue.file}:${issue.line} [${issue.rule}] ${issue.message}`)];
292
- console.log(lines.join("\n"));
300
+ writeLine([`Scanned files: ${report.scannedFiles}`, ...report.issues.map((issue) => `${issue.severity.toUpperCase()} ${issue.file}:${issue.line} [${issue.rule}] ${issue.message}`)].join("\n"));
293
301
  } catch (error) {
294
302
  printError(error instanceof Error ? error.message : "Failed to lint project", query.format);
295
303
  process.exitCode = 1;
@@ -305,11 +313,10 @@ function registerListCommand(program) {
305
313
  try {
306
314
  const components = listComponents(query.version);
307
315
  if (query.format === "json") {
308
- console.log(JSON.stringify({ components }, null, 2));
316
+ writeJson({ components });
309
317
  return;
310
318
  }
311
- const lines = components.map((component) => `- ${getComponentLabel(component, query.lang)} (${component.tag}): ${getComponentDescription(component, query.lang)}`);
312
- console.log(lines.join("\n"));
319
+ writeLine(components.map((component) => `- ${getComponentLabel(component, query.lang)} (${component.tag}): ${getComponentDescription(component, query.lang)}`).join("\n"));
313
320
  } catch (error) {
314
321
  printError(error instanceof Error ? error.message : "Failed to list components", query.format);
315
322
  process.exitCode = 1;
@@ -321,7 +328,7 @@ function registerListCommand(program) {
321
328
  //#region src/commands/mcp.ts
322
329
  function registerMcpCommand(program) {
323
330
  program.command("mcp").description("Start the wot-ui MCP server").action(async () => {
324
- const { startMcpServer } = await import("./server-HjZltXBO.mjs");
331
+ const { startMcpServer } = await import("./server-BWgY0XHJ.mjs");
325
332
  await startMcpServer();
326
333
  });
327
334
  }
@@ -333,11 +340,10 @@ function registerTokenCommand(program) {
333
340
  const query = normalizeQueryOptions(options);
334
341
  try {
335
342
  if (!componentName) {
336
- const tokens = listComponents(query.version).flatMap((component$1) => component$1.cssVars.map((cssVar) => ({
343
+ writeJson(listComponents(query.version).flatMap((component$1) => component$1.cssVars.map((cssVar) => ({
337
344
  component: component$1.name,
338
345
  ...cssVar
339
- })));
340
- console.log(JSON.stringify(tokens, null, 2));
346
+ }))));
341
347
  return;
342
348
  }
343
349
  const component = findComponent(componentName, query.version);
@@ -347,17 +353,16 @@ function registerTokenCommand(program) {
347
353
  return;
348
354
  }
349
355
  if (query.format === "json") {
350
- console.log(JSON.stringify({
356
+ writeJson({
351
357
  name: component.name,
352
358
  cssVars: formatCssVars(component.cssVars)
353
- }, null, 2));
359
+ });
354
360
  return;
355
361
  }
356
- const lines = [component.name, ...component.cssVars.map((cssVar) => {
362
+ writeLine([component.name, ...component.cssVars.map((cssVar) => {
357
363
  const defaultValue = cssVar.defaultValue ?? cssVar.token;
358
364
  return `- ${cssVar.name}${defaultValue ? ` = ${defaultValue}` : ""}: ${cssVar.description}`;
359
- })];
360
- console.log(lines.join("\n"));
365
+ })].join("\n"));
361
366
  } catch (error) {
362
367
  printError(error instanceof Error ? error.message : "Failed to query CSS variables", query.format);
363
368
  process.exitCode = 1;
@@ -373,7 +378,7 @@ function registerUsageCommand(program) {
373
378
  try {
374
379
  const report = analyzeUsage(resolve(dir), query.version);
375
380
  if (query.format === "json") {
376
- console.log(JSON.stringify(report, null, 2));
381
+ writeJson(report);
377
382
  return;
378
383
  }
379
384
  const lines = [
@@ -382,7 +387,7 @@ function registerUsageCommand(program) {
382
387
  ...report.components.map((component) => `- ${component.name} (${component.tag}): ${component.count} in ${component.files.join(", ")}`)
383
388
  ];
384
389
  if (report.imports.length) lines.push("", "Imports:", ...report.imports.map((item) => `- ${item}`));
385
- console.log(lines.join("\n"));
390
+ writeLine(lines.join("\n"));
386
391
  } catch (error) {
387
392
  printError(error instanceof Error ? error.message : "Failed to analyze project usage", query.format);
388
393
  process.exitCode = 1;
@@ -394,7 +399,7 @@ function registerUsageCommand(program) {
394
399
  //#region src/app.ts
395
400
  function createCliProgram() {
396
401
  const program = new Command();
397
- program.name("wot").description("wot-ui AI toolkit CLI").version("0.0.0");
402
+ program.name("wot").description("wot-ui AI toolkit CLI").version(version);
398
403
  registerListCommand(program);
399
404
  registerInfoCommand(program);
400
405
  registerDocCommand(program);
@@ -4,6 +4,10 @@ import { fileURLToPath } from "node:url";
4
4
  import { gunzipSync } from "node:zlib";
5
5
  import { parse } from "@vue/compiler-sfc";
6
6
 
7
+ //#region package.json
8
+ var version = "0.0.1-beta.6";
9
+
10
+ //#endregion
7
11
  //#region src/data/loader.ts
8
12
  const currentDir = dirname(fileURLToPath(import.meta.url));
9
13
  function resolveDataDir() {
@@ -48,15 +52,15 @@ function resolveVersion(requested) {
48
52
 
49
53
  //#endregion
50
54
  //#region src/data/metadata.ts
51
- function loadResolvedMetadata(version) {
52
- return loadMetadataFile(resolveVersion(version));
55
+ function loadResolvedMetadata(version$1) {
56
+ return loadMetadataFile(resolveVersion(version$1));
53
57
  }
54
- function listComponents(version) {
55
- return loadResolvedMetadata(version).components;
58
+ function listComponents(version$1) {
59
+ return loadResolvedMetadata(version$1).components;
56
60
  }
57
- function findComponent(name, version) {
61
+ function findComponent(name, version$1) {
58
62
  const normalized = name.trim().toLowerCase();
59
- return listComponents(version).find((component) => component.name.toLowerCase() === normalized || component.tag.toLowerCase() === normalized);
63
+ return listComponents(version$1).find((component) => component.name.toLowerCase() === normalized || component.tag.toLowerCase() === normalized);
60
64
  }
61
65
 
62
66
  //#endregion
@@ -114,10 +118,10 @@ function collectImports(scriptContent) {
114
118
  for (const match of scriptContent.matchAll(IMPORT_RE)) if (match[1]) imports.add(match[1]);
115
119
  return [...imports];
116
120
  }
117
- function analyzeUsage(targetDir, version) {
121
+ function analyzeUsage(targetDir, version$1) {
118
122
  const dir = resolve(targetDir);
119
123
  const files = walkFiles(dir, [".vue"]);
120
- const knownByTag = new Map(listComponents(version).map((component) => [component.tag.toLowerCase(), component]));
124
+ const knownByTag = new Map(listComponents(version$1).map((component) => [component.tag.toLowerCase(), component]));
121
125
  const usageMap = /* @__PURE__ */ new Map();
122
126
  const imports = /* @__PURE__ */ new Set();
123
127
  for (const file of files) {
@@ -148,7 +152,7 @@ function analyzeUsage(targetDir, version) {
148
152
  imports: [...imports].sort()
149
153
  };
150
154
  }
151
- function lintProject(targetDir, version) {
155
+ function lintProject(targetDir, version$1) {
152
156
  const dir = resolve(targetDir);
153
157
  const files = walkFiles(dir, [".vue"]);
154
158
  const issues = [];
@@ -157,7 +161,7 @@ function lintProject(targetDir, version) {
157
161
  for (const match of template.matchAll(TAG_RE)) {
158
162
  const tag = match[1]?.toLowerCase();
159
163
  if (!tag) continue;
160
- if (!findComponent(tag, version)) issues.push({
164
+ if (!findComponent(tag, version$1)) issues.push({
161
165
  file: safeRelative(dir, file),
162
166
  line: getLineNumber(template, match.index ?? 0),
163
167
  rule: "unknown-component",
@@ -175,7 +179,7 @@ function lintProject(targetDir, version) {
175
179
  severity: "warning",
176
180
  message: "wd-button should include visible text content or an icon attribute."
177
181
  });
178
- const component = findComponent("wd-button", version);
182
+ const component = findComponent("wd-button", version$1);
179
183
  for (const prop of component?.props ?? []) {
180
184
  if (!prop.deprecated) continue;
181
185
  if (!(/* @__PURE__ */ new RegExp(`\\b${prop.name}\\b`)).test(attrs)) continue;
@@ -196,4 +200,4 @@ function lintProject(targetDir, version) {
196
200
  }
197
201
 
198
202
  //#endregion
199
- export { resolveVersion as a, listComponents as i, lintProject as n, loadMetadataFile as o, findComponent as r, analyzeUsage as t };
203
+ export { resolveVersion as a, listComponents as i, lintProject as n, loadMetadataFile as o, findComponent as r, version as s, analyzeUsage as t };
@@ -1,4 +1,4 @@
1
- import { a as resolveVersion, i as listComponents, n as lintProject, o as loadMetadataFile, r as findComponent } from "./scanner-BFHnD5iE.mjs";
1
+ import { a as resolveVersion, i as listComponents, n as lintProject, o as loadMetadataFile, r as findComponent, s as version } from "./scanner-D0vLA-5K.mjs";
2
2
  import process from "node:process";
3
3
  import { McpServer, StdioServerTransport } from "@modelcontextprotocol/server";
4
4
  import * as z from "zod/v4";
@@ -31,10 +31,10 @@ function registerMcpTools(server) {
31
31
  idempotentHint: true,
32
32
  openWorldHint: false
33
33
  }
34
- }, async ({ version }) => {
34
+ }, async ({ version: version$1 }) => {
35
35
  return { content: [{
36
36
  type: "text",
37
- text: jsonText({ components: listComponents(version) })
37
+ text: jsonText({ components: listComponents(version$1) })
38
38
  }] };
39
39
  });
40
40
  server.registerTool("wot_info", {
@@ -49,8 +49,8 @@ function registerMcpTools(server) {
49
49
  idempotentHint: true,
50
50
  openWorldHint: false
51
51
  }
52
- }, async ({ component, version }) => {
53
- const result = findComponent(component, version);
52
+ }, async ({ component, version: version$1 }) => {
53
+ const result = findComponent(component, version$1);
54
54
  if (!result) return {
55
55
  isError: true,
56
56
  content: [{
@@ -75,8 +75,8 @@ function registerMcpTools(server) {
75
75
  idempotentHint: true,
76
76
  openWorldHint: false
77
77
  }
78
- }, async ({ component, version }) => {
79
- const result = findComponent(component, version);
78
+ }, async ({ component, version: version$1 }) => {
79
+ const result = findComponent(component, version$1);
80
80
  if (!result?.doc) return {
81
81
  isError: true,
82
82
  content: [{
@@ -102,8 +102,8 @@ function registerMcpTools(server) {
102
102
  idempotentHint: true,
103
103
  openWorldHint: false
104
104
  }
105
- }, async ({ component, demo, version }) => {
106
- const result = findComponent(component, version);
105
+ }, async ({ component, demo, version: version$1 }) => {
106
+ const result = findComponent(component, version$1);
107
107
  if (!result) return {
108
108
  isError: true,
109
109
  content: [{
@@ -140,15 +140,15 @@ function registerMcpTools(server) {
140
140
  idempotentHint: true,
141
141
  openWorldHint: false
142
142
  }
143
- }, async ({ component, version }) => {
143
+ }, async ({ component, version: version$1 }) => {
144
144
  if (!component) return { content: [{
145
145
  type: "text",
146
- text: jsonText({ components: listComponents(version).map((item) => ({
146
+ text: jsonText({ components: listComponents(version$1).map((item) => ({
147
147
  name: item.name,
148
148
  cssVars: item.cssVars
149
149
  })) })
150
150
  }] };
151
- const result = findComponent(component, version);
151
+ const result = findComponent(component, version$1);
152
152
  if (!result) return {
153
153
  isError: true,
154
154
  content: [{
@@ -176,11 +176,11 @@ function registerMcpTools(server) {
176
176
  idempotentHint: true,
177
177
  openWorldHint: false
178
178
  }
179
- }, async ({ version, component }) => {
179
+ }, async ({ version: version$1, component }) => {
180
180
  return { content: [{
181
181
  type: "text",
182
- text: jsonText({ entries: (loadMetadataFile(resolveVersion(version)).changelog ?? []).filter((entry) => {
183
- const versionMatches = version ? entry.version === version || `v${entry.version}` === version : true;
182
+ text: jsonText({ entries: (loadMetadataFile(resolveVersion(version$1)).changelog ?? []).filter((entry) => {
183
+ const versionMatches = version$1 ? entry.version === version$1 || `v${entry.version}` === version$1 : true;
184
184
  const componentMatches = component ? (entry.components ?? []).some((item) => item.toLowerCase() === component.toLowerCase()) : true;
185
185
  return versionMatches && componentMatches;
186
186
  }) })
@@ -198,10 +198,10 @@ function registerMcpTools(server) {
198
198
  idempotentHint: true,
199
199
  openWorldHint: true
200
200
  }
201
- }, async ({ dir, version }) => {
201
+ }, async ({ dir, version: version$1 }) => {
202
202
  return { content: [{
203
203
  type: "text",
204
- text: jsonText(lintProject(dir ?? process.cwd(), version))
204
+ text: jsonText(lintProject(dir ?? process.cwd(), version$1))
205
205
  }] };
206
206
  });
207
207
  }
@@ -211,7 +211,7 @@ function registerMcpTools(server) {
211
211
  async function startMcpServer() {
212
212
  const server = new McpServer({
213
213
  name: "wot-ui",
214
- version: "0.0.0"
214
+ version
215
215
  }, {
216
216
  instructions: "Use wot-ui component tools before generating UI code. Only wot-ui v2 metadata is available in this server.",
217
217
  capabilities: { logging: {} }
package/package.json CHANGED
@@ -1,15 +1,22 @@
1
1
  {
2
2
  "name": "@wot-ui/cli",
3
3
  "type": "module",
4
- "version": "0.0.1-beta.3",
5
- "description": "CLI, MCP and skills toolkit for wot-ui",
4
+ "version": "0.0.1-beta.6",
5
+ "description": "面向 wot-ui CLI、MCP 与数据提取工具集",
6
6
  "license": "MIT",
7
+ "funding": "https://github.com/sponsors/antfu",
7
8
  "homepage": "https://github.com/wot-ui/open-wot#readme",
8
9
  "repository": {
9
10
  "type": "git",
10
11
  "url": "git+https://github.com/wot-ui/open-wot.git"
11
12
  },
12
13
  "bugs": "https://github.com/wot-ui/open-wot/issues",
14
+ "keywords": [],
15
+ "sideEffects": false,
16
+ "exports": {
17
+ ".": "./dist/index.mjs",
18
+ "./package.json": "./package.json"
19
+ },
13
20
  "main": "./dist/index.mjs",
14
21
  "module": "./dist/index.mjs",
15
22
  "types": "./dist/index.d.mts",
@@ -18,32 +25,57 @@
18
25
  },
19
26
  "files": [
20
27
  "data",
21
- "dist",
22
- "skills"
28
+ "dist"
23
29
  ],
24
30
  "engines": {
25
31
  "node": ">=20.0.0"
26
32
  },
33
+ "dependencies": {
34
+ "@cfworker/json-schema": "^4.1.1",
35
+ "@modelcontextprotocol/server": "^2.0.0-alpha.2",
36
+ "@vue/compiler-sfc": "^3.5.13",
37
+ "commander": "^14.0.0",
38
+ "zod": "^4.1.12"
39
+ },
40
+ "devDependencies": {
41
+ "@antfu/eslint-config": "^6.6.1",
42
+ "@antfu/ni": "^28.0.0",
43
+ "@antfu/utils": "^9.3.0",
44
+ "@types/node": "^25.0.1",
45
+ "bumpp": "^10.3.2",
46
+ "eslint": "^9.39.2",
47
+ "lint-staged": "^16.2.7",
48
+ "publint": "^0.3.16",
49
+ "simple-git-hooks": "^2.13.1",
50
+ "tinyexec": "^1.0.2",
51
+ "tsdown": "^0.17.3",
52
+ "tsx": "^4.21.0",
53
+ "typescript": "^5.9.3",
54
+ "vitest": "^4.0.15",
55
+ "vitest-package-exports": "^0.1.1",
56
+ "yaml": "^2.8.2"
57
+ },
58
+ "simple-git-hooks": {
59
+ "pre-commit": "pnpm i --frozen-lockfile --ignore-scripts --offline && npx lint-staged"
60
+ },
61
+ "lint-staged": {
62
+ "*": "eslint --fix"
63
+ },
27
64
  "scripts": {
28
65
  "build": "tsdown",
29
66
  "dev": "tsdown --watch",
30
67
  "extract": "tsx scripts/extract.ts",
68
+ "extract:cli": "pnpm extract",
69
+ "extract:clone": "rm -rf /tmp/open-wot-wot-ui && git clone --depth 1 https://github.com/wot-ui/wot-ui.git /tmp/open-wot-wot-ui && pnpm extract --wot-dir /tmp/open-wot-wot-ui --output data/v2.json",
70
+ "lint": "eslint",
71
+ "release": "bumpp",
72
+ "start": "tsx src/index.ts",
31
73
  "test": "vitest run",
74
+ "test:all": "pnpm test",
75
+ "test:cli": "pnpm test",
32
76
  "test:watch": "vitest",
33
- "typecheck": "tsc --noEmit"
34
- },
35
- "dependencies": {
36
- "@cfworker/json-schema": "catalog:cli",
37
- "@modelcontextprotocol/server": "catalog:cli",
38
- "@vue/compiler-sfc": "catalog:cli",
39
- "commander": "catalog:cli",
40
- "zod": "catalog:cli"
41
- },
42
- "devDependencies": {
43
- "@types/node": "catalog:types",
44
- "tsdown": "catalog:cli",
45
- "tsx": "catalog:cli",
46
- "typescript": "catalog:cli",
47
- "vitest": "catalog:testing"
77
+ "typecheck": "tsc --noEmit",
78
+ "typecheck:all": "pnpm typecheck",
79
+ "typecheck:cli": "pnpm typecheck"
48
80
  }
49
- }
81
+ }
package/README.zh-CN.md DELETED
@@ -1,74 +0,0 @@
1
- # @wot-ui/cli
2
-
3
- 面向 wot-ui 的 CLI、MCP 与 Skills 工具集。
4
-
5
- ## 能力概览
6
-
7
- - 组件知识查询:`list`、`info`、`doc`、`demo`、`token`、`changelog`
8
- - 本地项目分析:`doctor`、`usage`、`lint`
9
- - 通过 `wot mcp` 启动 MCP stdio 服务
10
- - 通过提取脚本从 wot-ui 源码生成离线元数据
11
-
12
- ## 安装
13
-
14
- ```bash
15
- npm install -g @wot-ui/cli
16
- ```
17
-
18
- ## 命令示例
19
-
20
- ```bash
21
- wot list
22
- wot info Button
23
- wot doc Button
24
- wot demo Button basic
25
- wot token Button
26
- wot changelog
27
- wot doctor ./my-app
28
- wot usage ./my-app
29
- wot lint ./my-app
30
- wot mcp
31
- ```
32
-
33
- ## 命令说明
34
-
35
- - `wot list`:列出可用组件
36
- - `wot info <Component>`:查看组件详情
37
- - `wot doc <Component>`:输出组件 markdown 文档
38
- - `wot demo <Component> [name]`:查看 demo 列表或示例源码
39
- - `wot token [Component]`:查看 CSS 变量与默认值
40
- - `wot changelog [version] [component]`:查看更新记录
41
- - `wot doctor [dir]`:检查工程依赖与环境
42
- - `wot usage [dir]`:统计 `.vue` 中的 `wd-*` 使用情况
43
- - `wot lint [dir]`:执行 wot-ui 相关规则检查
44
- - `wot mcp`:启动 MCP stdio Server
45
-
46
- ## 提取命令
47
-
48
- 使用本地已有的 wot-ui 仓库:
49
-
50
- ```bash
51
- pnpm extract --wot-dir ../wot-ui --output ./data/v2.json
52
- ```
53
-
54
- 直接克隆上游仓库并提取:
55
-
56
- ```bash
57
- pnpm extract:clone
58
- ```
59
-
60
- ## 开发调试
61
-
62
- ```bash
63
- pnpm --filter @wot-ui/cli exec tsx src/index.ts list
64
- pnpm --filter @wot-ui/cli exec tsx src/index.ts mcp
65
- pnpm --filter @wot-ui/cli build
66
- pnpm --filter @wot-ui/cli test
67
- pnpm --filter @wot-ui/cli typecheck
68
- ```
69
-
70
- ## 当前边界
71
-
72
- - 当前只支持 wot-ui v2
73
- - `usage` 和 `lint` 当前只聚焦 `.vue` 文件
74
- - CSS 变量优先从组件 SCSS 源码提取
@@ -1,18 +0,0 @@
1
- ---
2
- name: wot-ui
3
- description: Query wot-ui component knowledge before generating or refactoring UI code.
4
- summary: Query wot-ui component knowledge before generating code.
5
- ---
6
-
7
- Use the local `wot` CLI before generating or refactoring wot-ui based code.
8
-
9
- Recommended workflow:
10
- 1. Run `wot list` to find the target component.
11
- 2. Run `wot info <Component>` to inspect props, events, slots, and CSS variables.
12
- 3. Run `wot doc <Component>` when you need the markdown documentation.
13
- 4. Run `wot token <Component>` when theme customization is involved.
14
-
15
- Current limitations:
16
- - Only wot-ui v2 is supported.
17
- - Bundled data is still a seed dataset until `pnpm extract` is run against the full wot-ui source repository.
18
- - `usage` and `lint` currently focus on `.vue` files.