UNPKG

@qin-ui/antd-vue-pro

Version:
416 lines (355 loc) 13 kB
#!/usr/bin/env node /* global process -- Node.js CLI 脚本 */ /** * @qin-ui/antd-vue-pro AI 上下文初始化 CLI 工具 * * 在消费方项目中生成双载体 AI 上下文: * 1. 根目录 AGENTS.md -- 核心使用规则,跨工具自动注入(主载体) * 2. .agents/skills/{pkg}/SKILL.md + references/ -- 分层参考文档,支持 skills 发现的工具按需逐层调取(参考载体) * * 用法: * npx @qin-ui/antd-vue-pro init-ai */ import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; // ==================== 常量 ==================== const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const PKG_ROOT = path.resolve(__dirname, '..'); const PKG_JSON = JSON.parse( fs.readFileSync(path.join(PKG_ROOT, 'package.json'), 'utf-8') ); const PKG_NAME = PKG_JSON.name; const PKG_SHORT = PKG_NAME.replace(/^@qin-ui\//, ''); // AGENTS.md 智能合并区块标记(支持多库共存,幂等更新) const BEGIN_MARKER = `<!-- BEGIN ${PKG_NAME} -->`; const END_MARKER = `<!-- END ${PKG_NAME} -->`; // ==================== 终端颜色 ==================== const green = s => `\x1b[32m${s}\x1b[0m`; const cyan = s => `\x1b[36m${s}\x1b[0m`; const bold = s => `\x1b[1m${s}\x1b[0m`; const yellow = s => `\x1b[33m${s}\x1b[0m`; const dim = s => `\x1b[2m${s}\x1b[0m`; // ==================== 内容读取 ==================== function readPackageFile(filename) { const filePath = path.join(PKG_ROOT, filename); if (fs.existsSync(filePath)) { return fs.readFileSync(filePath, 'utf-8').trim(); } return null; } function getAiContextContent() { return ( readPackageFile('AI-CONTEXT.md') || `# ${PKG_NAME}\n\n> 基于 Vue 3 的配置驱动组件库。` ); } function getReadmeContent() { return readPackageFile('README.md') || ''; } function getApiJsonContent() { try { const raw = readPackageFile('api.json'); if (!raw) return null; return JSON.parse(raw); } catch { return null; } } // ==================== 工具函数 ==================== function escapeRegExp(s) { return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } function ensureDir(dirPath) { if (!fs.existsSync(dirPath)) { fs.mkdirSync(dirPath, { recursive: true }); } } function writeFileWithLog(filePath, content, label) { const dir = path.dirname(filePath); ensureDir(dir); const existed = fs.existsSync(filePath); fs.writeFileSync(filePath, content, 'utf-8'); const status = existed ? yellow('[更新]') : green('[创建]'); console.log(` ${status} ${cyan(label)}`); } // ==================== AGENTS.md(主载体,自动注入)==================== /** * 生成 AGENTS.md 区块内容 * = AI-CONTEXT.md 全文(核心使用规则,AI 必然读到) */ function getAgentsBlock() { return getAiContextContent(); } /** * 智能合并 AGENTS.md: * - 文件不存在 -> 创建,内容 = 标记区块 * - 已有本库区块 -> 幂等替换区块内容(支持升级后更新) * - 已有其他内容但无本库区块 -> 末尾追加区块(多库共存不冲突) */ function writeAgentsMd(cwd) { const agentsPath = path.join(cwd, 'AGENTS.md'); const blockContent = getAgentsBlock(); const newBlock = `${BEGIN_MARKER}\n${blockContent}\n${END_MARKER}`; let existing = ''; if (fs.existsSync(agentsPath)) { existing = fs.readFileSync(agentsPath, 'utf-8'); } let result; const hasBlock = existing.includes(BEGIN_MARKER) && existing.includes(END_MARKER); if (hasBlock) { // 幂等替换已有区块 const blockRegex = new RegExp( `${escapeRegExp(BEGIN_MARKER)}[\\s\\S]*?${escapeRegExp(END_MARKER)}`, 'g' ); result = existing.replace(blockRegex, newBlock); } else if (existing.trim()) { // 已有其他内容,追加区块 result = `${existing.trimEnd()}\n\n${newBlock}\n`; } else { // 文件不存在或空 result = `${newBlock}\n`; } const existed = fs.existsSync(agentsPath); fs.writeFileSync(agentsPath, result, 'utf-8'); const status = existed ? yellow('[更新]') : green('[创建]'); console.log(` ${status} ${cyan('AGENTS.md')}`); } // ==================== Skills(参考载体,按需调取)==================== /** * 生成 SKILL.md 内容 * = skill frontmatter + AI-CONTEXT.md 速查内容 + references 导航 * 供支持 skills 发现的工具按需调取,精准定位后查阅 references */ function getSkillMainContent() { const aiContext = getAiContextContent(); const sections = []; // skill frontmatter sections.push('---'); sections.push(`name: ${PKG_SHORT}`); sections.push( `description: ${PKG_NAME} 使用指南 - 组件、Hooks、类型、Field/Column 配置。Schema 驱动的配置式组件库。当需要组件映射、默认预设、属性透传规则或完整用法时按需调取。` ); sections.push('---'); sections.push(''); // AI-CONTEXT.md 速查内容(与 AGENTS.md 主载体同源,确保一致) sections.push(aiContext); sections.push(''); // references 导航 sections.push('---'); sections.push(''); sections.push('## 参考文档'); sections.push(''); sections.push( `以下文件位于 \`.agents/skills/${PKG_SHORT}/references/\`,可在需要精确细节时进一步查阅:` ); sections.push(''); sections.push( `- [references/README.md](references/README.md) — 完整使用文档与进阶示例` ); sections.push( `- [references/api.md](references/api.md) — 结构化 API 元数据(函数签名、参数类型、返回值,提取自源码 JSDoc)` ); sections.push(`- 底层组件属性查阅 ant-design-vue 官方文档:https://antdv.com`); sections.push(''); return sections.join('\n'); } /** * 生成 references/api.md 内容(结构化 API 元数据 + skill frontmatter) * 从 api.json 提取 @public 标记的 JSDoc,含签名、参数、返回值、示例 */ function getSkillApiContent() { const apiJson = getApiJsonContent(); const sections = []; // skill frontmatter sections.push('---'); sections.push(`name: ${PKG_SHORT}-api`); sections.push( `description: ${PKG_NAME} 结构化 API 元数据 - 函数签名、参数类型、返回值、示例。从源码 JSDoc(@public 标记)自动提取。` ); sections.push('---'); sections.push(''); sections.push(`# ${PKG_NAME} - 结构化 API 元数据`, ''); sections.push( `> 自动提取自源码 JSDoc(\`@public\` 标记)。版本: ${PKG_JSON.version}`, '' ); // 结构化 API 元数据 if (apiJson && apiJson.api && apiJson.api.length > 0) { for (const item of apiJson.api) { const typeLabel = { component: '组件', function: '函数/Hook', type: '类型', interface: '接口', constant: '常量', }[item.type] || ''; sections.push(`### ${typeLabel} \`${item.name}\``); sections.push(''); sections.push(`**类型:** ${item.type}`); if (item.signature) { sections.push(''); sections.push('```typescript'); sections.push(item.signature); sections.push('```'); } if (item.description) { sections.push(''); sections.push(item.description); } if (item.typeParams && item.typeParams.length > 0) { sections.push(''); sections.push('**泛型参数:**'); for (const tp of item.typeParams) { const extras = []; if (tp.extends) extras.push(`extends ${tp.extends}`); if (tp.default) extras.push(`默认 ${tp.default}`); const extra = extras.length ? ` (${extras.join(', ')})` : ''; sections.push(`- \`${tp.name}\`${extra}`); } } if (item.params && item.params.length > 0) { sections.push(''); sections.push('**参数:**'); sections.push(''); sections.push('| 参数名 | 类型 | 可选 | 描述 |'); sections.push('| :--- | :--- | :--- | :--- |'); for (const p of item.params) { sections.push( `| \`${p.name}\` | \`${p.type}\` | ${p.optional ? '是' : '否'} | ${p.description} |` ); } } if (item.returns) { sections.push(''); sections.push(`**返回值:** ${item.returns}`); } if (item.examples && item.examples.length > 0) { sections.push(''); sections.push('**示例:**'); for (const ex of item.examples) { sections.push(''); sections.push(ex); } } sections.push(''); sections.push('---'); sections.push(''); } } return sections.join('\n'); } // ==================== CLI 入口 ==================== function printHelp() { console.log(` ${bold(`${PKG_NAME} CLI - AI 上下文初始化`)} ${bold('用法:')} npx ${PKG_NAME} init-ai ${bold('说明:')} 在项目中生成双载体 AI 上下文,使 AI 工具能够深度理解和规范使用 ${PKG_NAME}。 生成的文件结构: AGENTS.md 核心使用规则(跨工具自动注入) .agents/ skills/ ${PKG_SHORT}/ SKILL.md skills 入口(速查 + 导航) references/ README.md 完整使用文档 api.md 结构化 API 元数据 ${dim('AGENTS.md 是跨工具开放约定,Codex / Claude Code / Cursor 等会话时自动注入。')} ${dim('.agents/skills/ 供支持 skills 发现的工具按需逐层调取。')} ${bold('选项:')} --help 显示帮助信息 `); } function main() { const args = process.argv.slice(2); const subcommand = args.find(a => !a.startsWith('-')); const flags = args.filter(a => a.startsWith('-')); if (!subcommand || flags.includes('--help') || flags.includes('-h')) { printHelp(); process.exit(0); } if (subcommand !== 'init-ai') { console.error(`\n ❌ 未知命令: ${subcommand}\n`); printHelp(); process.exit(1); } console.log(''); console.log(bold(`📦 ${PKG_NAME} - AI 上下文初始化 v${PKG_JSON.version}`)); console.log(dim(` 基于 ant-design-vue 的 Schema 驱动组件库`)); console.log(''); // 1. 生成 AGENTS.md(主载体) console.log(bold('📋 主载体:AGENTS.md(自动注入)')); writeAgentsMd(process.cwd()); console.log( dim(' -> 核心使用规则,Codex/Claude Code/Cursor 等会话自动加载') ); console.log(''); // 2. 生成 Skills(标准结构:SKILL.md + references/) console.log(bold('📖 参考载体:.agents/skills/(按需调取)')); const skillDir = path.join(process.cwd(), '.agents/skills', PKG_SHORT); const skillRefsDir = path.join(skillDir, 'references'); // SKILL.md(入口:frontmatter + 速查内容 + 参考导航) writeFileWithLog( path.join(skillDir, 'SKILL.md'), getSkillMainContent(), `.agents/skills/${PKG_SHORT}/SKILL.md` ); // references/README.md(完整使用文档) const readme = getReadmeContent(); if (readme) { writeFileWithLog( path.join(skillRefsDir, 'README.md'), readme, `.agents/skills/${PKG_SHORT}/references/README.md` ); } // references/api.md(结构化 API 元数据) const apiJson = getApiJsonContent(); if (apiJson && apiJson.api && apiJson.api.length > 0) { writeFileWithLog( path.join(skillRefsDir, 'api.md'), getSkillApiContent(), `.agents/skills/${PKG_SHORT}/references/api.md` ); } console.log( dim(' -> SKILL.md 入口 + references/ 完整文档,skills 工具按需逐层调取') ); console.log(''); // 3. 完成提示 console.log(green('✅ 完成!已生成双载体 AI 上下文文件。')); console.log(''); console.log(`${bold('📂 生成的文件:')}`); console.log( ` ${cyan('AGENTS.md')} ${dim('← 核心规则(AI 自动读取)')}` ); console.log(` ${cyan('.agents/skills/' + PKG_SHORT + '/')}`); console.log( ` ├── ${cyan('SKILL.md')} ${dim('← skills 入口(速查 + 导航)')}` ); console.log(` └── ${cyan('references/')}`); console.log( ` ├── ${cyan('README.md')} ${dim('← 完整使用文档')}` ); if (apiJson && apiJson.api && apiJson.api.length > 0) { console.log( ` └── ${cyan('api.md')} ${dim('← 结构化 API 元数据')}` ); } console.log(''); console.log(`${bold('🔄 说明:')}`); console.log( ` - AGENTS.md 已用标记区块写入,重复执行 init-ai 可安全更新(不破坏其他库的指令)` ); console.log( ` - 编写 Field 中输入控件属性前,查阅 ant-design-vue 官方文档:${cyan('https://antdv.com')}` ); console.log(''); } main();