fe-kit-cli 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +89 -0
  2. package/dist/cli.mjs +1738 -0
  3. package/dist/cli.mjs.map +1 -0
  4. package/dist/rules/common/typescript.mdc +21 -0
  5. package/dist/rules/react/component-conventions.mdc +24 -0
  6. package/dist/rules/react/hooks.mdc +20 -0
  7. package/dist/rules/react/react-router.mdc +18 -0
  8. package/dist/rules/react/state-management.mdc +21 -0
  9. package/dist/rules/vue/component-conventions.mdc +23 -0
  10. package/dist/rules/vue/composition-api.mdc +24 -0
  11. package/dist/rules/vue/state-management.mdc +16 -0
  12. package/dist/rules/vue/vue-router.mdc +18 -0
  13. package/dist/skills/app-ui-design/SKILL.md +62 -0
  14. package/dist/skills/app-ui-design/references/rules.md +127 -0
  15. package/dist/skills/e2e-testing/SKILL.md +327 -0
  16. package/dist/skills/eval-harness/SKILL.md +271 -0
  17. package/dist/skills/frontend-design/SKILL.md +43 -0
  18. package/dist/skills/frontend-patterns/SKILL.md +643 -0
  19. package/dist/skills/security-review/SKILL.md +496 -0
  20. package/dist/skills/tailwindcss-advanced-layouts/SKILL.md +595 -0
  21. package/dist/skills/tdd-workflow/SKILL.md +464 -0
  22. package/dist/skills/verification-loop/SKILL.md +127 -0
  23. package/dist/skills/wechat-ui-design/SKILL.md +64 -0
  24. package/dist/skills/wechat-ui-design/references/rules.md +121 -0
  25. package/dist/templates/react-rspack-ts/index.html +11 -0
  26. package/dist/templates/react-rspack-ts/package.json +20 -0
  27. package/dist/templates/react-rspack-ts/rspack.config.ts +23 -0
  28. package/dist/templates/react-rspack-ts/src/App.tsx +7 -0
  29. package/dist/templates/react-rspack-ts/src/main.tsx +9 -0
  30. package/dist/templates/react-rspack-ts/tsconfig.json +17 -0
  31. package/dist/templates/react-vite-ts/index.html +12 -0
  32. package/dist/templates/react-vite-ts/package.json +22 -0
  33. package/dist/templates/react-vite-ts/src/App.tsx +7 -0
  34. package/dist/templates/react-vite-ts/src/main.tsx +9 -0
  35. package/dist/templates/react-vite-ts/tsconfig.json +19 -0
  36. package/dist/templates/react-vite-ts/vite.config.ts +9 -0
  37. package/dist/templates/react-webpack-ts/index.html +11 -0
  38. package/dist/templates/react-webpack-ts/package.json +25 -0
  39. package/dist/templates/react-webpack-ts/src/App.tsx +7 -0
  40. package/dist/templates/react-webpack-ts/src/main.tsx +9 -0
  41. package/dist/templates/react-webpack-ts/tsconfig.json +17 -0
  42. package/dist/templates/react-webpack-ts/webpack.config.ts +29 -0
  43. package/dist/templates/vue-rspack-ts/index.html +11 -0
  44. package/dist/templates/vue-rspack-ts/package.json +18 -0
  45. package/dist/templates/vue-rspack-ts/rspack.config.ts +16 -0
  46. package/dist/templates/vue-rspack-ts/src/App.vue +7 -0
  47. package/dist/templates/vue-rspack-ts/src/main.ts +4 -0
  48. package/dist/templates/vue-rspack-ts/tsconfig.json +17 -0
  49. package/dist/templates/vue-vite-ts/index.html +12 -0
  50. package/dist/templates/vue-vite-ts/package.json +19 -0
  51. package/dist/templates/vue-vite-ts/src/App.vue +7 -0
  52. package/dist/templates/vue-vite-ts/src/main.ts +4 -0
  53. package/dist/templates/vue-vite-ts/tsconfig.json +19 -0
  54. package/dist/templates/vue-vite-ts/vite.config.ts +9 -0
  55. package/dist/templates/vue-webpack-ts/index.html +11 -0
  56. package/dist/templates/vue-webpack-ts/package.json +24 -0
  57. package/dist/templates/vue-webpack-ts/src/App.vue +7 -0
  58. package/dist/templates/vue-webpack-ts/src/main.ts +4 -0
  59. package/dist/templates/vue-webpack-ts/tsconfig.json +17 -0
  60. package/dist/templates/vue-webpack-ts/webpack.config.ts +32 -0
  61. package/package.json +63 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts","../src/constants/meta.ts","../src/constants/frameworks.ts","../src/constants/bundlers.ts","../src/constants/tools.ts","../src/constants/lint.ts","../src/prompts/init-prompts.ts","../src/skills/catalog.ts","../src/mcp/catalog.ts","../src/generators/project-generator.ts","../src/utils/logger.ts","../src/generators/lint-generator.ts","../src/generators/fe-kit-meta-generator.ts","../src/utils/fs.ts","../src/core/merge-config.ts","../src/core/write-rules.ts","../src/generators/readme-generator.ts","../src/adapters/cursor.ts","../src/core/paths.ts","../src/core/rule-writers.ts","../src/adapters/claude-code.ts","../src/adapters/vscode.ts","../src/adapters/codebuddy-cn.ts","../src/adapters/trae.ts","../src/adapters/idea.ts","../src/adapters/registry.ts","../src/core/apply-adapters.ts","../src/commands/init.ts","../src/commands/enhance.ts","../src/core/detect-project.ts","../src/core/detect-stack.ts","../src/prompts/enhance-prompts.ts","../src/generators/quality-generator.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { CLI_NAME, CLI_VERSION } from './constants/index.js';\nimport { initCommand } from './commands/init.js';\nimport { enhanceCommand } from './commands/enhance.js';\n\nconst program = new Command();\n\nprogram\n .name(CLI_NAME)\n .description('Frontend project scaffold CLI — init, enhance, and manage your dev environment.')\n .version(CLI_VERSION);\n\nprogram\n .command('init')\n .description('Initialize a new frontend project with Vue or React + TypeScript')\n .action(async () => {\n try {\n await initCommand();\n } catch (err) {\n console.error(err);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command('enhance')\n .description('Enhance an existing frontend project with dev tools, skills, MCP, and rules')\n .action(async () => {\n try {\n await enhanceCommand();\n } catch (err) {\n console.error(err);\n process.exitCode = 1;\n }\n });\n\nprogram.parse();\n","export const CLI_NAME = 'fe-kit';\nexport const META_DIR = '.fe-kit';\nexport const CLI_VERSION = '0.1.0';\n","export const FRAMEWORKS = ['vue', 'react'] as const;\nexport type Framework = (typeof FRAMEWORKS)[number];\n\nexport const ROUTERS: Record<Framework, string> = {\n vue: 'vue-router',\n react: 'react-router',\n};\n\nexport const STATE_MANAGERS: Record<Framework, readonly string[]> = {\n vue: ['pinia', 'vuex'] as const,\n react: ['redux-toolkit', 'zustand', 'mobx'] as const,\n};\n","export const BUNDLERS = ['vite', 'webpack', 'rspack'] as const;\nexport type Bundler = (typeof BUNDLERS)[number];\n","export const DEV_TOOLS = [\n 'cursor',\n 'claude-code',\n 'vscode',\n 'codebuddy-cn',\n 'trae',\n 'idea',\n] as const;\n\nexport type DevToolId = (typeof DEV_TOOLS)[number];\n","export const LINT_TOOLS = [\n 'eslint',\n 'stylelint',\n 'prettier',\n 'editorconfig',\n] as const;\n\nexport type LintTool = (typeof LINT_TOOLS)[number];\n\nexport const QUALITY_TOOLS = [\n 'eslint',\n 'stylelint',\n 'prettier',\n 'editorconfig',\n 'commitlint',\n] as const;\n\nexport type QualityTool = (typeof QUALITY_TOOLS)[number];\n","import path from 'node:path';\nimport prompts from 'prompts';\nimport type { InitAnswers } from '../types/selections.js';\nimport { FRAMEWORKS, ROUTERS, STATE_MANAGERS, type Framework } from '../constants/frameworks.js';\nimport { BUNDLERS } from '../constants/bundlers.js';\nimport { DEV_TOOLS } from '../constants/tools.js';\nimport { LINT_TOOLS } from '../constants/lint.js';\nimport { getSkillCatalog } from '../skills/catalog.js';\nimport { getMcpCatalog } from '../mcp/catalog.js';\n\n\nexport async function runInitPrompts(): Promise<InitAnswers | null> {\n const response = await prompts(\n [\n {\n type: 'text',\n name: 'projectName',\n message: 'Project name:',\n validate: (v: string) => (v.trim() ? true : 'Project name is required'),\n },\n {\n type: 'text',\n name: 'projectPath',\n message: 'Project path:',\n initial: (prev: string) => `./${prev}`,\n format: (v: string) => path.resolve(v),\n },\n {\n type: 'select',\n name: 'framework',\n message: 'Frontend framework:',\n choices: FRAMEWORKS.map((f) => ({ title: f.charAt(0).toUpperCase() + f.slice(1), value: f })),\n },\n {\n type: 'select',\n name: 'router',\n message: 'Router:',\n choices: (_prev: unknown, answers: Record<string, unknown>) => {\n const fw = answers.framework as Framework;\n return [{ title: ROUTERS[fw], value: ROUTERS[fw] }];\n },\n },\n {\n type: 'select',\n name: 'stateManagement',\n message: 'State management:',\n choices: (_prev: unknown, answers: Record<string, unknown>) => {\n const fw = answers.framework as Framework;\n return STATE_MANAGERS[fw].map((s) => ({ title: s, value: s }));\n },\n },\n {\n type: 'select',\n name: 'bundler',\n message: 'Build tool:',\n choices: BUNDLERS.map((b) => ({ title: b.charAt(0).toUpperCase() + b.slice(1), value: b })),\n },\n {\n type: 'multiselect',\n name: 'lintTools',\n message: 'Code quality tools (space to toggle):',\n choices: LINT_TOOLS.map((t) => ({\n title: t,\n value: t,\n selected: true,\n })),\n hint: 'ESLint + Prettier recommended',\n },\n {\n type: 'multiselect',\n name: 'devTools',\n message: 'Dev tools to configure:',\n choices: DEV_TOOLS.map((t) => ({ title: t, value: t, selected: t === 'cursor' })),\n min: 1,\n hint: 'Select at least one',\n },\n {\n type: 'multiselect',\n name: 'skills',\n message: 'Built-in Skills to enable:',\n choices: getSkillCatalog().map((s) => ({\n title: `${s.label} — ${s.description}`,\n value: s.id,\n selected: false,\n })),\n },\n {\n type: 'multiselect',\n name: 'mcpServers',\n message: 'MCP servers to enable:',\n choices: getMcpCatalog().map((m) => ({\n title: `${m.label} — ${m.description}`,\n value: m.id,\n selected: false,\n })),\n },\n ],\n { onCancel: () => process.exit(0) },\n );\n\n if (!response.projectName) return null;\n\n return response as InitAnswers;\n}\n","import type { SkillSelection } from '../adapters/types.js';\nimport fs from 'fs-extra';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst { pathExistsSync, readdirSync, readFileSync } = fs;\n\nexport interface SkillDefinition {\n id: string;\n label: string;\n description: string;\n content: string;\n tags: string[];\n /** Absolute path to the original SKILL.md. */\n sourcePath: string;\n}\n\nfunction toLabel(id: string): string {\n return id\n .split(/[-_]/g)\n .filter(Boolean)\n .map((w) => w.slice(0, 1).toUpperCase() + w.slice(1))\n .join(' ');\n}\n\nfunction splitFrontmatter(raw: string): { meta: Record<string, string>; body: string } {\n if (!raw.startsWith('---\\n')) return { meta: {}, body: raw };\n\n const end = raw.indexOf('\\n---\\n', 4);\n if (end === -1) return { meta: {}, body: raw };\n\n const fm = raw.slice(4, end).trim();\n const body = raw.slice(end + '\\n---\\n'.length).replace(/^\\n+/, '');\n\n const meta: Record<string, string> = {};\n for (const line of fm.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const idx = trimmed.indexOf(':');\n if (idx <= 0) continue;\n const key = trimmed.slice(0, idx).trim();\n let value = trimmed.slice(idx + 1).trim();\n value = value.replace(/^\"(.*)\"$/, '$1').replace(/^'(.*)'$/, '$1');\n meta[key] = value;\n }\n\n return { meta, body };\n}\n\nfunction skillsDir(): string {\n return fileURLToPath(new URL('./skills/', import.meta.url));\n}\n\nfunction loadSkillsFromDir(): SkillDefinition[] {\n const dir = skillsDir();\n if (!pathExistsSync(dir)) return [];\n\n const entries = readdirSync(dir, { withFileTypes: true })\n .filter((d) => d.isDirectory())\n .map((d) => d.name)\n .sort((a, b) => a.localeCompare(b));\n\n const defs: SkillDefinition[] = [];\n for (const dirName of entries) {\n const p = path.join(dir, dirName, 'SKILL.md');\n if (!pathExistsSync(p)) continue;\n\n const raw = readFileSync(p, 'utf8');\n const { meta, body } = splitFrontmatter(raw);\n const id = meta.name?.trim() || dirName;\n const description = meta.description?.trim() || '';\n\n defs.push({\n id,\n label: toLabel(id),\n description,\n content: body.trimEnd(),\n tags: [],\n sourcePath: p,\n });\n }\n\n return defs;\n}\n\nexport function getSkillCatalog(): SkillDefinition[] {\n return loadSkillsFromDir();\n}\n\nexport function getSkillById(id: string): SkillSelection | undefined {\n const def = getSkillCatalog().find((s) => s.id === id);\n if (!def) return undefined;\n return { id: def.id, label: def.label, content: def.content, sourcePath: def.sourcePath };\n}\n","import type { McpSelection } from '../adapters/types.js';\n\nexport interface McpDefinition {\n id: string;\n label: string;\n description: string;\n config: Record<string, unknown>;\n}\n\nconst BUILTIN_MCP: McpDefinition[] = [\n {\n id: 'context7',\n label: 'Context7',\n description: 'Fetch up-to-date library documentation via Context7.',\n config: {\n command: 'npx',\n args: ['-y', '@upstash/context7-mcp@latest'],\n },\n },\n {\n id: 'sequential-thinking',\n label: 'Sequential Thinking',\n description: 'Step-by-step reasoning MCP server for complex problem solving.',\n config: {\n command: 'npx',\n args: ['-y', '@anthropic/sequential-thinking-mcp@latest'],\n },\n },\n {\n id: 'filesystem',\n label: 'Filesystem',\n description: 'Read/write project files via MCP.',\n config: {\n command: 'npx',\n args: ['-y', '@anthropic/filesystem-mcp@latest'],\n },\n },\n {\n id: 'exa-search',\n label: 'Exa Search',\n description: 'Neural web search for real-time information.',\n config: {\n command: 'npx',\n args: ['-y', 'exa-mcp-server@latest'],\n env: {\n EXA_API_KEY: '<your-exa-api-key>',\n },\n },\n },\n];\n\nexport function getMcpCatalog(): McpDefinition[] {\n return BUILTIN_MCP;\n}\n\nexport function getMcpById(id: string): McpSelection | undefined {\n const def = BUILTIN_MCP.find((m) => m.id === id);\n if (!def) return undefined;\n return { id: def.id, label: def.label, config: def.config };\n}\n","import path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport fs from 'fs-extra';\nimport type { InitAnswers } from '../types/selections.js';\nimport { logger } from '../utils/logger.js';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nfunction templateDir(framework: string, bundler: string): string {\n return path.resolve(__dirname, '..', 'templates', `${framework}-${bundler}-ts`);\n}\n\nexport async function generateProject(answers: InitAnswers): Promise<void> {\n const { projectPath, projectName, framework, bundler, router, stateManagement } = answers;\n\n await fs.ensureDir(projectPath);\n\n const srcTemplate = templateDir(framework, bundler);\n if (await fs.pathExists(srcTemplate)) {\n await fs.copy(srcTemplate, projectPath, { overwrite: false });\n logger.success(`Template ${framework}-${bundler}-ts copied`);\n } else {\n logger.warn(`No full template for ${framework}-${bundler}-ts. Generating minimal project.`);\n await generateMinimalProject(answers);\n }\n\n await patchPackageJson(projectPath, projectName, framework, bundler, router, stateManagement);\n logger.success('package.json configured');\n\n await ensureNextStyleScaffold(projectPath, framework);\n}\n\nasync function ensureNextStyleScaffold(projectPath: string, framework: InitAnswers['framework']): Promise<void> {\n // Next.js-like organization (no service/api). Keep it additive to avoid breaking existing templates.\n const dirs = [\n path.join(projectPath, 'public'),\n path.join(projectPath, 'src', 'app'),\n path.join(projectPath, 'src', 'components'),\n path.join(projectPath, 'src', 'hooks'),\n path.join(projectPath, 'src', 'lib'),\n path.join(projectPath, 'src', 'styles'),\n ];\n\n await Promise.all(dirs.map((d) => fs.ensureDir(d)));\n\n // Minimal placeholders to make folders visible in git and IDEs.\n const keepFiles = [\n path.join(projectPath, 'src', 'app', '.gitkeep'),\n path.join(projectPath, 'src', 'components', '.gitkeep'),\n path.join(projectPath, 'src', 'hooks', '.gitkeep'),\n path.join(projectPath, 'src', 'lib', '.gitkeep'),\n path.join(projectPath, 'src', 'styles', '.gitkeep'),\n path.join(projectPath, 'public', '.gitkeep'),\n ];\n await Promise.all(keepFiles.map((p) => fs.ensureFile(p)));\n\n // Framework-specific convention hints (purely additive).\n if (framework === 'vue') {\n await fs.ensureFile(path.join(projectPath, 'src', 'hooks', 'README.md'));\n await fs.writeFile(\n path.join(projectPath, 'src', 'hooks', 'README.md'),\n ['# hooks/', '', 'Vue 项目里这里更常放 `composables/`(可按团队习惯重命名)。', ''].join('\\n'),\n 'utf-8',\n );\n }\n}\n\nasync function generateMinimalProject(answers: InitAnswers): Promise<void> {\n const { projectPath, framework, bundler } = answers;\n const srcDir = path.join(projectPath, 'src');\n await fs.ensureDir(srcDir);\n\n const mainFile = framework === 'react' ? 'main.tsx' : 'main.ts';\n\n const mainContent = framework === 'react'\n ? [\n \"import React from 'react';\",\n \"import ReactDOM from 'react-dom/client';\",\n \"import App from './App';\",\n '',\n \"ReactDOM.createRoot(document.getElementById('root')!).render(\",\n ' <React.StrictMode>',\n ' <App />',\n ' </React.StrictMode>,',\n ');',\n ].join('\\n')\n : [\n \"import { createApp } from 'vue';\",\n \"import App from './App.vue';\",\n '',\n \"createApp(App).mount('#app');\",\n ].join('\\n');\n\n await fs.writeFile(path.join(srcDir, mainFile), mainContent, 'utf-8');\n\n if (framework === 'react') {\n await fs.writeFile(\n path.join(srcDir, 'App.tsx'),\n [\n \"import React from 'react';\",\n '',\n 'function App() {',\n ' return <div>Hello fe-kit</div>;',\n '}',\n '',\n 'export default App;',\n ].join('\\n'),\n 'utf-8',\n );\n } else {\n await fs.writeFile(\n path.join(srcDir, 'App.vue'),\n [\n '<script setup lang=\"ts\">',\n \"const msg = 'Hello fe-kit';\",\n '</script>',\n '',\n '<template>',\n ' <div>{{ msg }}</div>',\n '</template>',\n ].join('\\n'),\n 'utf-8',\n );\n }\n\n await fs.writeFile(\n path.join(projectPath, 'index.html'),\n [\n '<!DOCTYPE html>',\n '<html lang=\"en\">',\n '<head>',\n ' <meta charset=\"UTF-8\" />',\n ' <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />',\n ' <title>fe-kit project</title>',\n '</head>',\n '<body>',\n ` <div id=\"${framework === 'react' ? 'root' : 'app'}\"></div>`,\n ` <script type=\"module\" src=\"/src/${mainFile}\"></script>`,\n '</body>',\n '</html>',\n ].join('\\n'),\n 'utf-8',\n );\n\n const tsconfig = {\n compilerOptions: {\n target: 'ES2020',\n module: 'ESNext',\n moduleResolution: 'bundler',\n strict: true,\n jsx: framework === 'react' ? 'react-jsx' : 'preserve',\n esModuleInterop: true,\n skipLibCheck: true,\n forceConsistentCasingInFileNames: true,\n resolveJsonModule: true,\n isolatedModules: true,\n baseUrl: '.',\n paths: { '@/*': ['src/*'] },\n },\n include: ['src'],\n };\n await fs.writeJson(path.join(projectPath, 'tsconfig.json'), tsconfig, { spaces: 2 });\n\n await writeBundlerConfig(projectPath, framework, bundler);\n}\n\nasync function writeBundlerConfig(\n projectPath: string,\n framework: string,\n bundler: string,\n): Promise<void> {\n if (bundler === 'vite') {\n const plugin = framework === 'react'\n ? \"import react from '@vitejs/plugin-react';\"\n : \"import vue from '@vitejs/plugin-vue';\";\n const pluginCall = framework === 'react' ? 'react()' : 'vue()';\n\n await fs.writeFile(\n path.join(projectPath, 'vite.config.ts'),\n [\n \"import { defineConfig } from 'vite';\",\n plugin,\n '',\n 'export default defineConfig({',\n ` plugins: [${pluginCall}],`,\n ' resolve: {',\n \" alias: { '@': '/src' },\",\n ' },',\n '});',\n ].join('\\n'),\n 'utf-8',\n );\n } else if (bundler === 'webpack') {\n await fs.writeFile(\n path.join(projectPath, 'webpack.config.ts'),\n [\n \"// Webpack config placeholder — full template coming in P1\",\n \"import path from 'path';\",\n '',\n 'export default {',\n \" mode: 'development',\",\n \" entry: './src/main.\" + (framework === 'react' ? 'tsx' : 'ts') + \"',\",\n ' resolve: {',\n \" extensions: ['.ts', '.tsx', '.js', '.jsx', '.vue'],\",\n ' },',\n '};',\n ].join('\\n'),\n 'utf-8',\n );\n } else if (bundler === 'rspack') {\n await fs.writeFile(\n path.join(projectPath, 'rspack.config.ts'),\n [\n \"// Rspack config placeholder — full template coming in P1\",\n \"import { defineConfig } from '@rspack/cli';\",\n '',\n 'export default defineConfig({',\n \" entry: { main: './src/main.\" + (framework === 'react' ? 'tsx' : 'ts') + \"' },\",\n '});',\n ].join('\\n'),\n 'utf-8',\n );\n }\n}\n\nasync function patchPackageJson(\n projectPath: string,\n name: string,\n framework: string,\n bundler: string,\n router: string,\n stateManagement: string,\n): Promise<void> {\n const pkgPath = path.join(projectPath, 'package.json');\n const existing = (await fs.pathExists(pkgPath))\n ? await fs.readJson(pkgPath)\n : {};\n\n const deps: Record<string, string> = { ...existing.dependencies };\n const devDeps: Record<string, string> = { ...existing.devDependencies };\n\n if (framework === 'vue') {\n deps.vue = '^3.5.0';\n if (router === 'vue-router') deps['vue-router'] = '^4.5.0';\n if (stateManagement === 'pinia') deps.pinia = '^2.3.0';\n if (stateManagement === 'vuex') deps.vuex = '^4.1.0';\n } else {\n deps.react = '^19.0.0';\n deps['react-dom'] = '^19.0.0';\n devDeps['@types/react'] = '^19.0.0';\n devDeps['@types/react-dom'] = '^19.0.0';\n if (router === 'react-router') deps['react-router-dom'] = '^7.0.0';\n if (stateManagement === 'redux-toolkit') {\n deps['@reduxjs/toolkit'] = '^2.6.0';\n deps['react-redux'] = '^9.2.0';\n }\n if (stateManagement === 'zustand') deps.zustand = '^5.0.0';\n if (stateManagement === 'mobx') {\n deps.mobx = '^6.13.0';\n deps['mobx-react-lite'] = '^4.1.0';\n }\n }\n\n devDeps.typescript = '^5.8.0';\n\n if (bundler === 'vite') {\n devDeps.vite = '^6.3.0';\n if (framework === 'react') devDeps['@vitejs/plugin-react'] = '^4.4.0';\n if (framework === 'vue') devDeps['@vitejs/plugin-vue'] = '^5.2.0';\n } else if (bundler === 'webpack') {\n devDeps.webpack = '^5.99.0';\n devDeps['webpack-cli'] = '^6.0.0';\n devDeps['ts-loader'] = '^9.5.0';\n } else if (bundler === 'rspack') {\n devDeps['@rspack/core'] = '^1.3.0';\n devDeps['@rspack/cli'] = '^1.3.0';\n }\n\n const scripts: Record<string, string> = { ...existing.scripts };\n if (bundler === 'vite') {\n scripts.dev = 'vite';\n scripts.build = 'vite build';\n scripts.preview = 'vite preview';\n } else if (bundler === 'webpack') {\n scripts.dev = 'webpack serve --mode development';\n scripts.build = 'webpack --mode production';\n } else if (bundler === 'rspack') {\n scripts.dev = 'rspack serve';\n scripts.build = 'rspack build';\n }\n\n const pkg = {\n ...existing,\n name,\n version: '0.1.0',\n private: true,\n type: 'module',\n scripts,\n dependencies: deps,\n devDependencies: devDeps,\n };\n\n await fs.writeJson(pkgPath, pkg, { spaces: 2 });\n}\n","import pc from 'picocolors';\n\nexport const logger = {\n info: (msg: string) => console.log(pc.cyan('ℹ'), msg),\n success: (msg: string) => console.log(pc.green('✔'), msg),\n warn: (msg: string) => console.log(pc.yellow('⚠'), msg),\n error: (msg: string) => console.error(pc.red('✖'), msg),\n step: (msg: string) => console.log(pc.blue('→'), msg),\n};\n","import path from 'node:path';\nimport fs from 'fs-extra';\nimport type { InitAnswers } from '../types/selections.js';\nimport type { LintTool } from '../constants/lint.js';\nimport { logger } from '../utils/logger.js';\n\nexport async function generateLintConfigs(answers: InitAnswers): Promise<void> {\n const { projectPath, lintTools, framework } = answers;\n\n for (const tool of lintTools) {\n await GENERATORS[tool]?.(projectPath, framework);\n }\n}\n\nconst GENERATORS: Record<LintTool, (root: string, fw: string) => Promise<void>> = {\n eslint: generateEslint,\n stylelint: generateStylelint,\n prettier: generatePrettier,\n editorconfig: generateEditorConfig,\n};\n\nasync function generateEslint(root: string, fw: string): Promise<void> {\n const pkgPath = path.join(root, 'package.json');\n const pkg = await fs.readJson(pkgPath);\n const devDeps = pkg.devDependencies ?? {};\n\n devDeps.eslint = '^9.25.0';\n devDeps['@eslint/js'] = '^9.25.0';\n devDeps['typescript-eslint'] = '^8.30.0';\n devDeps.globals = '^16.0.0';\n\n if (fw === 'vue') {\n devDeps['eslint-plugin-vue'] = '^10.0.0';\n } else {\n devDeps['eslint-plugin-react-hooks'] = '^5.2.0';\n devDeps['eslint-plugin-react-refresh'] = '^0.4.0';\n }\n\n pkg.devDependencies = devDeps;\n await fs.writeJson(pkgPath, pkg, { spaces: 2 });\n\n const configLines = fw === 'vue'\n ? [\n \"import js from '@eslint/js';\",\n \"import tseslint from 'typescript-eslint';\",\n \"import pluginVue from 'eslint-plugin-vue';\",\n '',\n 'export default tseslint.config(',\n ' js.configs.recommended,',\n ' ...tseslint.configs.recommended,',\n \" ...pluginVue.configs['flat/recommended'],\",\n ' {',\n \" files: ['**/*.vue'],\",\n ' languageOptions: {',\n ' parserOptions: { parser: tseslint.parser },',\n ' },',\n ' },',\n ');',\n ]\n : [\n \"import js from '@eslint/js';\",\n \"import tseslint from 'typescript-eslint';\",\n \"import reactHooks from 'eslint-plugin-react-hooks';\",\n \"import reactRefresh from 'eslint-plugin-react-refresh';\",\n \"import globals from 'globals';\",\n '',\n 'export default tseslint.config(',\n ' js.configs.recommended,',\n ' ...tseslint.configs.recommended,',\n ' {',\n \" files: ['**/*.{ts,tsx}'],\",\n ' plugins: {',\n \" 'react-hooks': reactHooks,\",\n \" 'react-refresh': reactRefresh,\",\n ' },',\n ' languageOptions: {',\n ' globals: globals.browser,',\n ' },',\n ' rules: {',\n \" ...reactHooks.configs.recommended.rules,\",\n \" 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],\",\n ' },',\n ' },',\n ');',\n ];\n\n await fs.writeFile(path.join(root, 'eslint.config.mjs'), configLines.join('\\n'), 'utf-8');\n logger.success('ESLint 9 flat config generated');\n}\n\nasync function generateStylelint(root: string): Promise<void> {\n const pkgPath = path.join(root, 'package.json');\n const pkg = await fs.readJson(pkgPath);\n pkg.devDependencies = {\n ...pkg.devDependencies,\n stylelint: '^16.17.0',\n 'stylelint-config-standard': '^37.0.0',\n };\n await fs.writeJson(pkgPath, pkg, { spaces: 2 });\n\n await fs.writeJson(\n path.join(root, '.stylelintrc.json'),\n { extends: ['stylelint-config-standard'] },\n { spaces: 2 },\n );\n logger.success('Stylelint config generated');\n}\n\nasync function generatePrettier(root: string): Promise<void> {\n const pkgPath = path.join(root, 'package.json');\n const pkg = await fs.readJson(pkgPath);\n pkg.devDependencies = { ...pkg.devDependencies, prettier: '^3.5.0' };\n await fs.writeJson(pkgPath, pkg, { spaces: 2 });\n\n const config = {\n semi: true,\n singleQuote: true,\n tabWidth: 2,\n trailingComma: 'all' as const,\n printWidth: 100,\n };\n await fs.writeJson(path.join(root, '.prettierrc.json'), config, { spaces: 2 });\n logger.success('Prettier config generated');\n}\n\nasync function generateEditorConfig(root: string): Promise<void> {\n const content = [\n 'root = true',\n '',\n '[*]',\n 'indent_style = space',\n 'indent_size = 2',\n 'end_of_line = lf',\n 'charset = utf-8',\n 'trim_trailing_whitespace = true',\n 'insert_final_newline = true',\n ].join('\\n');\n\n await fs.writeFile(path.join(root, '.editorconfig'), content, 'utf-8');\n logger.success('EditorConfig generated');\n}\n\n","import path from 'node:path';\nimport fs from 'fs-extra';\nimport type { InitAnswers, EnhanceAnswers } from '../types/selections.js';\nimport type {\n ProjectMeta,\n SkillsMeta,\n McpMeta,\n ToolsMeta,\n SkillEntry,\n McpEntry,\n} from '../types/fe-kit-config.js';\nimport type { ProjectDetection } from '../core/detect-project.js';\nimport type { StackDetection } from '../core/detect-stack.js';\nimport { META_DIR, CLI_VERSION } from '../constants/meta.js';\nimport { readJsonSafe, writeJsonSafe } from '../utils/fs.js';\nimport { mergeConfig } from '../core/merge-config.js';\nimport { writeRules } from '../core/write-rules.js';\nimport { logger } from '../utils/logger.js';\n\nfunction metaDir(root: string): string {\n return path.join(root, META_DIR);\n}\n\n/** Called by `init` — writes fresh .fe-kit/ directory. */\nexport async function writeFeKitMeta(answers: InitAnswers): Promise<void> {\n const dir = metaDir(answers.projectPath);\n await fs.ensureDir(dir);\n\n const project: ProjectMeta = {\n name: answers.projectName,\n framework: answers.framework,\n router: answers.router,\n stateManagement: answers.stateManagement,\n bundler: answers.bundler,\n typescript: true,\n lintTools: answers.lintTools,\n templateVersion: '0.1.0',\n rulesVersion: '0.1.0',\n cliVersion: CLI_VERSION,\n };\n\n const skills: SkillsMeta = {\n enabled: answers.skills.map((id) => ({\n id,\n source: 'builtin' as const,\n targets: answers.devTools,\n version: CLI_VERSION,\n })),\n };\n\n const mcp: McpMeta = {\n enabled: answers.mcpServers.map((id) => ({\n id,\n adapterStatus: Object.fromEntries(answers.devTools.map((t) => [t, 'written' as const])),\n version: CLI_VERSION,\n })),\n configVersion: CLI_VERSION,\n };\n\n const tools: ToolsMeta = {\n selectedTools: answers.devTools,\n paths: {},\n extensionRecommendations: [],\n };\n\n await Promise.all([\n writeJsonSafe(path.join(dir, 'project.json'), project),\n writeJsonSafe(path.join(dir, 'skills.json'), skills),\n writeJsonSafe(path.join(dir, 'mcp.json'), mcp),\n writeJsonSafe(path.join(dir, 'tools.json'), tools),\n ]);\n\n await writeRules(answers.projectPath, answers.framework);\n logger.success(`.fe-kit/ metadata written`);\n}\n\n/** Called by `enhance` — merges into existing .fe-kit/ or creates it. */\nexport async function updateFeKitMeta(\n projectRoot: string,\n detection: ProjectDetection | StackDetection,\n answers: EnhanceAnswers,\n): Promise<void> {\n const dir = metaDir(projectRoot);\n await fs.ensureDir(dir);\n\n const fw = detection.framework;\n const isClassicDetection = 'router' in detection;\n\n const projectPath = path.join(dir, 'project.json');\n const existingProject = (await readJsonSafe<Record<string, unknown>>(projectPath)) ?? {\n name: detection.name,\n framework: fw,\n router: isClassicDetection ? ((detection as ProjectDetection).router ?? '') : '',\n stateManagement: isClassicDetection ? ((detection as ProjectDetection).stateManagement ?? '') : '',\n bundler: detection.bundler ?? 'vite',\n typescript: true,\n lintTools: [],\n templateVersion: '0.1.0',\n rulesVersion: '0.1.0',\n cliVersion: CLI_VERSION,\n };\n await writeJsonSafe(projectPath, { ...existingProject, cliVersion: CLI_VERSION });\n\n const skillsPath = path.join(dir, 'skills.json');\n const existingSkills = (await readJsonSafe<SkillsMeta>(skillsPath)) ?? { enabled: [] };\n const newSkillEntries: SkillEntry[] = answers.skills.map((id) => ({\n id,\n source: 'builtin' as const,\n targets: answers.devTools,\n version: CLI_VERSION,\n }));\n await writeJsonSafe(\n skillsPath,\n mergeConfig(existingSkills, { enabled: newSkillEntries }),\n );\n\n const mcpPath = path.join(dir, 'mcp.json');\n const existingMcp = (await readJsonSafe<McpMeta>(mcpPath)) ?? {\n enabled: [],\n configVersion: CLI_VERSION,\n };\n const newMcpEntries: McpEntry[] = answers.mcpServers.map((id) => ({\n id,\n adapterStatus: Object.fromEntries(answers.devTools.map((t) => [t, 'written' as const])),\n version: CLI_VERSION,\n }));\n await writeJsonSafe(\n mcpPath,\n mergeConfig(existingMcp, { enabled: newMcpEntries, configVersion: CLI_VERSION }),\n );\n\n const toolsPath = path.join(dir, 'tools.json');\n const existingTools = (await readJsonSafe<ToolsMeta>(toolsPath)) ?? {\n selectedTools: [],\n paths: {},\n extensionRecommendations: [],\n };\n await writeJsonSafe(\n toolsPath,\n mergeConfig(existingTools, { selectedTools: answers.devTools }),\n );\n\n await writeRules(projectRoot, fw);\n logger.success(`.fe-kit/ metadata updated`);\n}\n","import fs from 'fs-extra';\nimport path from 'node:path';\n\n/** Safely read a JSON file; returns undefined when file is missing or malformed. */\nexport async function readJsonSafe<T = unknown>(\n filePath: string,\n): Promise<T | undefined> {\n try {\n return (await fs.readJson(filePath)) as T;\n } catch {\n return undefined;\n }\n}\n\n/** Write JSON with consistent formatting. Creates parent dirs as needed. */\nexport async function writeJsonSafe(\n filePath: string,\n data: unknown,\n): Promise<void> {\n await fs.ensureDir(path.dirname(filePath));\n await fs.writeJson(filePath, data, { spaces: 2 });\n}\n","import deepmerge from 'deepmerge';\n\n/**\n * Deep-merge two objects. Arrays of objects with `id` fields are merged\n * by id (idempotent append), plain arrays are deduplicated.\n */\nexport function mergeConfig<T>(base: T, incoming: Partial<T>): T {\n return deepmerge(base as any, incoming as any, {\n arrayMerge: idempotentArrayMerge,\n }) as T;\n}\n\nfunction idempotentArrayMerge(target: unknown[], source: unknown[]): unknown[] {\n if (isIdArray(target) || isIdArray(source)) {\n return mergeById(target as HasId[], source as HasId[]);\n }\n return [...new Set([...target, ...source])];\n}\n\ninterface HasId {\n id: string;\n [key: string]: unknown;\n}\n\nfunction isIdArray(arr: unknown[]): arr is HasId[] {\n return arr.length > 0 && typeof arr[0] === 'object' && arr[0] !== null && 'id' in arr[0];\n}\n\nfunction mergeById(target: HasId[], source: HasId[]): HasId[] {\n const map = new Map<string, HasId>();\n for (const item of target) map.set(item.id, item);\n for (const item of source) {\n const existing = map.get(item.id);\n map.set(item.id, existing ? deepmerge(existing, item) : item);\n }\n return [...map.values()];\n}\n","import path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport fs from 'fs-extra';\nimport type { Framework } from '../constants/frameworks.js';\nimport type { StackFramework } from './detect-stack.js';\nimport { META_DIR } from '../constants/meta.js';\nimport { logger } from '../utils/logger.js';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nfunction rulesSourceDir(): string {\n return path.resolve(__dirname, '..', 'rules');\n}\n\nexport async function writeRules(\n projectRoot: string,\n framework: Framework | StackFramework,\n): Promise<void> {\n const targetDir = path.join(projectRoot, META_DIR, 'rules');\n const srcBase = rulesSourceDir();\n\n const frameworkDir = mapFrameworkRulesDir(framework);\n const dirs = [\n ...(frameworkDir ? [path.join(srcBase, frameworkDir)] : []),\n path.join(srcBase, 'common'),\n ];\n\n for (const dir of dirs) {\n if (!(await fs.pathExists(dir))) continue;\n const relative = path.basename(dir);\n await fs.copy(dir, path.join(targetDir, relative), { overwrite: false });\n }\n\n logger.success(`Rules for ${framework} written to ${META_DIR}/rules/`);\n}\n\nfunction mapFrameworkRulesDir(fw: Framework | StackFramework): string | null {\n if (fw === 'vue' || fw === 'nuxt') return 'vue';\n if (fw === 'react' || fw === 'next') return 'react';\n return null;\n}\n","import path from 'node:path';\nimport fs from 'fs-extra';\nimport type { InitAnswers } from '../types/selections.js';\nimport { logger } from '../utils/logger.js';\n\nfunction scriptBlock(bundler: InitAnswers['bundler']): string {\n if (bundler === 'vite') {\n return [\n '- `pnpm dev`:启动开发服务器',\n '- `pnpm build`:构建生产产物',\n '- `pnpm preview`:本地预览生产构建',\n ].join('\\n');\n }\n\n if (bundler === 'webpack') {\n return [\n '- `pnpm dev`:启动开发服务器',\n '- `pnpm build`:构建生产产物',\n ].join('\\n');\n }\n\n // rspack\n return [\n '- `pnpm dev`:启动开发服务器',\n '- `pnpm build`:构建生产产物',\n ].join('\\n');\n}\n\nfunction structureBlock(framework: InitAnswers['framework']): string {\n const lines: string[] = [\n '```text',\n '.',\n '├─ public/ # 静态资源(不经构建直接输出)',\n '├─ src/',\n '│ ├─ app/ # “应用层”组织',\n '│ ├─ components/ # 业务/通用组件',\n '│ ├─ hooks/ # React Hooks / Vue Composables(按需放)',\n '│ ├─ lib/ # 工具函数、请求封装、纯逻辑(不直接依赖 UI)',\n '│ ├─ styles/ # 样式与设计 token(按需放)',\n '│ └─ ' + (framework === 'react' ? 'main.tsx' : 'main.ts') + ' # 入口文件',\n '├─ .fe-kit/ # fe-kit 生成的元数据与规则',\n '├─ package.json',\n '├─ tsconfig.json',\n '└─ README.md',\n '```',\n ];\n return lines.join('\\n');\n}\n\nexport async function generateReadme(answers: InitAnswers): Promise<void> {\n const outPath = path.join(answers.projectPath, 'README.md');\n\n const content = [\n `# ${answers.projectName}`,\n '',\n '一个由 **fe-kit** 初始化的前端工程骨架。',\n '',\n '## 环境要求',\n '',\n '- Node.js >= 18',\n '- pnpm(推荐)',\n '',\n '## 快速开始',\n '',\n '安装依赖:',\n '',\n '```bash',\n 'pnpm install',\n '```',\n '',\n '常用脚本:',\n '',\n scriptBlock(answers.bundler),\n '',\n '## 目录结构',\n '',\n structureBlock(answers.framework),\n '',\n '## 约定说明(重要)',\n '',\n '- **不包含 service/back-end 内容**:本骨架不生成任何服务端目录与 API 路由。',\n '- **应用层组织**:`src/app/` 仅作为代码组织约定,不强绑定具体框架运行时。',\n '',\n ].join('\\n');\n\n await fs.writeFile(outPath, content, 'utf-8');\n logger.success('README.md generated');\n}\n\n","import path from 'node:path';\nimport fs from 'fs-extra';\nimport type { ToolAdapter, AdapterContext, SkillSelection, McpSelection } from './types.js';\nimport { readJsonSafe, writeJsonSafe } from '../utils/fs.js';\nimport { mergeConfig } from '../core/merge-config.js';\nimport { TOOL_CONFIG_PATHS } from '../core/paths.js';\nimport { writeCursorRules } from '../core/rule-writers.js';\nimport { logger } from '../utils/logger.js';\n\nexport const cursorAdapter: ToolAdapter = {\n id: 'cursor',\n\n async applySkills(_ctx, skills) {\n if (skills.length === 0) return;\n logger.info('Cursor: skills are applied via rules — no separate skills directory needed.');\n },\n\n async applyMcp(ctx, mcp) {\n if (mcp.length === 0) return;\n const configPath = path.join(ctx.projectRoot, TOOL_CONFIG_PATHS.cursor, 'mcp.json');\n await fs.ensureDir(path.dirname(configPath));\n\n const existing = (await readJsonSafe<Record<string, unknown>>(configPath)) ?? {};\n const mcpSection = (existing.mcpServers as Record<string, unknown>) ?? {};\n\n for (const m of mcp) {\n mcpSection[m.id] = m.config;\n }\n\n await writeJsonSafe(configPath, mergeConfig(existing, { mcpServers: mcpSection }));\n logger.success('Cursor: MCP config written to .cursor/mcp.json');\n },\n\n async applyRules(ctx) {\n await writeCursorRules(ctx.projectRoot, ctx.framework);\n logger.success('Cursor: rules written to .cursor/rules/*.mdc');\n },\n};\n","import type { DevToolId } from '../constants/tools.js';\n\n/** Default config directories/files per IDE/tool inside a project root. */\nexport const TOOL_CONFIG_PATHS: Record<DevToolId, string> = {\n cursor: '.cursor',\n 'claude-code': '.claude',\n vscode: '.vscode',\n 'codebuddy-cn': '.codebuddy',\n trae: '.trae',\n idea: '.idea',\n};\n","import path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport fs from 'fs-extra';\nimport type { Framework } from '../constants/frameworks.js';\nimport type { StackFramework } from './detect-stack.js';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nfunction rulesSourceDir(): string {\n return path.resolve(__dirname, '..', 'rules');\n}\n\nexport interface RuleFile {\n /** Filename stem, e.g. \"typescript\" */\n name: string;\n /** Category: \"common\", \"react\", or \"vue\" */\n category: string;\n /** Raw markdown body (no frontmatter) */\n content: string;\n}\n\nfunction mapFrameworkDir(fw: Framework | StackFramework): string | null {\n if (fw === 'vue' || fw === 'nuxt') return 'vue';\n if (fw === 'react' || fw === 'next') return 'react';\n return null;\n}\n\nexport async function loadRuleSources(\n framework: Framework | StackFramework,\n): Promise<RuleFile[]> {\n const srcBase = rulesSourceDir();\n const fwDir = mapFrameworkDir(framework);\n const dirs: { dir: string; category: string }[] = [\n { dir: path.join(srcBase, 'common'), category: 'common' },\n ];\n if (fwDir) {\n dirs.push({ dir: path.join(srcBase, fwDir), category: fwDir });\n }\n\n const rules: RuleFile[] = [];\n for (const { dir, category } of dirs) {\n if (!(await fs.pathExists(dir))) continue;\n const files = await fs.readdir(dir);\n for (const file of files) {\n if (!file.endsWith('.md')) continue;\n const content = await fs.readFile(path.join(dir, file), 'utf-8');\n rules.push({\n name: path.basename(file, '.md'),\n category,\n content: content.trim(),\n });\n }\n }\n return rules;\n}\n\nfunction toMdcContent(rule: RuleFile, globs?: string[]): string {\n const globLine = globs ? `globs: ${JSON.stringify(globs)}` : '';\n const lines = [\n '---',\n `description: ${rule.category}/${rule.name} conventions`,\n ...(globLine ? [globLine] : []),\n 'alwaysApply: true',\n '---',\n '',\n rule.content,\n '',\n ];\n return lines.join('\\n');\n}\n\nfunction ruleGlobs(rule: RuleFile): string[] | undefined {\n if (rule.category === 'react') return ['**/*.{tsx,jsx,ts,js}'];\n if (rule.category === 'vue') return ['**/*.{vue,ts,js}'];\n return undefined;\n}\n\nexport async function writeCursorRules(\n projectRoot: string,\n framework: Framework | StackFramework,\n): Promise<void> {\n const rules = await loadRuleSources(framework);\n const dir = path.join(projectRoot, '.cursor', 'rules');\n await fs.ensureDir(dir);\n\n for (const rule of rules) {\n const filename = `${rule.category}-${rule.name}.mdc`;\n await fs.writeFile(path.join(dir, filename), toMdcContent(rule, ruleGlobs(rule)), 'utf-8');\n }\n}\n\nexport async function writeCodeBuddyRules(\n projectRoot: string,\n framework: Framework | StackFramework,\n): Promise<void> {\n const rules = await loadRuleSources(framework);\n const dir = path.join(projectRoot, '.codebuddy', 'rules');\n await fs.ensureDir(dir);\n\n for (const rule of rules) {\n const filename = `${rule.category}-${rule.name}.mdc`;\n await fs.writeFile(path.join(dir, filename), toMdcContent(rule, ruleGlobs(rule)), 'utf-8');\n }\n}\n\nexport async function writeCopilotInstructions(\n projectRoot: string,\n framework: Framework | StackFramework,\n): Promise<void> {\n const rules = await loadRuleSources(framework);\n const dir = path.join(projectRoot, '.github');\n await fs.ensureDir(dir);\n\n const sections = rules.map((r) => r.content);\n const body = [\n '# Project Coding Guidelines',\n '',\n ...sections.flatMap((s) => [s, '']),\n ].join('\\n');\n\n await fs.writeFile(path.join(dir, 'copilot-instructions.md'), body, 'utf-8');\n}\n","import path from 'node:path';\nimport fs from 'fs-extra';\nimport type { ToolAdapter, AdapterContext, SkillSelection, McpSelection } from './types.js';\nimport { readJsonSafe, writeJsonSafe } from '../utils/fs.js';\nimport { mergeConfig } from '../core/merge-config.js';\nimport { TOOL_CONFIG_PATHS } from '../core/paths.js';\nimport { loadRuleSources } from '../core/rule-writers.js';\nimport { logger } from '../utils/logger.js';\n\nexport const claudeCodeAdapter: ToolAdapter = {\n id: 'claude-code',\n\n async applySkills(ctx, skills) {\n if (skills.length === 0) return;\n const skillsRoot = path.join(ctx.projectRoot, TOOL_CONFIG_PATHS['claude-code'], 'skills');\n await fs.ensureDir(skillsRoot);\n\n for (const skill of skills) {\n const targetDir = path.join(skillsRoot, skill.id);\n await fs.ensureDir(targetDir);\n\n if (skill.sourcePath) {\n const sourceDir = path.dirname(skill.sourcePath);\n await fs.copy(sourceDir, targetDir, { overwrite: true });\n } else {\n await fs.writeFile(path.join(targetDir, 'SKILL.md'), skill.content, 'utf-8');\n }\n }\n logger.success('Claude Code: skills copied to .claude/skills/<skill>/SKILL.md');\n },\n\n async applyMcp(ctx, mcp) {\n if (mcp.length === 0) return;\n const configPath = path.join(ctx.projectRoot, '.mcp.json');\n const existing = (await readJsonSafe<Record<string, unknown>>(configPath)) ?? {};\n const mcpSection = (existing.mcpServers as Record<string, unknown>) ?? {};\n\n for (const m of mcp) {\n mcpSection[m.id] = m.config;\n }\n\n await writeJsonSafe(configPath, mergeConfig(existing, { mcpServers: mcpSection }));\n logger.success('Claude Code: MCP config written to .mcp.json');\n },\n\n async applyRules(ctx) {\n const rulesDir = path.join(ctx.projectRoot, TOOL_CONFIG_PATHS['claude-code'], 'rules');\n await fs.ensureDir(rulesDir);\n\n const rules = await loadRuleSources(ctx.framework);\n for (const rule of rules) {\n const filename = `${rule.category}-${rule.name}.md`;\n await fs.writeFile(path.join(rulesDir, filename), rule.content + '\\n', 'utf-8');\n }\n logger.success('Claude Code: rules written to .claude/rules/');\n },\n};\n","import path from 'node:path';\nimport fs from 'fs-extra';\nimport type { ToolAdapter, AdapterContext, SkillSelection, McpSelection } from './types.js';\nimport { readJsonSafe, writeJsonSafe } from '../utils/fs.js';\nimport { mergeConfig } from '../core/merge-config.js';\nimport { writeCopilotInstructions } from '../core/rule-writers.js';\nimport { logger } from '../utils/logger.js';\nimport { TOOL_CONFIG_PATHS } from '../core/paths.js';\n\nexport const vscodeAdapter: ToolAdapter = {\n id: 'vscode',\n\n async applySkills(_ctx, skills) {\n if (skills.length === 0) return;\n logger.info('VS Code: skills are applied via Copilot instructions — no separate skills directory.');\n },\n\n async applyMcp(ctx, mcp) {\n if (mcp.length === 0) return;\n const dir = path.join(ctx.projectRoot, TOOL_CONFIG_PATHS.vscode);\n await fs.ensureDir(dir);\n\n const configPath = path.join(dir, 'mcp.json');\n const existing = (await readJsonSafe<Record<string, unknown>>(configPath)) ?? {};\n const serversSection = (existing.servers as Record<string, unknown>) ?? {};\n\n for (const m of mcp) {\n serversSection[m.id] = m.config;\n }\n\n await writeJsonSafe(configPath, mergeConfig(existing, { servers: serversSection }));\n logger.success('VS Code: MCP config written to .vscode/mcp.json (servers)');\n },\n\n async applyRules(ctx) {\n const dir = path.join(ctx.projectRoot, TOOL_CONFIG_PATHS.vscode);\n await fs.ensureDir(dir);\n\n const extensionsPath = path.join(dir, 'extensions.json');\n const existing = (await readJsonSafe<{ recommendations?: string[] }>(extensionsPath)) ?? {};\n const recs = new Set(existing.recommendations ?? []);\n\n const recommended = [\n 'dbaeumer.vscode-eslint',\n 'esbenp.prettier-vscode',\n 'stylelint.vscode-stylelint',\n ];\n if (ctx.framework === 'vue') recommended.push('Vue.volar');\n for (const ext of recommended) recs.add(ext);\n\n await writeJsonSafe(extensionsPath, { recommendations: [...recs] });\n\n await writeCopilotInstructions(ctx.projectRoot, ctx.framework);\n logger.success('VS Code: extensions.json + .github/copilot-instructions.md updated');\n },\n};\n","import type { ToolAdapter, AdapterContext, SkillSelection, McpSelection } from './types.js';\nimport path from 'node:path';\nimport { readJsonSafe, writeJsonSafe } from '../utils/fs.js';\nimport { mergeConfig } from '../core/merge-config.js';\nimport { writeCodeBuddyRules } from '../core/rule-writers.js';\nimport { logger } from '../utils/logger.js';\n\nexport const codebuddyCnAdapter: ToolAdapter = {\n id: 'codebuddy-cn',\n\n async applySkills(_ctx, skills) {\n if (skills.length === 0) return;\n logger.info('CodeBuddy: skills are applied via rules — no separate skills directory needed.');\n },\n\n async applyMcp(ctx, mcp) {\n if (mcp.length === 0) return;\n const configPath = path.join(ctx.projectRoot, '.mcp.json');\n const existing = (await readJsonSafe<Record<string, unknown>>(configPath)) ?? {};\n const mcpSection = (existing.mcpServers as Record<string, unknown>) ?? {};\n\n for (const m of mcp) {\n mcpSection[m.id] = m.config;\n }\n\n await writeJsonSafe(configPath, mergeConfig(existing, { mcpServers: mcpSection }));\n logger.success('CodeBuddy: MCP config written to .mcp.json');\n },\n\n async applyRules(ctx) {\n await writeCodeBuddyRules(ctx.projectRoot, ctx.framework);\n logger.success('CodeBuddy: rules written to .codebuddy/rules/*.mdc');\n },\n};\n","import path from 'node:path';\nimport fs from 'fs-extra';\nimport type { ToolAdapter, AdapterContext, SkillSelection, McpSelection } from './types.js';\nimport { readJsonSafe, writeJsonSafe } from '../utils/fs.js';\nimport { mergeConfig } from '../core/merge-config.js';\nimport { TOOL_CONFIG_PATHS } from '../core/paths.js';\nimport { loadRuleSources } from '../core/rule-writers.js';\nimport { logger } from '../utils/logger.js';\n\nexport const traeAdapter: ToolAdapter = {\n id: 'trae',\n\n async applySkills(ctx, skills) {\n if (skills.length === 0) return;\n const dir = path.join(ctx.projectRoot, TOOL_CONFIG_PATHS.trae, 'rules');\n await fs.ensureDir(dir);\n\n for (const skill of skills) {\n const filePath = path.join(dir, `${skill.id}.md`);\n await fs.writeFile(filePath, skill.content, 'utf-8');\n }\n logger.success('Trae: skills written to .trae/rules/');\n },\n\n async applyMcp(ctx, mcp) {\n if (mcp.length === 0) return;\n const configPath = path.join(ctx.projectRoot, TOOL_CONFIG_PATHS.trae, 'mcp.json');\n await fs.ensureDir(path.dirname(configPath));\n const existing = (await readJsonSafe<Record<string, unknown>>(configPath)) ?? {};\n const mcpSection = (existing.mcpServers as Record<string, unknown>) ?? {};\n\n for (const m of mcp) {\n mcpSection[m.id] = m.config;\n }\n\n await writeJsonSafe(configPath, mergeConfig(existing, { mcpServers: mcpSection }));\n logger.success('Trae: MCP config written to .trae/mcp.json');\n },\n\n async applyRules(ctx) {\n const rulesDir = path.join(ctx.projectRoot, TOOL_CONFIG_PATHS.trae, 'rules');\n await fs.ensureDir(rulesDir);\n\n const rules = await loadRuleSources(ctx.framework);\n for (const rule of rules) {\n const filename = `${rule.category}-${rule.name}.md`;\n await fs.writeFile(path.join(rulesDir, filename), rule.content + '\\n', 'utf-8');\n }\n logger.success('Trae: rules written to .trae/rules/');\n },\n};\n","import path from 'node:path';\nimport fs from 'fs-extra';\nimport type { ToolAdapter, AdapterContext } from './types.js';\nimport { TOOL_CONFIG_PATHS } from '../core/paths.js';\nimport { logger } from '../utils/logger.js';\n\nexport const ideaAdapter: ToolAdapter = {\n id: 'idea',\n\n async applySkills(ctx, skills) {\n if (skills.length === 0) return;\n const dir = path.join(ctx.projectRoot, TOOL_CONFIG_PATHS.idea);\n await fs.ensureDir(dir);\n logger.info('IDEA: skill integration is a placeholder — manual config may be needed.');\n },\n\n async applyMcp(ctx, mcp) {\n if (mcp.length === 0) return;\n const dir = path.join(ctx.projectRoot, TOOL_CONFIG_PATHS.idea);\n await fs.ensureDir(dir);\n logger.info('IDEA: MCP integration is a placeholder — manual config may be needed.');\n },\n\n async applyRules(ctx) {\n const dir = path.join(ctx.projectRoot, TOOL_CONFIG_PATHS.idea);\n await fs.ensureDir(dir);\n logger.info('IDEA: rules integration is a placeholder.');\n },\n};\n","import type { DevToolId } from '../constants/tools.js';\nimport type { ToolAdapter } from './types.js';\nimport { cursorAdapter } from './cursor.js';\nimport { claudeCodeAdapter } from './claude-code.js';\nimport { vscodeAdapter } from './vscode.js';\nimport { codebuddyCnAdapter } from './codebuddy-cn.js';\nimport { traeAdapter } from './trae.js';\nimport { ideaAdapter } from './idea.js';\n\nconst adapters: Record<DevToolId, ToolAdapter> = {\n cursor: cursorAdapter,\n 'claude-code': claudeCodeAdapter,\n vscode: vscodeAdapter,\n 'codebuddy-cn': codebuddyCnAdapter,\n trae: traeAdapter,\n idea: ideaAdapter,\n};\n\nexport function getAdapter(id: DevToolId): ToolAdapter {\n return adapters[id];\n}\n\nexport function getAdapters(ids: DevToolId[]): ToolAdapter[] {\n return ids.map((id) => adapters[id]);\n}\n","import type { AdapterContext, SkillSelection, McpSelection } from '../adapters/types.js';\nimport type { Framework } from '../constants/frameworks.js';\nimport type { StackFramework } from './detect-stack.js';\nimport type { DevToolId } from '../constants/tools.js';\nimport { getAdapters } from '../adapters/registry.js';\nimport { getSkillById } from '../skills/catalog.js';\nimport { getMcpById } from '../mcp/catalog.js';\nimport { logger } from '../utils/logger.js';\n\nexport interface AdapterInput {\n framework: Framework | StackFramework;\n devTools: DevToolId[];\n skills: string[];\n mcpServers: string[];\n}\n\nexport async function applyAdapters(\n projectRoot: string,\n input: AdapterInput,\n): Promise<void> {\n const adapters = getAdapters(input.devTools);\n const ctx: AdapterContext = { projectRoot, framework: input.framework };\n\n const skills: SkillSelection[] = input.skills\n .map(getSkillById)\n .filter((s): s is SkillSelection => s !== undefined);\n\n const mcp: McpSelection[] = input.mcpServers\n .map(getMcpById)\n .filter((m): m is McpSelection => m !== undefined);\n\n for (const adapter of adapters) {\n logger.step(`Applying config for ${adapter.id}...`);\n await adapter.applySkills(ctx, skills);\n await adapter.applyMcp(ctx, mcp);\n await adapter.applyRules(ctx);\n }\n}\n","import { runInitPrompts } from '../prompts/init-prompts.js';\nimport { generateProject } from '../generators/project-generator.js';\nimport { generateLintConfigs } from '../generators/lint-generator.js';\nimport { writeFeKitMeta } from '../generators/fe-kit-meta-generator.js';\nimport { generateReadme } from '../generators/readme-generator.js';\nimport { applyAdapters } from '../core/apply-adapters.js';\nimport { logger } from '../utils/index.js';\n\nexport async function initCommand(): Promise<void> {\n logger.step('Starting new project initialization...');\n\n const answers = await runInitPrompts();\n if (!answers) return;\n\n await generateProject(answers);\n await generateLintConfigs(answers);\n await writeFeKitMeta(answers);\n await generateReadme(answers);\n await applyAdapters(answers.projectPath, answers);\n\n logger.success(`Project \"${answers.projectName}\" created at ${answers.projectPath}`);\n}\n","import path from 'node:path';\nimport fs from 'fs-extra';\nimport { detectProject } from '../core/detect-project.js';\nimport type { ProjectDetection } from '../core/detect-project.js';\nimport { detectStack, summarizeStack } from '../core/detect-stack.js';\nimport type { StackDetection } from '../core/detect-stack.js';\nimport { runEnhancePrompts } from '../prompts/enhance-prompts.js';\nimport { updateFeKitMeta } from '../generators/fe-kit-meta-generator.js';\nimport { generateQualityTooling } from '../generators/quality-generator.js';\nimport { applyAdapters } from '../core/apply-adapters.js';\nimport { logger } from '../utils/index.js';\n\nexport async function enhanceCommand(): Promise<void> {\n logger.step('Analyzing current project...');\n\n const projectRoot = process.cwd();\n\n const classicDetection = await detectProject(projectRoot);\n const stack: StackDetection | null = classicDetection\n ? await toStackDetection(projectRoot, classicDetection)\n : await detectStack(projectRoot);\n\n if (!stack) {\n logger.error(\n 'Could not detect a project in the current directory. ' +\n 'Make sure package.json exists.',\n );\n process.exitCode = 1;\n return;\n }\n\n logger.info(`Detected: ${summarizeStack(stack)}`);\n\n const answers = await runEnhancePrompts(stack);\n if (!answers) return;\n\n await updateFeKitMeta(projectRoot, classicDetection ?? stack, answers);\n\n if (answers.qualityTools.length > 0) {\n await generateQualityTooling(projectRoot, stack, answers.qualityTools);\n }\n\n await applyAdapters(projectRoot, {\n framework: stack.framework,\n ...answers,\n });\n\n logger.success('Project enhanced successfully.');\n}\n\nasync function toStackDetection(\n root: string,\n d: ProjectDetection,\n): Promise<StackDetection> {\n return {\n name: d.name,\n projectKind: 'frontend',\n framework: d.framework,\n bundler: d.bundler,\n hasTypeScript: d.hasTypeScript,\n hasGit: await fs.pathExists(path.join(root, '.git')),\n };\n}\n","import path from 'node:path';\nimport fs from 'fs-extra';\nimport type { Framework } from '../constants/frameworks.js';\nimport type { Bundler } from '../constants/bundlers.js';\nimport { readJsonSafe } from '../utils/fs.js';\n\nexport interface ProjectDetection {\n name: string;\n framework: Framework;\n router?: string;\n stateManagement?: string;\n bundler?: Bundler;\n hasTypeScript: boolean;\n}\n\nexport async function detectProject(\n root: string,\n): Promise<ProjectDetection | null> {\n const pkgPath = path.join(root, 'package.json');\n if (!(await fs.pathExists(pkgPath))) return null;\n\n const pkg = await readJsonSafe<Record<string, unknown>>(pkgPath);\n if (!pkg) return null;\n\n const allDeps = {\n ...(pkg.dependencies as Record<string, string> | undefined),\n ...(pkg.devDependencies as Record<string, string> | undefined),\n };\n\n const framework = detectFramework(allDeps);\n if (!framework) return null;\n\n return {\n name: (pkg.name as string) ?? path.basename(root),\n framework,\n router: detectRouter(allDeps, framework),\n stateManagement: detectStateManagement(allDeps, framework),\n bundler: detectBundler(allDeps),\n hasTypeScript: 'typescript' in allDeps || (await fs.pathExists(path.join(root, 'tsconfig.json'))),\n };\n}\n\nfunction detectFramework(deps: Record<string, string>): Framework | null {\n if ('vue' in deps) return 'vue';\n if ('react' in deps) return 'react';\n return null;\n}\n\nfunction detectRouter(deps: Record<string, string>, fw: Framework): string | undefined {\n if (fw === 'vue' && 'vue-router' in deps) return 'vue-router';\n if (fw === 'react' && 'react-router' in deps) return 'react-router';\n if (fw === 'react' && 'react-router-dom' in deps) return 'react-router';\n return undefined;\n}\n\nfunction detectStateManagement(deps: Record<string, string>, fw: Framework): string | undefined {\n if (fw === 'vue') {\n if ('pinia' in deps) return 'pinia';\n if ('vuex' in deps) return 'vuex';\n }\n if (fw === 'react') {\n if ('@reduxjs/toolkit' in deps) return 'redux-toolkit';\n if ('zustand' in deps) return 'zustand';\n if ('mobx' in deps) return 'mobx';\n }\n return undefined;\n}\n\nfunction detectBundler(deps: Record<string, string>): Bundler | undefined {\n if ('vite' in deps) return 'vite';\n if ('webpack' in deps) return 'webpack';\n if ('@rspack/cli' in deps || '@rspack/core' in deps) return 'rspack';\n return undefined;\n}\n","import path from 'node:path';\nimport fs from 'fs-extra';\nimport type { Bundler } from '../constants/bundlers.js';\nimport { readJsonSafe } from '../utils/fs.js';\n\nexport const STACK_FRAMEWORKS = ['vue', 'react', 'next', 'nuxt', 'unknown'] as const;\nexport type StackFramework = (typeof STACK_FRAMEWORKS)[number];\n\nexport const PROJECT_KINDS = ['frontend', 'node', 'unknown'] as const;\nexport type ProjectKind = (typeof PROJECT_KINDS)[number];\n\nexport interface StackDetection {\n name: string;\n projectKind: ProjectKind;\n framework: StackFramework;\n bundler: Bundler | undefined;\n hasTypeScript: boolean;\n hasGit: boolean;\n}\n\nexport async function detectStack(root: string): Promise<StackDetection | null> {\n const pkgPath = path.join(root, 'package.json');\n if (!(await fs.pathExists(pkgPath))) return null;\n\n const pkg = await readJsonSafe<Record<string, unknown>>(pkgPath);\n if (!pkg) return null;\n\n const allDeps: Record<string, string> = {\n ...(pkg.dependencies as Record<string, string> | undefined),\n ...(pkg.devDependencies as Record<string, string> | undefined),\n };\n\n const framework = inferFramework(allDeps);\n const bundler = inferBundler(allDeps);\n const hasTypeScript =\n 'typescript' in allDeps ||\n (await fs.pathExists(path.join(root, 'tsconfig.json')));\n const hasGit = await fs.pathExists(path.join(root, '.git'));\n\n return {\n name: (pkg.name as string) ?? path.basename(root),\n projectKind: inferProjectKind(pkg, allDeps, framework),\n framework,\n bundler,\n hasTypeScript,\n hasGit,\n };\n}\n\nfunction inferFramework(deps: Record<string, string>): StackFramework {\n if ('nuxt' in deps) return 'nuxt';\n if ('next' in deps) return 'next';\n if ('vue' in deps) return 'vue';\n if ('react' in deps) return 'react';\n return 'unknown';\n}\n\nfunction inferBundler(deps: Record<string, string>): Bundler | undefined {\n if ('vite' in deps) return 'vite';\n if ('webpack' in deps) return 'webpack';\n if ('@rspack/cli' in deps || '@rspack/core' in deps) return 'rspack';\n return undefined;\n}\n\nfunction inferProjectKind(\n pkg: Record<string, unknown>,\n deps: Record<string, string>,\n framework: StackFramework,\n): ProjectKind {\n if (framework !== 'unknown') return 'frontend';\n\n const hasNodeSignals =\n pkg.bin !== undefined ||\n pkg.main !== undefined ||\n pkg.exports !== undefined ||\n 'express' in deps ||\n 'fastify' in deps ||\n 'koa' in deps ||\n '@types/node' in deps;\n\n if (hasNodeSignals) return 'node';\n\n return 'unknown';\n}\n\nexport function summarizeStack(stack: StackDetection): string {\n const parts: string[] = [];\n\n if (stack.framework !== 'unknown') {\n parts.push(stack.framework.charAt(0).toUpperCase() + stack.framework.slice(1));\n } else if (stack.projectKind === 'node') {\n parts.push('Node');\n } else {\n parts.push('JavaScript/TypeScript');\n }\n\n if (stack.bundler) {\n parts.push(stack.bundler.charAt(0).toUpperCase() + stack.bundler.slice(1));\n }\n\n if (stack.hasTypeScript) parts.push('TypeScript');\n\n return parts.join(' + ');\n}\n","import prompts from 'prompts';\nimport type { EnhanceAnswers } from '../types/selections.js';\nimport type { StackDetection } from '../core/detect-stack.js';\nimport { summarizeStack } from '../core/detect-stack.js';\nimport type { QualityTool } from '../constants/lint.js';\nimport { DEV_TOOLS } from '../constants/tools.js';\nimport { getSkillCatalog } from '../skills/catalog.js';\nimport { getMcpCatalog } from '../mcp/catalog.js';\n\n\ninterface QualityToolOption {\n id: QualityTool;\n label: string;\n description: string;\n selected: boolean;\n}\n\nfunction getApplicableTools(stack: StackDetection): QualityToolOption[] {\n const tools: QualityToolOption[] = [];\n\n tools.push({\n id: 'eslint',\n label: 'ESLint',\n description: 'Linting for JavaScript / TypeScript',\n selected: true,\n });\n\n tools.push({\n id: 'prettier',\n label: 'Prettier',\n description: 'Code formatting',\n selected: true,\n });\n\n tools.push({\n id: 'editorconfig',\n label: 'EditorConfig',\n description: 'Cross-editor indentation & whitespace settings',\n selected: true,\n });\n\n if (stack.projectKind === 'frontend') {\n tools.push({\n id: 'stylelint',\n label: 'Stylelint',\n description: 'CSS / SCSS linting',\n selected: false,\n });\n }\n\n tools.push({\n id: 'commitlint',\n label: 'commitlint',\n description: 'Enforce conventional commit messages',\n selected: false,\n });\n\n return tools;\n}\n\nexport async function runEnhancePrompts(\n stack: StackDetection,\n): Promise<EnhanceAnswers | null> {\n const stackLabel = summarizeStack(stack);\n const applicableTools = getApplicableTools(stack);\n\n const response = await prompts(\n [\n {\n type: 'multiselect',\n name: 'devTools',\n message: `Dev tools to configure for this ${stackLabel} project:`,\n choices: DEV_TOOLS.map((t) => ({ title: t, value: t, selected: t === 'cursor' })),\n min: 1,\n hint: 'Select at least one',\n },\n {\n type: 'multiselect',\n name: 'qualityTools',\n message: 'Code quality tools to install & configure:',\n choices: applicableTools.map((t) => ({\n title: `${t.label} — ${t.description}`,\n value: t.id,\n selected: t.selected,\n })),\n hint: 'Space to toggle, Enter to confirm',\n },\n {\n type: 'multiselect',\n name: 'skills',\n message: 'Skills to add:',\n choices: getSkillCatalog().map((s) => ({\n title: `${s.label} — ${s.description}`,\n value: s.id,\n selected: false,\n })),\n },\n {\n type: 'multiselect',\n name: 'mcpServers',\n message: 'MCP servers to add:',\n choices: getMcpCatalog().map((m) => ({\n title: `${m.label} — ${m.description}`,\n value: m.id,\n selected: false,\n })),\n },\n ],\n { onCancel: () => process.exit(0) },\n );\n\n if (!response.devTools) return null;\n\n return {\n devTools: response.devTools,\n qualityTools: response.qualityTools ?? [],\n skills: response.skills ?? [],\n mcpServers: response.mcpServers ?? [],\n };\n}\n","import path from 'node:path';\nimport fs from 'fs-extra';\nimport type { StackDetection, StackFramework } from '../core/detect-stack.js';\nimport type { QualityTool } from '../constants/lint.js';\nimport { logger } from '../utils/logger.js';\n\ntype Generator = (root: string, stack: StackDetection) => Promise<void>;\n\nconst GENERATORS: Record<QualityTool, Generator> = {\n eslint: generateEslint,\n stylelint: generateStylelint,\n prettier: generatePrettier,\n editorconfig: generateEditorConfig,\n commitlint: generateCommitlint,\n};\n\nexport async function generateQualityTooling(\n root: string,\n stack: StackDetection,\n tools: QualityTool[],\n): Promise<void> {\n for (const tool of tools) {\n await GENERATORS[tool](root, stack);\n }\n}\n\n// ---------------------------------------------------------------------------\n// ESLint — stack-aware config & optional bundler plugin\n// ---------------------------------------------------------------------------\n\nasync function generateEslint(root: string, stack: StackDetection): Promise<void> {\n const pkg = await readPkg(root);\n const devDeps: Record<string, string> = {\n ...(pkg.devDependencies as Record<string, string> | undefined),\n };\n\n devDeps.eslint = '^9.25.0';\n devDeps['@eslint/js'] = '^9.25.0';\n devDeps.globals = '^16.0.0';\n\n if (stack.hasTypeScript) {\n devDeps['typescript-eslint'] = '^8.30.0';\n }\n\n addFrameworkEslintDeps(devDeps, stack.framework);\n addBundlerEslintPlugin(devDeps, stack);\n\n pkg.devDependencies = devDeps;\n await writePkg(root, pkg);\n\n const configContent = buildEslintConfig(stack);\n await fs.writeFile(path.join(root, 'eslint.config.mjs'), configContent, 'utf-8');\n logger.success('ESLint 9 flat config generated');\n}\n\nfunction addFrameworkEslintDeps(devDeps: Record<string, string>, fw: StackFramework): void {\n if (fw === 'vue' || fw === 'nuxt') {\n devDeps['eslint-plugin-vue'] = '^10.0.0';\n } else if (fw === 'react' || fw === 'next') {\n devDeps['eslint-plugin-react-hooks'] = '^5.2.0';\n devDeps['eslint-plugin-react-refresh'] = '^0.4.0';\n }\n}\n\nfunction addBundlerEslintPlugin(devDeps: Record<string, string>, stack: StackDetection): void {\n if (stack.projectKind !== 'frontend') return;\n\n if (stack.bundler === 'vite') {\n devDeps['vite-plugin-eslint2'] = '^5.0.0';\n } else if (stack.bundler === 'webpack' || stack.bundler === 'rspack') {\n devDeps['eslint-webpack-plugin'] = '^4.2.0';\n }\n}\n\nfunction buildEslintConfig(stack: StackDetection): string {\n const fw = stack.framework;\n\n if (fw === 'vue' || fw === 'nuxt') return buildVueEslintConfig(stack);\n if (fw === 'react' || fw === 'next') return buildReactEslintConfig(stack);\n return buildGenericEslintConfig(stack);\n}\n\nfunction buildVueEslintConfig(stack: StackDetection): string {\n const lines = [\n \"import js from '@eslint/js';\",\n ...(stack.hasTypeScript ? [\"import tseslint from 'typescript-eslint';\"] : []),\n \"import pluginVue from 'eslint-plugin-vue';\",\n '',\n ...(stack.hasTypeScript\n ? [\n 'export default tseslint.config(',\n ' js.configs.recommended,',\n ' ...tseslint.configs.recommended,',\n ]\n : ['export default [', ' js.configs.recommended,']),\n \" ...pluginVue.configs['flat/recommended'],\",\n ...(stack.hasTypeScript\n ? [\n ' {',\n \" files: ['**/*.vue'],\",\n ' languageOptions: {',\n ' parserOptions: { parser: tseslint.parser },',\n ' },',\n ' },',\n ');',\n ]\n : ['];']),\n ];\n return lines.join('\\n');\n}\n\nfunction buildReactEslintConfig(stack: StackDetection): string {\n const lines = [\n \"import js from '@eslint/js';\",\n ...(stack.hasTypeScript ? [\"import tseslint from 'typescript-eslint';\"] : []),\n \"import reactHooks from 'eslint-plugin-react-hooks';\",\n \"import reactRefresh from 'eslint-plugin-react-refresh';\",\n \"import globals from 'globals';\",\n '',\n ...(stack.hasTypeScript\n ? [\n 'export default tseslint.config(',\n ' js.configs.recommended,',\n ' ...tseslint.configs.recommended,',\n ]\n : ['export default [', ' js.configs.recommended,']),\n ' {',\n \" files: ['**/*.{ts,tsx,js,jsx}'],\",\n ' plugins: {',\n \" 'react-hooks': reactHooks,\",\n \" 'react-refresh': reactRefresh,\",\n ' },',\n ' languageOptions: {',\n ' globals: globals.browser,',\n ' },',\n ' rules: {',\n ' ...reactHooks.configs.recommended.rules,',\n \" 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],\",\n ' },',\n ' },',\n ...(stack.hasTypeScript ? [');'] : ['];']),\n ];\n return lines.join('\\n');\n}\n\nfunction buildGenericEslintConfig(stack: StackDetection): string {\n const lines = [\n \"import js from '@eslint/js';\",\n ...(stack.hasTypeScript ? [\"import tseslint from 'typescript-eslint';\"] : []),\n \"import globals from 'globals';\",\n '',\n ...(stack.hasTypeScript\n ? [\n 'export default tseslint.config(',\n ' js.configs.recommended,',\n ' ...tseslint.configs.recommended,',\n ]\n : ['export default [', ' js.configs.recommended,']),\n ' {',\n \" files: ['**/*.{ts,js}'],\",\n ' languageOptions: {',\n ' globals: {',\n ' ...globals.node,',\n ' },',\n ' },',\n ' },',\n ...(stack.hasTypeScript ? [');'] : ['];']),\n ];\n return lines.join('\\n');\n}\n\n// ---------------------------------------------------------------------------\n// Stylelint\n// ---------------------------------------------------------------------------\n\nasync function generateStylelint(root: string, stack: StackDetection): Promise<void> {\n const pkg = await readPkg(root);\n const devDeps: Record<string, string> = {\n ...(pkg.devDependencies as Record<string, string> | undefined),\n stylelint: '^16.17.0',\n 'stylelint-config-standard': '^37.0.0',\n };\n\n const fw = stack.framework;\n if (fw === 'vue' || fw === 'nuxt') {\n devDeps['stylelint-config-standard-vue'] = '^1.0.0';\n }\n\n pkg.devDependencies = devDeps;\n await writePkg(root, pkg);\n\n const extendsArr = ['stylelint-config-standard'];\n if (fw === 'vue' || fw === 'nuxt') {\n extendsArr.push('stylelint-config-standard-vue');\n }\n\n await fs.writeJson(\n path.join(root, '.stylelintrc.json'),\n { extends: extendsArr },\n { spaces: 2 },\n );\n logger.success('Stylelint config generated');\n}\n\n// ---------------------------------------------------------------------------\n// Prettier\n// ---------------------------------------------------------------------------\n\nasync function generatePrettier(root: string): Promise<void> {\n const pkg = await readPkg(root);\n pkg.devDependencies = {\n ...(pkg.devDependencies as Record<string, string> | undefined),\n prettier: '^3.5.0',\n };\n await writePkg(root, pkg);\n\n const config = {\n semi: true,\n singleQuote: true,\n tabWidth: 2,\n trailingComma: 'all' as const,\n printWidth: 100,\n };\n await fs.writeJson(path.join(root, '.prettierrc.json'), config, { spaces: 2 });\n logger.success('Prettier config generated');\n}\n\n// ---------------------------------------------------------------------------\n// EditorConfig\n// ---------------------------------------------------------------------------\n\nasync function generateEditorConfig(root: string): Promise<void> {\n const content = [\n 'root = true',\n '',\n '[*]',\n 'indent_style = space',\n 'indent_size = 2',\n 'end_of_line = lf',\n 'charset = utf-8',\n 'trim_trailing_whitespace = true',\n 'insert_final_newline = true',\n ].join('\\n');\n\n await fs.writeFile(path.join(root, '.editorconfig'), content, 'utf-8');\n logger.success('EditorConfig generated');\n}\n\n// ---------------------------------------------------------------------------\n// commitlint\n// ---------------------------------------------------------------------------\n\nasync function generateCommitlint(root: string, stack: StackDetection): Promise<void> {\n const pkg = await readPkg(root);\n const devDeps: Record<string, string> = {\n ...(pkg.devDependencies as Record<string, string> | undefined),\n '@commitlint/cli': '^19.8.0',\n '@commitlint/config-conventional': '^19.8.0',\n };\n\n devDeps.husky = '^9.1.0';\n\n pkg.devDependencies = devDeps;\n\n const scripts = (pkg.scripts ?? {}) as Record<string, string>;\n scripts.prepare ??= 'husky';\n pkg.scripts = scripts;\n\n await writePkg(root, pkg);\n\n const isESM = pkg.type === 'module';\n const configName = isESM ? 'commitlint.config.cjs' : 'commitlint.config.js';\n const configContent = [\n \"module.exports = { extends: ['@commitlint/config-conventional'] };\",\n '',\n ].join('\\n');\n\n await fs.writeFile(path.join(root, configName), configContent, 'utf-8');\n\n await fs.ensureDir(path.join(root, '.husky'));\n const hookContent = 'npx --no -- commitlint --edit \"$1\"\\n';\n await fs.writeFile(path.join(root, '.husky', 'commit-msg'), hookContent, 'utf-8');\n\n if (!stack.hasGit) {\n logger.warn('No .git directory detected — commitlint hooks will activate after git init.');\n }\n\n logger.success('commitlint + husky generated');\n}\n\n// ---------------------------------------------------------------------------\n// Helpers — reduce repeated readJson / writeJson boilerplate\n// ---------------------------------------------------------------------------\n\nasync function readPkg(root: string): Promise<Record<string, unknown>> {\n return fs.readJson(path.join(root, 'package.json'));\n}\n\nasync function writePkg(root: string, data: Record<string, unknown>): Promise<void> {\n await fs.writeJson(path.join(root, 'package.json'), data, { spaces: 2 });\n}\n"],"mappings":"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","names":["path","path","path","fileURLToPath","fs","path","fileURLToPath","fs","path","fs","path","fs","path","fs","fs","path","path","fileURLToPath","fs","__dirname","path","fileURLToPath","fs","path","fs","path","fs","path","fs","path","fs","path","fileURLToPath","fs","__dirname","rulesSourceDir","path","fs","path","fs","path","fs","path","fs","path","fs","path","path","path","fs","path","fs","path","fs","path","fs","adapters","path","fs","path","fs","path","fs","path","fs","path","fs","prompts","prompts","path","fs","GENERATORS","generateEslint","generateStylelint","generatePrettier","generateEditorConfig","fs","path","fs","path"]}
@@ -0,0 +1,21 @@
1
+ ---
2
+ description: TypeScript conventions (strict config, type patterns, naming)
3
+ globs: **/*.{ts,tsx}
4
+ alwaysApply: false
5
+ ---
6
+ # TypeScript Conventions
7
+
8
+ ## Config
9
+ - Enable `strict: true` in all projects.
10
+ - Use path aliases (`@/`) for clean imports.
11
+
12
+ ## Types
13
+ - Prefer interfaces for object shapes; use type for unions/intersections.
14
+ - Export shared types from `src/types/`.
15
+ - Avoid `enum`; prefer `as const` objects or union types.
16
+
17
+ ## Patterns
18
+ - Use discriminated unions for variant types.
19
+ - Narrow types with type guards, not type assertions.
20
+ - Use `satisfies` to validate types without widening.
21
+ - Generics should be named descriptively: `TItem`, `TResponse`.
@@ -0,0 +1,24 @@
1
+ ---
2
+ description: React component conventions (naming, structure, props, composition)
3
+ globs: **/*.{tsx,jsx}
4
+ alwaysApply: false
5
+ ---
6
+ # React Component Conventions
7
+
8
+ ## File Naming
9
+ - PascalCase for component files: `UserProfile.tsx`.
10
+ - Co-locate styles, tests, and types with the component.
11
+
12
+ ## Structure
13
+ - Prefer function components with arrow syntax and explicit return types.
14
+ - One exported component per file.
15
+ - Destructure props in the function signature.
16
+
17
+ ## Props
18
+ - Define props with TypeScript interfaces (not `type` aliases for components).
19
+ - Use `React.PropsWithChildren<T>` for wrapper components.
20
+ - Provide defaults via destructuring default values.
21
+
22
+ ## Composition
23
+ - Use children or render props for flexible composition.
24
+ - Avoid deeply nested component trees; flatten with composition.
@@ -0,0 +1,20 @@
1
+ ---
2
+ description: React hooks guidelines (rules of hooks, custom hooks, common patterns)
3
+ globs: **/*.{ts,tsx,js,jsx}
4
+ alwaysApply: false
5
+ ---
6
+ # React Hooks Guidelines
7
+
8
+ ## Rules of Hooks
9
+ - Only call hooks at the top level — never inside loops, conditions, or nested functions.
10
+ - Only call hooks from React function components or custom hooks.
11
+
12
+ ## Custom Hooks
13
+ - Prefix with `use`: `useAuth`, `useFetch`, `useDebounce`.
14
+ - Each custom hook should have a single responsibility.
15
+ - Return stable references where possible (useCallback, useMemo).
16
+
17
+ ## Common Patterns
18
+ - Use `useEffect` cleanup to prevent memory leaks.
19
+ - Prefer `useReducer` over `useState` for complex state logic.
20
+ - Avoid over-memoization; profile before optimizing.
@@ -0,0 +1,18 @@
1
+ ---
2
+ description: React Router conventions (route organization, layouts, data loading)
3
+ globs: **/router/**/*.{ts,tsx,js,jsx}
4
+ alwaysApply: false
5
+ ---
6
+ # React Router Conventions
7
+
8
+ ## Route Organization
9
+ - Define routes in `src/router/index.tsx` using `createBrowserRouter`.
10
+ - Use lazy loading with `React.lazy()` for route components.
11
+
12
+ ## Layout Routes
13
+ - Use layout routes for shared UI (nav, sidebar).
14
+ - Place layouts in `src/layouts/`.
15
+
16
+ ## Data Loading
17
+ - Use route loaders for data fetching when available.
18
+ - Handle error states with `errorElement`.
@@ -0,0 +1,21 @@
1
+ ---
2
+ description: React state management conventions (Redux Toolkit, Zustand, general principles)
3
+ globs: **/store/**/*.{ts,tsx,js,jsx}, **/stores/**/*.{ts,tsx,js,jsx}
4
+ alwaysApply: false
5
+ ---
6
+ # React State Management
7
+
8
+ ## Redux Toolkit
9
+ - Use `createSlice` for reducers.
10
+ - Use `createAsyncThunk` for async operations.
11
+ - Keep slices under `src/store/slices/`.
12
+
13
+ ## Zustand
14
+ - One store per domain with `create()`.
15
+ - Use selectors to avoid unnecessary re-renders.
16
+ - Keep stores in `src/stores/`.
17
+
18
+ ## General Principles
19
+ - Colocate state with the component that owns it.
20
+ - Lift state only when needed by siblings.
21
+ - Server state (API data) belongs in a data-fetching library (TanStack Query, SWR), not in global state.
@@ -0,0 +1,23 @@
1
+ ---
2
+ description: Vue SFC component conventions (naming, structure, props, slots)
3
+ globs: **/*.vue
4
+ alwaysApply: false
5
+ ---
6
+ # Vue Component Conventions
7
+
8
+ ## File Naming
9
+ - Use PascalCase for component files: `UserProfile.vue`.
10
+ - Use kebab-case for component usage in templates: `<user-profile />`.
11
+
12
+ ## Structure
13
+ - Order in SFC: `<script setup>` → `<template>` → `<style scoped>`.
14
+ - One component per file.
15
+
16
+ ## Props & Events
17
+ - Always type props with TypeScript interfaces via `defineProps<T>()`.
18
+ - Use `defineEmits<T>()` for typed event declarations.
19
+ - Provide default values for optional props.
20
+
21
+ ## Slots
22
+ - Use named slots for complex layouts.
23
+ - Document slot contracts with comments or types.
@@ -0,0 +1,24 @@
1
+ ---
2
+ description: Vue Composition API best practices (script setup, composables, reactivity, lifecycle)
3
+ globs: **/*.vue, **/composables/**/*.{ts,js}
4
+ alwaysApply: false
5
+ ---
6
+ # Vue Composition API Best Practices
7
+
8
+ ## Setup Function
9
+ - Use `<script setup>` syntax for concise single-file components.
10
+ - Group reactive state declarations at the top, followed by computed, then watchers.
11
+
12
+ ## Composables
13
+ - Extract shared logic into `use*` composables under `src/composables/`.
14
+ - Each composable should have a single responsibility.
15
+ - Always return reactive refs, not raw values.
16
+
17
+ ## Reactivity
18
+ - Prefer `ref()` for primitives, `reactive()` for objects.
19
+ - Use `toRefs()` when destructuring reactive objects to preserve reactivity.
20
+ - Avoid mutating props directly; emit events instead.
21
+
22
+ ## Lifecycle
23
+ - Prefer `onMounted`, `onUnmounted` over Options API equivalents.
24
+ - Clean up side effects (event listeners, timers) in `onUnmounted`.
@@ -0,0 +1,16 @@
1
+ ---
2
+ description: Vue state management conventions for Pinia stores
3
+ globs: **/stores/**/*.{ts,js}, **/*.vue
4
+ alwaysApply: false
5
+ ---
6
+ # Vue State Management (Pinia)
7
+
8
+ ## Store Organization
9
+ - One store per domain: `useUserStore`, `useCartStore`.
10
+ - Place stores in `src/stores/`.
11
+
12
+ ## Best Practices
13
+ - Use `defineStore` with setup syntax for better TypeScript support.
14
+ - Keep store actions focused; delegate complex logic to service layers.
15
+ - Use getters for derived state instead of computed in components.
16
+ - Avoid storing UI-only state (modals, tooltips) in global stores.
@@ -0,0 +1,18 @@
1
+ ---
2
+ description: Vue Router conventions (organization, guards, naming, lazy routes)
3
+ globs: **/router/**/*.{ts,js}, **/*.vue
4
+ alwaysApply: false
5
+ ---
6
+ # Vue Router Conventions
7
+
8
+ ## Route Organization
9
+ - Define routes in `src/router/index.ts`.
10
+ - Use lazy loading: `() => import('../views/About.vue')`.
11
+
12
+ ## Navigation Guards
13
+ - Use `beforeEach` for authentication checks.
14
+ - Keep guard logic in dedicated files under `src/router/guards/`.
15
+
16
+ ## Naming
17
+ - Name all routes for programmatic navigation.
18
+ - Use consistent path patterns: kebab-case.
@@ -0,0 +1,62 @@
1
+ ---
2
+ name: app-ui-design
3
+ description: Review App/H5 UI code for UI 设计规范 compliance. Use when the user asks to “检查 UI 规范/对齐规范/审查页面”, “review UI”, “按设计规范检查 App/H5”, or wants a terse issues list in `file:line - finding` format plus a final `✓ pass` when clean.
4
+ metadata:
5
+ author: internal
6
+ version: "1.0.0"
7
+ argument-hint: <file-or-pattern>
8
+ ---
9
+
10
+ # App UI Design Guidelines Checker
11
+
12
+ 在开发过程中,按“设计规范”对指定文件进行快速审查,输出**可定位、可执行**的问题清单。
13
+
14
+ 输出风格对齐 Web Interface Guidelines:**先读取最新规范 → 读取目标文件 → 按固定格式输出问题**。
15
+
16
+ ## How It Works
17
+
18
+ 1. 读取最新的 UI 规范规则文件(见下方 Source)
19
+ 2. 读取用户指定的文件/目录/模式(前端代码、样式文件、设计稿标注文档等)
20
+ 3. 对照规则逐条检查,产出**可定位**的问题列表
21
+ 4. 若无问题:输出 `✓ pass`
22
+
23
+ ## Guidelines Source
24
+
25
+ 默认从仓库内的规则说明文件读取(单一真源):
26
+
27
+ - `src/skills/app-ui-design/references/rules.md`
28
+
29
+ 可选:如果你把规则托管到远程(例如 GitHub Raw),审查时应优先从远程拉取最新版本,再进行检查。
30
+
31
+ ## Usage
32
+
33
+ 当用户提供 `<file-or-pattern>` 时:
34
+
35
+ 1. 读取 `references/rules.md`(作为审查规则)
36
+ 2. 读取并遍历用户目标(单文件、目录或 glob pattern)
37
+ 3. 按规则检查并输出发现
38
+
39
+ 当用户没有提供 `<file-or-pattern>` 时:询问需要审查的文件/目录/模式。
40
+
41
+ ## Output Format (MUST)
42
+
43
+ 输出必须是**简洁问题列表**,每条一行,格式如下(示例):
44
+
45
+ ```text
46
+ path/to/file.tsx:123 - [app-ui] <finding>
47
+ path/to/file.css:45 - [app-ui] <finding>
48
+ ✓ pass - no app-ui issues found
49
+ ```
50
+
51
+ 规则:
52
+
53
+ - 每条 finding 必须能落地为“可执行动作”(要改什么/怎么对齐),不要写成散文
54
+ - 尽可能给出最具体的定位(文件路径 + 行号)
55
+ - 若无法精确到行号(例如仅能判断组件结构/布局语义),至少要定位到文件,并在 finding 中写明“无法精确行号”的原因
56
+ - 避免把“软方向/品牌调性”当作硬验收;若引用软方向,必须同时给出可执行的约束(例如“字号范围/间距/颜色/对比度”)
57
+
58
+ ## Scope Notes
59
+
60
+ - 本 skill 只做“对照规则的 UI 审查”,不负责从 `.docx` 抽取规则;规则维护请直接更新 `references/rules.md`
61
+ - 若项目存在多端差异(App vs H5),审查时必须在 finding 中写明端类型与差异理由,避免把某端特例当成通用规则
62
+