diff --git a/packages/nutui-react-cli/.gitignore b/packages/nutui-react-cli/.gitignore new file mode 100644 index 0000000000..f3f54af74e --- /dev/null +++ b/packages/nutui-react-cli/.gitignore @@ -0,0 +1,5 @@ +node_modules +dist +data +.DS_Store +*.log diff --git a/packages/nutui-react-cli/README.md b/packages/nutui-react-cli/README.md new file mode 100644 index 0000000000..faf8f29486 --- /dev/null +++ b/packages/nutui-react-cli/README.md @@ -0,0 +1,124 @@ +# @nutui/nutui-react-cli + +面向 AI Coding 的 **NutUI React 离线知识查询 CLI**。把组件的 Props、文档、示例、Design Token 打包随包分发,让 AI 编程助手(Claude Code / Cursor / Copilot 等)从「猜 API」变成「查 API」,从根源消除 API 幻觉。 + +## 特点 + +- **完全离线、零 API Key**:组件元数据与文档/示例在构建期打包进入,安装后本地毫秒级查询。 +- **结构化输出**:所有命令支持 `--format json`,供 Agent 直接解析,而非正则抓文本。 +- **拼写纠错**:组件名大小写不敏感,未命中时给出「你是否想找」建议。 + +## 使用 + +免安装(推荐): + +```bash +npx -y @nutui/nutui-react-cli list +npx -y @nutui/nutui-react-cli info Button +``` + +或全局安装后用 `nutui-react` 命令: + +```bash +npm i -g @nutui/nutui-react-cli +nutui-react info Button --format json +``` + +## 命令 + +| 命令 | 说明 | +| --- | --- | +| `nutui-react list [--category ]` | 按分类列出全部组件(名称 / 中文名 / 版本) | +| `nutui-react info ` | 查看组件 Props 表(属性 / 说明 / 类型 / 默认值) | +| `nutui-react doc [--lang zh\|en]` | 查看组件完整文档,默认中文 | +| `nutui-react demo [name]` | 省略 `name` 列出全部示例;指定 `name`(如 `demo1`)输出源码 | +| `nutui-react token [Component]` | 查看 Design Token;省略组件名则列出全局 token | +| `nutui-react mcp` | 启动本地 MCP 服务(stdio),供 Claude Code / Cursor / VS Code / Codex 等 IDE 调用 | + +全局选项:`--format, -f `(默认 `text`)、`--help, -h`、`--version, -v`。 + +示例: + +```bash +nutui-react list --category feedback +nutui-react info Button --format json +nutui-react doc Button --lang en +nutui-react demo Button # 列出示例 +nutui-react demo Button demo1 # 查看某个示例源码 +nutui-react token Button +``` + +## MCP(IDE 集成) + +CLI 是「Agent 主动敲命令」,MCP 则把同一份能力注册成 IDE 原生工具,让 Claude Code / Cursor / VS Code / Codex 在对话中**按需自动调用**,无需拼命令行字符串。二者复用同一份离线 meta 快照,等于给同一个知识库套了两种调用协议。 + +`nutui-react mcp` 启动一个 stdio MCP 服务,暴露 5 个只读工具与 2 个提示词: + +| 工具 | 说明 | +| --- | --- | +| `nutui_list` | 列出全部组件(可按分类筛选) | +| `nutui_info` | 组件 Props 规格 | +| `nutui_doc` | 组件完整文档(`lang: zh\|en`) | +| `nutui_demo` | H5 示例列表 / 源码 | +| `nutui_token` | Design Token(全局 / 组件级) | + +| 提示词 | 说明 | +| --- | --- | +| `nutui-expert` | 把 Agent 定位为 NutUI React 专家(先查后写) | +| `nutui-page-generator` | 基于组件生成完整可运行页面 | + +### 客户端配置 + +**Claude Code**(`.mcp.json` 或 `claude mcp add`)、**Cursor**(`.cursor/mcp.json`)、**VS Code**(`.vscode/mcp.json` 的 `servers` 字段)通用配置: + +```json +{ + "mcpServers": { + "nutui-react": { + "command": "npx", + "args": ["-y", "@nutui/nutui-react-cli", "mcp"] + } + } +} +``` + +**Codex**(`~/.codex/config.toml`): + +```toml +[mcp_servers.nutui-react] +command = "npx" +args = ["-y", "@nutui/nutui-react-cli", "mcp"] +``` + +> `npx -y` 免全局安装即可拉起;也可全局安装后把 `command` 换成 `nutui-react`、`args` 换成 `["mcp"]`。 + +## CLI 内 Skill(教 Agent 何时用) + +CLI 内置一份 [Skill 文件](./skills/nutui-react/SKILL.md)(遵循 Anthropic Agent Skills 规范),随 npm 包一起分发。CLI / MCP 提供的是「能力」,Skill 则约束 Agent「**什么时候、按什么顺序**」用这些能力——例如「写组件前先 `nutui-react info` 查 Props、再 `nutui-react demo` 拿示例」「定制样式用 `var(--nutui-*)` token 而非硬编码颜色」。 + +安装(skill 已随包 bundle,装好 CLI 后从本地路径装进当前项目): + +```bash +npm i -D @nutui/nutui-react-cli +npx skills add ./node_modules/@nutui/nutui-react-cli/skills/nutui-react +``` + +兼容 Claude Code / Cursor / VS Code / Codex 等所有支持 [skills](https://github.com/vercel-labs/skills) 协议的 Agent。安装后,Agent 在遇到 NutUI React 相关任务时会自动遵循「先查后写」的流程。 + +## 本地开发 + +```bash +# 本包:构建(build 会先自动 generate:meta 再 prepare-data + tsup) +pnpm --dir packages/nutui-react-cli build +# 本地试跑 +node packages/nutui-react-cli/dist/cli.js list +``` + +## 发布 + +```bash +# 发布 beta(bumpp 选版本 -> prepublishOnly 跑 build -> pnpm publish --tag beta) +pnpm --dir packages/nutui-react-cli release:beta +# 或发布正式版 +pnpm --dir packages/nutui-react-cli release +``` diff --git a/packages/nutui-react-cli/package.json b/packages/nutui-react-cli/package.json new file mode 100644 index 0000000000..1d8322e23a --- /dev/null +++ b/packages/nutui-react-cli/package.json @@ -0,0 +1,55 @@ +{ + "name": "@nutui/nutui-react-cli", + "version": "0.1.0", + "type": "module", + "description": "NutUI React 面向 AI Coding 的离线知识查询 CLI:list / info / doc / demo / token。", + "keywords": [ + "nutui", + "nutui-react", + "cli", + "ai-coding", + "llm", + "react component" + ], + "license": "MIT", + "author": "jdcfe", + "homepage": "https://github.com/jdf2e/nutui-react.git", + "repository": { + "type": "git", + "url": "https://github.com/jdf2e/nutui-react.git" + }, + "bin": { + "nutui-react": "./dist/cli.js" + }, + "files": [ + "dist", + "data", + "skills" + ], + "engines": { + "node": ">=18.12.0" + }, + "publishConfig": { + "access": "public" + }, + "scripts": { + "prepare-data": "node scripts/prepare-data.mjs", + "build": "node scripts/prepare-data.mjs && tsup", + "dev": "tsup --watch", + "typecheck": "tsc --noEmit", + "prepublishOnly": "pnpm run build", + "release": "bumpp && pnpm publish", + "release:beta": "bumpp --preid beta && pnpm publish --tag beta" + }, + "dependencies": { + "@modelcontextprotocol/sdk": "^1.29.0", + "yargs": "^17.7.2" + }, + "devDependencies": { + "@types/node": "^22.5.5", + "@types/yargs": "^17.0.33", + "bumpp": "^9.5.2", + "tsup": "^8.3.0", + "typescript": "^5.6.2" + } +} diff --git a/packages/nutui-react-cli/scripts/prepare-data.mjs b/packages/nutui-react-cli/scripts/prepare-data.mjs new file mode 100644 index 0000000000..c4f3070506 --- /dev/null +++ b/packages/nutui-react-cli/scripts/prepare-data.mjs @@ -0,0 +1,114 @@ +// 读仓库根 meta/components.json,为 @nutui/nutui-react-cli 产出自包含的 data/ 快照。 +// 仅 React(H5)端:docs 取 h5(中文)/enUS(英文),demos 取 h5。忽略 zhTW / taro 维度。 +// 让发布后的 CLI 无需依赖仓库源码即可离线运行 doc / demo 命令。 +// 会先自动重生成 meta(generate:meta),无需手动同步。 +// DO NOT manual edit the output (data/). Run: pnpm run prepare-data +import fs from 'node:fs' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import { execFileSync } from 'node:child_process' + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) +const PKG_DIR = path.resolve(__dirname, '..') +// 仓库根:packages/nutui-react-cli/scripts -> ../../.. +const REPO_ROOT = path.resolve(PKG_DIR, '..', '..') +const META_PATH = path.join(REPO_ROOT, 'meta/components.json') +const BUILD_META_SCRIPT = path.join(REPO_ROOT, 'scripts/build-meta.mjs') +const DATA_DIR = path.join(PKG_DIR, 'data') + +// meta.docs 的 key -> CLI 语言维度。仅保留 React/H5 端用到的两种。 +const DOC_KEYS = ['h5', 'enUS'] + +// 先重生成 meta 再读,确保快照与仓库源码(config/properties/demos/...)同步, +// 免去手动 generate:meta 的漏同步风险。build-meta 纯读源码且幂等,可安全重复执行。 +function regenerateMeta() { + if (!fs.existsSync(BUILD_META_SCRIPT)) { + // 脱离 monorepo(如已发布包被重新 build),无源码可生成,沿用现有快照。 + console.log('ℹ️ 未找到 build-meta 脚本,跳过 meta 重生成(沿用现有快照)') + return + } + console.log('🔄 重新生成 meta/components.json(generate:meta)...') + execFileSync(process.execPath, [BUILD_META_SCRIPT], { stdio: 'inherit' }) +} + +function readMeta() { + try { + regenerateMeta() + } catch (err) { + // meta 生成失败:有旧快照则告警后沿用,否则无从继续。 + if (fs.existsSync(META_PATH)) { + console.warn( + `⚠️ meta 重生成失败(${err.message}),沿用现有 ${path.relative(REPO_ROOT, META_PATH)}` + ) + } else { + console.error( + `❌ meta 重生成失败且无现有快照:${err.message}\n` + + ` 请在仓库根手动执行:npm run generate:meta` + ) + process.exit(1) + } + } + if (!fs.existsSync(META_PATH)) { + console.error( + `❌ 未找到 ${path.relative(REPO_ROOT, META_PATH)}。\n` + + ` 它是构建产物,请先在仓库根执行:npm run generate:meta` + ) + process.exit(1) + } + return JSON.parse(fs.readFileSync(META_PATH, 'utf-8')) +} + +// meta 里的路径始终是 posix 相对仓库根路径,用 posix 取 basename,再 join 到本地。 +function copyRepoFile(relPosixPath, destAbs) { + const srcAbs = path.join(REPO_ROOT, relPosixPath) + if (!fs.existsSync(srcAbs)) return false + fs.mkdirSync(path.dirname(destAbs), { recursive: true }) + fs.copyFileSync(srcAbs, destAbs) + return true +} + +function main() { + console.log('🚀 building @nutui/nutui-react-cli data snapshot (React/H5) ...') + const meta = readMeta() + + // 全量重建,避免残留上一版删掉的组件。 + fs.rmSync(DATA_DIR, { recursive: true, force: true }) + fs.mkdirSync(DATA_DIR, { recursive: true }) + + // 1. meta.json 逐字复制。 + fs.copyFileSync(META_PATH, path.join(DATA_DIR, 'meta.json')) + + let docCount = 0 + let demoCount = 0 + const missing = [] + + for (const c of Object.values(meta.components)) { + // 2. docs:仅 h5 / enUS 的非 null 路径。 + for (const key of DOC_KEYS) { + const rel = c.docs && c.docs[key] + if (!rel) continue + const ok = copyRepoFile(rel, path.join(DATA_DIR, 'docs', c.id, `${key}.md`)) + if (ok) docCount++ + else missing.push(rel) + } + + // 3. demos:仅 H5,扁平放到 data/demos//.tsx(无 platform 子层)。 + const h5Demos = (c.demos && c.demos.h5) || [] + for (const rel of h5Demos) { + const base = path.posix.basename(rel) + const ok = copyRepoFile(rel, path.join(DATA_DIR, 'demos', c.id, base)) + if (ok) demoCount++ + else missing.push(rel) + } + } + + console.log(`✅ 写入 ${path.relative(PKG_DIR, DATA_DIR)}/`) + console.log(` meta.json + docs ${docCount} 份 + demos ${demoCount} 份`) + if (missing.length) { + console.log(`\n⚠️ ${missing.length} 个 meta 引用的文件在仓库中缺失(已跳过):`) + for (const m of missing.slice(0, 20)) console.log(` - ${m}`) + if (missing.length > 20) console.log(` … 其余 ${missing.length - 20} 条省略`) + } +} + +main() diff --git a/packages/nutui-react-cli/skills/.npmignore b/packages/nutui-react-cli/skills/.npmignore new file mode 100644 index 0000000000..cf7098890e --- /dev/null +++ b/packages/nutui-react-cli/skills/.npmignore @@ -0,0 +1 @@ +**/node_modules diff --git a/packages/nutui-react-cli/skills/nutui-react/SKILL.md b/packages/nutui-react-cli/skills/nutui-react/SKILL.md new file mode 100644 index 0000000000..ddbc3dfdac --- /dev/null +++ b/packages/nutui-react-cli/skills/nutui-react/SKILL.md @@ -0,0 +1,135 @@ +--- +name: nutui-react +description: > + Use when the user's task involves NutUI React (@nutui/nutui-react) — writing + NutUI React components, debugging NutUI issues, or querying NutUI component + APIs/props/docs/demos/design-tokens. Triggers on NutUI-related code, imports + from '@nutui/nutui-react', or explicit NutUI questions. NutUI React is JD's + lightweight mobile (H5) component library. +allowed-tools: + - Bash(nutui-react *) + - Bash(npx -y @nutui/nutui-react-cli *) + - Bash(which nutui-react) +--- + +# NutUI React CLI + +You have access to `@nutui/nutui-react-cli` — a local CLI tool with bundled NutUI React metadata (component props, full docs, runnable demos, and Design Tokens). Use it to query component knowledge before writing code. All data is offline and packaged with the CLI — no network and no API key needed. + +## Setup + +Before first use, check if the CLI is available. If not, invoke it via `npx` (no global install required): + +```bash +which nutui-react || echo "use: npx -y @nutui/nutui-react-cli " +``` + +Both forms work — use whichever is available: + +- Installed globally: `nutui-react info Button` +- Via npx (no install): `npx -y @nutui/nutui-react-cli info Button` + +Examples below use the `nutui-react` form for brevity. + +**Always pass `--format json` for structured output you can parse programmatically** (default output is human-readable `text`). + +## Scenarios + +### 1. Writing NutUI React component code + +Before writing any NutUI component code, look up its API first — don't rely on memory. + +```bash +# Check what props are available (grouped by table, e.g. Props / sub-component props) +nutui-react info Button --format json + +# Get a runnable demo as a starting point +nutui-react demo Button # list all demo names first +nutui-react demo Button demo1 --format json # then fetch one demo's source + +# Check component-level Design Tokens for theming (var(--nutui-*) system) +nutui-react token Button --format json +``` + +**Workflow:** `nutui-react info` → understand props → `nutui-react demo` → grab a runnable example → write code. + +### 2. Looking up full documentation + +When you need comprehensive component docs (not just the props table): + +```bash +nutui-react doc Cell --format json # full markdown docs (Chinese, default) +nutui-react doc Cell --lang en --format json # English docs +``` + +`--lang` accepts `zh` (default) or `en`. + +### 3. Exploring available components + +When the user is choosing which component to use, or you need to confirm a component exists before importing it: + +```bash +# List all components with Chinese name and version, grouped by category +nutui-react list --format json + +# Filter to a category (pass the category enName, e.g. base / feedback / nav) +nutui-react list --category feedback --format json +``` + +If you query a component name that doesn't exist, the CLI returns a "did you mean" suggestion (e.g. `Buttn` → `Button`) — use it to correct the name rather than guessing. + +### 4. Querying Design Tokens + +When customizing theme/colors/spacing, use the `var(--nutui-*)` token system rather than hardcoding values: + +```bash +# Global tokens (colors, spacing, radius, etc.) +nutui-react token --format json + +# Component-level tokens +nutui-react token Button --format json +``` + +### 5. Using as an MCP server + +If working in an IDE that supports MCP (Claude Code, Cursor, VS Code, Codex, etc.), the CLI can run as a local stdio MCP server, exposing the same knowledge-query capabilities as IDE-native tools: + +```json +{ + "mcpServers": { + "nutui-react": { + "command": "npx", + "args": ["-y", "@nutui/nutui-react-cli", "mcp"] + } + } +} +``` + +This provides 5 tools (`nutui_list`, `nutui_info`, `nutui_doc`, `nutui_demo`, `nutui_token`) and 2 prompts (`nutui-expert`, `nutui-page-generator`) via the MCP protocol. When these tools are available in the conversation, prefer calling them directly over shelling out to the CLI. + +## Commands + +| Command | Purpose | +| --- | --- | +| `nutui-react list [--category ]` | List all components (name / Chinese name / version), grouped by category | +| `nutui-react info ` | Component props table (prop / desc / type / default), grouped by table | +| `nutui-react doc [--lang zh\|en]` | Full component markdown docs (default Chinese) | +| `nutui-react demo [name]` | Omit `name` to list demos; pass `name` (e.g. `demo1`) for source | +| `nutui-react token [Component]` | Design Tokens — omit component for global tokens | +| `nutui-react mcp` | Start a local stdio MCP server for IDE integration | + +## Global Flags + +| Flag | Purpose | +| --- | --- | +| `--format, -f ` | Output format; agents should prefer `json` (default: `text`) | +| `--lang, -l ` | Doc language for `doc` / `mcp` (default: `zh`) | +| `--help, -h` | Show help | +| `--version, -v` | Print CLI version | + +## Key Rules + +1. **Always query before writing** — Don't guess NutUI APIs, prop names, or enum values from memory. Run `nutui-react info` (and `nutui-react demo` for a working example) first. +2. **Use `--format json`** — Every command supports it. Parse the JSON output rather than regex-matching the human-readable text. +3. **Confirm the component exists** — If unsure of the exact name, run `nutui-react list` or rely on the CLI's "did you mean" suggestion instead of importing a guessed name. +4. **Use Design Tokens for styling** — NutUI uses `nut-` flat BEM class names and the `var(--nutui-*)` token system. When customizing appearance, query `nutui-react token` and use tokens rather than hardcoding colors or spacing. diff --git a/packages/nutui-react-cli/src/cli.ts b/packages/nutui-react-cli/src/cli.ts new file mode 100644 index 0000000000..e2d55faeab --- /dev/null +++ b/packages/nutui-react-cli/src/cli.ts @@ -0,0 +1,124 @@ +import yargs from 'yargs' +import { hideBin } from 'yargs/helpers' +import { runList } from './commands/list.js' +import { runInfo } from './commands/info.js' +import { runDoc } from './commands/doc.js' +import { runDemo } from './commands/demo.js' +import { runToken } from './commands/token.js' +import { runMcp } from './commands/mcp.js' +import type { Lang, OutputFormat } from './types.js' + +// eslint-disable-next-line @typescript-eslint/no-floating-promises +yargs(hideBin(process.argv)) + .scriptName('nutui-react') + .usage('$0 [options]') + .option('format', { + alias: 'f', + describe: '输出格式', + choices: ['text', 'json'] as const, + default: 'text' as OutputFormat, + global: true, + }) + .command( + ['list', 'ls'], + '列出全部组件(按分类)', + (y) => + y.option('category', { + alias: 'c', + type: 'string', + describe: '按分类 enName 筛选(如 base / feedback)', + }), + (argv) => + runList({ category: argv.category, format: argv.format as OutputFormat }) + ) + .command( + 'info ', + '查看组件 Props 表', + (y) => + y.positional('component', { + type: 'string', + describe: '组件名(大小写不敏感,如 Button)', + demandOption: true, + }), + (argv) => + runInfo({ + component: argv.component as string, + format: argv.format as OutputFormat, + }) + ) + .command( + 'doc ', + '查看组件完整文档', + (y) => + y + .positional('component', { + type: 'string', + describe: '组件名(大小写不敏感)', + demandOption: true, + }) + .option('lang', { + alias: 'l', + choices: ['zh', 'en'] as const, + default: 'zh' as Lang, + describe: '文档语言', + }), + (argv) => + runDoc({ + component: argv.component as string, + lang: argv.lang as Lang, + format: argv.format as OutputFormat, + }) + ) + .command( + 'demo [name]', + '列出或查看组件 H5 示例源码', + (y) => + y + .positional('component', { + type: 'string', + describe: '组件名(大小写不敏感)', + demandOption: true, + }) + .positional('name', { + type: 'string', + describe: '示例名(如 demo1);省略则列出全部', + }), + (argv) => + runDemo({ + component: argv.component as string, + name: argv.name as string | undefined, + format: argv.format as OutputFormat, + }) + ) + .command( + 'token [component]', + '查看 Design Token(省略组件名则列全局 token)', + (y) => + y.positional('component', { + type: 'string', + describe: '组件名(大小写不敏感);省略则列出全局 token', + }), + (argv) => + runToken({ + component: argv.component as string | undefined, + format: argv.format as OutputFormat, + }) + ) + .command( + 'mcp', + '启动本地 MCP 服务(stdio),供 Claude Code / Cursor / VS Code / Codex 等调用', + (y) => + y.option('lang', { + alias: 'l', + choices: ['zh', 'en'] as const, + default: 'zh' as Lang, + describe: '默认文档语言(工具未显式指定 lang 时生效)', + }), + (argv) => runMcp({ lang: argv.lang as Lang }) + ) + .demandCommand(1, '请指定一个命令。运行 nutui-react --help 查看用法。') + .strict() + .alias('h', 'help') + .alias('v', 'version') + .wrap(null) + .parse() diff --git a/packages/nutui-react-cli/src/commands/_shared.ts b/packages/nutui-react-cli/src/commands/_shared.ts new file mode 100644 index 0000000000..3c48acfdce --- /dev/null +++ b/packages/nutui-react-cli/src/commands/_shared.ts @@ -0,0 +1,14 @@ +// 命令间共享:解析组件名,未命中则打印 did-you-mean 并退出。 +import { resolveComponent, suggestComponents } from '../data.js' +import type { Component, Meta } from '../types.js' + +export function resolveOrExit(meta: Meta, query: string): Component { + const comp = resolveComponent(meta, query) + if (comp) return comp + const suggestions = suggestComponents(meta, query) + let msg = `未找到组件「${query}」。` + if (suggestions.length) msg += ` 你是否想找:${suggestions.join(' / ')}?` + msg += `\n运行 nutui-react list 查看全部组件。` + process.stderr.write(`${msg}\n`) + process.exit(1) +} diff --git a/packages/nutui-react-cli/src/commands/demo.ts b/packages/nutui-react-cli/src/commands/demo.ts new file mode 100644 index 0000000000..df64564c30 --- /dev/null +++ b/packages/nutui-react-cli/src/commands/demo.ts @@ -0,0 +1,51 @@ +// nutui-react demo [name] —— 列出或输出 H5 demo 源码。 +import { listDemos, loadMeta, readDemo } from '../data.js' +import { output } from '../format.js' +import { resolveOrExit } from './_shared.js' +import type { OutputFormat } from '../types.js' + +export interface DemoArgs { + component: string + name?: string + format: OutputFormat +} + +export function runDemo(args: DemoArgs): void { + const meta = loadMeta() + const comp = resolveOrExit(meta, args.component) + const demos = listDemos(comp) + + // 无 name:列出全部 demo 文件名。 + if (!args.name) { + const jsonData = { id: comp.id, name: comp.name, demos } + output(args.format, jsonData, () => { + if (!demos.length) return `${comp.name} ${comp.cName} 暂无 H5 示例。` + return `${comp.name} ${comp.cName} 的 H5 示例(${demos.length} 个):\n${demos + .map((d) => ` - ${d}`) + .join('\n')}\n\n查看源码:nutui-react demo ${comp.name} ${demos[0]}` + }) + return + } + + // 有 name:输出该 demo 源码。 + const code = readDemo(comp, args.name) + if (code === null) { + const jsonData = { + id: comp.id, + name: comp.name, + demo: args.name, + code: null, + } + output(args.format, jsonData, () => { + const avail = demos.length + ? `可选:${demos.join(' / ')}` + : '该组件暂无 H5 示例' + return `未找到示例「${args.name}」。${avail}` + }) + process.exitCode = 1 + return + } + + const jsonData = { id: comp.id, name: comp.name, demo: args.name, code } + output(args.format, jsonData, () => code) +} diff --git a/packages/nutui-react-cli/src/commands/doc.ts b/packages/nutui-react-cli/src/commands/doc.ts new file mode 100644 index 0000000000..ea9d2936d8 --- /dev/null +++ b/packages/nutui-react-cli/src/commands/doc.ts @@ -0,0 +1,34 @@ +// nutui-react doc [--lang zh|en] —— 输出组件完整文档原文。 +import { loadMeta, readDoc } from '../data.js' +import { output } from '../format.js' +import { resolveOrExit } from './_shared.js' +import type { Lang, OutputFormat } from '../types.js' + +export interface DocArgs { + component: string + lang: Lang + format: OutputFormat +} + +export function runDoc(args: DocArgs): void { + const meta = loadMeta() + const comp = resolveOrExit(meta, args.component) + const content = readDoc(comp, args.lang) + + if (content === null) { + const jsonData = { + id: comp.id, + name: comp.name, + lang: args.lang, + content: null, + } + output(args.format, jsonData, () => { + const langName = args.lang === 'en' ? '英文' : '中文' + return `${comp.name} ${comp.cName} 暂无${langName}文档(可能是隐藏子组件)。` + }) + return + } + + const jsonData = { id: comp.id, name: comp.name, lang: args.lang, content } + output(args.format, jsonData, () => content) +} diff --git a/packages/nutui-react-cli/src/commands/info.ts b/packages/nutui-react-cli/src/commands/info.ts new file mode 100644 index 0000000000..cfbb3b82b6 --- /dev/null +++ b/packages/nutui-react-cli/src/commands/info.ts @@ -0,0 +1,48 @@ +// nutui-react info —— 输出组件 Props 表。 +import { loadMeta } from '../data.js' +import { output, renderTable } from '../format.js' +import { resolveOrExit } from './_shared.js' +import type { OutputFormat } from '../types.js' + +export interface InfoArgs { + component: string + format: OutputFormat +} + +export function runInfo(args: InfoArgs): void { + const meta = loadMeta() + const comp = resolveOrExit(meta, args.component) + const tables = comp.api?.tables ?? [] + const propTables = tables.filter((t) => t.kind === 'props') + + const jsonData = { + id: comp.id, + name: comp.name, + cName: comp.cName, + version: comp.version, + tables: propTables.map((t) => ({ + name: t.name, + subComponent: t.subComponent, + rows: t.rows, + })), + } + + output(args.format, jsonData, () => { + if (!propTables.length) { + const others = tables.map((t) => `${t.name}(${t.kind})`).join('、') + let msg = `${comp.name} ${comp.cName} 没有 Props 表` + msg += others + ? `。它可能是布局/子组件;现有其它表:${others}。` + : `(可能是布局或纯样式组件)。` + return msg + } + const blocks = propTables.map((t) => { + const title = t.subComponent + ? `${t.name}(${comp.name}.${t.subComponent})` + : t.name + const rows = t.rows.map((r) => [r.prop, r.desc, r.type, r.default]) + return `▍${title}\n${renderTable(['属性', '说明', '类型', '默认值'], rows)}` + }) + return `${comp.name} ${comp.cName}(v${comp.version})\n\n${blocks.join('\n\n')}` + }) +} diff --git a/packages/nutui-react-cli/src/commands/list.ts b/packages/nutui-react-cli/src/commands/list.ts new file mode 100644 index 0000000000..1e14e1aaf3 --- /dev/null +++ b/packages/nutui-react-cli/src/commands/list.ts @@ -0,0 +1,56 @@ +// nutui-react list —— 按分类列出组件。 +import { loadMeta } from '../data.js' +import { output, renderTable } from '../format.js' +import type { OutputFormat } from '../types.js' + +export interface ListArgs { + category?: string + format: OutputFormat +} + +export function runList(args: ListArgs): void { + const meta = loadMeta() + let categories = meta.categories + if (args.category) { + const key = args.category.toLowerCase() + categories = categories.filter( + (c) => c.enName.toLowerCase() === key || c.name === args.category + ) + if (!categories.length) { + const all = meta.categories.map((c) => c.enName).join(' / ') + process.stderr.write(`未找到分类「${args.category}」。可选:${all}\n`) + process.exit(1) + } + } + + const jsonData = categories.map((cat) => ({ + name: cat.name, + enName: cat.enName, + components: cat.components + .map((id) => meta.components[id]) + .filter(Boolean) + .map((c) => ({ + id: c.id, + name: c.name, + cName: c.cName, + version: c.version, + })), + })) + + output(args.format, jsonData, () => { + const blocks: string[] = [] + let total = 0 + for (const cat of categories) { + const comps = cat.components + .map((id) => meta.components[id]) + .filter(Boolean) + total += comps.length + const rows = comps.map((c) => [c.name, c.cName ?? '', c.version ?? '']) + blocks.push( + `▍${cat.name} (${cat.enName})\n${renderTable(['组件', '中文名', '版本'], rows)}` + ) + } + const header = `NutUI React(H5)共 ${meta.componentCount} 个组件,版本 ${meta.libVersion}` + return `${header}\n\n${blocks.join('\n\n')}\n\n合计:${total} 个` + }) +} diff --git a/packages/nutui-react-cli/src/commands/mcp.ts b/packages/nutui-react-cli/src/commands/mcp.ts new file mode 100644 index 0000000000..f486864888 --- /dev/null +++ b/packages/nutui-react-cli/src/commands/mcp.ts @@ -0,0 +1,99 @@ +// nutui-react mcp —— 启动本地 MCP(stdio)服务,供 Claude Code / Cursor / VS Code / Codex +// 等客户端按需调用。复用与 CLI 命令相同的 meta 快照与查询原语。 +import { Server } from '@modelcontextprotocol/sdk/server/index.js' +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js' +import { + CallToolRequestSchema, + GetPromptRequestSchema, + ListPromptsRequestSchema, + ListToolsRequestSchema, +} from '@modelcontextprotocol/sdk/types.js' +import { createToolHandler, TOOL_DEFINITIONS } from '../mcp/tools.js' +import { + NUTUI_EXPERT_PROMPT, + NUTUI_PAGE_GENERATOR_PROMPT, +} from '../mcp/prompts.js' +import type { Lang } from '../types.js' + +// tsup define 注入的包版本号。 +declare const __CLI_VERSION__: string + +const PROMPTS = [ + { + name: 'nutui-expert', + description: 'NutUI React 专家助手:先查文档再写代码', + content: NUTUI_EXPERT_PROMPT, + }, + { + name: 'nutui-page-generator', + description: '基于 NutUI React 组件生成完整可运行页面', + content: NUTUI_PAGE_GENERATOR_PROMPT, + }, +] + +export interface McpArgs { + lang: Lang +} + +export async function runMcp(args: McpArgs): Promise { + // 在 TTY 直接运行时给出提示(MCP 走 stdio,不该在终端裸跑)。 + if (process.stdin.isTTY) { + process.stderr.write( + [ + 'NutUI React MCP Server', + '', + '该命令启动一个通过 stdio 通信的 MCP 服务,不应在终端直接运行。', + '请在 AI 工具中如下配置:', + '', + ' {', + ' "mcpServers": {', + ' "nutui-react": {', + ' "command": "npx",', + ' "args": ["-y", "@nutui/nutui-react-cli", "mcp"]', + ' }', + ' }', + ' }', + '', + '支持的客户端:Claude Code、Cursor、VS Code、Codex 等。', + '正在 stdio 上启动 MCP 服务……', + '', + ].join('\n') + ) + } + + const server = new Server( + { name: 'nutui-react', version: __CLI_VERSION__ }, + { capabilities: { tools: {}, prompts: {} } } + ) + + const handleTool = createToolHandler({ lang: args.lang }) + + server.setRequestHandler(ListToolsRequestSchema, async () => ({ + tools: TOOL_DEFINITIONS, + })) + + server.setRequestHandler(CallToolRequestSchema, async (request) => { + const { name, arguments: params } = request.params + return handleTool(name, (params as Record) ?? {}) + }) + + server.setRequestHandler(ListPromptsRequestSchema, async () => ({ + prompts: PROMPTS.map(({ name, description }) => ({ name, description })), + })) + + server.setRequestHandler(GetPromptRequestSchema, async (request) => { + const found = PROMPTS.find((p) => p.name === request.params.name) + if (!found) throw new Error(`未知提示词:${request.params.name}`) + return { + messages: [ + { + role: 'user' as const, + content: { type: 'text' as const, text: found.content }, + }, + ], + } + }) + + const transport = new StdioServerTransport() + await server.connect(transport) +} diff --git a/packages/nutui-react-cli/src/commands/token.ts b/packages/nutui-react-cli/src/commands/token.ts new file mode 100644 index 0000000000..f610890fd0 --- /dev/null +++ b/packages/nutui-react-cli/src/commands/token.ts @@ -0,0 +1,43 @@ +// nutui-react token [Component] —— 输出 Design Token。无参列全局 token,有参列组件 token。 +import { loadMeta } from '../data.js' +import { output, renderTable } from '../format.js' +import { resolveOrExit } from './_shared.js' +import type { OutputFormat, Token } from '../types.js' + +export interface TokenArgs { + component?: string + format: OutputFormat +} + +export function runToken(args: TokenArgs): void { + const meta = loadMeta() + + // 无参:全局 token。 + if (!args.component) { + output(args.format, { scope: 'global', tokens: meta.globalTokens }, () => + renderTokenText( + `NutUI React 全局 Design Token(${meta.globalTokens.length} 个)`, + meta.globalTokens + ) + ) + return + } + + // 有参:组件 token。 + const comp = resolveOrExit(meta, args.component) + const tokens = comp.tokens ?? [] + output(args.format, { scope: comp.id, name: comp.name, tokens }, () => { + if (!tokens.length) { + return `${comp.name} ${comp.cName} 无专属 Design Token(可运行 nutui-react token 查看全局 token)。` + } + return renderTokenText( + `${comp.name} ${comp.cName} 的 Design Token(${tokens.length} 个)`, + tokens + ) + }) +} + +function renderTokenText(title: string, tokens: Token[]): string { + const rows = tokens.map((t) => [t.cssVar, t.scssVar, t.default ?? '']) + return `${title}\n${renderTable(['CSS 变量', 'SCSS 变量', '默认值'], rows)}` +} diff --git a/packages/nutui-react-cli/src/data.ts b/packages/nutui-react-cli/src/data.ts new file mode 100644 index 0000000000..32530c16b7 --- /dev/null +++ b/packages/nutui-react-cli/src/data.ts @@ -0,0 +1,97 @@ +// 定位随包发布的 data/ 快照,加载 meta 与 doc/demo 文件。 +import fs from 'node:fs' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import type { Component, Lang, Meta } from './types.js' +import { LANG_TO_DOC_KEY } from './types.js' + +// dist/cli.js 运行时,data/ 与 dist/ 同级(见 package.json files: [dist, data])。 +const DATA_DIR = fileURLToPath(new URL('../data/', import.meta.url)) + +let cachedMeta: Meta | null = null + +export function loadMeta(): Meta { + if (cachedMeta) return cachedMeta + const metaPath = path.join(DATA_DIR, 'meta.json') + if (!fs.existsSync(metaPath)) { + throw new Error( + `未找到打包数据 ${metaPath}。若为源码开发,请先运行 pnpm run build(或 pnpm run prepare-data)。` + ) + } + cachedMeta = JSON.parse(fs.readFileSync(metaPath, 'utf-8')) as Meta + return cachedMeta +} + +// 组件名大小写不敏感解析:Button / button / BUTTON 均可。命中返回组件,否则 null。 +export function resolveComponent(meta: Meta, query: string): Component | null { + const id = query.trim().toLowerCase() + return meta.components[id] ?? null +} + +// Levenshtein 编辑距离,用于未命中时的 did-you-mean 建议。 +function editDistance(a: string, b: string): number { + const dp = Array.from({ length: a.length + 1 }, (_, i) => [ + i, + ...Array(b.length).fill(0), + ]) + for (let j = 0; j <= b.length; j++) dp[0][j] = j + for (let i = 1; i <= a.length; i++) { + for (let j = 1; j <= b.length; j++) { + const cost = a[i - 1] === b[j - 1] ? 0 : 1 + dp[i][j] = Math.min( + dp[i - 1][j] + 1, + dp[i][j - 1] + 1, + dp[i - 1][j - 1] + cost + ) + } + } + return dp[a.length][b.length] +} + +// 返回与 query 最接近的若干组件名(用于「did you mean」)。 +export function suggestComponents( + meta: Meta, + query: string, + limit = 3 +): string[] { + const q = query.trim().toLowerCase() + return Object.values(meta.components) + .map((c) => ({ name: c.name, d: editDistance(q, c.id) })) + .sort((a, b) => a.d - b.d) + .slice(0, limit) + .filter((x) => x.d <= Math.max(3, Math.ceil(q.length / 2))) + .map((x) => x.name) +} + +// 读取组件某语言的文档原文。缺失返回 null。 +export function readDoc(component: Component, lang: Lang): string | null { + const key = LANG_TO_DOC_KEY[lang] + const file = path.join(DATA_DIR, 'docs', component.id, `${key}.md`) + return fs.existsSync(file) ? fs.readFileSync(file, 'utf-8') : null +} + +// 列出组件的全部 H5 demo 文件名(不含扩展名,如 demo1),按序号排序。 +export function listDemos(component: Component): string[] { + const dir = path.join(DATA_DIR, 'demos', component.id) + if (!fs.existsSync(dir)) return [] + return fs + .readdirSync(dir) + .filter((f) => f.endsWith('.tsx')) + .map((f) => f.replace(/\.tsx$/, '')) + .sort((a, b) => { + const na = Number(a.replace(/\D/g, '')) + const nb = Number(b.replace(/\D/g, '')) + return Number.isNaN(na) || Number.isNaN(nb) ? a.localeCompare(b) : na - nb + }) +} + +// 读取组件某个 demo 的源码。name 形如 demo1(也容忍带 .tsx)。缺失返回 null。 +export function readDemo(component: Component, name: string): string | null { + // 防御路径穿越:确保 name 中不包含路径分隔符 + if (name.includes('/') || name.includes('\\')) { + return null + } + const base = name.endsWith('.tsx') ? name : `${name}.tsx` + const file = path.join(DATA_DIR, 'demos', component.id, base) + return fs.existsSync(file) ? fs.readFileSync(file, 'utf-8') : null +} diff --git a/packages/nutui-react-cli/src/error.ts b/packages/nutui-react-cli/src/error.ts new file mode 100644 index 0000000000..9b2df21069 --- /dev/null +++ b/packages/nutui-react-cli/src/error.ts @@ -0,0 +1,27 @@ +// MCP 层的结构化错误。CLI 命令用 process.exit 退出,MCP 不能退出进程, +// 需返回带 error/code 字段的对象,供 Agent 解析。 +export const ErrorCodes = { + COMPONENT_NOT_FOUND: 'COMPONENT_NOT_FOUND', + DOC_NOT_FOUND: 'DOC_NOT_FOUND', + DEMO_NOT_FOUND: 'DEMO_NOT_FOUND', + UNKNOWN_TOOL: 'UNKNOWN_TOOL', +} as const + +export type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes] + +export interface ErrorResult { + error: true + code: ErrorCode + message: string + suggestion?: string +} + +export function createError( + code: ErrorCode, + message: string, + suggestion?: string +): ErrorResult { + return suggestion + ? { error: true, code, message, suggestion } + : { error: true, code, message } +} diff --git a/packages/nutui-react-cli/src/format.ts b/packages/nutui-react-cli/src/format.ts new file mode 100644 index 0000000000..a191e5038b --- /dev/null +++ b/packages/nutui-react-cli/src/format.ts @@ -0,0 +1,43 @@ +// 输出辅助:统一 JSON 与人类可读文本两种形态。 +import type { OutputFormat } from './types.js' + +export function printJson(data: unknown): void { + process.stdout.write(`${JSON.stringify(data, null, 2)}\n`) +} + +export function printText(text: string): void { + process.stdout.write(`${text}\n`) +} + +// 渲染等宽对齐的文本表格。列宽按内容自适应(按显示宽度,中文按 2 计)。 +export function renderTable(headers: string[], rows: string[][]): string { + const widths = headers.map((h, i) => + Math.max(displayWidth(h), ...rows.map((r) => displayWidth(r[i] ?? ''))) + ) + const line = (cells: string[]) => + cells.map((c, i) => pad(c ?? '', widths[i])).join(' ') + const sep = widths.map((w) => '-'.repeat(w)).join(' ') + return [line(headers), sep, ...rows.map(line)].join('\n') +} + +// 东亚宽字符按 2 个显示宽度计,用于表格对齐。 +function displayWidth(s: string): number { + let w = 0 + for (const ch of s) + w += /[\u4e00-\u9fff\u3000-\u303f\uff00-\uffef]/.test(ch) ? 2 : 1 + return w +} + +function pad(s: string, width: number): string { + return s + ' '.repeat(Math.max(0, width - displayWidth(s))) +} + +// 统一的「按格式输出」入口:json 走 printJson,text 走回调产出的文本。 +export function output( + format: OutputFormat, + jsonData: unknown, + toText: () => string +): void { + if (format === 'json') printJson(jsonData) + else printText(toText()) +} diff --git a/packages/nutui-react-cli/src/mcp/prompts.ts b/packages/nutui-react-cli/src/mcp/prompts.ts new file mode 100644 index 0000000000..d3d9423668 --- /dev/null +++ b/packages/nutui-react-cli/src/mcp/prompts.ts @@ -0,0 +1,29 @@ +// MCP 提示词:把 Agent 定位为 NutUI React 专家 / 页面生成器。 + +const SHARED_TOOL_WORKFLOW = `## 工具使用流程 +1. 用 **nutui_list** 发现可用组件(中英文名、分类、版本) +2. 用 **nutui_info** 获取组件的 Props 规格(属性 / 说明 / 类型 / 默认值) +3. 用 **nutui_doc** 阅读组件完整文档 +4. 用 **nutui_demo** 获取组件的可运行示例源码 + +## 其它工具 +- 用 **nutui_token** 查询 Design Token(全局或组件级),用于主题定制(\`var(--nutui-*)\` 体系) + +## 规则 +- 查询先于编写:使用任何组件前,先用 nutui_info / nutui_doc 确认其真实 API,不要凭记忆猜 Prop 或枚举值 +- 避免重复调用:不要用相同参数重复调用同一个工具 +- 优先阅读真实文档与示例,而非编造用法 +- 组件采用 \`nut-\` 扁平 BEM 命名与 \`var(--nutui-*)\` Design Token,定制样式时优先用 token 而非硬编码颜色` + +export const NUTUI_EXPERT_PROMPT = `你是 NutUI React(京东风格的轻量级移动端组件库)的专家助手。 + +${SHARED_TOOL_WORKFLOW} +` + +export const NUTUI_PAGE_GENERATOR_PROMPT = `你是 NutUI React 页面生成专家,负责用 NutUI React 组件产出完整、可运行的 React 页面。 + +${SHARED_TOOL_WORKFLOW} +- 生成代码前,先拉取所有相关组件的文档与示例 +- 产出完整、可运行的代码,包含全部必要的 import +- 适当补充 TypeScript 类型 +` diff --git a/packages/nutui-react-cli/src/mcp/tools.ts b/packages/nutui-react-cli/src/mcp/tools.ts new file mode 100644 index 0000000000..9a85ead9ce --- /dev/null +++ b/packages/nutui-react-cli/src/mcp/tools.ts @@ -0,0 +1,258 @@ +// MCP 工具定义与处理器。复用 data.ts 原语,与 CLI 命令共享同一份 meta 快照, +// 输出结构与各命令的 --format json 保持一致。命名对齐 antd 风格(nutui_*)。 +import { + listDemos, + loadMeta, + readDemo, + readDoc, + resolveComponent, + suggestComponents, +} from '../data.js' +import { createError, ErrorCodes } from '../error.js' +import type { Component, Lang, Meta } from '../types.js' + +export interface McpContext { + lang: Lang +} + +function toMcpResult(data: unknown) { + const isError = + !!data && + typeof data === 'object' && + 'error' in data && + (data as { error: unknown }).error === true + const payload = { + content: [{ type: 'text' as const, text: JSON.stringify(data) }], + } + return isError ? { ...payload, isError: true } : payload +} + +// 解析组件名;未命中返回结构化错误(含 did-you-mean 建议),不退出进程。 +function resolve( + meta: Meta, + query: string +): Component | ReturnType { + const comp = resolveComponent(meta, query) + if (comp) return comp + const suggestions = suggestComponents(meta, query) + return createError( + ErrorCodes.COMPONENT_NOT_FOUND, + `未找到组件「${query}」。`, + suggestions.length + ? `你是否想找:${suggestions.join(' / ')}?或用 nutui_list 查看全部组件。` + : '用 nutui_list 查看全部组件。' + ) +} + +function isError(x: unknown): x is ReturnType { + return !!x && typeof x === 'object' && 'error' in x +} + +// 所有工具均为只读、无副作用、幂等、不访问外部世界。 +const TOOL_ANNOTATIONS = { + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, + openWorldHint: false, +} as const + +export const TOOL_DEFINITIONS = [ + { + name: 'nutui_list', + description: + '列出全部 NutUI React 组件(英文名、中文名、分类、版本)。可用 category 按分类筛选。', + inputSchema: { + type: 'object' as const, + properties: { + category: { + type: 'string', + description: + '按分类英文名筛选(如 base / feedback / form),省略则列出全部', + }, + }, + required: [] as string[], + }, + annotations: { title: '列出组件', ...TOOL_ANNOTATIONS }, + }, + { + name: 'nutui_info', + description: + '获取组件的 Props 规格(属性、说明、类型、默认值),按表格分组。', + inputSchema: { + type: 'object' as const, + properties: { + component: { + type: 'string', + description: '组件名(大小写不敏感,如 Button)', + }, + }, + required: ['component'], + }, + annotations: { title: '获取组件 Props', ...TOOL_ANNOTATIONS }, + }, + { + name: 'nutui_doc', + description: + '获取组件的完整 Markdown 文档。lang 可选 zh(中文,默认)或 en(英文)。', + inputSchema: { + type: 'object' as const, + properties: { + component: { + type: 'string', + description: '组件名(大小写不敏感,如 Button)', + }, + lang: { + type: 'string', + enum: ['zh', 'en'], + description: '文档语言,zh=中文(默认),en=英文', + }, + }, + required: ['component'], + }, + annotations: { title: '获取组件文档', ...TOOL_ANNOTATIONS }, + }, + { + name: 'nutui_demo', + description: + '获取组件的 H5 示例源码。不传 name 时列出全部示例名;传 name(如 demo1)时返回该示例源码。', + inputSchema: { + type: 'object' as const, + properties: { + component: { + type: 'string', + description: '组件名(大小写不敏感,如 Button)', + }, + name: { + type: 'string', + description: '示例名(如 demo1);省略则列出全部示例', + }, + }, + required: ['component'], + }, + annotations: { title: '获取组件示例', ...TOOL_ANNOTATIONS }, + }, + { + name: 'nutui_token', + description: + '查询 Design Token(var(--nutui-*) 体系)。不传 component 返回全局 token;传 component 返回组件级 token。', + inputSchema: { + type: 'object' as const, + properties: { + component: { + type: 'string', + description: '组件名,返回组件级 token;省略则返回全局 token', + }, + }, + required: [] as string[], + }, + annotations: { title: '查询 Design Token', ...TOOL_ANNOTATIONS }, + }, +] + +export function createToolHandler(ctx: McpContext) { + return async (name: string, params: Record) => { + const meta = loadMeta() + + switch (name) { + case 'nutui_list': { + const filter = params.category as string | undefined + let categories = meta.categories + if (filter) { + const key = filter.toLowerCase() + categories = categories.filter( + (c) => c.enName.toLowerCase() === key || c.name === filter + ) + } + const data = categories.map((cat) => ({ + name: cat.name, + enName: cat.enName, + components: cat.components + .map((id) => meta.components[id]) + .filter(Boolean) + .map((c) => ({ + name: c.name, + cName: c.cName, + version: c.version, + })), + })) + return toMcpResult({ libVersion: meta.libVersion, categories: data }) + } + + case 'nutui_info': { + const comp = resolve(meta, params.component as string) + if (isError(comp)) return toMcpResult(comp) + const propTables = (comp.api?.tables ?? []).filter( + (t) => t.kind === 'props' + ) + return toMcpResult({ + name: comp.name, + cName: comp.cName, + version: comp.version, + tables: propTables.map((t) => ({ + name: t.name, + subComponent: t.subComponent, + rows: t.rows, + })), + }) + } + + case 'nutui_doc': { + const comp = resolve(meta, params.component as string) + if (isError(comp)) return toMcpResult(comp) + const lang = (params.lang as Lang) ?? ctx.lang + const content = readDoc(comp, lang) + if (content === null) { + return toMcpResult( + createError( + ErrorCodes.DOC_NOT_FOUND, + `${comp.name} ${comp.cName} 暂无${lang === 'en' ? '英文' : '中文'}文档。` + ) + ) + } + return toMcpResult({ name: comp.name, lang, doc: content }) + } + + case 'nutui_demo': { + const comp = resolve(meta, params.component as string) + if (isError(comp)) return toMcpResult(comp) + const demos = listDemos(comp) + const demoName = params.name as string | undefined + if (!demoName) { + return toMcpResult({ component: comp.name, demos }) + } + const code = readDemo(comp, demoName) + if (code === null) { + return toMcpResult( + createError( + ErrorCodes.DEMO_NOT_FOUND, + `${comp.name} 未找到示例「${demoName}」。`, + demos.length + ? `可选:${demos.join(' / ')}` + : '该组件暂无 H5 示例。' + ) + ) + } + return toMcpResult({ component: comp.name, demo: demoName, code }) + } + + case 'nutui_token': { + const query = params.component as string | undefined + if (!query) { + return toMcpResult({ scope: 'global', tokens: meta.globalTokens }) + } + const comp = resolve(meta, query) + if (isError(comp)) return toMcpResult(comp) + return toMcpResult({ + scope: comp.id, + component: comp.name, + tokens: comp.tokens ?? [], + }) + } + + default: + return toMcpResult( + createError(ErrorCodes.UNKNOWN_TOOL, `未知工具:${name}`) + ) + } + } +} diff --git a/packages/nutui-react-cli/src/types.ts b/packages/nutui-react-cli/src/types.ts new file mode 100644 index 0000000000..33171dea9b --- /dev/null +++ b/packages/nutui-react-cli/src/types.ts @@ -0,0 +1,76 @@ +// meta/components.json 的结构类型(React/H5 视角)。schema 见仓库 scripts/build-meta.mjs。 + +export interface Token { + cssVar: string + scssVar: string + default: string | null +} + +export type TableKind = 'props' | 'methods' | 'ref' | 'other' + +export interface ApiRow { + prop: string + desc: string + type: string + default: string +} + +export interface ApiTable { + name: string + kind: TableKind + sourceComponent: string + subComponent: string | null + rows: ApiRow[] +} + +export interface DocRefs { + h5: string | null + enUS: string | null + zhTW: string | null + taro: string | null +} + +export interface Component { + id: string + name: string + cName: string + version: string + category: { name: string; enName: string } + taro: boolean + v15: boolean + v16: boolean + author?: string + type?: string + desc?: string + sort?: number + show?: boolean + docs: DocRefs + demos: { h5: string[]; taro: string[] } + api: { tables: ApiTable[] } + tokens: Token[] +} + +export interface Category { + name: string + enName: string + components: string[] +} + +export interface Meta { + schemaVersion: string + libVersion: string + componentCount: number + apiComponentCount: number + categories: Category[] + globalTokens: Token[] + components: Record +} + +// CLI 语言维度 -> meta.docs 的 key。React 端只支持 zh / en。 +export type Lang = 'zh' | 'en' +export const LANG_TO_DOC_KEY: Record = { + zh: 'h5', + en: 'enUS', +} + +export type OutputFormat = 'text' | 'json' diff --git a/packages/nutui-react-cli/tsconfig.json b/packages/nutui-react-cli/tsconfig.json new file mode 100644 index 0000000000..697f0799e6 --- /dev/null +++ b/packages/nutui-react-cli/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "es2022", + "lib": ["es2023"], + "moduleDetection": "force", + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "types": ["node"], + "strict": true, + "noUnusedLocals": true, + "declaration": false, + "esModuleInterop": true, + "isolatedModules": true, + "verbatimModuleSyntax": true, + "skipLibCheck": true + }, + "include": ["src"] +} diff --git a/packages/nutui-react-cli/tsup.config.ts b/packages/nutui-react-cli/tsup.config.ts new file mode 100644 index 0000000000..2a087a1912 --- /dev/null +++ b/packages/nutui-react-cli/tsup.config.ts @@ -0,0 +1,26 @@ +import { readFileSync } from 'node:fs' +import { defineConfig } from 'tsup' + +const { version } = JSON.parse(readFileSync('package.json', 'utf-8')) + +export default defineConfig({ + entry: ['src/cli.ts'], + format: ['esm'], + target: 'node18.12', + splitting: false, + dts: false, + clean: true, + // 把运行时依赖打进产物,使 dist/cli.js 自包含、零安装依赖即可运行。 + noExternal: ['yargs', '@modelcontextprotocol/sdk'], + banner: { + // MCP SDK 内部用到 CJS require,ESM 产物需补 createRequire。 + js: [ + '#!/usr/bin/env node', + 'import { createRequire } from "node:module";', + 'const require = createRequire(import.meta.url);', + ].join('\n'), + }, + define: { + __CLI_VERSION__: JSON.stringify(version), + }, +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index adb373abe7..b2335d4c31 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -116,22 +116,22 @@ importers: version: 1.15.40(@swc/helpers@0.5.23) '@tarojs/components': specifier: 4.2.0 - version: 4.2.0(@tarojs/helper@4.1.3(@swc/helpers@0.5.23))(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@4.60.4)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)) + version: 4.2.0(@tarojs/helper@4.2.0(@swc/helpers@0.5.23))(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@4.60.4)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)) '@tarojs/plugin-platform-alipay': specifier: 4.2.0 - version: 4.2.0(@tarojs/service@4.1.3(@swc/helpers@0.5.23))(@tarojs/shared@4.2.0) + version: 4.2.0(@tarojs/service@4.2.0(@swc/helpers@0.5.23))(@tarojs/shared@4.2.0) '@tarojs/plugin-platform-jd': specifier: 4.2.0 - version: 4.2.0(@tarojs/service@4.1.3(@swc/helpers@0.5.23))(@tarojs/shared@4.2.0) + version: 4.2.0(@tarojs/service@4.2.0(@swc/helpers@0.5.23))(@tarojs/shared@4.2.0) '@tarojs/plugin-platform-weapp': specifier: 4.2.0 - version: 4.2.0(@tarojs/service@4.1.3(@swc/helpers@0.5.23))(@tarojs/shared@4.2.0) + version: 4.2.0(@tarojs/service@4.2.0(@swc/helpers@0.5.23))(@tarojs/shared@4.2.0) '@tarojs/react': specifier: 4.2.0 version: 4.2.0(react@18.3.1) '@tarojs/taro': specifier: 4.2.0 - version: 4.2.0(@tarojs/components@4.2.0(@tarojs/helper@4.1.3(@swc/helpers@0.5.23))(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@4.60.4)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(@tarojs/helper@4.1.3(@swc/helpers@0.5.23))(@tarojs/shared@4.2.0)(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@4.60.4)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)) + version: 4.2.0(@tarojs/components@4.2.0(@tarojs/helper@4.2.0(@swc/helpers@0.5.23))(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@4.60.4)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(@tarojs/helper@4.2.0(@swc/helpers@0.5.23))(@tarojs/shared@4.2.0)(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@4.60.4)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)) '@testing-library/jest-dom': specifier: ^6.4.2 version: 6.9.1 @@ -486,6 +486,31 @@ importers: specifier: ^29.1.2 version: 29.4.11(@babel/core@7.29.7)(@jest/transform@30.4.1)(@jest/types@30.4.1)(babel-jest@30.4.1(@babel/core@7.29.7))(jest-util@30.4.1)(jest@30.4.2(@types/node@22.19.19))(typescript@5.9.3) + packages/nutui-react-cli: + dependencies: + '@modelcontextprotocol/sdk': + specifier: ^1.29.0 + version: 1.29.0(zod@4.4.3) + yargs: + specifier: ^17.7.2 + version: 17.7.2 + devDependencies: + '@types/node': + specifier: ^22.5.5 + version: 22.19.19 + '@types/yargs': + specifier: ^17.0.33 + version: 17.0.35 + bumpp: + specifier: ^9.5.2 + version: 9.11.1(magicast@0.3.5) + tsup: + specifier: ^8.3.0 + version: 8.5.1(@microsoft/api-extractor@7.47.7(@types/node@22.19.19))(@swc/core@1.15.40(@swc/helpers@0.5.23))(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) + typescript: + specifier: ^5.6.2 + version: 5.9.3 + packages/nutui-replace-icons: dependencies: '@babel/cli': @@ -2171,6 +2196,12 @@ packages: '@hapi/topo@6.0.2': resolution: {integrity: sha512-KR3rD5inZbGMrHmgPxsJ9dbi6zEK+C3ZwUwTa+eMwWLz7oijWUTWD2pMSNNYJAU6Qq+65NkxXjqHr/7LM2Xkqg==} + '@hono/node-server@1.19.14': + resolution: {integrity: sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + '@humanfs/core@0.19.2': resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} engines: {node: '>=18.18.0'} @@ -2533,6 +2564,16 @@ packages: '@mixmark-io/domino@2.2.0': resolution: {integrity: sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==} + '@modelcontextprotocol/sdk@1.29.0': + resolution: {integrity: sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==} + engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true + '@napi-rs/triples@1.2.0': resolution: {integrity: sha512-HAPjR3bnCsdXBsATpDIP5WCrw0JcACwhhrwIAQhiR46n+jm+a2F8kBsfseAuWtSyQ+H3Yebt2k43B5dy+04yMA==} @@ -2691,48 +2732,56 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-arm64-musl@0.125.0': resolution: {integrity: sha512-eIXyzpA12/+maKjMSsXdHfpzwQcoRfzokT+/ZhVEo6u/9RcXQrZZmZ70MmmJqwVcLez6U4ScjB/eiYlsEs7p0g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [musl] '@oxc-parser/binding-linux-ppc64-gnu@0.125.0': resolution: {integrity: sha512-w7ir5OuqSJUKLadmsSAWwTNso/ZGem2bPT/1LSU7l+ecmKPyegIvU+wzY0ADhZ/t/goaedqyp24SDRxyLxO9zg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-riscv64-gnu@0.125.0': resolution: {integrity: sha512-2KPTfWorcW8RNE8aEMHKbPSjHDBjFVYqg8nSLRBp7pe7VBqHsmkO9jpK8YmaYA5d5GcUy+J++5O4EgxkrQBEtw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-riscv64-musl@0.125.0': resolution: {integrity: sha512-Vsl8dmQdKtDsQiDPHP5VFjXOuVGcZQcziYMkU/yPnlaKHMqoX/q+bxt7K+BwResi9Cc8pnZ6oYGTgPcjAtt5QQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [riscv64] os: [linux] + libc: [musl] '@oxc-parser/binding-linux-s390x-gnu@0.125.0': resolution: {integrity: sha512-HwY5kuM818r/kHdHG2TZqzqxyF7fz90prPg85R/2VmgRWk8cMyGZo+8BNZDQAMJ6aGSTRvn2sdGXv3sZ5bsUWw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-x64-gnu@0.125.0': resolution: {integrity: sha512-o7k6+xAI2pIkjBsCqM0elI4q+qY/3TexH6cpIlGm+nJze1tvx7QEHCKdiy6wnRacFvUYmySEZ5hWFBc9MbxrIA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] '@oxc-parser/binding-linux-x64-musl@0.125.0': resolution: {integrity: sha512-vksRynFD6vytE1sDZCaeIk6y6rCsq0a18T4kcXbfGHBq2q/qSyDogWLk3A3S3hl/ikNfse7yrEwAuQ8ldIJeAg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [musl] '@oxc-parser/binding-openharmony-arm64@0.125.0': resolution: {integrity: sha512-AAtg4pnKvrKsay2ldZZRY98ALFBOgbyy3Gyxo658z6aecM0Zr5mI9BOHRCchSVKUHqMqmjhCA4wIdZvz02VrAw==} @@ -3006,66 +3055,79 @@ packages: resolution: {integrity: sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.60.4': resolution: {integrity: sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.60.4': resolution: {integrity: sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.60.4': resolution: {integrity: sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loong64-gnu@4.60.4': resolution: {integrity: sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-loong64-musl@4.60.4': resolution: {integrity: sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw==} cpu: [loong64] os: [linux] + libc: [musl] '@rollup/rollup-linux-ppc64-gnu@4.60.4': resolution: {integrity: sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-ppc64-musl@4.60.4': resolution: {integrity: sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A==} cpu: [ppc64] os: [linux] + libc: [musl] '@rollup/rollup-linux-riscv64-gnu@4.60.4': resolution: {integrity: sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.60.4': resolution: {integrity: sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.60.4': resolution: {integrity: sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.60.4': resolution: {integrity: sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.60.4': resolution: {integrity: sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-openbsd-x64@4.60.4': resolution: {integrity: sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA==} @@ -3254,60 +3316,70 @@ packages: engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [glibc] '@swc/core-linux-arm64-gnu@1.3.96': resolution: {integrity: sha512-c/IiJ0s1y3Ymm2BTpyC/xr6gOvoqAVETrivVXHq68xgNms95luSpbYQ28rqaZC8bQC8M5zdXpSc0T8DJu8RJGw==} engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [glibc] '@swc/core-linux-arm64-musl@1.15.40': resolution: {integrity: sha512-4z0MgHU+7M0pZDqBN1El7mFXDI1SBwinfcUkAyA4v8QrhOIUOZltySt2aStQLZGrdXVXM4Y4ylfiTC04ED+MoQ==} engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [musl] '@swc/core-linux-arm64-musl@1.3.96': resolution: {integrity: sha512-i5/UTUwmJLri7zhtF6SAo/4QDQJDH2fhYJaBIUhrICmIkRO/ltURmpejqxsM/ye9Jqv5zG7VszMC0v/GYn/7BQ==} engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [musl] '@swc/core-linux-ppc64-gnu@1.15.40': resolution: {integrity: sha512-fLI4iUgeSZu0eRWUXwe6YzPFx9gHbFiPkl8Rp3mJfP8OpNR3nTQCGPvHdDh9xniW7mVvgMY4ni7A4VzqI1KrpA==} engines: {node: '>=10'} cpu: [ppc64] os: [linux] + libc: [glibc] '@swc/core-linux-s390x-gnu@1.15.40': resolution: {integrity: sha512-YqeKMAb7d4nQSGMJQ454IlaCENpzcDqhvBE9+CPfdnYpnUXxd+BSrB6Xk0YjW8UyoEhUj4p6quATCxbsp6J3jg==} engines: {node: '>=10'} cpu: [s390x] os: [linux] + libc: [glibc] '@swc/core-linux-x64-gnu@1.15.40': resolution: {integrity: sha512-7HOuS1iGcme/j/TuL1TfmmLGiMQrjv/GmjyZeydl00FKPtpGXEldwqfI56xgd1YzrzoB2svWjxbGGyQ0TEASxg==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [glibc] '@swc/core-linux-x64-gnu@1.3.96': resolution: {integrity: sha512-USdaZu8lTIkm4Yf9cogct/j5eqtdZqTgcTib4I+NloUW0E/hySou3eSyp3V2UAA1qyuC72ld1otXuyKBna0YKQ==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [glibc] '@swc/core-linux-x64-musl@1.15.40': resolution: {integrity: sha512-h4kZYHc7dpc9P9u4brRJaS8Pl7tPVHAeiLSzw7T5RfIJgAoSdaCMKzI/2Uay9gFhaw8uyCDl0L5q37r0EpAfIA==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [musl] '@swc/core-linux-x64-musl@1.3.96': resolution: {integrity: sha512-QYErutd+G2SNaCinUVobfL7jWWjGTI0QEoQ6hqTp7PxCJS/dmKmj3C5ZkvxRYcq7XcZt7ovrYCTwPTHzt6lZBg==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [musl] '@swc/core-win32-arm64-msvc@1.15.40': resolution: {integrity: sha512-+mQgKZXSj6mV38Zh05QaxSjUDmGP/R2JWlXZTDLSPkDzHU6p3GxN9eeSf5dfyDVU86946fmCvSzyl/ucImx8+A==} @@ -3437,6 +3509,7 @@ packages: engines: {node: ^20 || ^22} cpu: [x64] os: [linux] + libc: [glibc] '@tarojs/binding-win32-x64-msvc@4.1.3': resolution: {integrity: sha512-5MO5k+LMP2oEhmvxK1HsDmcNwa33clIO517cpXoev0rj/chGizuJ/lCUVsvIxAW+wRPsigJjyD16hf3F/vt68w==} @@ -3474,6 +3547,10 @@ packages: resolution: {integrity: sha512-ReLy90gUHWS2u2lN2Xl3xO2oD5Q4K190sxiwkOCqTc5+lcfPAgNOOQ/hdVBORjT8ZDdclXSEjqsCDNwMJieAgQ==} engines: {node: ^20 || ^22} + '@tarojs/helper@4.2.0': + resolution: {integrity: sha512-F8D5EbwS/d0Kkh4PWFHhXoM1l1Iy2ZxjsWmXEkUratiq+CktogjQDa87pY+lyPLFsArA8oAd01p7rsQmVSDfoA==} + engines: {node: '>= 18'} + '@tarojs/parse-css-to-stylesheet-android-arm-eabi@0.0.69': resolution: {integrity: sha512-xfn55ehFWjbIzDTu+0QwMkCf8icC7jwAiDm2S7Cv5Og83gSzMUCb76KzEAwgTSTe0wiLrDai2HAhBftpE4V1Qw==} engines: {node: '>= 10'} @@ -3514,24 +3591,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@tarojs/parse-css-to-stylesheet-linux-arm64-musl@0.0.69': resolution: {integrity: sha512-bYODGCEx1Ni4EMNuZU95IUPqVZAXsY9gIc5CPSfKQ2j167Vbeo/gskQk/uNVjmnYJ69PplgJ9npylINgLIPIrA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@tarojs/parse-css-to-stylesheet-linux-x64-gnu@0.0.69': resolution: {integrity: sha512-89f03s+txGJ1c8Zc6Ib4qTAP4YhfFbVFq29XExqbC7eGvpQl5DeOtwonO5DBwMc7lA+LG4b1Q4CMXE3qodn2eA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@tarojs/parse-css-to-stylesheet-linux-x64-musl@0.0.69': resolution: {integrity: sha512-vyewIf1KysXYNIJdkzc9JSPguTG9zD65Belk3H186mLR18KtsvrqNqlWnP8kKfduF4ixh6qt0F2PkKbeI9PZvg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@tarojs/parse-css-to-stylesheet-win32-x64-msvc@0.0.69': resolution: {integrity: sha512-CHKlVjAiSAZTFNV8GkfXV88Jy9yyFSvKBAO3++l2KSQUBUWmPX775FbH+god2BOLf5SfAXRPd0HVAEK9qNeHXQ==} @@ -3571,24 +3652,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@tarojs/plugin-doctor-linux-arm64-musl@0.0.13': resolution: {integrity: sha512-V1HnFITOLgHVyQ+OCa1oPFKOtGFRtP91vlbUGfOwMA4GeOVw9g28W/hfTyucTCkfZWlrssLehgW6L2AGAMXh2w==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@tarojs/plugin-doctor-linux-x64-gnu@0.0.13': resolution: {integrity: sha512-oetfzBW60uenPBBF4/NE6Mf0Iwkw1YGqIIBiN++aVQynbWrmMzWBsW8kleZ5vN1npxI9aud9EfRU1uM37DrG2A==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@tarojs/plugin-doctor-linux-x64-musl@0.0.13': resolution: {integrity: sha512-OdIF/kFwwM0kQPDnpkanhvfWRaAI6EtDmpM9rQA/Lu2QcJq86w5d7X/WSN0U2xF1nialAUrfl79NyIaEzp4Fcw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@tarojs/plugin-doctor-win32-ia32-msvc@0.0.13': resolution: {integrity: sha512-nIbG2SliRhRwACLa1kNMskcfjsihp+3tZQMAxl+LoYUq6JRaWgP3vH2nHkDyZHTCheBTDtAaupqXWrYF3w+U6g==} @@ -3740,6 +3825,10 @@ packages: resolution: {integrity: sha512-GKQ/oMAGuUSXbn79yO48AkYW7mmQJ5YQm/QU2Tsn0cOZbcH9JMR54GnoqQk/LywbrrMzr3ojdGvxxJ3nN16RRw==} engines: {node: ^20 || ^22} + '@tarojs/runner-utils@4.2.0': + resolution: {integrity: sha512-M79iDSKjO3FNBBWfNiFlaihLsHGSQaXjSCglH0d9G1a/YWx2hfKtZaT67ca86YkfR/glz6ZBtIY5PTNQlED8AA==} + engines: {node: '>= 18'} + '@tarojs/runtime@4.1.3': resolution: {integrity: sha512-fJ0Jgi2243HrlFwAczufDgkD5+nCJpoQeCm4+0qnPCU7t+q+CFL7MG2PTfYdBOL3QbQwtB4NBeDcMt5E886ubQ==} engines: {node: ^20 || ^22} @@ -3752,6 +3841,10 @@ packages: resolution: {integrity: sha512-MYGj/H9TXh/v+ult/N/oNlXokD/QqNTl1UzTOpt+KyeDsXlmkOfunqE7v85Y2VYJVmraosCjqGrs2qyl8yctyA==} engines: {node: ^20 || ^22} + '@tarojs/service@4.2.0': + resolution: {integrity: sha512-shUXAkxUNjrlgucU5yP4S1ZZnKFQmAvlnpDiignCF1dUvsDB+7Q8I+XTwI6JuK39HcCXxs3xIgYeIsBEHrIbZw==} + engines: {node: '>= 18'} + '@tarojs/shared@4.1.3': resolution: {integrity: sha512-OWLojvDJGX7+Jd6UIllCZMr5ogOFKgWeI7g5QH0Ebv0c6BNoX5q2zY7zNPMbl3mqHlFnsmoHbB5PPTFCWJhnGw==} engines: {node: ^20 || ^22} @@ -4413,51 +4506,61 @@ packages: resolution: {integrity: sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==} cpu: [arm64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-arm64-musl@1.12.2': resolution: {integrity: sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==} cpu: [arm64] os: [linux] + libc: [musl] '@unrs/resolver-binding-linux-loong64-gnu@1.12.2': resolution: {integrity: sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==} cpu: [loong64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-loong64-musl@1.12.2': resolution: {integrity: sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==} cpu: [loong64] os: [linux] + libc: [musl] '@unrs/resolver-binding-linux-ppc64-gnu@1.12.2': resolution: {integrity: sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==} cpu: [ppc64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-riscv64-gnu@1.12.2': resolution: {integrity: sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==} cpu: [riscv64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-riscv64-musl@1.12.2': resolution: {integrity: sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==} cpu: [riscv64] os: [linux] + libc: [musl] '@unrs/resolver-binding-linux-s390x-gnu@1.12.2': resolution: {integrity: sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==} cpu: [s390x] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-x64-gnu@1.12.2': resolution: {integrity: sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==} cpu: [x64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-x64-musl@1.12.2': resolution: {integrity: sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==} cpu: [x64] os: [linux] + libc: [musl] '@unrs/resolver-binding-openharmony-arm64@1.12.2': resolution: {integrity: sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==} @@ -4687,6 +4790,10 @@ packages: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + acorn-import-assertions@1.9.0: resolution: {integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==} deprecated: package has been renamed to acorn-import-attributes @@ -5258,6 +5365,10 @@ packages: resolution: {integrity: sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + body-parser@2.3.0: + resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==} + engines: {node: '>=18'} + bonjour-service@1.4.0: resolution: {integrity: sha512-fGQtj1qdR9vIKjFiWPQd52qIqwjaYqhcI40JEiDuvlZ86E7ZBPBwY9fPgHy9r2rYGIjiRfctNPYz6OQU73ww2w==} @@ -5816,10 +5927,18 @@ packages: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} engines: {node: '>= 0.6'} + content-disposition@1.1.0: + resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} + engines: {node: '>=18'} + content-type@1.0.5: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} + content-type@2.0.0: + resolution: {integrity: sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==} + engines: {node: '>=18'} + conventional-changelog-angular@8.3.1: resolution: {integrity: sha512-6gfI3otXK5Ph5DfCOI1dblr+kN3FAm5a97hYoQkqNZxOaYa5WKfXH+AnpsmS+iUH2mgVC2Cg2Qw9m5OKcmNrIg==} engines: {node: '>=18'} @@ -5842,6 +5961,10 @@ packages: cookie-signature@1.0.7: resolution: {integrity: sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==} + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + cookie@0.7.2: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} @@ -5886,6 +6009,10 @@ packages: core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} + engines: {node: '>= 0.10'} + cosmiconfig-typescript-loader@6.3.0: resolution: {integrity: sha512-Akr82WH1Wfqatyiqpj8HDkO2o2KmJRu1FhKfSNJP3K4IdXwHfEyL7MOb62i1AGQVLtIQM+iCE9CGOtrfhR+mmA==} engines: {node: '>=v18'} @@ -6985,6 +7112,14 @@ packages: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} + eventsource-parser@3.1.0: + resolution: {integrity: sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==} + engines: {node: '>=18.0.0'} + + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} + execa@0.4.0: resolution: {integrity: sha512-QPexBaNjeOjyiZ47q0FCukTO1kX3F+HMM0EWpnxXddcr3MZtElILMkz9Y38nmSZtp03+ZiSRMffrKWBPOIoSIg==} engines: {node: '>=0.12'} @@ -7036,10 +7171,20 @@ packages: expr-parser@1.0.0: resolution: {integrity: sha512-ncuWTCWH0M5KbaYikXxZ3FG3Q+FTYIEXeXAbxYscdZLFNnR5Le5gRU2r/a/JUZHnxwBDZcxWEWzCoPQlW9Engg==} + express-rate-limit@8.5.2: + resolution: {integrity: sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + express@4.22.2: resolution: {integrity: sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==} engines: {node: '>= 0.10.0'} + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + exsolve@1.0.8: resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} @@ -7213,6 +7358,10 @@ packages: resolution: {integrity: sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==} engines: {node: '>= 0.8'} + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} + find-cache-dir@2.1.0: resolution: {integrity: sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==} engines: {node: '>=6'} @@ -7331,6 +7480,10 @@ packages: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + from2@2.3.0: resolution: {integrity: sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==} @@ -7818,6 +7971,10 @@ packages: resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} engines: {node: '>=0.10.0'} + hono@4.12.30: + resolution: {integrity: sha512-emn+JoJjrN9YTpRDS5it/UI2SO9BAE37T6I3d963RxcZ81G9A4pr2SZTEiiaiKbzx+NKRg5BZ89fCL7gCJCUog==} + engines: {node: '>=16.9.0'} + hookified@1.15.1: resolution: {integrity: sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==} @@ -8369,6 +8526,9 @@ packages: is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-redirect@1.0.0: resolution: {integrity: sha512-cr/SlUEe5zOGmzvj9bUyC4LVvkNVAXu4GytXLNMr1pny+a65MpQ9IJzFHD5vi7FyJgb4qt27+eS3TuQnqB+RQw==} engines: {node: '>=0.10.0'} @@ -8726,6 +8886,9 @@ packages: resolution: {integrity: sha512-2/OKlogiESf2Nh3TFCrRjrr9z1DRHeW0I+KReF67+4J0Ns+8hBtHRmoWAZ2OFU6I5+TWLEe6sVlSdXPjHm5UbQ==} engines: {node: '>= 20'} + jose@6.2.3: + resolution: {integrity: sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==} + joycon@3.1.1: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} @@ -8804,6 +8967,9 @@ packages: json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + json-schema-typed@8.0.2: + resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} + json-schema@0.4.0: resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} @@ -8986,24 +9152,28 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-musl@1.32.0: resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-x64-gnu@1.32.0: resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-musl@1.32.0: resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-win32-arm64-msvc@1.32.0: resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} @@ -9407,6 +9577,10 @@ packages: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + memfs@3.5.3: resolution: {integrity: sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==} engines: {node: '>= 4.0.0'} @@ -9418,6 +9592,10 @@ packages: merge-descriptors@1.0.3: resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -9559,6 +9737,10 @@ packages: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + mime@1.6.0: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} engines: {node: '>=4'} @@ -9774,6 +9956,10 @@ packages: resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} engines: {node: '>= 0.6'} + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} @@ -10242,6 +10428,9 @@ packages: path-to-regexp@6.3.0: resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + path-to-regexp@8.4.2: + resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -10322,6 +10511,10 @@ packages: resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + pkg-dir@3.0.0: resolution: {integrity: sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==} engines: {node: '>=6'} @@ -10886,6 +11079,10 @@ packages: resolution: {integrity: sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==} engines: {node: '>= 0.8'} + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} + rc9@2.1.2: resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} @@ -11334,6 +11531,10 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + rrweb-cssom@0.7.1: resolution: {integrity: sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==} @@ -11504,6 +11705,10 @@ packages: resolution: {integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==} engines: {node: '>= 0.8.0'} + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + sentence-case@3.0.4: resolution: {integrity: sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==} @@ -11528,6 +11733,10 @@ packages: resolution: {integrity: sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==} engines: {node: '>= 0.8.0'} + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + set-cookie-parser@2.7.2: resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} @@ -12448,6 +12657,10 @@ packages: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} + type-is@2.1.0: + resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==} + engines: {node: '>= 18'} + typed-array-buffer@1.0.3: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} @@ -13218,6 +13431,14 @@ packages: yup@1.7.1: resolution: {integrity: sha512-GKHFX2nXul2/4Dtfxhozv701jLQHdf6J34YDh2cEkpqoo8le5Mg6/LrdseVLrFarmFygZTlfIhHx/QKfb/QWXw==} + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} + peerDependencies: + zod: ^3.25.28 || ^4 + + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} @@ -14751,6 +14972,10 @@ snapshots: dependencies: '@hapi/hoek': 11.0.7 + '@hono/node-server@1.19.14(hono@4.12.30)': + dependencies: + hono: 4.12.30 + '@humanfs/core@0.19.2': dependencies: '@humanfs/types': 0.15.0 @@ -15419,6 +15644,28 @@ snapshots: '@mixmark-io/domino@2.2.0': {} + '@modelcontextprotocol/sdk@1.29.0(zod@4.4.3)': + dependencies: + '@hono/node-server': 1.19.14(hono@4.12.30) + ajv: 8.20.0 + ajv-formats: 3.0.1(ajv@8.20.0) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.1.0 + express: 5.2.1 + express-rate-limit: 8.5.2(express@5.2.1) + hono: 4.12.30 + jose: 6.2.3 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 4.4.3 + zod-to-json-schema: 3.25.2(zod@4.4.3) + transitivePeerDependencies: + - supports-color + '@napi-rs/triples@1.2.0': {} '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': @@ -16321,12 +16568,12 @@ snapshots: - webpack-chain - webpack-dev-server - '@tarojs/components@4.2.0(@tarojs/helper@4.1.3(@swc/helpers@0.5.23))(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@4.60.4)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15))': + '@tarojs/components@4.2.0(@tarojs/helper@4.1.3(@swc/helpers@0.5.23))(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@3.30.0)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15))': dependencies: '@stencil/core': 2.22.3 '@tarojs/runtime': 4.2.0 '@tarojs/shared': 4.2.0 - '@tarojs/taro': 4.2.0(@tarojs/components@4.2.0(@tarojs/helper@4.1.3(@swc/helpers@0.5.23))(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@4.60.4)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(@tarojs/helper@4.1.3(@swc/helpers@0.5.23))(@tarojs/shared@4.2.0)(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@4.60.4)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)) + '@tarojs/taro': 4.2.0(@tarojs/components@4.2.0(@tarojs/helper@4.1.3(@swc/helpers@0.5.23))(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@3.30.0)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(@tarojs/helper@4.1.3(@swc/helpers@0.5.23))(@tarojs/shared@4.2.0)(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@3.30.0)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)) classnames: 2.5.1 hammerjs: 2.0.8 hls.js: 1.6.16 @@ -16344,12 +16591,12 @@ snapshots: - webpack-chain - webpack-dev-server - '@tarojs/components@4.2.0(@tarojs/helper@4.1.3(@swc/helpers@0.5.23))(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@3.30.0)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15))': + '@tarojs/components@4.2.0(@tarojs/helper@4.2.0(@swc/helpers@0.5.23))(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@4.60.4)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15))': dependencies: '@stencil/core': 2.22.3 '@tarojs/runtime': 4.2.0 '@tarojs/shared': 4.2.0 - '@tarojs/taro': 4.2.0(@tarojs/components@4.2.0(@tarojs/helper@4.1.3(@swc/helpers@0.5.23))(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@3.30.0)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(@tarojs/helper@4.1.3(@swc/helpers@0.5.23))(@tarojs/shared@4.2.0)(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@3.30.0)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)) + '@tarojs/taro': 4.2.0(@tarojs/components@4.2.0(@tarojs/helper@4.2.0(@swc/helpers@0.5.23))(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@4.60.4)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(@tarojs/helper@4.2.0(@swc/helpers@0.5.23))(@tarojs/shared@4.2.0)(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@4.60.4)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)) classnames: 2.5.1 hammerjs: 2.0.8 hls.js: 1.6.16 @@ -16394,6 +16641,33 @@ snapshots: - '@swc/helpers' - supports-color + '@tarojs/helper@4.2.0(@swc/helpers@0.5.23)': + dependencies: + '@babel/core': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + '@swc/core': 1.3.96(@swc/helpers@0.5.23) + '@swc/register': 0.1.10(@swc/core@1.3.96(@swc/helpers@0.5.23)) + ansi-escapes: 4.3.2 + chalk: 4.1.2 + chokidar: 3.6.0 + cross-spawn: 7.0.6 + debug: 4.4.3(supports-color@8.1.1) + dotenv: 16.6.1 + dotenv-expand: 11.0.7 + esbuild: 0.21.5 + find-yarn-workspace-root: 2.0.0 + fs-extra: 11.3.5 + lodash: 4.18.1 + require-from-string: 2.0.2 + resolve: 1.22.12 + supports-hyperlinks: 3.2.0 + transitivePeerDependencies: + - '@swc/helpers' + - supports-color + '@tarojs/parse-css-to-stylesheet-android-arm-eabi@0.0.69': optional: true @@ -16516,9 +16790,9 @@ snapshots: '@tarojs/service': 4.1.3(@swc/helpers@0.5.23) '@tarojs/shared': 4.1.3 - '@tarojs/plugin-platform-alipay@4.2.0(@tarojs/service@4.1.3(@swc/helpers@0.5.23))(@tarojs/shared@4.2.0)': + '@tarojs/plugin-platform-alipay@4.2.0(@tarojs/service@4.2.0(@swc/helpers@0.5.23))(@tarojs/shared@4.2.0)': dependencies: - '@tarojs/service': 4.1.3(@swc/helpers@0.5.23) + '@tarojs/service': 4.2.0(@swc/helpers@0.5.23) '@tarojs/shared': 4.2.0 '@tarojs/plugin-platform-h5@4.1.3(61616c2ed6adcfead3c5df5cc362031d)': @@ -16591,9 +16865,9 @@ snapshots: '@tarojs/service': 4.1.3(@swc/helpers@0.5.23) '@tarojs/shared': 4.1.3 - '@tarojs/plugin-platform-jd@4.2.0(@tarojs/service@4.1.3(@swc/helpers@0.5.23))(@tarojs/shared@4.2.0)': + '@tarojs/plugin-platform-jd@4.2.0(@tarojs/service@4.2.0(@swc/helpers@0.5.23))(@tarojs/shared@4.2.0)': dependencies: - '@tarojs/service': 4.1.3(@swc/helpers@0.5.23) + '@tarojs/service': 4.2.0(@swc/helpers@0.5.23) '@tarojs/shared': 4.2.0 '@tarojs/plugin-platform-qq@4.1.3(@tarojs/plugin-platform-weapp@4.1.3(@tarojs/service@4.1.3(@swc/helpers@0.5.23))(@tarojs/shared@4.1.3))(@tarojs/shared@4.1.3)': @@ -16617,9 +16891,9 @@ snapshots: '@tarojs/service': 4.1.3(@swc/helpers@0.5.23) '@tarojs/shared': 4.1.3 - '@tarojs/plugin-platform-weapp@4.2.0(@tarojs/service@4.1.3(@swc/helpers@0.5.23))(@tarojs/shared@4.2.0)': + '@tarojs/plugin-platform-weapp@4.2.0(@tarojs/service@4.2.0(@swc/helpers@0.5.23))(@tarojs/shared@4.2.0)': dependencies: - '@tarojs/service': 4.1.3(@swc/helpers@0.5.23) + '@tarojs/service': 4.2.0(@swc/helpers@0.5.23) '@tarojs/shared': 4.2.0 '@tarojs/react@4.1.3(react@18.3.1)': @@ -16657,6 +16931,15 @@ snapshots: - '@swc/helpers' - supports-color + '@tarojs/runner-utils@4.2.0(@swc/helpers@0.5.23)': + dependencies: + '@tarojs/helper': 4.2.0(@swc/helpers@0.5.23) + rollup: 3.30.0 + scss-bundle: 3.1.2 + transitivePeerDependencies: + - '@swc/helpers' + - supports-color + '@tarojs/runtime@4.1.3': dependencies: '@tarojs/shared': 4.1.3 @@ -16682,6 +16965,21 @@ snapshots: - '@swc/helpers' - supports-color + '@tarojs/service@4.2.0(@swc/helpers@0.5.23)': + dependencies: + '@tarojs/helper': 4.2.0(@swc/helpers@0.5.23) + '@tarojs/runner-utils': 4.2.0(@swc/helpers@0.5.23) + '@tarojs/shared': 4.2.0 + joi: 17.13.3 + lodash: 4.18.1 + ora: 5.4.1 + resolve: 1.22.12 + tapable: 2.3.3 + webpack-merge: 5.10.0 + transitivePeerDependencies: + - '@swc/helpers' + - supports-color + '@tarojs/shared@4.1.3': {} '@tarojs/shared@4.2.0': {} @@ -16732,10 +17030,10 @@ snapshots: webpack-chain: 6.5.1 webpack-dev-server: 4.15.2(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)) - '@tarojs/taro@4.2.0(@tarojs/components@4.2.0(@tarojs/helper@4.1.3(@swc/helpers@0.5.23))(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@4.60.4)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(@tarojs/helper@4.1.3(@swc/helpers@0.5.23))(@tarojs/shared@4.2.0)(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@4.60.4)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15))': + '@tarojs/taro@4.2.0(@tarojs/components@4.2.0(@tarojs/helper@4.1.3(@swc/helpers@0.5.23))(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@3.30.0)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(@tarojs/helper@4.1.3(@swc/helpers@0.5.23))(@tarojs/shared@4.2.0)(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@3.30.0)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15))': dependencies: '@tarojs/api': 4.2.0(@tarojs/runtime@4.2.0)(@tarojs/shared@4.2.0) - '@tarojs/components': 4.2.0(@tarojs/helper@4.1.3(@swc/helpers@0.5.23))(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@4.60.4)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)) + '@tarojs/components': 4.2.0(@tarojs/helper@4.1.3(@swc/helpers@0.5.23))(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@3.30.0)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)) '@tarojs/helper': 4.1.3(@swc/helpers@0.5.23) '@tarojs/runtime': 4.2.0 '@tarojs/shared': 4.2.0 @@ -16743,28 +17041,28 @@ snapshots: postcss: 8.5.15 optionalDependencies: '@types/react': 18.3.29 - html-webpack-plugin: 5.6.7(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)) - rollup: 4.60.4 - webpack: 5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15) + html-webpack-plugin: 5.6.7(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)) + rollup: 3.30.0 + webpack: 5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15) webpack-chain: 6.5.1 - webpack-dev-server: 4.15.2(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)) + webpack-dev-server: 4.15.2(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)) - '@tarojs/taro@4.2.0(@tarojs/components@4.2.0(@tarojs/helper@4.1.3(@swc/helpers@0.5.23))(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@3.30.0)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(@tarojs/helper@4.1.3(@swc/helpers@0.5.23))(@tarojs/shared@4.2.0)(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@3.30.0)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15))': + '@tarojs/taro@4.2.0(@tarojs/components@4.2.0(@tarojs/helper@4.2.0(@swc/helpers@0.5.23))(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@4.60.4)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(@tarojs/helper@4.2.0(@swc/helpers@0.5.23))(@tarojs/shared@4.2.0)(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@4.60.4)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15))': dependencies: '@tarojs/api': 4.2.0(@tarojs/runtime@4.2.0)(@tarojs/shared@4.2.0) - '@tarojs/components': 4.2.0(@tarojs/helper@4.1.3(@swc/helpers@0.5.23))(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@3.30.0)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)) - '@tarojs/helper': 4.1.3(@swc/helpers@0.5.23) + '@tarojs/components': 4.2.0(@tarojs/helper@4.2.0(@swc/helpers@0.5.23))(@types/react@18.3.29)(html-webpack-plugin@5.6.7(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(postcss@8.5.15)(rollup@4.60.4)(webpack-chain@6.5.1)(webpack-dev-server@4.15.2(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)))(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)) + '@tarojs/helper': 4.2.0(@swc/helpers@0.5.23) '@tarojs/runtime': 4.2.0 '@tarojs/shared': 4.2.0 '@types/postcss-url': 10.0.4 postcss: 8.5.15 optionalDependencies: '@types/react': 18.3.29 - html-webpack-plugin: 5.6.7(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)) - rollup: 3.30.0 - webpack: 5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15) + html-webpack-plugin: 5.6.7(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)) + rollup: 4.60.4 + webpack: 5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15) webpack-chain: 6.5.1 - webpack-dev-server: 4.15.2(webpack@5.91.0(@swc/core@1.3.96(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)) + webpack-dev-server: 4.15.2(webpack@5.91.0(@swc/core@1.15.40(@swc/helpers@0.5.23))(lightningcss@1.32.0)(postcss@8.5.15)) '@tarojs/vite-runner@4.1.3(@swc/helpers@0.5.23)(@tarojs/runtime@4.1.3)(@types/babel__core@7.20.5)(jiti@2.7.0)(postcss@8.5.15)(rollup@3.30.0)(terser@5.48.0)(tsx@4.22.4)(typescript@5.9.3)(vite@5.4.21(@types/node@22.19.19)(less@3.13.1)(lightningcss@1.32.0)(sass@1.77.6)(stylus@0.64.0)(terser@5.48.0))': dependencies: @@ -17088,7 +17386,7 @@ snapshots: '@types/jsonfile@6.1.4': dependencies: - '@types/node': 20.19.41 + '@types/node': 22.19.19 '@types/keyv@3.1.4': dependencies: @@ -17158,7 +17456,7 @@ snapshots: '@types/postcss-url@10.0.4': dependencies: - '@types/node': 20.19.41 + '@types/node': 22.19.19 postcss: 8.5.15 '@types/prop-types@15.7.15': {} @@ -17255,7 +17553,7 @@ snapshots: '@types/vinyl@2.0.12': dependencies: '@types/expect': 1.20.4 - '@types/node': 20.19.41 + '@types/node': 22.19.19 '@types/webpack-env@1.18.8': {} @@ -17275,7 +17573,7 @@ snapshots: '@types/yauzl@2.10.3': dependencies: - '@types/node': 20.19.41 + '@types/node': 22.19.19 optional: true '@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3)': @@ -17970,6 +18268,11 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 + accepts@2.0.0: + dependencies: + mime-types: 3.0.2 + negotiator: 1.0.0 + acorn-import-assertions@1.9.0(acorn@8.16.0): dependencies: acorn: 8.16.0 @@ -18026,6 +18329,10 @@ snapshots: optionalDependencies: ajv: 8.13.0 + ajv-formats@3.0.1(ajv@8.20.0): + optionalDependencies: + ajv: 8.20.0 + ajv-keywords@3.5.2(ajv@6.15.0): dependencies: ajv: 6.15.0 @@ -18569,6 +18876,20 @@ snapshots: transitivePeerDependencies: - supports-color + body-parser@2.3.0: + dependencies: + bytes: 3.1.2 + content-type: 2.0.0 + debug: 4.4.3(supports-color@8.1.1) + http-errors: 2.0.1 + iconv-lite: 0.7.2 + on-finished: 2.4.1 + qs: 6.15.2 + raw-body: 3.0.2 + type-is: 2.1.0 + transitivePeerDependencies: + - supports-color + bonjour-service@1.4.0: dependencies: fast-deep-equal: 3.1.3 @@ -19227,8 +19548,12 @@ snapshots: dependencies: safe-buffer: 5.2.1 + content-disposition@1.1.0: {} + content-type@1.0.5: {} + content-type@2.0.0: {} + conventional-changelog-angular@8.3.1: dependencies: compare-func: 2.0.0 @@ -19248,6 +19573,8 @@ snapshots: cookie-signature@1.0.7: {} + cookie-signature@1.2.2: {} + cookie@0.7.2: {} cookie@1.1.1: {} @@ -19294,6 +19621,11 @@ snapshots: core-util-is@1.0.3: {} + cors@2.8.6: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + cosmiconfig-typescript-loader@6.3.0(@types/node@20.19.41)(cosmiconfig@9.0.1(typescript@5.9.3))(typescript@5.9.3): dependencies: '@types/node': 20.19.41 @@ -20840,6 +21172,12 @@ snapshots: events@3.3.0: {} + eventsource-parser@3.1.0: {} + + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.1.0 + execa@0.4.0: dependencies: cross-spawn-async: 2.2.5 @@ -20937,6 +21275,11 @@ snapshots: expr-parser@1.0.0: {} + express-rate-limit@8.5.2(express@5.2.1): + dependencies: + express: 5.2.1 + ip-address: 10.2.0 + express@4.22.2: dependencies: accepts: 1.3.8 @@ -20973,6 +21316,39 @@ snapshots: transitivePeerDependencies: - supports-color + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.3.0 + content-disposition: 1.1.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3(supports-color@8.1.1) + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.2 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.15.2 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 + statuses: 2.0.2 + type-is: 2.1.0 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + exsolve@1.0.8: {} ext-list@2.2.2: @@ -21139,6 +21515,17 @@ snapshots: transitivePeerDependencies: - supports-color + finalhandler@2.1.1: + dependencies: + debug: 4.4.3(supports-color@8.1.1) + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + find-cache-dir@2.1.0: dependencies: commondir: 1.0.1 @@ -21266,6 +21653,8 @@ snapshots: fresh@0.5.2: {} + fresh@2.0.0: {} + from2@2.3.0: dependencies: inherits: 2.0.4 @@ -21945,6 +22334,8 @@ snapshots: dependencies: parse-passwd: 1.0.0 + hono@4.12.30: {} + hookified@1.15.1: {} hookified@2.2.0: {} @@ -22480,6 +22871,8 @@ snapshots: is-potential-custom-element-name@1.0.1: {} + is-promise@4.0.0: {} + is-redirect@1.0.0: {} is-reference@1.2.1: @@ -23037,6 +23430,8 @@ snapshots: '@hapi/topo': 6.0.2 '@standard-schema/spec': 1.1.0 + jose@6.2.3: {} + joycon@3.1.1: {} js-tokens@10.0.0: {} @@ -23129,6 +23524,8 @@ snapshots: json-schema-traverse@1.0.0: {} + json-schema-typed@8.0.2: {} + json-schema@0.4.0: {} json-stable-stringify-without-jsonify@1.0.1: {} @@ -23852,6 +24249,8 @@ snapshots: media-typer@0.3.0: {} + media-typer@1.1.0: {} + memfs@3.5.3: dependencies: fs-monkey: 1.1.0 @@ -23860,6 +24259,8 @@ snapshots: merge-descriptors@1.0.3: {} + merge-descriptors@2.0.0: {} + merge-stream@2.0.0: {} merge2@1.4.1: {} @@ -24167,6 +24568,10 @@ snapshots: dependencies: mime-db: 1.52.0 + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + mime@1.6.0: {} mime@2.5.2: {} @@ -24363,6 +24768,8 @@ snapshots: negotiator@0.6.4: {} + negotiator@1.0.0: {} + neo-async@2.6.2: {} netmask@2.1.1: {} @@ -24941,6 +25348,8 @@ snapshots: path-to-regexp@6.3.0: {} + path-to-regexp@8.4.2: {} + path-type@4.0.0: {} path-type@5.0.0: {} @@ -24989,6 +25398,8 @@ snapshots: pirates@4.0.7: {} + pkce-challenge@5.0.1: {} + pkg-dir@3.0.0: dependencies: find-up: 3.0.0 @@ -25526,6 +25937,13 @@ snapshots: iconv-lite: 0.4.24 unpipe: 1.0.0 + raw-body@3.0.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + unpipe: 1.0.0 + rc9@2.1.2: dependencies: defu: 6.1.7 @@ -26140,6 +26558,16 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.60.4 fsevents: 2.3.3 + router@2.2.0: + dependencies: + debug: 4.4.3(supports-color@8.1.1) + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.4.2 + transitivePeerDependencies: + - supports-color + rrweb-cssom@0.7.1: {} rrweb-cssom@0.8.0: {} @@ -26322,6 +26750,22 @@ snapshots: transitivePeerDependencies: - supports-color + send@1.2.1: + dependencies: + debug: 4.4.3(supports-color@8.1.1) + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.1 + mime-types: 3.0.2 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + sentence-case@3.0.4: dependencies: no-case: 3.0.4 @@ -26359,6 +26803,15 @@ snapshots: transitivePeerDependencies: - supports-color + serve-static@2.2.1: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.1 + transitivePeerDependencies: + - supports-color + set-cookie-parser@2.7.2: {} set-function-length@1.2.2: @@ -27368,6 +27821,12 @@ snapshots: media-typer: 0.3.0 mime-types: 2.1.35 + type-is@2.1.0: + dependencies: + content-type: 2.0.0 + media-typer: 1.1.0 + mime-types: 3.0.2 + typed-array-buffer@1.0.3: dependencies: call-bound: 1.0.4 @@ -28547,4 +29006,10 @@ snapshots: toposort: 2.0.2 type-fest: 2.19.0 + zod-to-json-schema@3.25.2(zod@4.4.3): + dependencies: + zod: 4.4.3 + + zod@4.4.3: {} + zwitch@2.0.4: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 70bb652a18..deb0fcfdaf 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -2,4 +2,5 @@ packages: - 'packages/nutui-codemod' - 'packages/nutui-auto-import' - 'packages/nutui-taro-demo' - - 'packages/nutui-replace-icons' \ No newline at end of file + - 'packages/nutui-replace-icons' + - 'packages/nutui-react-cli' \ No newline at end of file diff --git a/src/sites/config/baseConfig.ts b/src/sites/config/baseConfig.ts index 5738631669..3e5a0ac1ec 100644 --- a/src/sites/config/baseConfig.ts +++ b/src/sites/config/baseConfig.ts @@ -46,8 +46,8 @@ export const SiteReact = { name: 'llms', cName: 'AI', eName: 'AI', - path: '/zh-CN/ai/llms', - pathName: 'llms' + path: '/zh-CN/ai/for-agents', + pathName: 'for-agents' } ], language: 'react' @@ -100,8 +100,8 @@ export const SiteReactTaro = { name: 'llms', cName: 'AI', eName: 'AI', - path: '/zh-CN/ai/llms', - pathName: 'llms' + path: '/zh-CN/ai/for-agents', + pathName: 'for-agents' } ], language: 'react' diff --git a/src/sites/sites-react/doc/components/nav/nav.tsx b/src/sites/sites-react/doc/components/nav/nav.tsx index 13a4f7790d..69b8e38ae0 100644 --- a/src/sites/sites-react/doc/components/nav/nav.tsx +++ b/src/sites/sites-react/doc/components/nav/nav.tsx @@ -46,6 +46,36 @@ const Nav = () => { {isAi ? (
      +
    • + + isPending ? '' : isActive ? 'active' : '' + } + to={`${lang ? `/${lang}` : ''}/ai/for-agents`} + > + For Agents + +
    • +
    • + + isPending ? '' : isActive ? 'active' : '' + } + to={`${lang ? `/${lang}` : ''}/ai/cli`} + > + CLI + +
    • +
    • + + isPending ? '' : isActive ? 'active' : '' + } + to={`${lang ? `/${lang}` : ''}/ai/mcp`} + > + MCP Server + +
    • diff --git a/src/sites/sites-react/doc/docs/ai-react/cli.en-US.md b/src/sites/sites-react/doc/docs/ai-react/cli.en-US.md new file mode 100644 index 0000000000..6acae8157c --- /dev/null +++ b/src/sites/sites-react/doc/docs/ai-react/cli.en-US.md @@ -0,0 +1,91 @@ +# CLI + +This guide explains how to use `@nutui/nutui-react-cli` to query NutUI-React component knowledge from the command line. + +## What is the NutUI-React CLI? + +[@nutui/nutui-react-cli](https://www.npmjs.com/package/@nutui/nutui-react-cli) is an **offline knowledge-query CLI for NutUI-React**, built for AI coding. It bundles component props, docs, demos, and Design Tokens with the package, so AI coding assistants (Claude Code / Cursor / Copilot, etc.) can _look up_ APIs instead of _guessing_ them — eliminating API hallucinations at the source. + +## Highlights + +- **Fully offline, zero API key** — Component metadata, docs, and demos are bundled at build time. Once installed, queries run locally in milliseconds with no network requests and no latency. +- **Structured output** — Every command supports `--format json` for agents to parse directly, instead of regex-matching text. +- **Smart correction** — Component names are case-insensitive; typed `Buttn`? The CLI suggests `Button` based on edit distance rather than just erroring out. +- **Bilingual docs** — The `doc` command supports `--lang zh|en` to switch between Chinese and English. + +## Install + +```bash +npm install -g @nutui/nutui-react-cli +``` + +Requires Node.js `>=18.12.0`. You can also skip the install and invoke it via `npx` (recommended, always uses the latest version): + +```bash +npx @nutui/nutui-react-cli list +npx @nutui/nutui-react-cli info Button +``` + +After a global install, use the `nutui-react` command: + +```bash +nutui-react info Button --format json +``` + +## Quick start + +```bash +nutui-react list # List all components (by category) +nutui-react list --category feedback # Filter by category +nutui-react info Button # Props table (prop / desc / type / default) +nutui-react doc Button # Full Markdown docs (Chinese by default) +nutui-react doc Button --lang en # English docs +nutui-react demo Button # List all H5 demo names for the component +nutui-react demo Button demo1 # View a demo's source +nutui-react token # Global Design Tokens +nutui-react token Button # Component-level Design Tokens +nutui-react mcp # Start a local MCP server for IDE integration +``` + +## Commands + +| Command | Description | +| --- | --- | +| `nutui-react list [--category ]` | List all components (name / Chinese name / category / version); filter by category enName (e.g. `base` / `feedback`) | +| `nutui-react info ` | Component props table, grouped by table (prop / desc / type / default) | +| `nutui-react doc [--lang zh\|en]` | Full component Markdown docs (Chinese by default) | +| `nutui-react demo [name]` | Omit `name` to list all demos; pass `name` (e.g. `demo1`) for source | +| `nutui-react token [Component]` | Design Tokens; omit the component name to list global tokens | +| `nutui-react mcp` | Start a local MCP server (stdio) for Claude Code / Cursor / VS Code / Codex IDE integration | + +When a component name isn't found, the CLI returns a "did you mean" suggestion (e.g. `Buttn` → `Button`) — use it to correct the name rather than guessing. + +## Global flags + +| Flag | Description | Default | +| --- | --- | --- | +| `--format, -f ` | Output format; agents should prefer `json` | `text` | +| `--lang, -l ` | Doc language (for `doc` / `mcp`) | `zh` | +| `--help, -h` | Show help | - | +| `--version, -v` | Print the CLI version | - | + +## Usage with AI tools + +The CLI ships with a Skill file following the [Agent Skills](https://github.com/vercel-labs/skills) spec, distributed with the npm package. It guides the agent to call the right command at the right time — e.g. "look up props with `info` and grab a demo before writing a component" and "customize styles with `var(--nutui-*)` tokens instead of hardcoded colors". + +Install into the current project (the skill is bundled with the package; install it from the local path after installing the CLI): + +```bash +npm i -D @nutui/nutui-react-cli +npx skills add ./node_modules/@nutui/nutui-react-cli/skills/nutui-react +``` + +Once installed, the agent automatically follows the "look up first, then write" workflow when it encounters NutUI-React tasks. Compatible with Claude Code / Cursor / VS Code / Codex and any agent that supports the skills protocol. + +If your IDE supports MCP, the CLI can also run as an MCP server, registering the same capabilities as IDE-native tools. See the [MCP Server](/#/en-US/ai/mcp) guide. + +## Learn more + +- [MCP Server](/#/en-US/ai/mcp) +- [LLMs.txt](/#/en-US/ai/llms) +- [For Agents](/#/en-US/ai/for-agents) diff --git a/src/sites/sites-react/doc/docs/ai-react/cli.md b/src/sites/sites-react/doc/docs/ai-react/cli.md new file mode 100644 index 0000000000..4772d759c5 --- /dev/null +++ b/src/sites/sites-react/doc/docs/ai-react/cli.md @@ -0,0 +1,91 @@ +# CLI + +本篇介绍如何使用 `@nutui/nutui-react-cli` 从命令行查询 NutUI-React 的组件知识。 + +## 什么是 NutUI-React CLI? + +[@nutui/nutui-react-cli](https://www.npmjs.com/package/@nutui/nutui-react-cli) 是面向 AI Coding 的 **NutUI-React 离线知识查询 CLI**。它把组件的 Props、文档、示例与 Design Token 打包随包分发,让 AI 编程助手(Claude Code / Cursor / Copilot 等)从「猜 API」变成「查 API」,从根源消除 API 幻觉。 + +## 亮点 + +- **完全离线、零 API Key** — 组件元数据与文档、示例在构建期打包进入,安装后本地毫秒级查询,无网络请求、无延迟。 +- **结构化输出** — 所有命令支持 `--format json`,供 Agent 直接解析,而非正则抓文本。 +- **智能纠错** — 组件名大小写不敏感;输入 `Buttn`?CLI 基于编辑距离建议 `Button`,而非直接报错。 +- **双语文档** — `doc` 命令支持 `--lang zh|en` 切换中英文。 + +## 安装 + +```bash +npm install -g @nutui/nutui-react-cli +``` + +需要 Node.js `>=18.12.0`。也可以免安装,用 `npx` 直接调用(推荐,始终使用最新版): + +```bash +npx @nutui/nutui-react-cli list +npx @nutui/nutui-react-cli info Button +``` + +全局安装后使用 `nutui-react` 命令: + +```bash +nutui-react info Button --format json +``` + +## 快速开始 + +```bash +nutui-react list # 列出全部组件(按分类) +nutui-react list --category feedback # 按分类筛选 +nutui-react info Button # 组件 Props 表(属性 / 说明 / 类型 / 默认值) +nutui-react doc Button # 组件完整 Markdown 文档(默认中文) +nutui-react doc Button --lang en # 英文文档 +nutui-react demo Button # 列出组件的全部 H5 示例名 +nutui-react demo Button demo1 # 查看某个示例的源码 +nutui-react token # 全局 Design Token +nutui-react token Button # 组件级 Design Token +nutui-react mcp # 启动本地 MCP 服务,供 IDE 集成 +``` + +## 命令 + +| 命令 | 说明 | +| --- | --- | +| `nutui-react list [--category ]` | 列出全部组件(英文名 / 中文名 / 分类 / 版本),可按分类英文名筛选(如 `base` / `feedback`) | +| `nutui-react info ` | 组件 Props 表,按表格分组(属性 / 说明 / 类型 / 默认值) | +| `nutui-react doc [--lang zh\|en]` | 组件完整 Markdown 文档,默认中文 | +| `nutui-react demo [name]` | 省略 `name` 列出全部示例;指定 `name`(如 `demo1`)输出源码 | +| `nutui-react token [Component]` | Design Token;省略组件名则列出全局 token | +| `nutui-react mcp` | 启动本地 MCP 服务(stdio),供 Claude Code / Cursor / VS Code / Codex 等 IDE 集成 | + +未命中组件名时,CLI 会给出「你是否想找」建议(如 `Buttn` → `Button`),据此纠正而非凭空猜测。 + +## 全局参数 + +| 参数 | 说明 | 默认值 | +| --- | --- | --- | +| `--format, -f ` | 输出格式;Agent 应优先用 `json` | `text` | +| `--lang, -l ` | 文档语言(用于 `doc` / `mcp`) | `zh` | +| `--help, -h` | 显示帮助 | - | +| `--version, -v` | 打印 CLI 版本号 | - | + +## 在 AI 工具中使用 + +CLI 内置一份遵循 [Agent Skills](https://github.com/vercel-labs/skills) 规范的 Skill 文件,随 npm 包分发,指导 Agent 在正确的时机调用正确的命令——例如「写组件前先 `info` 查 Props、再 `demo` 拿示例」「定制样式用 `var(--nutui-*)` token 而非硬编码颜色」。 + +安装到当前项目(skill 已随包 bundle,装好 CLI 后从本地路径安装): + +```bash +npm i -D @nutui/nutui-react-cli +npx skills add ./node_modules/@nutui/nutui-react-cli/skills/nutui-react +``` + +安装后,Agent 在遇到 NutUI-React 相关任务时会自动遵循「先查后写」的流程。兼容 Claude Code / Cursor / VS Code / Codex 等所有支持 skills 协议的 Agent。 + +如果你的 IDE 支持 MCP,CLI 也能作为 MCP 服务运行,把同一份能力注册成 IDE 原生工具,详见 [MCP Server](/#/zh-CN/ai/mcp) 指南。 + +## 了解更多 + +- [MCP Server](/#/zh-CN/ai/mcp) +- [LLMs.txt](/#/zh-CN/ai/llms) +- [For Agents](/#/zh-CN/ai/for-agents) diff --git a/src/sites/sites-react/doc/docs/ai-react/for-agents.en-US.md b/src/sites/sites-react/doc/docs/ai-react/for-agents.en-US.md new file mode 100644 index 0000000000..a0fdb3eb6f --- /dev/null +++ b/src/sites/sites-react/doc/docs/ai-react/for-agents.en-US.md @@ -0,0 +1,67 @@ +# For Agents + +This page provides a ready-to-use prompt that lets any AI coding agent work effectively with NutUI-React. + +## Copy this prompt + +Paste the following into your agent conversation or automation flow, so it builds the right context before writing any NutUI-React code: + +```text +Before writing any NutUI-React (@nutui/nutui-react) code, first read https://nutui.jd.com/h5/react/4x/llms-full.txt to understand the components' real APIs, usage, and style structure. Do not guess props or enum values from memory. Always look up the docs before using a component, then write code. + +If your environment supports skills, run: +npm i -D @nutui/nutui-react-cli +npx skills add ./node_modules/@nutui/nutui-react-cli/skills/nutui-react +``` + +## What the agent gets + +### CLI — offline knowledge query + +[@nutui/nutui-react-cli](https://www.npmjs.com/package/@nutui/nutui-react-cli) bundles component props, docs, demos, and Design Tokens with the package, so queries run locally in milliseconds — no network, no API key. + +```bash +npx @nutui/nutui-react-cli info Button +``` + +Full reference: [CLI](/#/en-US/ai/cli) + +### MCP Server — IDE integration + +The CLI can also run as a local MCP server, registering the same knowledge as IDE-native tools so Claude Code, Cursor, VS Code, Codex, and others can call them on demand in conversation. It exposes 5 read-only tools and 2 prompts. + +```json +{ + "mcpServers": { + "nutui-react": { + "command": "npx", + "args": ["-y", "@nutui/nutui-react-cli", "mcp"] + } + } +} +``` + +Full reference: [MCP Server](/#/en-US/ai/mcp) + +### Skill — teaches the agent when to use it + +The CLI ships with a Skill file following the Agent Skills spec. The CLI/MCP provide the _capabilities_; the Skill constrains _when and in what order_ the agent uses them — e.g. "look up props and grab a demo before writing a component" and "customize styles with `var(--nutui-*)` tokens instead of hardcoded colors". + +```bash +npm i -D @nutui/nutui-react-cli +npx skills add ./node_modules/@nutui/nutui-react-cli/skills/nutui-react +``` + +### LLMs.txt — structured documentation + +Inject the complete component documentation directly into the AI context — ideal for tools that don't support CLI/MCP: + +| File | Description | +| --- | --- | +| [llms.txt](https://nutui.jd.com/h5/react/4x/llms.txt) | Documentation navigation index | +| [llms-full.txt](https://nutui.jd.com/h5/react/4x/llms-full.txt) | Complete component documentation (English) | +| [llms-full-cn.txt](https://nutui.jd.com/h5/react/4x/llms-full-cn.txt) | Complete component documentation (Chinese) | + +You can also fetch a single component's docs: `https://nutui.jd.com/h5/react/4x/components/button.md`. + +Full reference: [LLMs.txt](/#/en-US/ai/llms) diff --git a/src/sites/sites-react/doc/docs/ai-react/for-agents.md b/src/sites/sites-react/doc/docs/ai-react/for-agents.md new file mode 100644 index 0000000000..176a28a731 --- /dev/null +++ b/src/sites/sites-react/doc/docs/ai-react/for-agents.md @@ -0,0 +1,67 @@ +# For Agents + +本页提供一段开箱即用的提示词,让任何 AI 编程 Agent 高效使用 NutUI-React。 + +## 复制这段提示词 + +把下面这段话复制到你的 Agent 对话或自动化流程中,让它在写 NutUI-React 代码前先建立正确的上下文: + +```text +在编写任何 NutUI-React(@nutui/nutui-react)代码之前,请先阅读 https://nutui.jd.com/h5/react/4x/llms-full-cn.txt 理解组件的真实 API、用法与样式结构,不要凭记忆猜测 Prop 或枚举值。使用任何组件前先查文档,再写代码。 + +如果你的环境支持 skills,请运行: +npm i -D @nutui/nutui-react-cli +npx skills add ./node_modules/@nutui/nutui-react-cli/skills/nutui-react +``` + +## Agent 获得什么 + +### CLI — 离线知识查询 + +[@nutui/nutui-react-cli](https://www.npmjs.com/package/@nutui/nutui-react-cli) 把组件的 Props、文档、示例与 Design Token 打包随包分发,安装后本地毫秒级查询,无需网络、无需 API Key。 + +```bash +npx @nutui/nutui-react-cli info Button +``` + +完整参考:[CLI](/#/zh-CN/ai/cli) + +### MCP Server — IDE 集成 + +CLI 同时可作为本地 MCP 服务运行,把同一份知识注册成 IDE 原生工具,让 Claude Code、Cursor、VS Code、Codex 等在对话中按需自动调用,提供 5 个只读工具与 2 个提示词。 + +```json +{ + "mcpServers": { + "nutui-react": { + "command": "npx", + "args": ["-y", "@nutui/nutui-react-cli", "mcp"] + } + } +} +``` + +完整参考:[MCP Server](/#/zh-CN/ai/mcp) + +### Skill — 教 Agent 何时用 + +CLI 内置一份遵循 Agent Skills 规范的 Skill 文件,随包分发。CLI/MCP 提供的是「能力」,Skill 则约束 Agent「什么时候、按什么顺序」用这些能力——例如「写组件前先查 Props 再拿示例」「定制样式用 `var(--nutui-*)` token 而非硬编码颜色」。 + +```bash +npm i -D @nutui/nutui-react-cli +npx skills add ./node_modules/@nutui/nutui-react-cli/skills/nutui-react +``` + +### LLMs.txt — 结构化文档 + +把完整的组件文档直接注入 AI 上下文,适合不支持 CLI/MCP 的工具: + +| 文件 | 说明 | +| --- | --- | +| [llms.txt](https://nutui.jd.com/h5/react/4x/llms.txt) | 文档导航索引 | +| [llms-full-cn.txt](https://nutui.jd.com/h5/react/4x/llms-full-cn.txt) | 全部组件文档(中文) | +| [llms-full.txt](https://nutui.jd.com/h5/react/4x/llms-full.txt) | 全部组件文档(英文) | + +也可以获取单个组件文档:`https://nutui.jd.com/h5/react/4x/components/button.md`。 + +完整参考:[LLMs.txt](/#/zh-CN/ai/llms) diff --git a/src/sites/sites-react/doc/docs/ai-react/mcp.en-US.md b/src/sites/sites-react/doc/docs/ai-react/mcp.en-US.md new file mode 100644 index 0000000000..88be6273a6 --- /dev/null +++ b/src/sites/sites-react/doc/docs/ai-react/mcp.en-US.md @@ -0,0 +1,79 @@ +# MCP Server + +This guide explains how to use NutUI-React in AI tools through the Model Context Protocol (MCP). + +## What is MCP? + +[Model Context Protocol (MCP)](https://modelcontextprotocol.io/) is an open protocol that lets AI models interact with external tools and data sources. Through MCP, AI assistants can directly access NutUI-React's component docs, code examples, and API references. + +The CLI is "the agent runs commands"; MCP registers the same capabilities as IDE-native tools, so Claude Code / Cursor / VS Code / Codex can call them **automatically on demand** in conversation, without assembling command-line strings. Both reuse the same offline metadata snapshot — two calling protocols over one knowledge base. + +## Start the MCP server + +`nutui-react mcp` starts a local MCP server that communicates over stdio, exposing 5 read-only tools and 2 prompts. This command shouldn't be run directly in a terminal — configure it in your AI tool instead (see below). + +### Tools + +| Tool | Description | +| --- | --- | +| `nutui_list` | List all components (filterable by category) | +| `nutui_info` | Get a component's props spec | +| `nutui_doc` | Get a component's full docs (`lang: zh\|en`) | +| `nutui_demo` | Get a component's H5 demo list / source | +| `nutui_token` | Query Design Tokens (global / component-level) | + +All tools are read-only, side-effect-free, and do not access the external network. + +### Prompts + +| Prompt | Description | +| --- | --- | +| `nutui-expert` | Positions the agent as a NutUI-React expert (look up first, then write) | +| `nutui-page-generator` | Generate a complete, runnable page from NutUI-React components | + +## Configuration + +Shared config for **Claude Code** (`.mcp.json` or `claude mcp add`), **Cursor** (`.cursor/mcp.json`), and **VS Code** (the `servers` field in `.vscode/mcp.json`): + +```json +{ + "mcpServers": { + "nutui-react": { + "command": "npx", + "args": ["-y", "@nutui/nutui-react-cli", "mcp"] + } + } +} +``` + +**Codex** (`~/.codex/config.toml`): + +```toml +[mcp_servers.nutui-react] +command = "npx" +args = ["-y", "@nutui/nutui-react-cli", "mcp"] +``` + +`npx -y` launches it without a global install; alternatively, after a global install, change `command` to `nutui-react` and `args` to `["mcp"]`. + +## Usage with AI tools + +| Tool | Configuration | +| --- | --- | +| **Claude Code** | Add to `.mcp.json`, or use the `claude mcp add` command | +| **Cursor** | Add to `.cursor/mcp.json`, or Settings → MCP | +| **VS Code** | Add to the `servers` field in `.vscode/mcp.json` | +| **Codex** | Add to `~/.codex/config.toml` | + +When these tools are available in the conversation, the agent prefers to call them directly instead of assembling command-line strings. + +## Alternative: use LLMs.txt + +If your AI tool doesn't support MCP, use the [LLMs.txt](/#/en-US/ai/llms) support to inject complete component documentation directly into the AI context. + +## Learn more + +- [Model Context Protocol docs](https://modelcontextprotocol.io/) +- [CLI](/#/en-US/ai/cli) +- [LLMs.txt](/#/en-US/ai/llms) +- [For Agents](/#/en-US/ai/for-agents) diff --git a/src/sites/sites-react/doc/docs/ai-react/mcp.md b/src/sites/sites-react/doc/docs/ai-react/mcp.md new file mode 100644 index 0000000000..f153dd4e05 --- /dev/null +++ b/src/sites/sites-react/doc/docs/ai-react/mcp.md @@ -0,0 +1,79 @@ +# MCP Server + +本篇介绍如何通过 Model Context Protocol (MCP) 在 AI 工具中使用 NutUI-React。 + +## 什么是 MCP? + +[Model Context Protocol (MCP)](https://modelcontextprotocol.io/) 是一个开放协议,使 AI 模型能够与外部工具和数据源交互。通过 MCP,AI 助手可以直接访问 NutUI-React 的组件文档、代码示例和 API 参考。 + +CLI 是「Agent 主动敲命令」,MCP 则把同一份能力注册成 IDE 原生工具,让 Claude Code / Cursor / VS Code / Codex 在对话中**按需自动调用**,无需拼命令行字符串。二者复用同一份离线元数据快照,等于给同一个知识库套了两种调用协议。 + +## 启动 MCP 服务 + +`nutui-react mcp` 启动一个通过 stdio 通信的本地 MCP 服务,暴露 5 个只读工具与 2 个提示词。该命令不应在终端直接裸跑,而应在 AI 工具中配置(见下方)。 + +### 工具 + +| 工具 | 说明 | +| --- | --- | +| `nutui_list` | 列出全部组件(可按分类筛选) | +| `nutui_info` | 获取组件的 Props 规格 | +| `nutui_doc` | 获取组件完整文档(`lang: zh\|en`) | +| `nutui_demo` | 获取组件 H5 示例列表 / 源码 | +| `nutui_token` | 查询 Design Token(全局 / 组件级) | + +所有工具均为只读、无副作用、不访问外部网络。 + +### 提示词 + +| 提示词 | 说明 | +| --- | --- | +| `nutui-expert` | 把 Agent 定位为 NutUI-React 专家(先查后写) | +| `nutui-page-generator` | 基于 NutUI-React 组件生成完整可运行页面 | + +## 配置 + +**Claude Code**(`.mcp.json` 或 `claude mcp add`)、**Cursor**(`.cursor/mcp.json`)、**VS Code**(`.vscode/mcp.json` 的 `servers` 字段)通用配置: + +```json +{ + "mcpServers": { + "nutui-react": { + "command": "npx", + "args": ["-y", "@nutui/nutui-react-cli", "mcp"] + } + } +} +``` + +**Codex**(`~/.codex/config.toml`): + +```toml +[mcp_servers.nutui-react] +command = "npx" +args = ["-y", "@nutui/nutui-react-cli", "mcp"] +``` + +`npx -y` 免全局安装即可拉起;也可全局安装 CLI 后把 `command` 换成 `nutui-react`、`args` 换成 `["mcp"]`。 + +## 在 AI 工具中的使用 + +| 工具 | 配置 | +| --- | --- | +| **Claude Code** | 添加到 `.mcp.json`,或用 `claude mcp add` 命令 | +| **Cursor** | 添加到 `.cursor/mcp.json`,或设置 → MCP | +| **VS Code** | 添加到 `.vscode/mcp.json` 的 `servers` 字段 | +| **Codex** | 添加到 `~/.codex/config.toml` | + +当这些工具在对话中可用时,Agent 会优先直接调用,而非再拼命令行字符串。 + +## 备选方案:使用 LLMs.txt + +如果你的 AI 工具不支持 MCP,可以使用 [LLMs.txt](/#/zh-CN/ai/llms) 支持,把完整的组件文档直接注入 AI 上下文。 + +## 了解更多 + +- [Model Context Protocol 文档](https://modelcontextprotocol.io/) +- [CLI](/#/zh-CN/ai/cli) +- [LLMs.txt](/#/zh-CN/ai/llms) +- [For Agents](/#/zh-CN/ai/for-agents)