@mikulgohil/ai-kit 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +73 -0
- package/commands/accessibility-audit.md +143 -0
- package/commands/api-route.md +203 -0
- package/commands/commit-msg.md +127 -0
- package/commands/dep-check.md +148 -0
- package/commands/design-tokens.md +146 -0
- package/commands/document.md +175 -0
- package/commands/env-setup.md +165 -0
- package/commands/error-boundary.md +254 -0
- package/commands/extract-hook.md +237 -0
- package/commands/figma-to-code.md +152 -0
- package/commands/fix-bug.md +112 -0
- package/commands/migrate.md +174 -0
- package/commands/new-component.md +121 -0
- package/commands/new-page.md +113 -0
- package/commands/optimize.md +120 -0
- package/commands/pre-pr.md +159 -0
- package/commands/prompt-help.md +175 -0
- package/commands/refactor.md +219 -0
- package/commands/responsive-check.md +164 -0
- package/commands/review.md +120 -0
- package/commands/security-check.md +175 -0
- package/commands/sitecore-debug.md +216 -0
- package/commands/test.md +154 -0
- package/commands/token-tips.md +72 -0
- package/commands/type-fix.md +224 -0
- package/commands/understand.md +84 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1425 -0
- package/dist/index.js.map +1 -0
- package/docs-scaffolds/component-doc.md +35 -0
- package/docs-scaffolds/decisions-log.md +15 -0
- package/docs-scaffolds/mistakes-log.md +15 -0
- package/docs-scaffolds/time-log.md +14 -0
- package/guides/figma-workflow.md +135 -0
- package/guides/getting-started.md +61 -0
- package/guides/prompt-playbook.md +64 -0
- package/guides/token-saving-tips.md +50 -0
- package/guides/when-to-use-ai.md +44 -0
- package/package.json +58 -0
- package/templates/claude-md/base.md +173 -0
- package/templates/claude-md/figma.md +62 -0
- package/templates/claude-md/monorepo.md +17 -0
- package/templates/claude-md/nextjs-app-router.md +29 -0
- package/templates/claude-md/nextjs-pages-router.md +28 -0
- package/templates/claude-md/sitecore-xmc.md +46 -0
- package/templates/claude-md/tailwind.md +18 -0
- package/templates/claude-md/typescript.md +19 -0
- package/templates/cursorrules/base.md +84 -0
- package/templates/cursorrules/figma.md +32 -0
- package/templates/cursorrules/monorepo.md +7 -0
- package/templates/cursorrules/nextjs-app-router.md +8 -0
- package/templates/cursorrules/nextjs-pages-router.md +7 -0
- package/templates/cursorrules/sitecore-xmc.md +9 -0
- package/templates/cursorrules/tailwind.md +8 -0
- package/templates/cursorrules/typescript.md +8 -0
- package/templates/header.md +4 -0
- package/templates/token-dashboard.html +732 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/commands/init.ts","../src/scanner/index.ts","../src/utils.ts","../src/scanner/nextjs.ts","../src/scanner/sitecore.ts","../src/scanner/styling.ts","../src/scanner/typescript.ts","../src/scanner/monorepo.ts","../src/scanner/package-manager.ts","../src/scanner/figma.ts","../src/scanner/tools.ts","../src/scanner/mcp.ts","../src/generator/assembler.ts","../src/generator/claude-md.ts","../src/generator/cursorrules.ts","../src/generator/cursor-mdc.ts","../src/generator/config.ts","../src/copier/commands.ts","../src/copier/guides.ts","../src/copier/docs.ts","../src/commands/update.ts","../src/commands/reset.ts","../src/commands/tokens.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { VERSION } from './constants.js';\nimport { initCommand } from './commands/init.js';\nimport { updateCommand } from './commands/update.js';\nimport { resetCommand } from './commands/reset.js';\nimport { tokensCommand } from './commands/tokens.js';\n\nconst program = new Command();\n\nprogram\n .name('ai-kit')\n .description(\n 'AI-powered project setup — generates CLAUDE.md, .cursorrules, slash commands, and guides tailored to your stack.',\n )\n .version(VERSION);\n\nprogram\n .command('init')\n .description('Scan your project and generate AI configs')\n .argument('[path]', 'Project directory (defaults to current directory)')\n .action(async (targetPath?: string) => {\n try {\n await initCommand(targetPath);\n } catch (err) {\n if ((err as Error).name === 'ExitPromptError') {\n process.exit(0);\n }\n console.error(err);\n process.exit(1);\n }\n });\n\nprogram\n .command('update')\n .description('Re-scan and update all generated AI configs')\n .argument('[path]', 'Project directory (defaults to current directory)')\n .action(async (targetPath?: string) => {\n try {\n await updateCommand(targetPath);\n } catch (err) {\n if ((err as Error).name === 'ExitPromptError') {\n process.exit(0);\n }\n console.error(err);\n process.exit(1);\n }\n });\n\nprogram\n .command('reset')\n .description('Remove all AI Kit generated files')\n .argument('[path]', 'Project directory (defaults to current directory)')\n .action(async (targetPath?: string) => {\n try {\n await resetCommand(targetPath);\n } catch (err) {\n if ((err as Error).name === 'ExitPromptError') {\n process.exit(0);\n }\n console.error(err);\n process.exit(1);\n }\n });\n\nprogram\n .command('tokens')\n .description('Show token usage summary and cost estimates')\n .option('--export', 'Export data and open HTML dashboard')\n .action(async (opts: { export?: boolean }) => {\n try {\n await tokensCommand(opts);\n } catch (err) {\n if ((err as Error).name === 'ExitPromptError') {\n process.exit(0);\n }\n console.error(err);\n process.exit(1);\n }\n });\n\nprogram.parse();\n","import { fileURLToPath } from 'url';\nimport path from 'path';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport const PACKAGE_ROOT = path.resolve(__dirname, '..');\nexport const TEMPLATES_DIR = path.join(PACKAGE_ROOT, 'templates');\nexport const COMMANDS_DIR = path.join(PACKAGE_ROOT, 'commands');\nexport const GUIDES_DIR = path.join(PACKAGE_ROOT, 'guides');\nexport const DOCS_SCAFFOLDS_DIR = path.join(PACKAGE_ROOT, 'docs-scaffolds');\n\nexport const VERSION = '1.0.0';\n\nexport const AI_KIT_FOLDER = 'ai-kit';\nexport const AI_KIT_CONFIG_FILE = 'ai-kit.config.json';\n\nexport const GENERATED_FILES = {\n claudeMd: 'CLAUDE.md',\n cursorRules: '.cursorrules',\n cursorMdcDir: '.cursor/rules',\n claudeSettings: '.claude/settings.json',\n claudeCommands: '.claude/commands',\n} as const;\n\nexport const TEMPLATE_FRAGMENTS = [\n 'base',\n 'nextjs-app-router',\n 'nextjs-pages-router',\n 'sitecore-xmc',\n 'tailwind',\n 'typescript',\n 'monorepo',\n 'figma',\n] as const;\n\nexport type TemplateFragment = (typeof TEMPLATE_FRAGMENTS)[number];\n","import path from 'path';\nimport fs from 'fs-extra';\nimport { select, confirm, input } from '@inquirer/prompts';\nimport ora from 'ora';\nimport { scanProject } from '../scanner/index.js';\nimport { generateClaudeMd } from '../generator/claude-md.js';\nimport { generateCursorRules } from '../generator/cursorrules.js';\nimport { generateMdcFiles } from '../generator/cursor-mdc.js';\nimport { generateConfig } from '../generator/config.js';\nimport { copyCommands } from '../copier/commands.js';\nimport { copyGuides } from '../copier/guides.js';\nimport { scaffoldDocs } from '../copier/docs.js';\nimport { AI_KIT_CONFIG_FILE, GENERATED_FILES } from '../constants.js';\nimport {\n logSuccess,\n logWarning,\n logError,\n logInfo,\n logSection,\n fileExists,\n} from '../utils.js';\nimport type { ProjectScan, ConflictResolution, ClarificationAnswer } from '../types.js';\n\nexport async function initCommand(targetPath?: string): Promise<void> {\n const projectDir = path.resolve(targetPath || process.cwd());\n\n logSection('AI Kit — Project Setup');\n logInfo(`Scanning: ${projectDir}`);\n\n // Check for existing config\n const configPath = path.join(projectDir, AI_KIT_CONFIG_FILE);\n if (fileExists(configPath)) {\n const overwrite = await confirm({\n message: 'AI Kit is already configured in this project. Re-initialize?',\n default: false,\n });\n if (!overwrite) {\n logInfo('Cancelled. Use `ai-kit update` to refresh configs.');\n return;\n }\n }\n\n // Scan the project\n const spinner = ora('Scanning project...').start();\n let scan: ProjectScan;\n try {\n scan = await scanProject(projectDir);\n spinner.succeed('Project scanned');\n } catch (err) {\n spinner.fail('Failed to scan project');\n logError(String(err));\n return;\n }\n\n // Show detected stack\n logSection('Detected Stack');\n logInfo(`Framework: ${formatFramework(scan)}`);\n logInfo(`CMS: ${scan.cms === 'none' ? 'None' : scan.cms}`);\n logInfo(`Styling: ${scan.styling.join(', ') || 'None detected'}`);\n logInfo(`TypeScript: ${scan.typescript ? 'Yes' : 'No'}`);\n logInfo(`Monorepo: ${scan.monorepo ? `Yes (${scan.monorepoTool})` : 'No'}`);\n logInfo(`Package Manager: ${scan.packageManager}`);\n\n // Clarification questions for ambiguous detections\n const clarifications = await askClarifications(scan);\n scan = applyClarifications(scan, clarifications);\n\n // Ask what to generate\n const tools = await selectTools();\n\n // Ask conflict resolution strategy\n const conflict = await selectConflictStrategy(projectDir);\n\n // Generate files\n logSection('Generating Files');\n const results = await generate(projectDir, scan, tools, conflict);\n\n // Summary\n logSection('Setup Complete');\n if (results.claudeMd) logSuccess(`CLAUDE.md generated`);\n if (results.cursorRules) logSuccess(`.cursorrules generated`);\n if (results.cursorMdcFiles > 0)\n logSuccess(`${results.cursorMdcFiles} .cursor/rules/*.mdc files generated`);\n if (results.commands.length > 0)\n logSuccess(`${results.commands.length} slash commands copied`);\n if (results.guides.length > 0)\n logSuccess(`${results.guides.length} guides added to ai-kit/guides/`);\n if (results.docs.length > 0)\n logSuccess(`${results.docs.length} doc scaffolds created in docs/`);\n\n // Recommended tools & MCP servers\n showRecommendations(scan);\n\n console.log('');\n logInfo('Run `ai-kit update` anytime to refresh configs after project changes.');\n logInfo('Check ai-kit/guides/getting-started.md to get started.');\n}\n\nfunction formatFramework(scan: ProjectScan): string {\n if (scan.framework === 'nextjs') {\n const version = scan.nextjsVersion ? ` ${scan.nextjsVersion}` : '';\n const router = scan.routerType ? ` (${scan.routerType} router)` : '';\n return `Next.js${version}${router}`;\n }\n return scan.framework;\n}\n\nasync function askClarifications(scan: ProjectScan): Promise<ClarificationAnswer> {\n const answers: ClarificationAnswer = {};\n\n // If Next.js detected but router type unclear\n if (scan.framework === 'nextjs' && !scan.routerType) {\n answers.routerType = await select({\n message: 'Which Next.js router does this project use?',\n choices: [\n { name: 'App Router (app/ directory)', value: 'app' as const },\n { name: 'Pages Router (pages/ directory)', value: 'pages' as const },\n { name: 'Both (hybrid)', value: 'hybrid' as const },\n ],\n });\n }\n\n return answers;\n}\n\nfunction applyClarifications(\n scan: ProjectScan,\n clarifications: ClarificationAnswer,\n): ProjectScan {\n return {\n ...scan,\n ...(clarifications.routerType && { routerType: clarifications.routerType }),\n ...(clarifications.cms && { cms: clarifications.cms }),\n };\n}\n\nasync function selectTools(): Promise<{ claude: boolean; cursor: boolean }> {\n const tool = await select({\n message: 'Which AI tools does this project use?',\n choices: [\n { name: 'Both Claude Code & Cursor', value: 'both' },\n { name: 'Claude Code only', value: 'claude' },\n { name: 'Cursor only', value: 'cursor' },\n ],\n default: 'both',\n });\n\n return {\n claude: tool === 'both' || tool === 'claude',\n cursor: tool === 'both' || tool === 'cursor',\n };\n}\n\nasync function selectConflictStrategy(\n projectDir: string,\n): Promise<ConflictResolution> {\n const hasExisting =\n fileExists(path.join(projectDir, GENERATED_FILES.claudeMd)) ||\n fileExists(path.join(projectDir, GENERATED_FILES.cursorRules));\n\n if (!hasExisting) return 'overwrite';\n\n return select({\n message: 'Existing AI config files detected. How should we handle conflicts?',\n choices: [\n {\n name: 'Overwrite — replace with fresh generated files',\n value: 'overwrite' as const,\n },\n {\n name: 'Skip — keep existing files, only add missing ones',\n value: 'skip' as const,\n },\n ],\n default: 'overwrite',\n });\n}\n\ninterface GenerateResult {\n claudeMd: boolean;\n cursorRules: boolean;\n cursorMdcFiles: number;\n commands: string[];\n guides: string[];\n docs: string[];\n}\n\nasync function generate(\n projectDir: string,\n scan: ProjectScan,\n tools: { claude: boolean; cursor: boolean },\n conflict: ConflictResolution,\n): Promise<GenerateResult> {\n const result: GenerateResult = {\n claudeMd: false,\n cursorRules: false,\n cursorMdcFiles: 0,\n commands: [],\n guides: [],\n docs: [],\n };\n\n // Generate CLAUDE.md\n if (tools.claude) {\n const claudeMdPath = path.join(projectDir, GENERATED_FILES.claudeMd);\n if (conflict === 'overwrite' || !fileExists(claudeMdPath)) {\n const content = generateClaudeMd(scan);\n await fs.writeFile(claudeMdPath, content, 'utf-8');\n result.claudeMd = true;\n } else {\n logWarning('CLAUDE.md exists, skipping');\n }\n\n // Copy slash commands\n result.commands = await copyCommands(projectDir);\n\n // Ensure .claude/commands directory\n await fs.ensureDir(path.join(projectDir, '.claude', 'commands'));\n }\n\n // Generate .cursorrules\n if (tools.cursor) {\n const cursorPath = path.join(projectDir, GENERATED_FILES.cursorRules);\n if (conflict === 'overwrite' || !fileExists(cursorPath)) {\n const content = generateCursorRules(scan);\n await fs.writeFile(cursorPath, content, 'utf-8');\n result.cursorRules = true;\n } else {\n logWarning('.cursorrules exists, skipping');\n }\n\n // Generate .cursor/rules/*.mdc files\n const mdcDir = path.join(projectDir, GENERATED_FILES.cursorMdcDir);\n await fs.ensureDir(mdcDir);\n const mdcFiles = generateMdcFiles(scan);\n for (const mdc of mdcFiles) {\n await fs.writeFile(path.join(mdcDir, mdc.filename), mdc.content, 'utf-8');\n }\n result.cursorMdcFiles = mdcFiles.length;\n }\n\n // Copy guides\n result.guides = await copyGuides(projectDir);\n\n // Scaffold docs\n result.docs = await scaffoldDocs(projectDir);\n\n // Write ai-kit config\n const templates = [];\n if (result.claudeMd) templates.push('CLAUDE.md');\n if (result.cursorRules) templates.push('.cursorrules');\n\n const config = generateConfig(scan, templates, result.commands, result.guides);\n await fs.writeJson(\n path.join(projectDir, AI_KIT_CONFIG_FILE),\n config,\n { spaces: 2 },\n );\n\n return result;\n}\n\nfunction showRecommendations(scan: ProjectScan): void {\n const toolRecs: { check: boolean; label: string; hint: string }[] = [\n {\n check: scan.tools.playwright,\n label: 'Playwright not detected — install for E2E testing:',\n hint: ' npm install -D @playwright/test && npx playwright install',\n },\n {\n check: scan.tools.eslint,\n label: 'ESLint not detected — install for code quality:',\n hint: ' npm install -D eslint @typescript-eslint/eslint-plugin',\n },\n {\n check: scan.tools.prettier,\n label: 'Prettier not detected — install for code formatting:',\n hint: ' npm install -D prettier',\n },\n {\n check: scan.tools.axeCore,\n label: 'axe-core not detected — install for accessibility testing:',\n hint: ' npm install -D @axe-core/playwright',\n },\n {\n check: scan.tools.knip,\n label: 'Knip not detected — install to find unused code:',\n hint: ' npm install -D knip',\n },\n {\n check: scan.tools.bundleAnalyzer,\n label: 'Bundle analyzer not detected — install for bundle insights:',\n hint: ' npm install -D @next/bundle-analyzer',\n },\n ];\n\n const mcpRecs: { check: boolean; label: string; hint: string }[] = [\n {\n check: scan.mcpServers.context7,\n label: 'Context7 MCP not configured — enables up-to-date library docs:',\n hint: ' Add to .claude/settings.json mcpServers',\n },\n {\n check: scan.mcpServers.playwright,\n label: 'Playwright MCP not configured — enables browser automation:',\n hint: ' Add to .claude/settings.json mcpServers',\n },\n {\n check: scan.mcpServers.github,\n label: 'GitHub MCP not configured — enables PR/issue management:',\n hint: ' Add to .claude/settings.json mcpServers',\n },\n {\n check: scan.mcpServers.perplexity,\n label: 'Perplexity MCP not configured — enables web research:',\n hint: ' Add to .claude/settings.json mcpServers',\n },\n ];\n\n const missingTools = toolRecs.filter((r) => !r.check);\n const missingMcps = mcpRecs.filter((r) => !r.check);\n\n if (missingTools.length === 0 && missingMcps.length === 0) return;\n\n logSection('Recommended Setup');\n\n for (const rec of missingTools) {\n logInfo(rec.label);\n logInfo(rec.hint);\n }\n\n for (const rec of missingMcps) {\n logInfo(rec.label);\n logInfo(rec.hint);\n }\n}\n","import path from 'path';\nimport { readJsonSafe } from '../utils.js';\nimport { detectNextjs } from './nextjs.js';\nimport { detectSitecore } from './sitecore.js';\nimport { detectStyling } from './styling.js';\nimport { detectTypescript } from './typescript.js';\nimport { detectMonorepo } from './monorepo.js';\nimport { detectPackageManager } from './package-manager.js';\nimport { detectFigma } from './figma.js';\nimport { detectTools } from './tools.js';\nimport { detectMcpServers } from './mcp.js';\nimport type { ProjectScan } from '../types.js';\n\nexport async function scanProject(projectPath: string): Promise<ProjectScan> {\n const pkgPath = path.join(projectPath, 'package.json');\n const pkg = readJsonSafe<Record<string, unknown>>(pkgPath) || {};\n\n const scripts = (pkg.scripts as Record<string, string>) || {};\n const projectName =\n (pkg.name as string) || path.basename(projectPath);\n\n const nextjsResult = detectNextjs(projectPath, pkg);\n const sitecoreResult = detectSitecore(pkg);\n const stylingResult = detectStyling(projectPath, pkg);\n const tsResult = detectTypescript(projectPath);\n const monorepoResult = detectMonorepo(projectPath, pkg);\n const packageManager = detectPackageManager(projectPath);\n const figmaResult = detectFigma(projectPath, pkg);\n const toolsResult = detectTools(projectPath, pkg);\n const mcpResult = detectMcpServers(projectPath);\n\n const figmaDetected =\n figmaResult.figmaMcp ||\n figmaResult.figmaCodeCli ||\n figmaResult.designTokens;\n\n return {\n ...nextjsResult,\n ...sitecoreResult,\n ...stylingResult,\n ...tsResult,\n ...monorepoResult,\n figma: {\n detected: figmaDetected,\n ...figmaResult,\n },\n tools: toolsResult,\n mcpServers: mcpResult,\n packageManager,\n projectName,\n projectPath,\n scripts,\n };\n}\n\nexport {\n detectNextjs,\n detectSitecore,\n detectStyling,\n detectTypescript,\n detectMonorepo,\n detectPackageManager,\n detectFigma,\n detectTools,\n detectMcpServers,\n};\n","import fs from 'fs-extra';\nimport path from 'path';\nimport chalk from 'chalk';\n\nexport function readJsonSafe<T = Record<string, unknown>>(\n filePath: string,\n): T | null {\n try {\n return fs.readJsonSync(filePath) as T;\n } catch {\n return null;\n }\n}\n\nexport function fileExists(filePath: string): boolean {\n return fs.existsSync(filePath);\n}\n\nexport function dirExists(dirPath: string): boolean {\n try {\n return fs.statSync(dirPath).isDirectory();\n } catch {\n return false;\n }\n}\n\nexport function readFileSafe(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, 'utf-8');\n } catch {\n return null;\n }\n}\n\nexport function log(message: string): void {\n console.log(message);\n}\n\nexport function logSuccess(message: string): void {\n console.log(chalk.green('✓') + ' ' + message);\n}\n\nexport function logWarning(message: string): void {\n console.log(chalk.yellow('⚠') + ' ' + message);\n}\n\nexport function logError(message: string): void {\n console.log(chalk.red('✗') + ' ' + message);\n}\n\nexport function logInfo(message: string): void {\n console.log(chalk.blue('ℹ') + ' ' + message);\n}\n\nexport function logSection(title: string): void {\n console.log('\\n' + chalk.bold.underline(title));\n}\n\nexport function getRelativePath(from: string, to: string): string {\n return path.relative(from, to);\n}\n\nconst AI_KIT_START = '<!-- AI-KIT:START -->';\nconst AI_KIT_END = '<!-- AI-KIT:END -->';\n\nexport function mergeWithMarkers(\n existingContent: string,\n newGenerated: string,\n): string {\n const startIdx = existingContent.indexOf(AI_KIT_START);\n const endIdx = existingContent.indexOf(AI_KIT_END);\n\n if (startIdx === -1 || endIdx === -1) {\n // No markers found — file was generated before markers existed.\n // Replace entirely with new content (which includes markers).\n return newGenerated;\n }\n\n const before = existingContent.substring(0, startIdx);\n const after = existingContent.substring(endIdx + AI_KIT_END.length);\n\n return `${before}${newGenerated}${after}`;\n}\n","import path from 'path';\nimport { dirExists, readJsonSafe } from '../utils.js';\n\ninterface NextjsResult {\n framework: 'nextjs' | 'react' | 'unknown';\n nextjsVersion?: string;\n routerType?: 'app' | 'pages' | 'hybrid';\n}\n\nexport function detectNextjs(\n projectPath: string,\n pkg: Record<string, unknown>,\n): NextjsResult {\n const deps = {\n ...(pkg.dependencies as Record<string, string> | undefined),\n ...(pkg.devDependencies as Record<string, string> | undefined),\n };\n\n if (!deps.next) {\n if (deps.react) return { framework: 'react' };\n return { framework: 'unknown' };\n }\n\n const nextjsVersion = deps.next.replace(/[\\^~>=<]/g, '');\n\n const hasAppDir =\n dirExists(path.join(projectPath, 'app')) ||\n dirExists(path.join(projectPath, 'src', 'app'));\n\n const hasPagesDir =\n dirExists(path.join(projectPath, 'pages')) ||\n dirExists(path.join(projectPath, 'src', 'pages'));\n\n let routerType: 'app' | 'pages' | 'hybrid' | undefined;\n if (hasAppDir && hasPagesDir) routerType = 'hybrid';\n else if (hasAppDir) routerType = 'app';\n else if (hasPagesDir) routerType = 'pages';\n\n return { framework: 'nextjs', nextjsVersion, routerType };\n}\n","interface SitecoreResult {\n cms: 'sitecore-xmc' | 'sitecore-jss' | 'none';\n sitecorejssVersion?: string;\n}\n\nexport function detectSitecore(pkg: Record<string, unknown>): SitecoreResult {\n const deps = {\n ...(pkg.dependencies as Record<string, string> | undefined),\n ...(pkg.devDependencies as Record<string, string> | undefined),\n };\n\n const jssNextjs = deps['@sitecore-jss/sitecore-jss-nextjs'];\n const jssReact = deps['@sitecore-jss/sitecore-jss-react'];\n const contentSdk = deps['@sitecore-content-sdk/nextjs'];\n\n if (contentSdk || jssNextjs) {\n const version = (contentSdk || jssNextjs || '').replace(/[\\^~>=<]/g, '');\n return { cms: 'sitecore-xmc', sitecorejssVersion: version || undefined };\n }\n\n if (jssReact) {\n const version = jssReact.replace(/[\\^~>=<]/g, '');\n return { cms: 'sitecore-jss', sitecorejssVersion: version || undefined };\n }\n\n return { cms: 'none' };\n}\n","import path from 'path';\nimport { fileExists } from '../utils.js';\n\ntype StylingTool = 'tailwind' | 'css-modules' | 'styled-components' | 'scss';\n\ninterface StylingResult {\n styling: StylingTool[];\n tailwindVersion?: string;\n}\n\nexport function detectStyling(\n projectPath: string,\n pkg: Record<string, unknown>,\n): StylingResult {\n const deps = {\n ...(pkg.dependencies as Record<string, string> | undefined),\n ...(pkg.devDependencies as Record<string, string> | undefined),\n };\n\n const styling: StylingTool[] = [];\n let tailwindVersion: string | undefined;\n\n if (deps.tailwindcss || deps['@tailwindcss/postcss']) {\n styling.push('tailwind');\n tailwindVersion = (deps.tailwindcss || deps['@tailwindcss/postcss'] || '')\n .replace(/[\\^~>=<]/g, '');\n }\n\n const hasTailwindConfig =\n fileExists(path.join(projectPath, 'tailwind.config.js')) ||\n fileExists(path.join(projectPath, 'tailwind.config.ts')) ||\n fileExists(path.join(projectPath, 'tailwind.config.mjs'));\n\n if (hasTailwindConfig && !styling.includes('tailwind')) {\n styling.push('tailwind');\n }\n\n if (deps['styled-components']) styling.push('styled-components');\n if (deps.sass || deps['node-sass']) styling.push('scss');\n\n return {\n styling,\n tailwindVersion: tailwindVersion || undefined,\n };\n}\n","import path from 'path';\nimport { fileExists, readJsonSafe } from '../utils.js';\n\ninterface TypescriptResult {\n typescript: boolean;\n typescriptStrict?: boolean;\n}\n\nexport function detectTypescript(projectPath: string): TypescriptResult {\n const tsconfigPath = path.join(projectPath, 'tsconfig.json');\n\n if (!fileExists(tsconfigPath)) {\n return { typescript: false };\n }\n\n const tsconfig = readJsonSafe<{\n compilerOptions?: { strict?: boolean };\n }>(tsconfigPath);\n\n return {\n typescript: true,\n typescriptStrict: tsconfig?.compilerOptions?.strict ?? false,\n };\n}\n","import path from 'path';\nimport { fileExists } from '../utils.js';\n\ntype MonorepoTool = 'turborepo' | 'nx' | 'lerna' | 'pnpm-workspaces';\n\ninterface MonorepoResult {\n monorepo: boolean;\n monorepoTool?: MonorepoTool;\n}\n\nexport function detectMonorepo(\n projectPath: string,\n pkg: Record<string, unknown>,\n): MonorepoResult {\n if (fileExists(path.join(projectPath, 'turbo.json'))) {\n return { monorepo: true, monorepoTool: 'turborepo' };\n }\n\n if (fileExists(path.join(projectPath, 'nx.json'))) {\n return { monorepo: true, monorepoTool: 'nx' };\n }\n\n if (fileExists(path.join(projectPath, 'lerna.json'))) {\n return { monorepo: true, monorepoTool: 'lerna' };\n }\n\n if (fileExists(path.join(projectPath, 'pnpm-workspace.yaml'))) {\n return { monorepo: true, monorepoTool: 'pnpm-workspaces' };\n }\n\n if (pkg.workspaces) {\n return { monorepo: true };\n }\n\n return { monorepo: false };\n}\n","import path from 'path';\nimport { fileExists, readJsonSafe } from '../utils.js';\n\ntype PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun';\n\nexport function detectPackageManager(projectPath: string): PackageManager {\n const pkg = readJsonSafe<{ packageManager?: string }>(\n path.join(projectPath, 'package.json'),\n );\n\n if (pkg?.packageManager) {\n if (pkg.packageManager.startsWith('pnpm')) return 'pnpm';\n if (pkg.packageManager.startsWith('yarn')) return 'yarn';\n if (pkg.packageManager.startsWith('bun')) return 'bun';\n return 'npm';\n }\n\n if (fileExists(path.join(projectPath, 'pnpm-lock.yaml'))) return 'pnpm';\n if (fileExists(path.join(projectPath, 'yarn.lock'))) return 'yarn';\n if (fileExists(path.join(projectPath, 'bun.lockb'))) return 'bun';\n if (fileExists(path.join(projectPath, 'bun.lock'))) return 'bun';\n\n return 'npm';\n}\n","import path from 'path';\nimport { fileExists, readJsonSafe, readFileSafe } from '../utils.js';\n\nexport interface FigmaDetection {\n figmaMcp: boolean;\n figmaCodeCli: boolean;\n designTokens: boolean;\n tokenFormat: 'tailwind-v4' | 'tailwind-v3' | 'css-variables' | 'none';\n visualTests: boolean;\n}\n\nexport function detectFigma(\n projectPath: string,\n pkg: Record<string, unknown>,\n): FigmaDetection {\n return {\n figmaMcp: detectFigmaMcp(projectPath),\n figmaCodeCli: detectFigmaCodeCli(pkg),\n designTokens: detectDesignTokens(projectPath),\n tokenFormat: detectTokenFormat(projectPath),\n visualTests: detectVisualTests(projectPath, pkg),\n };\n}\n\nfunction detectFigmaMcp(projectPath: string): boolean {\n // Check .claude/settings.json or .claude/settings.local.json for Figma MCP\n const settingsPaths = [\n path.join(projectPath, '.claude', 'settings.json'),\n path.join(projectPath, '.claude', 'settings.local.json'),\n path.join(projectPath, '.mcp.json'),\n ];\n\n for (const settingsPath of settingsPaths) {\n const content = readFileSafe(settingsPath);\n if (content && content.toLowerCase().includes('figma')) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction detectFigmaCodeCli(pkg: Record<string, unknown>): boolean {\n const deps = {\n ...(pkg.dependencies as Record<string, string> | undefined),\n ...(pkg.devDependencies as Record<string, string> | undefined),\n };\n\n return Object.keys(deps).some(\n (dep) => dep.startsWith('@figma-code/') || dep === 'figma-code-cli',\n );\n}\n\nfunction detectDesignTokens(projectPath: string): boolean {\n const tokenPaths = [\n path.join(projectPath, 'tokens.json'),\n path.join(projectPath, 'tokens'),\n path.join(projectPath, 'design-tokens.json'),\n path.join(projectPath, 'src', 'tokens'),\n ];\n\n for (const tokenPath of tokenPaths) {\n if (fileExists(tokenPath)) return true;\n }\n\n // Check for @theme inline in globals.css\n const globalsCss = readFileSafe(\n path.join(projectPath, 'src', 'app', 'globals.css'),\n );\n if (globalsCss && globalsCss.includes('@theme')) return true;\n\n return false;\n}\n\nfunction detectTokenFormat(\n projectPath: string,\n): FigmaDetection['tokenFormat'] {\n // Check for Tailwind v4 @theme inline\n const globalsCss = readFileSafe(\n path.join(projectPath, 'src', 'app', 'globals.css'),\n );\n if (globalsCss && globalsCss.includes('@theme')) return 'tailwind-v4';\n\n // Check for Tailwind v3 config with custom theme\n const twConfigPaths = [\n path.join(projectPath, 'tailwind.config.ts'),\n path.join(projectPath, 'tailwind.config.js'),\n ];\n\n for (const twPath of twConfigPaths) {\n const content = readFileSafe(twPath);\n if (content && content.includes('theme')) return 'tailwind-v3';\n }\n\n // Check for raw CSS variables\n if (globalsCss && globalsCss.includes('--')) return 'css-variables';\n\n return 'none';\n}\n\nfunction detectVisualTests(\n projectPath: string,\n pkg: Record<string, unknown>,\n): boolean {\n const deps = {\n ...(pkg.dependencies as Record<string, string> | undefined),\n ...(pkg.devDependencies as Record<string, string> | undefined),\n };\n\n const hasPlaywright = '@playwright/test' in deps || 'playwright' in deps;\n const hasPlaywrightConfig =\n fileExists(path.join(projectPath, 'playwright.config.ts')) ||\n fileExists(path.join(projectPath, 'playwright.config.js'));\n\n return hasPlaywright || hasPlaywrightConfig;\n}\n","import path from 'path';\nimport { fileExists, dirExists } from '../utils.js';\n\nexport interface ToolsDetection {\n playwright: boolean;\n storybook: boolean;\n eslint: boolean;\n prettier: boolean;\n axeCore: boolean;\n snyk: boolean;\n knip: boolean;\n bundleAnalyzer: boolean;\n}\n\nexport function detectTools(\n projectPath: string,\n pkg: Record<string, unknown>,\n): ToolsDetection {\n const deps = {\n ...(pkg.dependencies as Record<string, string> | undefined),\n ...(pkg.devDependencies as Record<string, string> | undefined),\n };\n\n return {\n playwright: detectPlaywright(projectPath, deps),\n storybook: detectStorybook(projectPath, deps),\n eslint: detectEslint(projectPath, deps),\n prettier: detectPrettier(projectPath, deps),\n axeCore: detectAxeCore(deps),\n snyk: detectSnyk(projectPath, deps),\n knip: detectKnip(projectPath, deps),\n bundleAnalyzer: detectBundleAnalyzer(deps),\n };\n}\n\nfunction detectPlaywright(\n projectPath: string,\n deps: Record<string, string>,\n): boolean {\n if ('@playwright/test' in deps) return true;\n if (fileExists(path.join(projectPath, 'playwright.config.ts'))) return true;\n if (fileExists(path.join(projectPath, 'playwright.config.js'))) return true;\n return false;\n}\n\nfunction detectStorybook(\n projectPath: string,\n deps: Record<string, string>,\n): boolean {\n if ('@storybook/react' in deps) return true;\n if (dirExists(path.join(projectPath, '.storybook'))) return true;\n return false;\n}\n\nfunction detectEslint(\n projectPath: string,\n deps: Record<string, string>,\n): boolean {\n if ('eslint' in deps) return true;\n const eslintConfigs = [\n '.eslintrc',\n '.eslintrc.js',\n '.eslintrc.cjs',\n '.eslintrc.json',\n '.eslintrc.yml',\n '.eslintrc.yaml',\n 'eslint.config.js',\n 'eslint.config.mjs',\n 'eslint.config.cjs',\n 'eslint.config.ts',\n ];\n for (const config of eslintConfigs) {\n if (fileExists(path.join(projectPath, config))) return true;\n }\n return false;\n}\n\nfunction detectPrettier(\n projectPath: string,\n deps: Record<string, string>,\n): boolean {\n if ('prettier' in deps) return true;\n const prettierConfigs = [\n '.prettierrc',\n '.prettierrc.js',\n '.prettierrc.cjs',\n '.prettierrc.json',\n '.prettierrc.yml',\n '.prettierrc.yaml',\n '.prettierrc.toml',\n 'prettier.config.js',\n 'prettier.config.cjs',\n 'prettier.config.ts',\n ];\n for (const config of prettierConfigs) {\n if (fileExists(path.join(projectPath, config))) return true;\n }\n return false;\n}\n\nfunction detectAxeCore(deps: Record<string, string>): boolean {\n return '@axe-core/playwright' in deps || 'axe-core' in deps;\n}\n\nfunction detectSnyk(\n projectPath: string,\n deps: Record<string, string>,\n): boolean {\n if ('snyk' in deps) return true;\n if (fileExists(path.join(projectPath, '.snyk'))) return true;\n return false;\n}\n\nfunction detectKnip(\n projectPath: string,\n deps: Record<string, string>,\n): boolean {\n if ('knip' in deps) return true;\n if (fileExists(path.join(projectPath, 'knip.json'))) return true;\n if (fileExists(path.join(projectPath, 'knip.config.ts'))) return true;\n return false;\n}\n\nfunction detectBundleAnalyzer(deps: Record<string, string>): boolean {\n return '@next/bundle-analyzer' in deps;\n}\n","import path from 'path';\nimport { readFileSafe } from '../utils.js';\n\nexport interface McpDetection {\n playwright: boolean;\n figma: boolean;\n github: boolean;\n context7: boolean;\n perplexity: boolean;\n notion: boolean;\n}\n\nexport function detectMcpServers(projectPath: string): McpDetection {\n const settingsPaths = [\n path.join(projectPath, '.claude', 'settings.json'),\n path.join(projectPath, '.claude', 'settings.local.json'),\n path.join(projectPath, '.mcp.json'),\n ];\n\n // Combine all MCP config file contents for searching\n let combined = '';\n for (const settingsPath of settingsPaths) {\n const content = readFileSafe(settingsPath);\n if (content) {\n combined += content.toLowerCase() + '\\n';\n }\n }\n\n return {\n playwright: combined.includes('playwright'),\n figma: combined.includes('figma'),\n github: combined.includes('github'),\n context7: combined.includes('context7'),\n perplexity: combined.includes('perplexity'),\n notion: combined.includes('notion'),\n };\n}\n","import path from 'path';\nimport { TEMPLATES_DIR, VERSION } from '../constants.js';\nimport { readFileSafe } from '../utils.js';\n\nexport function readTemplate(relativePath: string): string {\n const fullPath = path.join(TEMPLATES_DIR, relativePath);\n const content = readFileSafe(fullPath);\n if (!content) {\n throw new Error(`Template not found: ${relativePath}`);\n }\n return content.trim();\n}\n\nexport function assembleTemplate(\n subfolder: 'claude-md' | 'cursorrules',\n fragments: string[],\n variables: Record<string, string>,\n): string {\n const versionComment = `<!-- Generated by ai-kit v${VERSION} -->`;\n const header = readTemplate('header.md');\n const body = fragments\n .map((name) => readTemplate(`${subfolder}/${name}.md`))\n .join('\\n\\n---\\n\\n');\n\n const full = `${versionComment}\\n${header}\\n\\n---\\n\\n${body}`;\n const replaced = replacePlaceholders(full, variables);\n return `<!-- AI-KIT:START -->\\n${replaced}\\n<!-- AI-KIT:END -->`;\n}\n\nexport function replacePlaceholders(\n content: string,\n variables: Record<string, string>,\n): string {\n let result = content;\n for (const [key, value] of Object.entries(variables)) {\n result = result.replaceAll(`{{${key}}}`, value);\n }\n return result;\n}\n","import type { ProjectScan } from '../types.js';\nimport { assembleTemplate } from './assembler.js';\n\nexport function selectFragments(scan: ProjectScan): string[] {\n const fragments: string[] = ['base'];\n\n if (scan.framework === 'nextjs') {\n if (scan.routerType === 'app' || scan.routerType === 'hybrid') {\n fragments.push('nextjs-app-router');\n }\n if (scan.routerType === 'pages' || scan.routerType === 'hybrid') {\n fragments.push('nextjs-pages-router');\n }\n }\n\n if (scan.cms !== 'none') {\n fragments.push('sitecore-xmc');\n }\n\n if (scan.styling.includes('tailwind')) {\n fragments.push('tailwind');\n }\n\n if (scan.typescript) {\n fragments.push('typescript');\n }\n\n if (scan.monorepo) {\n fragments.push('monorepo');\n }\n\n if (scan.figma?.detected) {\n fragments.push('figma');\n }\n\n return fragments;\n}\n\nexport function generateClaudeMd(scan: ProjectScan): string {\n const fragments = selectFragments(scan);\n const variables = buildVariables(scan);\n return assembleTemplate('claude-md', fragments, variables);\n}\n\nfunction buildVariables(scan: ProjectScan): Record<string, string> {\n const techStack: string[] = [];\n\n if (scan.framework === 'nextjs') {\n techStack.push(`Next.js ${scan.nextjsVersion || ''}`);\n }\n if (scan.cms !== 'none') {\n techStack.push(\n scan.cms === 'sitecore-xmc'\n ? `Sitecore XM Cloud${scan.sitecorejssVersion ? ` (JSS ${scan.sitecorejssVersion})` : ''}`\n : 'Sitecore JSS',\n );\n }\n if (scan.typescript) techStack.push('TypeScript');\n if (scan.styling.includes('tailwind'))\n techStack.push(`Tailwind CSS ${scan.tailwindVersion || ''}`);\n if (scan.styling.includes('scss')) techStack.push('SCSS');\n if (scan.styling.includes('styled-components'))\n techStack.push('styled-components');\n if (scan.monorepo && scan.monorepoTool)\n techStack.push(scan.monorepoTool);\n\n const scripts = Object.entries(scan.scripts)\n .filter(([key]) =>\n ['dev', 'build', 'start', 'lint', 'test', 'type-check', 'typecheck'].includes(key),\n )\n .map(([key, value]) => `- \\`${scan.packageManager} run ${key}\\` → \\`${value}\\``)\n .join('\\n');\n\n return {\n projectName: scan.projectName,\n techStack: techStack.join(' · '),\n packageManager: scan.packageManager,\n routerType: scan.routerType || 'unknown',\n scripts: scripts || '- No scripts detected',\n framework: scan.framework,\n };\n}\n","import type { ProjectScan } from '../types.js';\nimport { assembleTemplate } from './assembler.js';\nimport { selectFragments } from './claude-md.js';\n\nexport function generateCursorRules(scan: ProjectScan): string {\n const fragments = selectFragments(scan);\n const variables = buildCursorVariables(scan);\n return assembleTemplate('cursorrules', fragments, variables);\n}\n\nexport function buildCursorVariables(scan: ProjectScan): Record<string, string> {\n const techStack: string[] = [];\n\n if (scan.framework === 'nextjs') {\n techStack.push(`Next.js ${scan.nextjsVersion || ''}`);\n }\n if (scan.cms !== 'none') {\n techStack.push(scan.cms === 'sitecore-xmc' ? 'Sitecore XM Cloud' : 'Sitecore JSS');\n }\n if (scan.typescript) techStack.push('TypeScript');\n if (scan.styling.includes('tailwind')) techStack.push('Tailwind CSS');\n if (scan.monorepo && scan.monorepoTool) techStack.push(scan.monorepoTool);\n\n const scripts = Object.entries(scan.scripts)\n .filter(([key]) =>\n ['dev', 'build', 'start', 'lint', 'test', 'type-check', 'typecheck'].includes(key),\n )\n .map(([key, value]) => `- \\`${scan.packageManager} run ${key}\\` → \\`${value}\\``)\n .join('\\n');\n\n return {\n projectName: scan.projectName,\n techStack: techStack.join(' · '),\n packageManager: scan.packageManager,\n routerType: scan.routerType || 'unknown',\n scripts: scripts || '- No scripts detected',\n framework: scan.framework,\n };\n}\n","import type { ProjectScan } from '../types.js';\nimport { selectFragments } from './claude-md.js';\nimport { readTemplate, replacePlaceholders } from './assembler.js';\nimport { buildCursorVariables } from './cursorrules.js';\nimport { VERSION } from '../constants.js';\n\nexport interface MdcFile {\n filename: string;\n content: string;\n}\n\nconst MDC_CONFIG: Record<string, { description: string; globs: string }> = {\n base: {\n description: 'Project coding standards and conventions',\n globs: '**/*',\n },\n 'nextjs-app-router': {\n description: 'Next.js App Router patterns and best practices',\n globs: 'app/**/*.{ts,tsx}, src/app/**/*.{ts,tsx}',\n },\n 'nextjs-pages-router': {\n description: 'Next.js Pages Router patterns and best practices',\n globs: 'pages/**/*.{ts,tsx}, src/pages/**/*.{ts,tsx}',\n },\n 'sitecore-xmc': {\n description: 'Sitecore XM Cloud component patterns and field helpers',\n globs: 'src/components/**/*.{ts,tsx}',\n },\n tailwind: {\n description: 'Tailwind CSS conventions and utility patterns',\n globs: '**/*.{tsx,jsx,css}',\n },\n typescript: {\n description: 'TypeScript strict typing conventions',\n globs: '**/*.{ts,tsx}',\n },\n monorepo: {\n description: 'Monorepo workspace conventions',\n globs: '**/*',\n },\n figma: {\n description: 'Figma-to-code workflow and design token rules',\n globs: 'src/components/**/*.{ts,tsx}, tokens/**/*',\n },\n};\n\nexport function generateMdcFiles(scan: ProjectScan): MdcFile[] {\n const fragments = selectFragments(scan);\n const variables = buildCursorVariables(scan);\n\n return fragments.map((fragment) => {\n const config = MDC_CONFIG[fragment] || {\n description: fragment,\n globs: '**/*',\n };\n const body = readTemplate(`cursorrules/${fragment}.md`);\n const replaced = replacePlaceholders(body, variables);\n\n const frontmatter = [\n '---',\n `description: ${config.description}`,\n `globs: ${config.globs}`,\n 'alwaysApply: true',\n '---',\n ].join('\\n');\n\n return {\n filename: `${fragment}.mdc`,\n content: `${frontmatter}\\n\\n<!-- Generated by ai-kit v${VERSION} -->\\n\\n${replaced}`,\n };\n });\n}\n","import type { AiKitConfig, ProjectScan } from '../types.js';\nimport { VERSION } from '../constants.js';\n\nexport function generateConfig(\n scan: ProjectScan,\n templates: string[],\n commands: string[],\n guides: string[],\n): AiKitConfig {\n return {\n version: VERSION,\n scanResult: scan,\n generatedAt: new Date().toISOString(),\n templates,\n commands,\n guides,\n };\n}\n","import path from 'path';\nimport fs from 'fs-extra';\nimport { COMMANDS_DIR } from '../constants.js';\n\nconst AVAILABLE_COMMANDS = [\n 'prompt-help',\n 'review',\n 'fix-bug',\n 'new-component',\n 'new-page',\n 'understand',\n 'test',\n 'optimize',\n 'figma-to-code',\n 'design-tokens',\n 'accessibility-audit',\n 'security-check',\n 'refactor',\n 'api-route',\n 'pre-pr',\n 'migrate',\n 'error-boundary',\n 'type-fix',\n 'extract-hook',\n 'dep-check',\n 'env-setup',\n 'commit-msg',\n 'sitecore-debug',\n 'responsive-check',\n 'document',\n 'token-tips',\n];\n\nexport async function copyCommands(targetDir: string): Promise<string[]> {\n const commandsTarget = path.join(targetDir, '.claude', 'commands');\n await fs.ensureDir(commandsTarget);\n\n const copied: string[] = [];\n\n for (const cmd of AVAILABLE_COMMANDS) {\n const src = path.join(COMMANDS_DIR, `${cmd}.md`);\n const dest = path.join(commandsTarget, `${cmd}.md`);\n\n if (await fs.pathExists(src)) {\n await fs.copy(src, dest, { overwrite: true });\n copied.push(cmd);\n }\n }\n\n return copied;\n}\n","import path from 'path';\nimport fs from 'fs-extra';\nimport { GUIDES_DIR } from '../constants.js';\n\nconst AVAILABLE_GUIDES = [\n 'getting-started',\n 'prompt-playbook',\n 'when-to-use-ai',\n 'token-saving-tips',\n 'figma-workflow',\n];\n\nexport async function copyGuides(targetDir: string): Promise<string[]> {\n const guidesTarget = path.join(targetDir, 'ai-kit', 'guides');\n await fs.ensureDir(guidesTarget);\n\n const copied: string[] = [];\n\n for (const guide of AVAILABLE_GUIDES) {\n const src = path.join(GUIDES_DIR, `${guide}.md`);\n const dest = path.join(guidesTarget, `${guide}.md`);\n\n if (await fs.pathExists(src)) {\n await fs.copy(src, dest, { overwrite: true });\n copied.push(guide);\n }\n }\n\n return copied;\n}\n","import path from 'path';\nimport fs from 'fs-extra';\nimport { DOCS_SCAFFOLDS_DIR } from '../constants.js';\n\nconst DOC_SCAFFOLDS = ['mistakes-log', 'decisions-log', 'time-log'];\n\nexport async function scaffoldDocs(targetDir: string): Promise<string[]> {\n const docsTarget = path.join(targetDir, 'docs');\n await fs.ensureDir(docsTarget);\n\n const created: string[] = [];\n\n for (const doc of DOC_SCAFFOLDS) {\n const src = path.join(DOCS_SCAFFOLDS_DIR, `${doc}.md`);\n const dest = path.join(docsTarget, `${doc}.md`);\n\n if ((await fs.pathExists(dest))) {\n continue; // Don't overwrite existing docs\n }\n\n if (await fs.pathExists(src)) {\n await fs.copy(src, dest);\n created.push(doc);\n }\n }\n\n return created;\n}\n","import path from 'path';\nimport fs from 'fs-extra';\nimport ora from 'ora';\nimport { confirm } from '@inquirer/prompts';\nimport { scanProject } from '../scanner/index.js';\nimport { generateClaudeMd } from '../generator/claude-md.js';\nimport { generateCursorRules } from '../generator/cursorrules.js';\nimport { generateMdcFiles } from '../generator/cursor-mdc.js';\nimport { generateConfig } from '../generator/config.js';\nimport { copyCommands } from '../copier/commands.js';\nimport { copyGuides } from '../copier/guides.js';\nimport { AI_KIT_CONFIG_FILE, GENERATED_FILES, VERSION } from '../constants.js';\nimport {\n logSuccess,\n logError,\n logInfo,\n logWarning,\n logSection,\n fileExists,\n readJsonSafe,\n readFileSafe,\n mergeWithMarkers,\n} from '../utils.js';\nimport type { AiKitConfig } from '../types.js';\n\nexport async function updateCommand(targetPath?: string): Promise<void> {\n const projectDir = path.resolve(targetPath || process.cwd());\n const configPath = path.join(projectDir, AI_KIT_CONFIG_FILE);\n\n if (!fileExists(configPath)) {\n logError('No ai-kit.config.json found. Run `ai-kit init` first.');\n return;\n }\n\n const existingConfig = readJsonSafe<AiKitConfig>(configPath);\n if (!existingConfig) {\n logError('Could not read ai-kit.config.json. Run `ai-kit init` to re-initialize.');\n return;\n }\n\n // Warn if major version mismatch\n const existingMajor = parseInt(existingConfig.version.split('.')[0], 10);\n const currentMajor = parseInt(VERSION.split('.')[0], 10);\n if (existingMajor !== currentMajor) {\n logWarning(\n `Config was generated with ai-kit v${existingConfig.version}, but you're running v${VERSION}. Consider running \\`ai-kit init\\` to re-initialize.`,\n );\n }\n\n const proceed = await confirm({\n message: 'Re-scan project and update all generated files?',\n default: true,\n });\n\n if (!proceed) return;\n\n const spinner = ora('Re-scanning project...').start();\n const scan = await scanProject(projectDir);\n spinner.succeed('Project re-scanned');\n\n logSection('Updating Files');\n\n const templates: string[] = [];\n\n // Update CLAUDE.md if it was previously generated\n if (\n existingConfig.templates.includes('CLAUDE.md') ||\n fileExists(path.join(projectDir, GENERATED_FILES.claudeMd))\n ) {\n const claudeMdPath = path.join(projectDir, GENERATED_FILES.claudeMd);\n const newContent = generateClaudeMd(scan);\n const existing = readFileSafe(claudeMdPath);\n if (existing) {\n await fs.writeFile(claudeMdPath, mergeWithMarkers(existing, newContent), 'utf-8');\n } else {\n await fs.writeFile(claudeMdPath, newContent, 'utf-8');\n }\n templates.push('CLAUDE.md');\n logSuccess('CLAUDE.md updated');\n }\n\n // Update .cursorrules if it was previously generated\n if (\n existingConfig.templates.includes('.cursorrules') ||\n fileExists(path.join(projectDir, GENERATED_FILES.cursorRules))\n ) {\n const cursorRulesPath = path.join(projectDir, GENERATED_FILES.cursorRules);\n const newContent = generateCursorRules(scan);\n const existing = readFileSafe(cursorRulesPath);\n if (existing) {\n await fs.writeFile(cursorRulesPath, mergeWithMarkers(existing, newContent), 'utf-8');\n } else {\n await fs.writeFile(cursorRulesPath, newContent, 'utf-8');\n }\n templates.push('.cursorrules');\n logSuccess('.cursorrules updated');\n\n // Update .cursor/rules/*.mdc files\n const mdcDir = path.join(projectDir, GENERATED_FILES.cursorMdcDir);\n await fs.ensureDir(mdcDir);\n const mdcFiles = generateMdcFiles(scan);\n for (const mdc of mdcFiles) {\n await fs.writeFile(path.join(mdcDir, mdc.filename), mdc.content, 'utf-8');\n }\n logSuccess(`${mdcFiles.length} .cursor/rules/*.mdc files updated`);\n }\n\n // Update commands and guides\n const commands = await copyCommands(projectDir);\n logSuccess(`${commands.length} slash commands updated`);\n\n const guides = await copyGuides(projectDir);\n logSuccess(`${guides.length} guides updated`);\n\n // Update config\n const config = generateConfig(scan, templates, commands, guides);\n await fs.writeJson(configPath, config, { spaces: 2 });\n logSuccess('ai-kit.config.json updated');\n\n console.log('');\n logInfo('All AI configs refreshed with latest project scan.');\n}\n","import path from 'path';\nimport fs from 'fs-extra';\nimport { confirm } from '@inquirer/prompts';\nimport { AI_KIT_CONFIG_FILE, GENERATED_FILES } from '../constants.js';\nimport { logSuccess, logWarning, logInfo, logSection, fileExists } from '../utils.js';\n\nexport async function resetCommand(targetPath?: string): Promise<void> {\n const projectDir = path.resolve(targetPath || process.cwd());\n\n logSection('AI Kit — Reset');\n logWarning('This will remove all AI Kit generated files:');\n logInfo(` - ${GENERATED_FILES.claudeMd}`);\n logInfo(` - ${GENERATED_FILES.cursorRules}`);\n logInfo(` - ${GENERATED_FILES.cursorMdcDir}/`);\n logInfo(` - ${GENERATED_FILES.claudeCommands}/`);\n logInfo(` - ai-kit/`);\n logInfo(` - ${AI_KIT_CONFIG_FILE}`);\n console.log('');\n\n const proceed = await confirm({\n message: 'Are you sure? This cannot be undone.',\n default: false,\n });\n\n if (!proceed) {\n logInfo('Cancelled.');\n return;\n }\n\n const removed: string[] = [];\n\n // Remove CLAUDE.md\n const claudeMdPath = path.join(projectDir, GENERATED_FILES.claudeMd);\n if (fileExists(claudeMdPath)) {\n await fs.remove(claudeMdPath);\n removed.push(GENERATED_FILES.claudeMd);\n }\n\n // Remove .cursorrules\n const cursorPath = path.join(projectDir, GENERATED_FILES.cursorRules);\n if (fileExists(cursorPath)) {\n await fs.remove(cursorPath);\n removed.push(GENERATED_FILES.cursorRules);\n }\n\n // Remove .cursor/rules/ (mdc files)\n const cursorMdcDir = path.join(projectDir, GENERATED_FILES.cursorMdcDir);\n if (fileExists(cursorMdcDir)) {\n await fs.remove(cursorMdcDir);\n removed.push(GENERATED_FILES.cursorMdcDir);\n }\n\n // Remove .claude/commands/ (only ai-kit commands)\n const commandsDir = path.join(projectDir, GENERATED_FILES.claudeCommands);\n if (fileExists(commandsDir)) {\n await fs.remove(commandsDir);\n removed.push(GENERATED_FILES.claudeCommands);\n }\n\n // Remove ai-kit/ folder\n const aiKitDir = path.join(projectDir, 'ai-kit');\n if (fileExists(aiKitDir)) {\n await fs.remove(aiKitDir);\n removed.push('ai-kit/');\n }\n\n // Remove config\n const configPath = path.join(projectDir, AI_KIT_CONFIG_FILE);\n if (fileExists(configPath)) {\n await fs.remove(configPath);\n removed.push(AI_KIT_CONFIG_FILE);\n }\n\n logSection('Reset Complete');\n if (removed.length > 0) {\n removed.forEach((f) => logSuccess(`Removed ${f}`));\n } else {\n logInfo('No AI Kit files found to remove.');\n }\n}\n","import path from 'path';\nimport fs from 'fs-extra';\nimport chalk from 'chalk';\nimport ora from 'ora';\nimport os from 'os';\nimport { logSection, logInfo, logWarning } from '../utils.js';\nimport { PACKAGE_ROOT } from '../constants.js';\n\n// ─── Pricing (per 1M tokens) ──────────────────────────────────────────\nconst PRICING = {\n sonnet: { input: 3, output: 15, cacheRead: 0.3 },\n opus: { input: 15, output: 75, cacheRead: 0.3 },\n} as const;\n\nconst PLAN_BUDGET = 20; // $20 monthly plan\n\n// ─── Types ─────────────────────────────────────────────────────────────\ninterface TokenUsage {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheCreationTokens: number;\n}\n\ninterface SessionSummary {\n sessionId: string;\n filePath: string;\n date: string; // YYYY-MM-DD\n usage: TokenUsage;\n model: string;\n messageCount: number;\n}\n\ninterface DailySummary {\n date: string;\n sessions: number;\n usage: TokenUsage;\n cost: number;\n}\n\ninterface ExportData {\n generatedAt: string;\n planBudget: number;\n daily: DailySummary[];\n sessions: SessionSummary[];\n totals: {\n thisWeek: { usage: TokenUsage; cost: number; sessions: number };\n thisMonth: { usage: TokenUsage; cost: number; sessions: number };\n today: { usage: TokenUsage; cost: number; sessions: number };\n };\n}\n\n// ─── JSONL Parsing ─────────────────────────────────────────────────────\nfunction findSessionFiles(): string[] {\n const claudeDir = path.join(os.homedir(), '.claude', 'projects');\n if (!fs.existsSync(claudeDir)) return [];\n\n const files: string[] = [];\n\n function walkDir(dir: string): void {\n try {\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n const full = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n walkDir(full);\n } else if (entry.name.endsWith('.jsonl')) {\n files.push(full);\n }\n }\n } catch {\n // skip unreadable dirs\n }\n }\n\n walkDir(claudeDir);\n return files;\n}\n\nfunction parseSessionFile(filePath: string): SessionSummary | null {\n try {\n const content = fs.readFileSync(filePath, 'utf-8');\n const lines = content.split('\\n').filter((l) => l.trim());\n\n const usage: TokenUsage = {\n inputTokens: 0,\n outputTokens: 0,\n cacheReadTokens: 0,\n cacheCreationTokens: 0,\n };\n\n let model = 'sonnet';\n let messageCount = 0;\n let sessionDate = '';\n\n for (const line of lines) {\n try {\n const obj = JSON.parse(line);\n\n // Extract timestamp for date grouping\n if (obj.timestamp && !sessionDate) {\n sessionDate = new Date(obj.timestamp).toISOString().slice(0, 10);\n }\n\n // Detect model from message content\n if (obj.model) {\n const m = String(obj.model).toLowerCase();\n if (m.includes('opus')) model = 'opus';\n else model = 'sonnet';\n }\n\n // Count assistant messages\n if (obj.type === 'assistant' || obj.role === 'assistant') {\n messageCount++;\n }\n\n // Extract usage data — Claude Code logs usage in various shapes\n const u =\n obj.usage ||\n obj.message?.usage ||\n obj.costInfo ||\n obj.result?.usage ||\n null;\n\n if (u) {\n usage.inputTokens += u.input_tokens || u.inputTokens || 0;\n usage.outputTokens += u.output_tokens || u.outputTokens || 0;\n usage.cacheReadTokens +=\n u.cache_read_input_tokens || u.cacheReadTokens || u.cache_read || 0;\n usage.cacheCreationTokens +=\n u.cache_creation_input_tokens ||\n u.cacheCreationTokens ||\n u.cache_creation ||\n 0;\n }\n } catch {\n // skip malformed lines\n }\n }\n\n // Skip empty sessions\n if (usage.inputTokens === 0 && usage.outputTokens === 0) return null;\n\n // Fallback date from file stat\n if (!sessionDate) {\n const stat = fs.statSync(filePath);\n sessionDate = stat.mtime.toISOString().slice(0, 10);\n }\n\n const sessionId = path.basename(filePath, '.jsonl');\n\n return {\n sessionId,\n filePath,\n date: sessionDate,\n usage,\n model,\n messageCount,\n };\n } catch {\n return null;\n }\n}\n\nfunction calculateCost(usage: TokenUsage, model: string = 'sonnet'): number {\n const rates = model === 'opus' ? PRICING.opus : PRICING.sonnet;\n const inputCost = (usage.inputTokens / 1_000_000) * rates.input;\n const outputCost = (usage.outputTokens / 1_000_000) * rates.output;\n const cacheCost = (usage.cacheReadTokens / 1_000_000) * rates.cacheRead;\n return inputCost + outputCost + cacheCost;\n}\n\n// ─── Aggregation ───────────────────────────────────────────────────────\nfunction aggregateByDate(sessions: SessionSummary[]): DailySummary[] {\n const map = new Map<string, { sessions: number; usage: TokenUsage; models: string[] }>();\n\n for (const s of sessions) {\n const existing = map.get(s.date) || {\n sessions: 0,\n usage: { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheCreationTokens: 0 },\n models: [],\n };\n\n existing.sessions++;\n existing.usage.inputTokens += s.usage.inputTokens;\n existing.usage.outputTokens += s.usage.outputTokens;\n existing.usage.cacheReadTokens += s.usage.cacheReadTokens;\n existing.usage.cacheCreationTokens += s.usage.cacheCreationTokens;\n existing.models.push(s.model);\n\n map.set(s.date, existing);\n }\n\n return Array.from(map.entries())\n .map(([date, data]) => ({\n date,\n sessions: data.sessions,\n usage: data.usage,\n cost: calculateCost(data.usage, data.models.includes('opus') ? 'opus' : 'sonnet'),\n }))\n .sort((a, b) => b.date.localeCompare(a.date));\n}\n\nfunction filterDateRange(\n sessions: SessionSummary[],\n startDate: string,\n endDate: string,\n): SessionSummary[] {\n return sessions.filter((s) => s.date >= startDate && s.date <= endDate);\n}\n\nfunction sumUsage(sessions: SessionSummary[]): TokenUsage {\n return sessions.reduce(\n (acc, s) => ({\n inputTokens: acc.inputTokens + s.usage.inputTokens,\n outputTokens: acc.outputTokens + s.usage.outputTokens,\n cacheReadTokens: acc.cacheReadTokens + s.usage.cacheReadTokens,\n cacheCreationTokens: acc.cacheCreationTokens + s.usage.cacheCreationTokens,\n }),\n { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheCreationTokens: 0 },\n );\n}\n\nfunction sumCost(sessions: SessionSummary[]): number {\n return sessions.reduce((acc, s) => acc + calculateCost(s.usage, s.model), 0);\n}\n\n// ─── Formatting ────────────────────────────────────────────────────────\nfunction fmt(n: number): string {\n return n.toLocaleString('en-US');\n}\n\nfunction fmtCost(n: number): string {\n return `$${n.toFixed(2)}`;\n}\n\nfunction progressBar(percent: number, width: number = 20): string {\n const filled = Math.round((percent / 100) * width);\n const empty = width - filled;\n const bar = chalk.green('\\u2588'.repeat(filled)) + chalk.gray('\\u2591'.repeat(empty));\n return bar;\n}\n\nfunction printPeriodSummary(\n label: string,\n sessions: SessionSummary[],\n): void {\n const usage = sumUsage(sessions);\n const cost = sumCost(sessions);\n\n console.log(`\\n${chalk.bold(label)}`);\n console.log(` Sessions: ${chalk.cyan(String(sessions.length))}`);\n console.log(` Input tokens: ${chalk.white(fmt(usage.inputTokens))}`);\n console.log(` Output tokens: ${chalk.white(fmt(usage.outputTokens))}`);\n console.log(` Cache read: ${chalk.white(fmt(usage.cacheReadTokens))}`);\n console.log(` Estimated cost: ${chalk.yellow('~' + fmtCost(cost))}`);\n}\n\n// ─── Main Command ──────────────────────────────────────────────────────\nexport async function tokensCommand(options: { export?: boolean } = {}): Promise<void> {\n logSection('AI Kit \\u2014 Token Usage');\n\n const spinner = ora('Scanning Claude Code session logs...').start();\n\n const sessionFiles = findSessionFiles();\n if (sessionFiles.length === 0) {\n spinner.fail('No Claude Code session logs found');\n logInfo('Session logs are stored in ~/.claude/projects/');\n logInfo('Use Claude Code to generate some activity first.');\n return;\n }\n\n const sessions: SessionSummary[] = [];\n for (const file of sessionFiles) {\n const s = parseSessionFile(file);\n if (s) sessions.push(s);\n }\n\n spinner.succeed(`Parsed ${sessions.length} sessions from ${sessionFiles.length} log files`);\n\n if (sessions.length === 0) {\n logWarning('No token usage data found in session logs.');\n return;\n }\n\n // Date ranges\n const today = new Date().toISOString().slice(0, 10);\n\n const dayOfWeek = new Date().getDay();\n const mondayOffset = dayOfWeek === 0 ? 6 : dayOfWeek - 1;\n const weekStart = new Date();\n weekStart.setDate(weekStart.getDate() - mondayOffset);\n const weekStartStr = weekStart.toISOString().slice(0, 10);\n\n const monthStart = today.slice(0, 7) + '-01';\n\n const todaySessions = filterDateRange(sessions, today, today);\n const weekSessions = filterDateRange(sessions, weekStartStr, today);\n const monthSessions = filterDateRange(sessions, monthStart, today);\n\n // Print summaries\n printPeriodSummary(`Today (${today})`, todaySessions);\n printPeriodSummary('This Week', weekSessions);\n printPeriodSummary('This Month', monthSessions);\n\n // Budget progress\n const monthCost = sumCost(monthSessions);\n const budgetPercent = Math.min((monthCost / PLAN_BUDGET) * 100, 100);\n const daysInMonth = new Date(\n new Date().getFullYear(),\n new Date().getMonth() + 1,\n 0,\n ).getDate();\n const dayOfMonth = new Date().getDate();\n const daysRemaining = daysInMonth - dayOfMonth;\n const dailyAvg = dayOfMonth > 0 ? monthCost / dayOfMonth : 0;\n const estimatedDaysLeft =\n dailyAvg > 0 ? Math.floor((PLAN_BUDGET - monthCost) / dailyAvg) : daysRemaining;\n\n console.log(`\\n${chalk.bold(`$${PLAN_BUDGET} Plan Budget`)}`);\n console.log(\n ` ${progressBar(budgetPercent)} ${Math.round(budgetPercent)}% used (~${fmtCost(monthCost)} of ${fmtCost(PLAN_BUDGET)})`,\n );\n console.log(\n ` Estimated days remaining at this rate: ${chalk.cyan(String(Math.max(estimatedDaysLeft, 0)))} days`,\n );\n console.log(` Daily average: ${chalk.yellow(fmtCost(dailyAvg))}`);\n\n // Tip\n console.log(\n `\\n${chalk.dim('Tip: Use /understand before modifying unfamiliar code \\u2014')}`,\n );\n console.log(\n chalk.dim(\" it's cheaper than a failed implementation attempt.\"),\n );\n console.log('');\n\n // Export mode\n if (options.export) {\n await exportDashboard(sessions, todaySessions, weekSessions, monthSessions);\n }\n}\n\n// ─── Export ────────────────────────────────────────────────────────────\nasync function exportDashboard(\n allSessions: SessionSummary[],\n todaySessions: SessionSummary[],\n weekSessions: SessionSummary[],\n monthSessions: SessionSummary[],\n): Promise<void> {\n const spinner = ora('Generating dashboard...').start();\n\n const exportData: ExportData = {\n generatedAt: new Date().toISOString(),\n planBudget: PLAN_BUDGET,\n daily: aggregateByDate(allSessions),\n sessions: allSessions\n .sort((a, b) => b.date.localeCompare(a.date))\n .slice(0, 50)\n .map((s) => ({\n ...s,\n filePath: s.filePath, // keep for reference\n })),\n totals: {\n today: {\n usage: sumUsage(todaySessions),\n cost: sumCost(todaySessions),\n sessions: todaySessions.length,\n },\n thisWeek: {\n usage: sumUsage(weekSessions),\n cost: sumCost(weekSessions),\n sessions: weekSessions.length,\n },\n thisMonth: {\n usage: sumUsage(monthSessions),\n cost: sumCost(monthSessions),\n sessions: monthSessions.length,\n },\n },\n };\n\n const outputDir = process.cwd();\n const dataPath = path.join(outputDir, 'token-data.json');\n const dashboardSrc = path.join(PACKAGE_ROOT, 'templates', 'token-dashboard.html');\n const dashboardDest = path.join(outputDir, 'token-dashboard.html');\n\n await fs.writeJson(dataPath, exportData, { spaces: 2 });\n logInfo(`Token data written to ${dataPath}`);\n\n if (await fs.pathExists(dashboardSrc)) {\n await fs.copy(dashboardSrc, dashboardDest, { overwrite: true });\n logInfo(`Dashboard copied to ${dashboardDest}`);\n } else {\n logWarning('Dashboard template not found. Skipping HTML export.');\n }\n\n spinner.succeed('Dashboard exported');\n\n // Try to open in browser\n try {\n const { exec } = await import('child_process');\n const openCmd =\n process.platform === 'darwin'\n ? 'open'\n : process.platform === 'win32'\n ? 'start'\n : 'xdg-open';\n exec(`${openCmd} \"${dashboardDest}\"`);\n logInfo('Opening dashboard in browser...');\n } catch {\n logInfo(`Open ${dashboardDest} in your browser to view the dashboard.`);\n }\n}\n"],"mappings":"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","names":["path","fs","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","path","fs","path","fs","path","fs","path","fs","path","fs","path","fs","path","fs","path","fs","ora","confirm","path","confirm","ora","fs","path","fs","confirm","path","confirm","fs","path","fs","chalk","ora","path","fs","chalk","ora"]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# ComponentName
|
|
2
|
+
|
|
3
|
+
> Brief description of what this component does and when to use it.
|
|
4
|
+
|
|
5
|
+
## Props
|
|
6
|
+
|
|
7
|
+
| Prop | Type | Required | Default | Description |
|
|
8
|
+
|------|------|----------|---------|-------------|
|
|
9
|
+
| | | | | |
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { ComponentName } from './ComponentName';
|
|
15
|
+
|
|
16
|
+
<ComponentName prop="value" />
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## States
|
|
20
|
+
|
|
21
|
+
- **Loading**: How does it look while data is loading?
|
|
22
|
+
- **Error**: What does the user see on failure?
|
|
23
|
+
- **Empty**: What if there's no data?
|
|
24
|
+
|
|
25
|
+
## Design Decisions
|
|
26
|
+
|
|
27
|
+
- Why was this built this way? Note any trade-offs.
|
|
28
|
+
|
|
29
|
+
## Edge Cases
|
|
30
|
+
|
|
31
|
+
- List known edge cases and how they're handled.
|
|
32
|
+
|
|
33
|
+
## Change Log
|
|
34
|
+
|
|
35
|
+
- YYYY-MM-DD: Initial implementation — [reason/ticket]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Decisions Log
|
|
2
|
+
|
|
3
|
+
Record architectural and technical decisions for future reference.
|
|
4
|
+
|
|
5
|
+
## Template
|
|
6
|
+
|
|
7
|
+
### YYYY-MM-DD — Decision title
|
|
8
|
+
- **Context**: Why this decision was needed
|
|
9
|
+
- **Options considered**: What alternatives were evaluated
|
|
10
|
+
- **Decision**: What was chosen and why
|
|
11
|
+
- **Consequences**: Trade-offs and follow-up items
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
<!-- Add entries below -->
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Mistakes Log
|
|
2
|
+
|
|
3
|
+
Track mistakes and lessons learned to prevent repeating them.
|
|
4
|
+
|
|
5
|
+
## Template
|
|
6
|
+
|
|
7
|
+
### YYYY-MM-DD — Brief title
|
|
8
|
+
- **What happened**: Describe the mistake
|
|
9
|
+
- **Root cause**: Why it happened
|
|
10
|
+
- **Fix**: How it was resolved
|
|
11
|
+
- **Lesson**: What to do differently next time
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
<!-- Add entries below -->
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Time Log
|
|
2
|
+
|
|
3
|
+
Track time spent on tasks for estimation improvement.
|
|
4
|
+
|
|
5
|
+
## Template
|
|
6
|
+
|
|
7
|
+
### YYYY-MM-DD — Task description
|
|
8
|
+
- **Estimated**: Xh
|
|
9
|
+
- **Actual**: Xh
|
|
10
|
+
- **Notes**: What took longer/shorter than expected
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
<!-- Add entries below -->
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Figma-to-Code Workflow Guide
|
|
2
|
+
|
|
3
|
+
How to convert Figma designs to production code using AI — the right way.
|
|
4
|
+
|
|
5
|
+
## The Wrong Way (What Most Developers Do)
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
Developer: "Build this component" + [pastes Figma screenshot]
|
|
9
|
+
AI: Generates code with hardcoded #hex colors, arbitrary spacing,
|
|
10
|
+
no design tokens, doesn't reuse existing components
|
|
11
|
+
Developer: Spends 2 hours manually fixing tokens and spacing
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## The Right Way (With ai-kit)
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
Developer: /figma-to-code
|
|
18
|
+
AI: Asks targeted questions → extracts Figma context via MCP →
|
|
19
|
+
maps to project tokens → reuses existing components →
|
|
20
|
+
generates clean code → verifies visually
|
|
21
|
+
Developer: Reviews one clean output, ships it
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Setup: Figma MCP (2 Minutes)
|
|
27
|
+
|
|
28
|
+
Figma MCP lets Claude Code and Cursor read your Figma files directly — extracting colors, spacing, typography, and layout without you pasting anything.
|
|
29
|
+
|
|
30
|
+
### Option 1: Remote (Recommended)
|
|
31
|
+
Add to your project's `.mcp.json`:
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"servers": {
|
|
35
|
+
"figma": {
|
|
36
|
+
"type": "http",
|
|
37
|
+
"url": "https://mcp.figma.com/mcp"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
First use will prompt for OAuth login.
|
|
43
|
+
|
|
44
|
+
### Option 2: Local (Figma Desktop)
|
|
45
|
+
Requires Figma desktop app with Dev Mode enabled:
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"servers": {
|
|
49
|
+
"figma": {
|
|
50
|
+
"type": "http",
|
|
51
|
+
"url": "http://127.0.0.1:3845/mcp"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## The Workflow
|
|
60
|
+
|
|
61
|
+
### Step 1: Get the Figma Link
|
|
62
|
+
|
|
63
|
+
Copy the link to the specific frame you want to implement. Right-click the frame in Figma → "Copy link to selection".
|
|
64
|
+
|
|
65
|
+
A good link looks like:
|
|
66
|
+
```
|
|
67
|
+
https://www.figma.com/design/ABC123/MyProject?node-id=1234-5678
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Step 2: Use /figma-to-code
|
|
71
|
+
|
|
72
|
+
Run the slash command. It will:
|
|
73
|
+
1. Ask what you're building (component, page, update)
|
|
74
|
+
2. Extract design context from Figma via MCP
|
|
75
|
+
3. Map values to your project's design tokens
|
|
76
|
+
4. Check for existing components to reuse
|
|
77
|
+
5. Generate code following project patterns
|
|
78
|
+
6. Verify visually
|
|
79
|
+
|
|
80
|
+
### Step 3: Review and Ship
|
|
81
|
+
|
|
82
|
+
The output should use correct design tokens, reuse existing components, and follow your project's code patterns. Review once, make minor adjustments if needed, ship it.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Quick Reference: Token Mapping
|
|
87
|
+
|
|
88
|
+
| Figma | Code (Tailwind) |
|
|
89
|
+
|-------|-----------------|
|
|
90
|
+
| Fill color #3b82f6 | `bg-primary-500` (use token, not hex) |
|
|
91
|
+
| Padding 16px | `p-4` (use scale, not arbitrary) |
|
|
92
|
+
| Font size 32px Bold | `text-h1` (use type scale) |
|
|
93
|
+
| Border radius 8px | `rounded-card` (use named token) |
|
|
94
|
+
| Gap 24px | `gap-6` (use scale) |
|
|
95
|
+
| Auto Layout horizontal | `flex flex-row` |
|
|
96
|
+
| Auto Layout vertical | `flex flex-col` |
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## When to Use AI vs figma-code-cli
|
|
101
|
+
|
|
102
|
+
| Scenario | Tool |
|
|
103
|
+
|----------|------|
|
|
104
|
+
| Single component from Figma | `/figma-to-code` in Claude Code |
|
|
105
|
+
| Quick design token extraction | `/design-tokens` in Claude Code |
|
|
106
|
+
| Full page with 5+ components | `figma-code-cli` pipeline |
|
|
107
|
+
| Sitecore component + YML items | `figma-code-cli` (4-gate pipeline) |
|
|
108
|
+
| Brand implementation from scratch | `figma-code-cli` + reference ssd-figma-code |
|
|
109
|
+
| Quick visual tweak or spacing fix | Direct AI prompt is fine |
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Common Mistakes
|
|
114
|
+
|
|
115
|
+
1. **Pasting screenshots instead of using MCP** — MCP gives structured data (colors, spacing, layout). Screenshots give the AI only visual info, leading to guessed values.
|
|
116
|
+
|
|
117
|
+
2. **Not checking existing components** — Before building from scratch, search your `src/components/` for reusable pieces.
|
|
118
|
+
|
|
119
|
+
3. **Accepting hardcoded values** — If the AI output has `text-[#333333]` or `mt-[47px]`, reject it. Ask it to use design tokens.
|
|
120
|
+
|
|
121
|
+
4. **Skipping mobile verification** — Never assume mobile is just "desktop but smaller". Check mobile designs in Figma separately.
|
|
122
|
+
|
|
123
|
+
5. **Not reading design tokens first** — Run `/design-tokens` before starting Figma work. Know what tokens are available.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Tips for Better Figma Files
|
|
128
|
+
|
|
129
|
+
If you work with designers, share these tips to improve AI output:
|
|
130
|
+
|
|
131
|
+
1. **Name layers semantically** — "HeroBanner" not "Frame 47"
|
|
132
|
+
2. **Use Auto Layout everywhere** — it maps directly to flexbox
|
|
133
|
+
3. **Define variables for colors/spacing** — AI can extract them
|
|
134
|
+
4. **Create variants for states** — hover, active, disabled, empty
|
|
135
|
+
5. **Keep layer order = reading order** — top to bottom = left to right
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Getting Started with AI Kit
|
|
2
|
+
|
|
3
|
+
## What Just Happened?
|
|
4
|
+
|
|
5
|
+
`ai-kit init` scanned your project and generated AI configuration files tailored to your tech stack. Here's what was created:
|
|
6
|
+
|
|
7
|
+
| File | Purpose |
|
|
8
|
+
|------|---------|
|
|
9
|
+
| `CLAUDE.md` | Rules for Claude Code — tells the AI about your project |
|
|
10
|
+
| `.cursorrules` | Rules for Cursor — same purpose, Cursor format |
|
|
11
|
+
| `.claude/commands/` | Slash commands — pre-built workflows for common tasks |
|
|
12
|
+
| `ai-kit/guides/` | Guides — tips and playbooks for using AI effectively |
|
|
13
|
+
| `docs/` | Doc templates — for tracking decisions and mistakes |
|
|
14
|
+
| `ai-kit.config.json` | Config — what AI Kit detected and generated |
|
|
15
|
+
|
|
16
|
+
## First Thing to Do
|
|
17
|
+
|
|
18
|
+
### If you use Claude Code:
|
|
19
|
+
Run the `/prompt-help` command. It's an interactive prompt builder that asks you all the right questions before generating a perfect prompt. No more "fix this" and getting garbage output.
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
/prompt-help
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### If you use Cursor:
|
|
26
|
+
Open any file and use Cmd+K or the chat panel. The `.cursorrules` file is automatically loaded and gives Cursor context about your project.
|
|
27
|
+
|
|
28
|
+
## Available Slash Commands (Claude Code)
|
|
29
|
+
|
|
30
|
+
| Command | What it does |
|
|
31
|
+
|---------|-------------|
|
|
32
|
+
| `/prompt-help` | Interactive prompt builder — **start here** |
|
|
33
|
+
| `/review` | Deep code review as a Senior Engineer |
|
|
34
|
+
| `/fix-bug` | Guided bug fix workflow |
|
|
35
|
+
| `/new-component` | Scaffold a new component |
|
|
36
|
+
| `/new-page` | Create a new page/route |
|
|
37
|
+
| `/understand` | Explain code in detail |
|
|
38
|
+
| `/test` | Generate tests |
|
|
39
|
+
| `/optimize` | Performance optimization |
|
|
40
|
+
|
|
41
|
+
## Tips
|
|
42
|
+
|
|
43
|
+
1. **Always start with `/prompt-help`** if you're unsure how to ask for something
|
|
44
|
+
2. **Be specific about files** — mention paths like `src/components/Header.tsx`
|
|
45
|
+
3. **Don't start from scratch** — ask the AI to read existing code first
|
|
46
|
+
4. **One task per conversation** — keep conversations focused
|
|
47
|
+
5. **Review AI output** — always read what it generates before accepting
|
|
48
|
+
|
|
49
|
+
## Updating
|
|
50
|
+
|
|
51
|
+
When you add new packages or change your project structure:
|
|
52
|
+
```bash
|
|
53
|
+
npx ai-kit update
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Removing
|
|
57
|
+
|
|
58
|
+
To remove all AI Kit generated files:
|
|
59
|
+
```bash
|
|
60
|
+
npx ai-kit reset
|
|
61
|
+
```
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Prompt Playbook
|
|
2
|
+
|
|
3
|
+
Quick reference for writing effective AI prompts. When in doubt, use `/prompt-help` instead.
|
|
4
|
+
|
|
5
|
+
## The Golden Rule
|
|
6
|
+
|
|
7
|
+
> Tell the AI **what** you want, **where** it is, and **why** — don't make it guess.
|
|
8
|
+
|
|
9
|
+
## Bad vs Good Prompts
|
|
10
|
+
|
|
11
|
+
### ❌ Bad
|
|
12
|
+
> "Fix the header"
|
|
13
|
+
|
|
14
|
+
### ✅ Good
|
|
15
|
+
> "The mobile hamburger menu in `src/components/Header.tsx` doesn't close when clicking outside. Read the component, find where the click-outside handler should be, and fix it. Test that the menu still opens on hamburger click."
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Templates
|
|
20
|
+
|
|
21
|
+
### New Component
|
|
22
|
+
```
|
|
23
|
+
Create a [ComponentName] component in [path].
|
|
24
|
+
It should: [what it does].
|
|
25
|
+
Props: [list props with types].
|
|
26
|
+
It needs to be a [Server/Client] Component.
|
|
27
|
+
Reference [existing similar component] for patterns.
|
|
28
|
+
Use [Tailwind/SCSS] for styling.
|
|
29
|
+
Handle these states: [loading, empty, error].
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Bug Fix
|
|
33
|
+
```
|
|
34
|
+
Bug in [file path].
|
|
35
|
+
Expected: [what should happen]
|
|
36
|
+
Actual: [what happens instead]
|
|
37
|
+
Steps to reproduce: [1, 2, 3]
|
|
38
|
+
Error message: [paste it]
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Feature
|
|
42
|
+
```
|
|
43
|
+
Add [feature] to [file/area].
|
|
44
|
+
When user [action], it should [behavior].
|
|
45
|
+
It needs to call [API endpoint] and display [data].
|
|
46
|
+
Handle error case by [showing message / retry].
|
|
47
|
+
Reference [similar feature] for patterns.
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Refactor
|
|
51
|
+
```
|
|
52
|
+
Refactor [file path].
|
|
53
|
+
Current problem: [why it needs refactoring].
|
|
54
|
+
Expected result: [what good looks like].
|
|
55
|
+
Keep behavior identical — only change structure.
|
|
56
|
+
Tests must still pass.
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Context Shortcuts
|
|
60
|
+
|
|
61
|
+
Instead of explaining your whole project, point the AI to files:
|
|
62
|
+
- "Read `src/components/Card.tsx` and create a similar component for Products"
|
|
63
|
+
- "Follow the pattern in `src/pages/about.tsx` for this new page"
|
|
64
|
+
- "Use the same API pattern as `src/lib/api/users.ts`"
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Token-Saving Tips
|
|
2
|
+
|
|
3
|
+
Tokens = cost. Here's how to use fewer tokens while getting better results.
|
|
4
|
+
|
|
5
|
+
## Biggest Token Wasters
|
|
6
|
+
|
|
7
|
+
| Habit | Token Cost | Fix |
|
|
8
|
+
|-------|-----------|-----|
|
|
9
|
+
| Pasting entire files into chat | 🔴 Very High | Point AI to file paths instead |
|
|
10
|
+
| Long back-and-forth conversations | 🔴 Very High | Start new conversations per task |
|
|
11
|
+
| Vague prompts that need clarification | 🟡 Medium | Use `/prompt-help` to get it right first time |
|
|
12
|
+
| Asking AI to read the whole codebase | 🔴 Very High | Be specific about which files |
|
|
13
|
+
| Not using existing patterns | 🟡 Medium | Reference existing files: "follow the pattern in X" |
|
|
14
|
+
|
|
15
|
+
## Quick Wins
|
|
16
|
+
|
|
17
|
+
### 1. Reference Files, Don't Paste
|
|
18
|
+
```
|
|
19
|
+
❌ "Here's my component: [500 lines of code]"
|
|
20
|
+
✅ "Read src/components/Header.tsx and fix the mobile menu"
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### 2. One Task Per Conversation
|
|
24
|
+
Each new message includes ALL previous context. A 20-message conversation sends everything 20 times. Start fresh for new tasks.
|
|
25
|
+
|
|
26
|
+
### 3. Be Specific Upfront
|
|
27
|
+
```
|
|
28
|
+
❌ "Make a form" → AI asks 5 questions → 10 messages → 5000 tokens wasted
|
|
29
|
+
✅ Use /prompt-help → 1 structured prompt → done in 2 messages
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### 4. Use Slash Commands
|
|
33
|
+
Commands include pre-built context. `/new-component Button` is more efficient than typing all the instructions manually.
|
|
34
|
+
|
|
35
|
+
### 5. Point to Patterns
|
|
36
|
+
```
|
|
37
|
+
"Create ProductCard following the exact same pattern as src/components/UserCard.tsx"
|
|
38
|
+
```
|
|
39
|
+
The AI reads one file and replicates the pattern — much cheaper than you explaining the pattern.
|
|
40
|
+
|
|
41
|
+
## The 2-Try Rule
|
|
42
|
+
|
|
43
|
+
If the AI doesn't get it right in 2 attempts:
|
|
44
|
+
1. Something is wrong with the prompt (missing context)
|
|
45
|
+
2. The task might be too complex for a single prompt
|
|
46
|
+
3. Take over manually — you'll save tokens and time
|
|
47
|
+
|
|
48
|
+
## CLAUDE.md Is Free Context
|
|
49
|
+
|
|
50
|
+
Your `CLAUDE.md` file is loaded automatically — everything in it gives the AI context without using your conversation tokens. That's why `ai-kit` generates it: better output from fewer tokens.
|