docmk 1.0.3 → 1.0.5

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 (48) hide show
  1. package/dist/index.js +4 -3
  2. package/dist/index.js.map +1 -1
  3. package/package.json +6 -1
  4. package/src/builder/vite-dev.ts +4 -1
  5. package/src/cli/commands/dev.ts +3 -3
  6. package/.claude/skills/pdf/SKILL.md +0 -89
  7. package/.claude/skills/web-scraping/SKILL.md +0 -78
  8. package/CLAUDE.md +0 -90
  9. package/final-site/assets/main-B4orIFxK.css +0 -1
  10. package/final-site/assets/main-CSoKXua6.js +0 -25
  11. package/final-site/favicon.svg +0 -4
  12. package/final-site/index.html +0 -26
  13. package/final-site/robots.txt +0 -4
  14. package/final-site/sitemap.xml +0 -14
  15. package/my-docs/api/README.md +0 -152
  16. package/my-docs/api/advanced.md +0 -260
  17. package/my-docs/getting-started/README.md +0 -24
  18. package/my-docs/tutorials/README.md +0 -272
  19. package/my-docs/tutorials/customization.md +0 -492
  20. package/postcss.config.js +0 -6
  21. package/site/assets/main-BZUsYUCF.css +0 -1
  22. package/site/assets/main-q6laQtCD.js +0 -114
  23. package/site/favicon.svg +0 -4
  24. package/site/index.html +0 -23
  25. package/site/robots.txt +0 -4
  26. package/site/sitemap.xml +0 -34
  27. package/site-output/assets/main-B4orIFxK.css +0 -1
  28. package/site-output/assets/main-CSoKXua6.js +0 -25
  29. package/site-output/favicon.svg +0 -4
  30. package/site-output/index.html +0 -26
  31. package/site-output/robots.txt +0 -4
  32. package/site-output/sitemap.xml +0 -14
  33. package/tailwind.config.js +0 -65
  34. package/test-build/assets/main-C2ARPC0e.css +0 -1
  35. package/test-build/assets/main-CHIQpV3B.js +0 -25
  36. package/test-build/favicon.svg +0 -4
  37. package/test-build/index.html +0 -47
  38. package/test-build/robots.txt +0 -4
  39. package/test-build/sitemap.xml +0 -19
  40. package/test-dist/assets/main-B4orIFxK.css +0 -1
  41. package/test-dist/assets/main-CSoKXua6.js +0 -25
  42. package/test-dist/favicon.svg +0 -4
  43. package/test-dist/index.html +0 -26
  44. package/test-dist/robots.txt +0 -4
  45. package/test-dist/sitemap.xml +0 -14
  46. package/tsconfig.json +0 -30
  47. package/tsup.config.ts +0 -13
  48. package/vite.config.ts +0 -21
package/dist/index.js CHANGED
@@ -386,12 +386,13 @@ async function createViteDevServer(options) {
386
386
  }
387
387
  });
388
388
  await server.listen();
389
+ const actualPort = server.config.server.port;
389
390
  const originalClose = server.close.bind(server);
390
391
  server.close = async () => {
391
392
  await watcher?.close();
392
393
  return originalClose();
393
394
  };
394
- return server;
395
+ return { server, actualPort };
395
396
  }
396
397
 
397
398
  // src/cli/commands/dev.ts
@@ -412,12 +413,12 @@ async function devCommand(options) {
412
413
  skillsDir: sourceDir,
413
414
  outputDir: "dist"
414
415
  });
415
- const server = await createViteDevServer({
416
+ const { server, actualPort } = await createViteDevServer({
416
417
  port,
417
418
  skillsDir: sourceDir,
418
419
  config
419
420
  });
420
- console.log(`\u{1F389} Dev server running at http://localhost:${port}`);
421
+ console.log(`\u{1F389} Dev server running at http://localhost:${actualPort}`);
421
422
  process.on("SIGINT", async () => {
422
423
  console.log("\\n\u{1F44B} Shutting down dev server...");
423
424
  await server.close();
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/scanner/index.ts","../src/parser/index.ts","../src/cli/index.ts","../src/cli/commands/dev.ts","../src/builder/vite-dev.ts","../src/cli/commands/build.ts","../src/builder/index.ts","../src/cli/commands/preview.ts"],"sourcesContent":["import fs from 'fs/promises'\nimport path from 'path'\nimport { SkillDirectory, SkillFile } from '../types/index.js'\n\nexport async function scanSkillsDirectory(sourceDir: string): Promise<SkillDirectory[]> {\n try {\n await fs.access(sourceDir)\n } catch {\n throw new Error(`Source directory not found: ${sourceDir}`)\n }\n\n const entries = await fs.readdir(sourceDir, { withFileTypes: true })\n const directories: SkillDirectory[] = []\n\n for (const entry of entries) {\n if (entry.isDirectory()) {\n const dirPath = path.join(sourceDir, entry.name)\n const skillDirectory = await scanDirectory(dirPath, entry.name)\n directories.push(skillDirectory)\n }\n }\n\n return directories\n}\n\nasync function scanDirectory(dirPath: string, name: string): Promise<SkillDirectory> {\n const entries = await fs.readdir(dirPath, { withFileTypes: true })\n const children: (SkillDirectory | SkillFile)[] = []\n let skillFile: SkillFile | undefined\n\n for (const entry of entries) {\n const entryPath = path.join(dirPath, entry.name)\n\n if (entry.isDirectory()) {\n const subDir = await scanDirectory(entryPath, entry.name)\n children.push(subDir)\n } else if (entry.isFile() && entry.name.endsWith('.md')) {\n const file = await parseMarkdownFile(entryPath, entry.name)\n \n if (entry.name === 'SKILL.md') {\n skillFile = file\n } else {\n children.push(file)\n }\n }\n }\n\n return {\n path: dirPath,\n name,\n children,\n skillFile\n }\n}\n\nasync function parseMarkdownFile(filePath: string, fileName: string): Promise<SkillFile> {\n const content = await fs.readFile(filePath, 'utf-8')\n const stats = await fs.stat(filePath)\n\n // Basic frontmatter extraction\n const frontmatterMatch = content.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n/)\n const frontmatter: Record<string, any> = {}\n let markdownContent = content\n\n if (frontmatterMatch) {\n // Remove frontmatter from content\n markdownContent = content.slice(frontmatterMatch[0].length)\n \n // Parse frontmatter key-value pairs\n const fmLines = frontmatterMatch[1].split(/\\r?\\n/)\n for (const line of fmLines) {\n const colonIndex = line.indexOf(':')\n if (colonIndex > 0) {\n const key = line.slice(0, colonIndex).trim()\n const value = line.slice(colonIndex + 1).trim().replace(/^[\"']|[\"']$/g, '')\n if (key && value) {\n frontmatter[key] = value\n }\n }\n }\n }\n\n return {\n path: filePath,\n name: fileName,\n title: frontmatter.title || fileName.replace('.md', ''),\n description: frontmatter.description,\n content: markdownContent,\n frontmatter,\n lastModified: stats.mtime.getTime()\n }\n}\n\nexport async function watchSkillsDirectory(\n sourceDir: string, \n callback: (directories: SkillDirectory[]) => void\n) {\n const chokidar = await import('chokidar')\n \n const watcher = chokidar.watch(sourceDir, {\n ignored: /node_modules/,\n persistent: true,\n ignoreInitial: true\n })\n\n let debounceTimer: NodeJS.Timeout\n\n const handleChange = () => {\n clearTimeout(debounceTimer)\n debounceTimer = setTimeout(async () => {\n try {\n const directories = await scanSkillsDirectory(sourceDir)\n callback(directories)\n } catch (error) {\n console.error('Error rescanning source directory:', error)\n }\n }, 300)\n }\n\n watcher.on('add', handleChange)\n watcher.on('change', handleChange)\n watcher.on('unlink', handleChange)\n watcher.on('addDir', handleChange)\n watcher.on('unlinkDir', handleChange)\n\n return watcher\n}","import matter from 'gray-matter'\nimport MarkdownIt from 'markdown-it'\nimport { createHighlighter, Highlighter } from 'shiki'\nimport { SkillDirectory, SkillFile, SiteConfig, DocGenConfig, Navigation } from '../types/index.js'\n\nlet highlighter: Highlighter | null = null\n\nasync function getHighlighter() {\n if (!highlighter) {\n highlighter = await createHighlighter({\n themes: ['github-dark', 'github-light'],\n langs: ['javascript', 'typescript', 'bash', 'shell', 'json', 'html', 'css', 'vue', 'jsx', 'tsx', 'python', 'markdown', 'yaml', 'sql', 'go', 'rust', 'java', 'c', 'cpp']\n })\n }\n return highlighter\n}\n\nconst md = new MarkdownIt({\n html: true,\n linkify: true,\n typographer: true,\n highlight: function (str: string, lang: string) {\n // Synchronous fallback - actual highlighting done in enhanceFileContent\n return `<pre class=\"shiki-pending\" data-lang=\"${lang || 'text'}\"><code>${md.utils.escapeHtml(str)}</code></pre>`\n }\n})\n\nexport async function parseSkillsToConfig(\n directories: SkillDirectory[],\n siteConfig: SiteConfig\n): Promise<DocGenConfig> {\n const files: SkillFile[] = []\n const navigation = await generateNavigation(directories)\n\n // Collect all files for search indexing\n collectAllFiles(directories, files)\n\n // Enhance files with parsed content\n for (const file of files) {\n await enhanceFileContent(file)\n }\n\n return {\n siteConfig,\n navigation,\n files,\n directories\n }\n}\n\nfunction collectAllFiles(items: (SkillDirectory | SkillFile)[], files: SkillFile[]) {\n for (const item of items) {\n if ('content' in item) {\n // It's a SkillFile\n files.push(item)\n } else {\n // It's a SkillDirectory\n if (item.skillFile) {\n files.push(item.skillFile)\n }\n collectAllFiles(item.children, files)\n }\n }\n}\n\nasync function enhanceFileContent(file: SkillFile) {\n try {\n let content = file.content\n\n // Update title and description from frontmatter if available\n file.title = file.frontmatter.title || file.title\n file.description = file.frontmatter.description || file.description\n\n // Remove duplicate h1 if it matches frontmatter title\n if (file.frontmatter.title) {\n // Match first h1 heading in content (may have leading whitespace/newlines)\n const h1Match = content.match(/^\\s*#\\s+(.+)$/m)\n if (h1Match) {\n const h1Text = h1Match[1].trim()\n // If h1 matches title, remove it to avoid duplication\n if (h1Text === file.frontmatter.title) {\n content = content.replace(/^\\s*#\\s+.+\\n*/, '')\n }\n }\n }\n\n // Render markdown to HTML\n let html = md.render(content)\n \n // Apply syntax highlighting with shiki\n html = await highlightCodeBlocks(html)\n file.frontmatter.html = html\n\n // Extract headings for TOC\n const headings = extractHeadings(content)\n file.frontmatter.headings = headings\n\n } catch (error) {\n console.warn(`Failed to enhance content for ${file.path}:`, error)\n try {\n file.frontmatter.html = md.render(file.content)\n } catch (e) {\n console.error(`Failed to render markdown for ${file.path}:`, e)\n }\n }\n}\n\nasync function highlightCodeBlocks(html: string): Promise<string> {\n const hl = await getHighlighter()\n \n // Find all pending shiki code blocks and highlight them\n const codeBlockRegex = /<pre class=\"shiki-pending\" data-lang=\"([^\"]*)\"[^>]*><code>([^]*?)<\\/code><\\/pre>/g\n \n const matches = [...html.matchAll(codeBlockRegex)]\n \n for (const match of matches) {\n const [fullMatch, lang, escapedCode] = match\n // Unescape HTML entities\n const code = escapedCode\n .replace(/&lt;/g, '<')\n .replace(/&gt;/g, '>')\n .replace(/&amp;/g, '&')\n .replace(/&quot;/g, '\"')\n .replace(/&#39;/g, \"'\")\n \n try {\n const validLang = hl.getLoadedLanguages().includes(lang) ? lang : 'text'\n const highlighted = hl.codeToHtml(code, {\n lang: validLang,\n theme: 'github-dark'\n })\n html = html.replace(fullMatch, highlighted)\n } catch (e) {\n // Keep original if highlighting fails\n console.warn(`Failed to highlight ${lang}:`, e)\n }\n }\n \n return html\n}\n\nfunction extractHeadings(content: string) {\n const headings: Array<{ level: number; text: string; anchor: string }> = []\n const lines = content.split('\\n')\n\n for (const line of lines) {\n const match = line.match(/^(#{1,6})\\\\s+(.+)$/)\n if (match) {\n const level = match[1].length\n const text = match[2].trim()\n const anchor = text.toLowerCase()\n .replace(/[^\\\\w\\\\s-]/g, '')\n .replace(/\\\\s+/g, '-')\n .trim()\n\n headings.push({ level, text, anchor })\n }\n }\n\n return headings\n}\n\nasync function generateNavigation(directories: SkillDirectory[]): Promise<Navigation[]> {\n const navigation: Navigation[] = []\n\n for (const dir of directories) {\n const navItem: Navigation = {\n text: dir.skillFile?.title || formatDirName(dir.name),\n link: dir.skillFile ? getFileRoute(dir.skillFile) : undefined\n }\n\n if (dir.children.length > 0) {\n navItem.children = []\n \n for (const child of dir.children) {\n if ('content' in child) {\n // It's a file\n navItem.children.push({\n text: child.title || formatFileName(child.name),\n link: getFileRoute(child)\n })\n } else {\n // It's a subdirectory\n const subNav = await generateNavigation([child])\n navItem.children.push(...subNav)\n }\n }\n }\n\n navigation.push(navItem)\n }\n\n return navigation\n}\n\nfunction getFileRoute(file: SkillFile): string {\n // Import the utility function from client utils\n // For now, use inline implementation\n const filePath = file.path\n \n // Try common patterns\n const patterns = ['my-docs', 'docs', 'documentation', '.claude/skills']\n let relativePath = ''\n \n for (const pattern of patterns) {\n const index = filePath.indexOf(pattern)\n if (index !== -1) {\n relativePath = filePath.slice(index + pattern.length)\n break\n }\n }\n \n if (!relativePath) {\n // Fallback: use last 2 segments\n const segments = filePath.split('/').filter(Boolean)\n if (segments.length >= 2) {\n relativePath = '/' + segments.slice(-2).join('/')\n } else {\n return '/'\n }\n }\n \n const segments = relativePath.split('/').filter(Boolean)\n \n if (segments.length === 0) return '/'\n \n // Remove file extension\n const lastSegment = segments[segments.length - 1]\n if (lastSegment.endsWith('.md')) {\n segments[segments.length - 1] = lastSegment.slice(0, -3)\n }\n \n // SKILL.md and README.md should map to parent directory route\n const finalSegment = segments[segments.length - 1]\n if (finalSegment === 'SKILL' || finalSegment === 'README') {\n segments.pop()\n }\n \n return '/' + segments.join('/')\n}\n\nfunction formatDirName(name: string): string {\n return name.split('-').map(word => \n word.charAt(0).toUpperCase() + word.slice(1)\n ).join(' ')\n}\n\nfunction formatFileName(name: string): string {\n const baseName = name.replace('.md', '')\n return formatDirName(baseName)\n}\n\nexport { md as markdownRenderer }","#!/usr/bin/env node\n\nimport { Command } from 'commander'\nimport { devCommand } from './commands/dev.js'\nimport { buildCommand } from './commands/build.js'\nimport { previewCommand } from './commands/preview.js'\n\nconst program = new Command()\n\nprogram\n .name('docmk')\n .description('CLI tool for generating documentation from any directory')\n .version('1.0.0')\n .argument('[directory]', 'Source directory path (starts dev server)', './docs')\n .option('-p, --port <port>', 'Port to run dev server on', '3000')\n .action((directory, options) => {\n // Default action: start dev server\n devCommand({ dir: directory, port: options.port })\n })\n\nprogram\n .command('dev')\n .description('Start development server')\n .option('-p, --port <port>', 'Port to run dev server on', '3000')\n .option('-d, --dir <directory>', 'Source directory path', './docs')\n .action(devCommand)\n\nprogram\n .command('build')\n .description('Build static documentation site')\n .option('-d, --dir <directory>', 'Source directory path', './docs')\n .option('-o, --output <directory>', 'Output directory', 'dist')\n .action(buildCommand)\n\nprogram\n .command('preview')\n .description('Preview built documentation site')\n .option('-p, --port <port>', 'Port to run preview server on', '4173')\n .option('-o, --output <directory>', 'Built site directory', 'dist')\n .action(previewCommand)\n\nprogram.parse()","import path from 'path'\nimport { createViteDevServer } from '../../builder/vite-dev.js'\nimport { scanSkillsDirectory } from '../../scanner/index.js'\nimport { parseSkillsToConfig } from '../../parser/index.js'\n\ninterface DevOptions {\n port: string\n dir: string\n}\n\nexport async function devCommand(options: DevOptions) {\n console.log('🚀 Starting DocGen development server...')\n \n const sourceDir = path.resolve(process.cwd(), options.dir)\n const port = parseInt(options.port, 10)\n \n try {\n // Check if source directory exists\n console.log(`📁 Scanning source directory: ${sourceDir}`)\n const directories = await scanSkillsDirectory(sourceDir)\n \n console.log(`✅ Found ${directories.length} directories`)\n \n // Parse to config\n const config = await parseSkillsToConfig(directories, {\n title: 'Documentation',\n description: 'Documentation generated from source directory',\n baseUrl: '/',\n skillsDir: sourceDir,\n outputDir: 'dist'\n })\n \n // Start Vite dev server\n const server = await createViteDevServer({\n port,\n skillsDir: sourceDir,\n config\n })\n \n console.log(`🎉 Dev server running at http://localhost:${port}`)\n \n // Handle graceful shutdown\n process.on('SIGINT', async () => {\n console.log('\\\\n👋 Shutting down dev server...')\n await server.close()\n process.exit(0)\n })\n \n } catch (error) {\n console.error('❌ Failed to start dev server:', error)\n process.exit(1)\n }\n}","import { createServer, ViteDevServer } from 'vite'\nimport vue from '@vitejs/plugin-vue'\nimport path from 'path'\nimport { fileURLToPath } from 'url'\nimport { DocGenConfig } from '../types/index.js'\nimport { scanSkillsDirectory, watchSkillsDirectory } from '../scanner/index.js'\nimport { parseSkillsToConfig } from '../parser/index.js'\n\n// Get the package root directory (where src/client is located)\nconst __dirname = path.dirname(fileURLToPath(import.meta.url))\nconst packageRoot = path.resolve(__dirname, '../..')\n\ninterface DevServerOptions {\n port: number\n skillsDir: string\n config: DocGenConfig\n}\n\nexport async function createViteDevServer(options: DevServerOptions): Promise<ViteDevServer> {\n let currentConfig = options.config\n\n const server = await createServer({\n root: path.resolve(packageRoot, 'src/client'),\n server: {\n port: options.port,\n host: 'localhost'\n },\n publicDir: false, // Disable public dir in dev mode\n plugins: [\n vue(),\n // Custom plugin to inject config and handle API routes\n {\n name: 'docgen-dev',\n configureServer(server) {\n // API endpoint for configuration\n server.middlewares.use('/api/config', (req, res, next) => {\n if (req.method === 'GET') {\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify(currentConfig))\n } else {\n next()\n }\n })\n\n // SPA fallback - return index.html for all non-API routes\n return () => {\n server.middlewares.use((req, res, next) => {\n // Skip API routes and vite's own routes\n if (req.url?.startsWith('/api/') || req.url?.startsWith('/@') || req.url?.includes('.html')) {\n return next()\n }\n // For all other routes, serve index.html for SPA routing\n if (req.url && !req.url.includes('.')) {\n req.url = '/index.html'\n }\n next()\n })\n }\n },\n transformIndexHtml: {\n order: 'pre',\n handler(html) {\n // Inject lightweight config placeholder\n // Full config will be loaded via API to avoid HTML parsing issues\n const configScript = `\n <script>\n // Config will be loaded from /api/config\n globalThis.__DOCGEN_CONFIG__ = null;\n </script>\n `\n return html.replace('<head>', `<head>${configScript}`)\n }\n }\n }\n ],\n resolve: {\n alias: {\n '@': path.resolve(packageRoot, 'src/client')\n }\n },\n define: {\n __DOCGEN_CONFIG__: JSON.stringify(currentConfig)\n }\n })\n\n // Watch skills directory for changes\n const watcher = await watchSkillsDirectory(options.skillsDir, async (directories) => {\n console.log('📝 Skills directory changed, updating configuration...')\n \n try {\n currentConfig = await parseSkillsToConfig(directories, currentConfig.siteConfig)\n \n // Notify all connected clients to reload\n server.ws.send({\n type: 'full-reload'\n })\n \n console.log('✅ Configuration updated')\n } catch (error) {\n console.error('❌ Failed to update configuration:', error)\n \n // Send error to clients\n server.ws.send({\n type: 'error',\n err: {\n message: `Failed to update configuration: ${error.message}`,\n stack: error.stack\n }\n })\n }\n })\n\n // Start the server\n await server.listen()\n\n // Extend server with cleanup method\n const originalClose = server.close.bind(server)\n server.close = async () => {\n await watcher?.close()\n return originalClose()\n }\n\n return server\n}\n\nexport async function createProductionBuild() {\n // This will be implemented in the builder\n}","import path from 'path'\nimport { buildSite } from '../../builder/index.js'\nimport { scanSkillsDirectory } from '../../scanner/index.js'\nimport { parseSkillsToConfig } from '../../parser/index.js'\n\ninterface BuildOptions {\n dir: string\n output: string\n}\n\nexport async function buildCommand(options: BuildOptions) {\n console.log('🏗️ Building DocGen documentation site...')\n \n const sourceDir = path.resolve(process.cwd(), options.dir)\n const outputDir = path.resolve(process.cwd(), options.output)\n \n try {\n // Scan source directory\n console.log(`📁 Scanning source directory: ${sourceDir}`)\n const directories = await scanSkillsDirectory(sourceDir)\n \n console.log(`✅ Found ${directories.length} directories`)\n \n // Parse to config\n const config = await parseSkillsToConfig(directories, {\n title: 'Documentation',\n description: 'Documentation generated from source directory',\n baseUrl: '/',\n skillsDir: sourceDir,\n outputDir\n })\n \n // Build site\n console.log(`📦 Building to: ${outputDir}`)\n await buildSite({\n input: sourceDir,\n output: outputDir,\n mode: 'production'\n }, config)\n \n console.log('✅ Build completed successfully!')\n console.log(`📂 Built files are in: ${outputDir}`)\n \n } catch (error) {\n console.error('❌ Build failed:', error)\n process.exit(1)\n }\n}","import { build } from 'vite'\nimport vue from '@vitejs/plugin-vue'\nimport path from 'path'\nimport { fileURLToPath } from 'url'\nimport fs from 'fs/promises'\nimport { DocGenConfig, BuildOptions } from '../types/index.js'\n\n// Get the package root directory\nconst __dirname = path.dirname(fileURLToPath(import.meta.url))\nconst packageRoot = path.resolve(__dirname, '../..')\n\nexport async function buildSite(options: BuildOptions, config: DocGenConfig) {\n console.log('🏗️ Building documentation site...')\n\n // Ensure output directory exists\n await fs.mkdir(options.output, { recursive: true })\n\n // Write config to a temporary file for the build process\n const configPath = path.join(process.cwd(), 'temp-config.json')\n await fs.writeFile(configPath, JSON.stringify(config, null, 2))\n\n try {\n // Build the client application\n await build({\n root: path.resolve(packageRoot, 'src/client'),\n base: config.siteConfig.baseUrl,\n build: {\n outDir: options.output,\n emptyOutDir: true,\n rollupOptions: {\n input: {\n main: path.resolve(packageRoot, 'src/client/index.html')\n }\n }\n },\n plugins: [\n vue(),\n // Plugin to inject config during build\n {\n name: 'docgen-build',\n transformIndexHtml: {\n order: 'pre',\n handler(html) {\n // Encode config as base64 with proper UTF-8 handling\n const configJson = JSON.stringify(config)\n // Use encodeURIComponent to handle UTF-8 properly before base64\n const utf8Encoded = unescape(encodeURIComponent(configJson))\n const configBase64 = Buffer.from(utf8Encoded, 'binary').toString('base64')\n // Decode: atob -> decodeURIComponent(escape()) to restore UTF-8\n const configScript = `<script>globalThis.__DOCGEN_CONFIG__=JSON.parse(decodeURIComponent(escape(atob(\"${configBase64}\"))));</script>`\n return html.replace('</head>', `${configScript}\\n</head>`)\n }\n }\n }\n ],\n resolve: {\n alias: {\n '@': path.resolve(packageRoot, 'src/client')\n }\n },\n define: {\n __DOCGEN_CONFIG__: JSON.stringify(config)\n }\n })\n \n // Generate additional static files\n await generateSitemap(options.output, config)\n await generateRobotsTxt(options.output, config)\n await copyAssets(options.output)\n \n console.log('✅ Build completed successfully!')\n \n } finally {\n // Clean up temporary config file\n try {\n await fs.unlink(configPath)\n } catch {\n // Ignore if file doesn't exist\n }\n }\n}\n\nasync function generateSitemap(outputDir: string, config: DocGenConfig) {\n console.log('📄 Generating sitemap...')\n \n const baseUrl = config.siteConfig.baseUrl.replace(/\\/$/, '')\n const urls: string[] = []\n \n // Add home page\n urls.push(`${baseUrl}/`)\n \n // Add all skill pages\n for (const file of config.files) {\n const route = getFileRoute(file.path, config.siteConfig.skillsDir)\n if (route !== '/') {\n urls.push(`${baseUrl}${route}`)\n }\n }\n \n const sitemap = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n${urls.map(url => ` <url>\n <loc>${url}</loc>\n <lastmod>${new Date().toISOString().split('T')[0]}</lastmod>\n <changefreq>weekly</changefreq>\n <priority>0.8</priority>\n </url>`).join('\\\\n')}\n</urlset>`\n \n await fs.writeFile(path.join(outputDir, 'sitemap.xml'), sitemap)\n}\n\nasync function generateRobotsTxt(outputDir: string, config: DocGenConfig) {\n console.log('🤖 Generating robots.txt...')\n \n const baseUrl = config.siteConfig.baseUrl.replace(/\\/$/, '')\n const robotsTxt = `User-agent: *\nAllow: /\n\nSitemap: ${baseUrl}/sitemap.xml`\n \n await fs.writeFile(path.join(outputDir, 'robots.txt'), robotsTxt)\n}\n\nasync function copyAssets(outputDir: string) {\n console.log('📁 Copying static assets...')\n \n // Create a simple favicon if it doesn't exist\n const faviconPath = path.join(outputDir, 'favicon.ico')\n \n try {\n await fs.access(faviconPath)\n } catch {\n // Create a simple SVG favicon\n const faviconSvg = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\">\n <rect width=\"32\" height=\"32\" rx=\"4\" fill=\"#3182ce\"/>\n <text x=\"16\" y=\"22\" text-anchor=\"middle\" fill=\"white\" font-family=\"system-ui\" font-size=\"18\" font-weight=\"bold\">D</text>\n</svg>`\n \n await fs.writeFile(path.join(outputDir, 'favicon.svg'), faviconSvg)\n }\n}\n\nfunction getFileRoute(filePath: string, baseDir: string): string {\n // Normalize paths for comparison\n const normalizedFilePath = path.normalize(filePath)\n const normalizedBaseDir = path.normalize(baseDir)\n \n // Check if file is within base directory\n if (!normalizedFilePath.startsWith(normalizedBaseDir)) {\n return '/'\n }\n \n // Get relative path from base directory\n const relativePath = normalizedFilePath.slice(normalizedBaseDir.length)\n const segments = relativePath.split(path.sep).filter(Boolean)\n \n if (segments.length === 0) return '/'\n \n const lastSegment = segments[segments.length - 1]\n if (lastSegment.endsWith('.md')) {\n segments[segments.length - 1] = lastSegment.slice(0, -3)\n }\n \n // SKILL.md and README.md should map to parent directory route\n const finalSegment = segments[segments.length - 1]\n if (finalSegment === 'SKILL' || finalSegment === 'README') {\n segments.pop()\n }\n\n return '/' + segments.join('/')\n}\n\nexport async function buildForProduction(sourceDir: string, outputDir: string): Promise<DocGenConfig> {\n const { scanSkillsDirectory } = await import('../scanner/index.js')\n const { parseSkillsToConfig } = await import('../parser/index.js')\n \n const directories = await scanSkillsDirectory(sourceDir)\n const config = await parseSkillsToConfig(directories, {\n title: 'Documentation',\n description: 'Documentation generated from source directory',\n baseUrl: '/',\n skillsDir: sourceDir,\n outputDir\n })\n \n await buildSite({\n input: sourceDir,\n output: outputDir,\n mode: 'production'\n }, config)\n \n return config\n}","import path from 'path'\nimport fs from 'fs/promises'\nimport sirv from 'sirv'\nimport { createServer } from 'http'\n\ninterface PreviewOptions {\n port: string\n output: string\n}\n\nexport async function previewCommand(options: PreviewOptions) {\n console.log('👀 Starting DocGen preview server...')\n \n const outputDir = path.resolve(process.cwd(), options.output)\n const port = parseInt(options.port, 10)\n \n try {\n // Check if build directory exists\n try {\n await fs.access(outputDir)\n } catch {\n console.error(`❌ Build directory not found: ${outputDir}`)\n console.log('💡 Run \"docgen build\" first to generate the static site')\n process.exit(1)\n }\n \n // Create static file server\n const serve = sirv(outputDir, {\n single: true, // SPA mode\n dev: false,\n setHeaders: (res, pathname) => {\n if (pathname.endsWith('.html') || pathname === '/') {\n res.setHeader('Content-Type', 'text/html; charset=utf-8')\n }\n }\n })\n \n const server = createServer(serve)\n \n server.listen(port, () => {\n console.log(`🎉 Preview server running at http://localhost:${port}`)\n console.log(`📂 Serving files from: ${outputDir}`)\n })\n \n // Handle graceful shutdown\n process.on('SIGINT', () => {\n console.log('\\\\n👋 Shutting down preview server...')\n server.close(() => {\n process.exit(0)\n })\n })\n \n } catch (error) {\n console.error('❌ Failed to start preview server:', error)\n process.exit(1)\n }\n}"],"mappings":"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","names":["segments","path","path","server","path","path","vue","path","fileURLToPath","fs","__dirname","packageRoot","getFileRoute","path","path","fs","createServer"]}
1
+ {"version":3,"sources":["../src/scanner/index.ts","../src/parser/index.ts","../src/cli/index.ts","../src/cli/commands/dev.ts","../src/builder/vite-dev.ts","../src/cli/commands/build.ts","../src/builder/index.ts","../src/cli/commands/preview.ts"],"sourcesContent":["import fs from 'fs/promises'\nimport path from 'path'\nimport { SkillDirectory, SkillFile } from '../types/index.js'\n\nexport async function scanSkillsDirectory(sourceDir: string): Promise<SkillDirectory[]> {\n try {\n await fs.access(sourceDir)\n } catch {\n throw new Error(`Source directory not found: ${sourceDir}`)\n }\n\n const entries = await fs.readdir(sourceDir, { withFileTypes: true })\n const directories: SkillDirectory[] = []\n\n for (const entry of entries) {\n if (entry.isDirectory()) {\n const dirPath = path.join(sourceDir, entry.name)\n const skillDirectory = await scanDirectory(dirPath, entry.name)\n directories.push(skillDirectory)\n }\n }\n\n return directories\n}\n\nasync function scanDirectory(dirPath: string, name: string): Promise<SkillDirectory> {\n const entries = await fs.readdir(dirPath, { withFileTypes: true })\n const children: (SkillDirectory | SkillFile)[] = []\n let skillFile: SkillFile | undefined\n\n for (const entry of entries) {\n const entryPath = path.join(dirPath, entry.name)\n\n if (entry.isDirectory()) {\n const subDir = await scanDirectory(entryPath, entry.name)\n children.push(subDir)\n } else if (entry.isFile() && entry.name.endsWith('.md')) {\n const file = await parseMarkdownFile(entryPath, entry.name)\n \n if (entry.name === 'SKILL.md') {\n skillFile = file\n } else {\n children.push(file)\n }\n }\n }\n\n return {\n path: dirPath,\n name,\n children,\n skillFile\n }\n}\n\nasync function parseMarkdownFile(filePath: string, fileName: string): Promise<SkillFile> {\n const content = await fs.readFile(filePath, 'utf-8')\n const stats = await fs.stat(filePath)\n\n // Basic frontmatter extraction\n const frontmatterMatch = content.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n/)\n const frontmatter: Record<string, any> = {}\n let markdownContent = content\n\n if (frontmatterMatch) {\n // Remove frontmatter from content\n markdownContent = content.slice(frontmatterMatch[0].length)\n \n // Parse frontmatter key-value pairs\n const fmLines = frontmatterMatch[1].split(/\\r?\\n/)\n for (const line of fmLines) {\n const colonIndex = line.indexOf(':')\n if (colonIndex > 0) {\n const key = line.slice(0, colonIndex).trim()\n const value = line.slice(colonIndex + 1).trim().replace(/^[\"']|[\"']$/g, '')\n if (key && value) {\n frontmatter[key] = value\n }\n }\n }\n }\n\n return {\n path: filePath,\n name: fileName,\n title: frontmatter.title || fileName.replace('.md', ''),\n description: frontmatter.description,\n content: markdownContent,\n frontmatter,\n lastModified: stats.mtime.getTime()\n }\n}\n\nexport async function watchSkillsDirectory(\n sourceDir: string, \n callback: (directories: SkillDirectory[]) => void\n) {\n const chokidar = await import('chokidar')\n \n const watcher = chokidar.watch(sourceDir, {\n ignored: /node_modules/,\n persistent: true,\n ignoreInitial: true\n })\n\n let debounceTimer: NodeJS.Timeout\n\n const handleChange = () => {\n clearTimeout(debounceTimer)\n debounceTimer = setTimeout(async () => {\n try {\n const directories = await scanSkillsDirectory(sourceDir)\n callback(directories)\n } catch (error) {\n console.error('Error rescanning source directory:', error)\n }\n }, 300)\n }\n\n watcher.on('add', handleChange)\n watcher.on('change', handleChange)\n watcher.on('unlink', handleChange)\n watcher.on('addDir', handleChange)\n watcher.on('unlinkDir', handleChange)\n\n return watcher\n}","import matter from 'gray-matter'\nimport MarkdownIt from 'markdown-it'\nimport { createHighlighter, Highlighter } from 'shiki'\nimport { SkillDirectory, SkillFile, SiteConfig, DocGenConfig, Navigation } from '../types/index.js'\n\nlet highlighter: Highlighter | null = null\n\nasync function getHighlighter() {\n if (!highlighter) {\n highlighter = await createHighlighter({\n themes: ['github-dark', 'github-light'],\n langs: ['javascript', 'typescript', 'bash', 'shell', 'json', 'html', 'css', 'vue', 'jsx', 'tsx', 'python', 'markdown', 'yaml', 'sql', 'go', 'rust', 'java', 'c', 'cpp']\n })\n }\n return highlighter\n}\n\nconst md = new MarkdownIt({\n html: true,\n linkify: true,\n typographer: true,\n highlight: function (str: string, lang: string) {\n // Synchronous fallback - actual highlighting done in enhanceFileContent\n return `<pre class=\"shiki-pending\" data-lang=\"${lang || 'text'}\"><code>${md.utils.escapeHtml(str)}</code></pre>`\n }\n})\n\nexport async function parseSkillsToConfig(\n directories: SkillDirectory[],\n siteConfig: SiteConfig\n): Promise<DocGenConfig> {\n const files: SkillFile[] = []\n const navigation = await generateNavigation(directories)\n\n // Collect all files for search indexing\n collectAllFiles(directories, files)\n\n // Enhance files with parsed content\n for (const file of files) {\n await enhanceFileContent(file)\n }\n\n return {\n siteConfig,\n navigation,\n files,\n directories\n }\n}\n\nfunction collectAllFiles(items: (SkillDirectory | SkillFile)[], files: SkillFile[]) {\n for (const item of items) {\n if ('content' in item) {\n // It's a SkillFile\n files.push(item)\n } else {\n // It's a SkillDirectory\n if (item.skillFile) {\n files.push(item.skillFile)\n }\n collectAllFiles(item.children, files)\n }\n }\n}\n\nasync function enhanceFileContent(file: SkillFile) {\n try {\n let content = file.content\n\n // Update title and description from frontmatter if available\n file.title = file.frontmatter.title || file.title\n file.description = file.frontmatter.description || file.description\n\n // Remove duplicate h1 if it matches frontmatter title\n if (file.frontmatter.title) {\n // Match first h1 heading in content (may have leading whitespace/newlines)\n const h1Match = content.match(/^\\s*#\\s+(.+)$/m)\n if (h1Match) {\n const h1Text = h1Match[1].trim()\n // If h1 matches title, remove it to avoid duplication\n if (h1Text === file.frontmatter.title) {\n content = content.replace(/^\\s*#\\s+.+\\n*/, '')\n }\n }\n }\n\n // Render markdown to HTML\n let html = md.render(content)\n \n // Apply syntax highlighting with shiki\n html = await highlightCodeBlocks(html)\n file.frontmatter.html = html\n\n // Extract headings for TOC\n const headings = extractHeadings(content)\n file.frontmatter.headings = headings\n\n } catch (error) {\n console.warn(`Failed to enhance content for ${file.path}:`, error)\n try {\n file.frontmatter.html = md.render(file.content)\n } catch (e) {\n console.error(`Failed to render markdown for ${file.path}:`, e)\n }\n }\n}\n\nasync function highlightCodeBlocks(html: string): Promise<string> {\n const hl = await getHighlighter()\n \n // Find all pending shiki code blocks and highlight them\n const codeBlockRegex = /<pre class=\"shiki-pending\" data-lang=\"([^\"]*)\"[^>]*><code>([^]*?)<\\/code><\\/pre>/g\n \n const matches = [...html.matchAll(codeBlockRegex)]\n \n for (const match of matches) {\n const [fullMatch, lang, escapedCode] = match\n // Unescape HTML entities\n const code = escapedCode\n .replace(/&lt;/g, '<')\n .replace(/&gt;/g, '>')\n .replace(/&amp;/g, '&')\n .replace(/&quot;/g, '\"')\n .replace(/&#39;/g, \"'\")\n \n try {\n const validLang = hl.getLoadedLanguages().includes(lang) ? lang : 'text'\n const highlighted = hl.codeToHtml(code, {\n lang: validLang,\n theme: 'github-dark'\n })\n html = html.replace(fullMatch, highlighted)\n } catch (e) {\n // Keep original if highlighting fails\n console.warn(`Failed to highlight ${lang}:`, e)\n }\n }\n \n return html\n}\n\nfunction extractHeadings(content: string) {\n const headings: Array<{ level: number; text: string; anchor: string }> = []\n const lines = content.split('\\n')\n\n for (const line of lines) {\n const match = line.match(/^(#{1,6})\\\\s+(.+)$/)\n if (match) {\n const level = match[1].length\n const text = match[2].trim()\n const anchor = text.toLowerCase()\n .replace(/[^\\\\w\\\\s-]/g, '')\n .replace(/\\\\s+/g, '-')\n .trim()\n\n headings.push({ level, text, anchor })\n }\n }\n\n return headings\n}\n\nasync function generateNavigation(directories: SkillDirectory[]): Promise<Navigation[]> {\n const navigation: Navigation[] = []\n\n for (const dir of directories) {\n const navItem: Navigation = {\n text: dir.skillFile?.title || formatDirName(dir.name),\n link: dir.skillFile ? getFileRoute(dir.skillFile) : undefined\n }\n\n if (dir.children.length > 0) {\n navItem.children = []\n \n for (const child of dir.children) {\n if ('content' in child) {\n // It's a file\n navItem.children.push({\n text: child.title || formatFileName(child.name),\n link: getFileRoute(child)\n })\n } else {\n // It's a subdirectory\n const subNav = await generateNavigation([child])\n navItem.children.push(...subNav)\n }\n }\n }\n\n navigation.push(navItem)\n }\n\n return navigation\n}\n\nfunction getFileRoute(file: SkillFile): string {\n // Import the utility function from client utils\n // For now, use inline implementation\n const filePath = file.path\n \n // Try common patterns\n const patterns = ['my-docs', 'docs', 'documentation', '.claude/skills']\n let relativePath = ''\n \n for (const pattern of patterns) {\n const index = filePath.indexOf(pattern)\n if (index !== -1) {\n relativePath = filePath.slice(index + pattern.length)\n break\n }\n }\n \n if (!relativePath) {\n // Fallback: use last 2 segments\n const segments = filePath.split('/').filter(Boolean)\n if (segments.length >= 2) {\n relativePath = '/' + segments.slice(-2).join('/')\n } else {\n return '/'\n }\n }\n \n const segments = relativePath.split('/').filter(Boolean)\n \n if (segments.length === 0) return '/'\n \n // Remove file extension\n const lastSegment = segments[segments.length - 1]\n if (lastSegment.endsWith('.md')) {\n segments[segments.length - 1] = lastSegment.slice(0, -3)\n }\n \n // SKILL.md and README.md should map to parent directory route\n const finalSegment = segments[segments.length - 1]\n if (finalSegment === 'SKILL' || finalSegment === 'README') {\n segments.pop()\n }\n \n return '/' + segments.join('/')\n}\n\nfunction formatDirName(name: string): string {\n return name.split('-').map(word => \n word.charAt(0).toUpperCase() + word.slice(1)\n ).join(' ')\n}\n\nfunction formatFileName(name: string): string {\n const baseName = name.replace('.md', '')\n return formatDirName(baseName)\n}\n\nexport { md as markdownRenderer }","#!/usr/bin/env node\n\nimport { Command } from 'commander'\nimport { devCommand } from './commands/dev.js'\nimport { buildCommand } from './commands/build.js'\nimport { previewCommand } from './commands/preview.js'\n\nconst program = new Command()\n\nprogram\n .name('docmk')\n .description('CLI tool for generating documentation from any directory')\n .version('1.0.0')\n .argument('[directory]', 'Source directory path (starts dev server)', './docs')\n .option('-p, --port <port>', 'Port to run dev server on', '3000')\n .action((directory, options) => {\n // Default action: start dev server\n devCommand({ dir: directory, port: options.port })\n })\n\nprogram\n .command('dev')\n .description('Start development server')\n .option('-p, --port <port>', 'Port to run dev server on', '3000')\n .option('-d, --dir <directory>', 'Source directory path', './docs')\n .action(devCommand)\n\nprogram\n .command('build')\n .description('Build static documentation site')\n .option('-d, --dir <directory>', 'Source directory path', './docs')\n .option('-o, --output <directory>', 'Output directory', 'dist')\n .action(buildCommand)\n\nprogram\n .command('preview')\n .description('Preview built documentation site')\n .option('-p, --port <port>', 'Port to run preview server on', '4173')\n .option('-o, --output <directory>', 'Built site directory', 'dist')\n .action(previewCommand)\n\nprogram.parse()","import path from 'path'\nimport { createViteDevServer } from '../../builder/vite-dev.js'\nimport { scanSkillsDirectory } from '../../scanner/index.js'\nimport { parseSkillsToConfig } from '../../parser/index.js'\n\ninterface DevOptions {\n port: string\n dir: string\n}\n\nexport async function devCommand(options: DevOptions) {\n console.log('🚀 Starting DocGen development server...')\n \n const sourceDir = path.resolve(process.cwd(), options.dir)\n const port = parseInt(options.port, 10)\n \n try {\n // Check if source directory exists\n console.log(`📁 Scanning source directory: ${sourceDir}`)\n const directories = await scanSkillsDirectory(sourceDir)\n \n console.log(`✅ Found ${directories.length} directories`)\n \n // Parse to config\n const config = await parseSkillsToConfig(directories, {\n title: 'Documentation',\n description: 'Documentation generated from source directory',\n baseUrl: '/',\n skillsDir: sourceDir,\n outputDir: 'dist'\n })\n \n // Start Vite dev server\n const { server, actualPort } = await createViteDevServer({\n port,\n skillsDir: sourceDir,\n config\n })\n\n console.log(`🎉 Dev server running at http://localhost:${actualPort}`)\n \n // Handle graceful shutdown\n process.on('SIGINT', async () => {\n console.log('\\\\n👋 Shutting down dev server...')\n await server.close()\n process.exit(0)\n })\n \n } catch (error) {\n console.error('❌ Failed to start dev server:', error)\n process.exit(1)\n }\n}","import { createServer, ViteDevServer } from 'vite'\nimport vue from '@vitejs/plugin-vue'\nimport path from 'path'\nimport { fileURLToPath } from 'url'\nimport { DocGenConfig } from '../types/index.js'\nimport { scanSkillsDirectory, watchSkillsDirectory } from '../scanner/index.js'\nimport { parseSkillsToConfig } from '../parser/index.js'\n\n// Get the package root directory (where src/client is located)\nconst __dirname = path.dirname(fileURLToPath(import.meta.url))\nconst packageRoot = path.resolve(__dirname, '../..')\n\ninterface DevServerOptions {\n port: number\n skillsDir: string\n config: DocGenConfig\n}\n\nexport async function createViteDevServer(options: DevServerOptions): Promise<ViteDevServer> {\n let currentConfig = options.config\n\n const server = await createServer({\n root: path.resolve(packageRoot, 'src/client'),\n server: {\n port: options.port,\n host: 'localhost'\n },\n publicDir: false, // Disable public dir in dev mode\n plugins: [\n vue(),\n // Custom plugin to inject config and handle API routes\n {\n name: 'docgen-dev',\n configureServer(server) {\n // API endpoint for configuration\n server.middlewares.use('/api/config', (req, res, next) => {\n if (req.method === 'GET') {\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify(currentConfig))\n } else {\n next()\n }\n })\n\n // SPA fallback - return index.html for all non-API routes\n return () => {\n server.middlewares.use((req, res, next) => {\n // Skip API routes and vite's own routes\n if (req.url?.startsWith('/api/') || req.url?.startsWith('/@') || req.url?.includes('.html')) {\n return next()\n }\n // For all other routes, serve index.html for SPA routing\n if (req.url && !req.url.includes('.')) {\n req.url = '/index.html'\n }\n next()\n })\n }\n },\n transformIndexHtml: {\n order: 'pre',\n handler(html) {\n // Inject lightweight config placeholder\n // Full config will be loaded via API to avoid HTML parsing issues\n const configScript = `\n <script>\n // Config will be loaded from /api/config\n globalThis.__DOCGEN_CONFIG__ = null;\n </script>\n `\n return html.replace('<head>', `<head>${configScript}`)\n }\n }\n }\n ],\n resolve: {\n alias: {\n '@': path.resolve(packageRoot, 'src/client')\n }\n },\n define: {\n __DOCGEN_CONFIG__: JSON.stringify(currentConfig)\n }\n })\n\n // Watch skills directory for changes\n const watcher = await watchSkillsDirectory(options.skillsDir, async (directories) => {\n console.log('📝 Skills directory changed, updating configuration...')\n \n try {\n currentConfig = await parseSkillsToConfig(directories, currentConfig.siteConfig)\n \n // Notify all connected clients to reload\n server.ws.send({\n type: 'full-reload'\n })\n \n console.log('✅ Configuration updated')\n } catch (error) {\n console.error('❌ Failed to update configuration:', error)\n \n // Send error to clients\n server.ws.send({\n type: 'error',\n err: {\n message: `Failed to update configuration: ${error.message}`,\n stack: error.stack\n }\n })\n }\n })\n\n // Start the server\n await server.listen()\n\n // Get actual port (in case requested port was taken)\n const actualPort = server.config.server.port\n\n // Extend server with cleanup method\n const originalClose = server.close.bind(server)\n server.close = async () => {\n await watcher?.close()\n return originalClose()\n }\n\n return { server, actualPort }\n}\n\nexport async function createProductionBuild() {\n // This will be implemented in the builder\n}","import path from 'path'\nimport { buildSite } from '../../builder/index.js'\nimport { scanSkillsDirectory } from '../../scanner/index.js'\nimport { parseSkillsToConfig } from '../../parser/index.js'\n\ninterface BuildOptions {\n dir: string\n output: string\n}\n\nexport async function buildCommand(options: BuildOptions) {\n console.log('🏗️ Building DocGen documentation site...')\n \n const sourceDir = path.resolve(process.cwd(), options.dir)\n const outputDir = path.resolve(process.cwd(), options.output)\n \n try {\n // Scan source directory\n console.log(`📁 Scanning source directory: ${sourceDir}`)\n const directories = await scanSkillsDirectory(sourceDir)\n \n console.log(`✅ Found ${directories.length} directories`)\n \n // Parse to config\n const config = await parseSkillsToConfig(directories, {\n title: 'Documentation',\n description: 'Documentation generated from source directory',\n baseUrl: '/',\n skillsDir: sourceDir,\n outputDir\n })\n \n // Build site\n console.log(`📦 Building to: ${outputDir}`)\n await buildSite({\n input: sourceDir,\n output: outputDir,\n mode: 'production'\n }, config)\n \n console.log('✅ Build completed successfully!')\n console.log(`📂 Built files are in: ${outputDir}`)\n \n } catch (error) {\n console.error('❌ Build failed:', error)\n process.exit(1)\n }\n}","import { build } from 'vite'\nimport vue from '@vitejs/plugin-vue'\nimport path from 'path'\nimport { fileURLToPath } from 'url'\nimport fs from 'fs/promises'\nimport { DocGenConfig, BuildOptions } from '../types/index.js'\n\n// Get the package root directory\nconst __dirname = path.dirname(fileURLToPath(import.meta.url))\nconst packageRoot = path.resolve(__dirname, '../..')\n\nexport async function buildSite(options: BuildOptions, config: DocGenConfig) {\n console.log('🏗️ Building documentation site...')\n\n // Ensure output directory exists\n await fs.mkdir(options.output, { recursive: true })\n\n // Write config to a temporary file for the build process\n const configPath = path.join(process.cwd(), 'temp-config.json')\n await fs.writeFile(configPath, JSON.stringify(config, null, 2))\n\n try {\n // Build the client application\n await build({\n root: path.resolve(packageRoot, 'src/client'),\n base: config.siteConfig.baseUrl,\n build: {\n outDir: options.output,\n emptyOutDir: true,\n rollupOptions: {\n input: {\n main: path.resolve(packageRoot, 'src/client/index.html')\n }\n }\n },\n plugins: [\n vue(),\n // Plugin to inject config during build\n {\n name: 'docgen-build',\n transformIndexHtml: {\n order: 'pre',\n handler(html) {\n // Encode config as base64 with proper UTF-8 handling\n const configJson = JSON.stringify(config)\n // Use encodeURIComponent to handle UTF-8 properly before base64\n const utf8Encoded = unescape(encodeURIComponent(configJson))\n const configBase64 = Buffer.from(utf8Encoded, 'binary').toString('base64')\n // Decode: atob -> decodeURIComponent(escape()) to restore UTF-8\n const configScript = `<script>globalThis.__DOCGEN_CONFIG__=JSON.parse(decodeURIComponent(escape(atob(\"${configBase64}\"))));</script>`\n return html.replace('</head>', `${configScript}\\n</head>`)\n }\n }\n }\n ],\n resolve: {\n alias: {\n '@': path.resolve(packageRoot, 'src/client')\n }\n },\n define: {\n __DOCGEN_CONFIG__: JSON.stringify(config)\n }\n })\n \n // Generate additional static files\n await generateSitemap(options.output, config)\n await generateRobotsTxt(options.output, config)\n await copyAssets(options.output)\n \n console.log('✅ Build completed successfully!')\n \n } finally {\n // Clean up temporary config file\n try {\n await fs.unlink(configPath)\n } catch {\n // Ignore if file doesn't exist\n }\n }\n}\n\nasync function generateSitemap(outputDir: string, config: DocGenConfig) {\n console.log('📄 Generating sitemap...')\n \n const baseUrl = config.siteConfig.baseUrl.replace(/\\/$/, '')\n const urls: string[] = []\n \n // Add home page\n urls.push(`${baseUrl}/`)\n \n // Add all skill pages\n for (const file of config.files) {\n const route = getFileRoute(file.path, config.siteConfig.skillsDir)\n if (route !== '/') {\n urls.push(`${baseUrl}${route}`)\n }\n }\n \n const sitemap = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n${urls.map(url => ` <url>\n <loc>${url}</loc>\n <lastmod>${new Date().toISOString().split('T')[0]}</lastmod>\n <changefreq>weekly</changefreq>\n <priority>0.8</priority>\n </url>`).join('\\\\n')}\n</urlset>`\n \n await fs.writeFile(path.join(outputDir, 'sitemap.xml'), sitemap)\n}\n\nasync function generateRobotsTxt(outputDir: string, config: DocGenConfig) {\n console.log('🤖 Generating robots.txt...')\n \n const baseUrl = config.siteConfig.baseUrl.replace(/\\/$/, '')\n const robotsTxt = `User-agent: *\nAllow: /\n\nSitemap: ${baseUrl}/sitemap.xml`\n \n await fs.writeFile(path.join(outputDir, 'robots.txt'), robotsTxt)\n}\n\nasync function copyAssets(outputDir: string) {\n console.log('📁 Copying static assets...')\n \n // Create a simple favicon if it doesn't exist\n const faviconPath = path.join(outputDir, 'favicon.ico')\n \n try {\n await fs.access(faviconPath)\n } catch {\n // Create a simple SVG favicon\n const faviconSvg = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 32 32\">\n <rect width=\"32\" height=\"32\" rx=\"4\" fill=\"#3182ce\"/>\n <text x=\"16\" y=\"22\" text-anchor=\"middle\" fill=\"white\" font-family=\"system-ui\" font-size=\"18\" font-weight=\"bold\">D</text>\n</svg>`\n \n await fs.writeFile(path.join(outputDir, 'favicon.svg'), faviconSvg)\n }\n}\n\nfunction getFileRoute(filePath: string, baseDir: string): string {\n // Normalize paths for comparison\n const normalizedFilePath = path.normalize(filePath)\n const normalizedBaseDir = path.normalize(baseDir)\n \n // Check if file is within base directory\n if (!normalizedFilePath.startsWith(normalizedBaseDir)) {\n return '/'\n }\n \n // Get relative path from base directory\n const relativePath = normalizedFilePath.slice(normalizedBaseDir.length)\n const segments = relativePath.split(path.sep).filter(Boolean)\n \n if (segments.length === 0) return '/'\n \n const lastSegment = segments[segments.length - 1]\n if (lastSegment.endsWith('.md')) {\n segments[segments.length - 1] = lastSegment.slice(0, -3)\n }\n \n // SKILL.md and README.md should map to parent directory route\n const finalSegment = segments[segments.length - 1]\n if (finalSegment === 'SKILL' || finalSegment === 'README') {\n segments.pop()\n }\n\n return '/' + segments.join('/')\n}\n\nexport async function buildForProduction(sourceDir: string, outputDir: string): Promise<DocGenConfig> {\n const { scanSkillsDirectory } = await import('../scanner/index.js')\n const { parseSkillsToConfig } = await import('../parser/index.js')\n \n const directories = await scanSkillsDirectory(sourceDir)\n const config = await parseSkillsToConfig(directories, {\n title: 'Documentation',\n description: 'Documentation generated from source directory',\n baseUrl: '/',\n skillsDir: sourceDir,\n outputDir\n })\n \n await buildSite({\n input: sourceDir,\n output: outputDir,\n mode: 'production'\n }, config)\n \n return config\n}","import path from 'path'\nimport fs from 'fs/promises'\nimport sirv from 'sirv'\nimport { createServer } from 'http'\n\ninterface PreviewOptions {\n port: string\n output: string\n}\n\nexport async function previewCommand(options: PreviewOptions) {\n console.log('👀 Starting DocGen preview server...')\n \n const outputDir = path.resolve(process.cwd(), options.output)\n const port = parseInt(options.port, 10)\n \n try {\n // Check if build directory exists\n try {\n await fs.access(outputDir)\n } catch {\n console.error(`❌ Build directory not found: ${outputDir}`)\n console.log('💡 Run \"docgen build\" first to generate the static site')\n process.exit(1)\n }\n \n // Create static file server\n const serve = sirv(outputDir, {\n single: true, // SPA mode\n dev: false,\n setHeaders: (res, pathname) => {\n if (pathname.endsWith('.html') || pathname === '/') {\n res.setHeader('Content-Type', 'text/html; charset=utf-8')\n }\n }\n })\n \n const server = createServer(serve)\n \n server.listen(port, () => {\n console.log(`🎉 Preview server running at http://localhost:${port}`)\n console.log(`📂 Serving files from: ${outputDir}`)\n })\n \n // Handle graceful shutdown\n process.on('SIGINT', () => {\n console.log('\\\\n👋 Shutting down preview server...')\n server.close(() => {\n process.exit(0)\n })\n })\n \n } catch (error) {\n console.error('❌ Failed to start preview server:', error)\n process.exit(1)\n }\n}"],"mappings":"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","names":["segments","path","path","server","path","path","vue","path","fileURLToPath","fs","__dirname","packageRoot","getFileRoute","path","path","fs","createServer"]}
package/package.json CHANGED
@@ -1,12 +1,17 @@
1
1
  {
2
2
  "name": "docmk",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "A CLI tool for scanning directories and generating static documentation websites",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
7
7
  "docmk": "./bin/docmk.js"
8
8
  },
9
9
  "type": "module",
10
+ "files": [
11
+ "bin",
12
+ "dist",
13
+ "src"
14
+ ],
10
15
  "scripts": {
11
16
  "dev": "tsx src/cli/index.ts",
12
17
  "build": "tsup",
@@ -113,6 +113,9 @@ export async function createViteDevServer(options: DevServerOptions): Promise<Vi
113
113
  // Start the server
114
114
  await server.listen()
115
115
 
116
+ // Get actual port (in case requested port was taken)
117
+ const actualPort = server.config.server.port
118
+
116
119
  // Extend server with cleanup method
117
120
  const originalClose = server.close.bind(server)
118
121
  server.close = async () => {
@@ -120,7 +123,7 @@ export async function createViteDevServer(options: DevServerOptions): Promise<Vi
120
123
  return originalClose()
121
124
  }
122
125
 
123
- return server
126
+ return { server, actualPort }
124
127
  }
125
128
 
126
129
  export async function createProductionBuild() {
@@ -31,13 +31,13 @@ export async function devCommand(options: DevOptions) {
31
31
  })
32
32
 
33
33
  // Start Vite dev server
34
- const server = await createViteDevServer({
34
+ const { server, actualPort } = await createViteDevServer({
35
35
  port,
36
36
  skillsDir: sourceDir,
37
37
  config
38
38
  })
39
-
40
- console.log(`🎉 Dev server running at http://localhost:${port}`)
39
+
40
+ console.log(`🎉 Dev server running at http://localhost:${actualPort}`)
41
41
 
42
42
  // Handle graceful shutdown
43
43
  process.on('SIGINT', async () => {
@@ -1,89 +0,0 @@
1
- ---
2
- title: PDF Processing
3
- description: Comprehensive guide to working with PDF files including extraction, manipulation, and generation
4
- tags: ["pdf", "documents", "data-extraction"]
5
- ---
6
-
7
- # PDF Processing
8
-
9
- This skill covers various aspects of working with PDF documents programmatically.
10
-
11
- ## Overview
12
-
13
- PDF (Portable Document Format) is a widely used file format for documents. This skill includes:
14
-
15
- - Text extraction from PDFs
16
- - PDF generation and manipulation
17
- - Form handling
18
- - Metadata processing
19
- - Document conversion
20
-
21
- ## Key Libraries and Tools
22
-
23
- ### Python
24
- - **PyPDF2/PyPDF4** - Basic PDF operations
25
- - **pdfplumber** - Text extraction with layout preservation
26
- - **ReportLab** - PDF generation
27
- - **pdftk** - Command-line PDF toolkit
28
-
29
- ### JavaScript/Node.js
30
- - **pdf-lib** - Create and modify PDF documents
31
- - **pdf-parse** - Simple PDF parsing
32
- - **puppeteer** - Generate PDFs from web content
33
-
34
- ## Common Use Cases
35
-
36
- ### Text Extraction
37
- Extract text content from PDF files while preserving formatting and structure.
38
-
39
- ### Document Generation
40
- Create PDFs programmatically from data, templates, or web content.
41
-
42
- ### Form Processing
43
- Handle PDF forms, extract form data, and fill forms programmatically.
44
-
45
- ## Best Practices
46
-
47
- 1. **Memory Management** - Large PDFs can consume significant memory
48
- 2. **Error Handling** - PDFs can be corrupted or password-protected
49
- 3. **Performance** - Consider streaming for large documents
50
- 4. **Security** - Be cautious with user-uploaded PDFs
51
-
52
- ## Examples
53
-
54
- ### Basic Text Extraction (Python)
55
- ```python
56
- import PyPDF2
57
-
58
- with open('document.pdf', 'rb') as file:
59
- reader = PyPDF2.PdfReader(file)
60
- text = ""
61
- for page in reader.pages:
62
- text += page.extract_text()
63
- print(text)
64
- ```
65
-
66
- ### PDF Generation (JavaScript)
67
- ```javascript
68
- import { PDFDocument, rgb } from 'pdf-lib'
69
- import fs from 'fs'
70
-
71
- const pdfDoc = await PDFDocument.create()
72
- const page = pdfDoc.addPage()
73
-
74
- page.drawText('Hello, PDF!', {
75
- x: 50,
76
- y: 750,
77
- size: 30,
78
- color: rgb(0, 0, 0),
79
- })
80
-
81
- const pdfBytes = await pdfDoc.save()
82
- fs.writeFileSync('output.pdf', pdfBytes)
83
- ```
84
-
85
- ## Troubleshooting
86
-
87
- - **Encoding Issues** - Some PDFs may have encoding problems
88
- - **Layout Preservation** - Complex layouts may not extract cleanly
89
- - **Performance** - Large PDFs may require optimization
@@ -1,78 +0,0 @@
1
- ---
2
- title: Web Scraping
3
- description: Techniques and tools for extracting data from websites
4
- tags: ["scraping", "data-extraction", "automation"]
5
- ---
6
-
7
- # Web Scraping
8
-
9
- Web scraping is the process of extracting data from websites programmatically.
10
-
11
- ## Overview
12
-
13
- Web scraping involves:
14
-
15
- - Fetching web pages
16
- - Parsing HTML content
17
- - Extracting specific data
18
- - Handling dynamic content
19
- - Managing rate limits and ethics
20
-
21
- ## Tools and Libraries
22
-
23
- ### Python
24
- - **BeautifulSoup** - HTML parsing
25
- - **Scrapy** - Full-featured scraping framework
26
- - **Selenium** - Browser automation
27
- - **requests** - HTTP library
28
-
29
- ### JavaScript/Node.js
30
- - **Puppeteer** - Chrome automation
31
- - **Playwright** - Multi-browser automation
32
- - **Cheerio** - Server-side jQuery
33
- - **axios** - HTTP client
34
-
35
- ## Key Concepts
36
-
37
- ### Respect robots.txt
38
- Always check the robots.txt file of websites before scraping.
39
-
40
- ### Rate Limiting
41
- Implement delays between requests to avoid overwhelming servers.
42
-
43
- ### User Agents
44
- Rotate user agents to appear more like regular browsers.
45
-
46
- ## Examples
47
-
48
- ### Basic Scraping (Python)
49
- ```python
50
- import requests
51
- from bs4 import BeautifulSoup
52
-
53
- response = requests.get('https://example.com')
54
- soup = BeautifulSoup(response.content, 'html.parser')
55
-
56
- titles = soup.find_all('h2', class_='title')
57
- for title in titles:
58
- print(title.text)
59
- ```
60
-
61
- ### Dynamic Content (JavaScript)
62
- ```javascript
63
- const puppeteer = require('puppeteer');
64
-
65
- (async () => {
66
- const browser = await puppeteer.launch();
67
- const page = await browser.newPage();
68
-
69
- await page.goto('https://example.com');
70
- await page.waitForSelector('.dynamic-content');
71
-
72
- const content = await page.$eval('.dynamic-content',
73
- el => el.textContent);
74
-
75
- console.log(content);
76
- await browser.close();
77
- })();
78
- ```
package/CLAUDE.md DELETED
@@ -1,90 +0,0 @@
1
- # CLAUDE.md
2
-
3
- This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
-
5
- ## 项目概述
6
-
7
- DocGen 是一个文档生成 CLI 工具,用于扫描任意目录并自动生成静态文档网站。支持 Markdown 渲染、全文搜索、代码高亮等功能。
8
-
9
- ## 常用命令
10
-
11
- ```bash
12
- # 安装依赖
13
- npm install
14
-
15
- # 构建 CLI(输出到 dist/)
16
- npm run build
17
-
18
- # 类型检查
19
- npm run typecheck
20
-
21
- # 代码检查
22
- npm run lint
23
-
24
- # 开发模式运行 CLI(使用 tsx 直接执行)
25
- npm run dev
26
-
27
- # 使用 CLI 启动文档开发服务器
28
- node dist/index.js dev --dir ./my-docs --port 3000
29
-
30
- # 构建静态站点
31
- node dist/index.js build --dir ./my-docs --output ./dist
32
-
33
- # 预览构建结果
34
- node dist/index.js preview --output ./dist --port 4173
35
- ```
36
-
37
- ## 架构
38
-
39
- ```
40
- src/
41
- ├── cli/ # CLI 入口和命令实现
42
- │ ├── index.ts # 主入口,使用 Commander.js 定义命令
43
- │ └── commands/ # dev/build/preview 命令
44
- ├── scanner/ # 目录扫描器,递归扫描 .md 文件
45
- ├── parser/ # Markdown 解析,使用 gray-matter + markdown-it + shiki
46
- ├── builder/ # Vite 构建逻辑
47
- │ ├── index.ts # 生产构建,生成 sitemap/robots.txt
48
- │ └── vite-dev.ts # 开发服务器,支持文件监听热更新
49
- ├── client/ # Vue 3 前端 SPA
50
- │ ├── pages/ # Home(首页统计)和 SkillPage(文档渲染)
51
- │ ├── components/ # Sidebar、SearchBox 等
52
- │ └── router.ts # 路由配置,catch-all 匹配文档路径
53
- └── types/ # TypeScript 类型定义
54
- ```
55
-
56
- ## 核心数据流
57
-
58
- 1. **Scanner** (`src/scanner/index.ts`): 扫描源目录,递归收集 `.md` 文件,构建 `SkillDirectory[]` 树结构
59
- 2. **Parser** (`src/parser/index.ts`): 解析 frontmatter、渲染 Markdown 为 HTML、提取 TOC、应用 shiki 代码高亮
60
- 3. **Builder**:
61
- - 开发模式:通过 `/api/config` 端点注入配置,使用 chokidar 监听文件变化触发热更新
62
- - 生产模式:将配置 base64 编码注入 HTML `<head>`,生成 sitemap.xml 和 robots.txt
63
- 4. **Client**: Vue 3 SPA 从 `globalThis.__DOCGEN_CONFIG__` 或 `/api/config` 获取配置,渲染文档
64
-
65
- ## 关键类型
66
-
67
- - `SkillDirectory`: 目录节点,包含 `children` 和可选的 `skillFile`(SKILL.md)
68
- - `SkillFile`: 文件节点,包含 `content`、`frontmatter`、`lastModified`
69
- - `DocGenConfig`: 完整站点配置,包含 `navigation`、`files`、`directories`
70
-
71
- ## 技术栈
72
-
73
- - **CLI**: Commander.js + tsup 打包
74
- - **前端**: Vue 3 + Vue Router + Vite + Tailwind CSS
75
- - **解析**: gray-matter(frontmatter)+ markdown-it(渲染)+ shiki(代码高亮)
76
- - **监听**: chokidar
77
-
78
- ## 文档目录结构约定
79
-
80
- ```
81
- docs/
82
- ├── category/
83
- │ ├── SKILL.md # 主文档(可选,作为该目录的入口)
84
- │ ├── advanced.md # 其他文档
85
- │ └── sub-category/ # 子目录
86
- └── another/
87
- └── SKILL.md
88
- ```
89
-
90
- 路由规则:`SKILL.md` 文件映射到目录路径(如 `/api/SKILL.md` → `/api`),其他 `.md` 文件保留文件名(如 `/api/advanced.md` → `/api/advanced`)。
@@ -1 +0,0 @@
1
- .sidebar-item[data-v-b5febdd6]{margin-bottom:.25rem}.item-wrapper[data-v-b5febdd6]{display:flex;align-items:center;padding:.5rem 1.5rem;position:relative}.expand-button[data-v-b5febdd6]{background:none;border:none;color:#666;cursor:pointer;padding:.25rem;margin-right:.5rem;display:flex;align-items:center;justify-content:center;transition:transform .2s ease}.expand-button.expanded[data-v-b5febdd6]{transform:rotate(90deg)}.expand-button[data-v-b5febdd6]:hover{color:#333}.nav-link[data-v-b5febdd6],.nav-text[data-v-b5febdd6]{flex:1;text-decoration:none;color:#555;font-weight:500;font-size:.9rem;line-height:1.4;transition:color .2s ease}.nav-link[data-v-b5febdd6]:hover{color:#3182ce}.nav-link.active[data-v-b5febdd6]{color:#3182ce;font-weight:600;position:relative}.nav-link.active[data-v-b5febdd6]:before{content:"";position:absolute;left:-1.5rem;top:50%;transform:translateY(-50%);width:3px;height:20px;background-color:#3182ce;border-radius:2px}.nav-text[data-v-b5febdd6]{color:#333;font-weight:600}.children[data-v-b5febdd6]{overflow:hidden;max-height:0;transition:max-height .3s ease;padding-left:1rem}.children.expanded[data-v-b5febdd6]{max-height:1000px}.children .sidebar-item[data-v-b5febdd6]{margin-left:1rem}.children .nav-link[data-v-b5febdd6],.children .nav-text[data-v-b5febdd6]{font-size:.85rem;font-weight:400;color:#666}.children .nav-link[data-v-b5febdd6]:hover{color:#3182ce}.children .nav-link.active[data-v-b5febdd6]{color:#3182ce;font-weight:500}.sidebar-nav[data-v-014c42bf]{height:100%;overflow-y:auto}.nav-content[data-v-014c42bf]{padding:1.5rem 0}.search-box[data-v-732fbf59]{position:relative;width:100%}.relative[data-v-732fbf59]{position:relative}.absolute[data-v-732fbf59]{position:absolute}.w-full[data-v-732fbf59]{width:100%}.h-4[data-v-732fbf59]{height:1rem}.w-4[data-v-732fbf59]{width:1rem}.h-5[data-v-732fbf59]{height:1.25rem}.h-9[data-v-732fbf59]{height:2.25rem}.left-3[data-v-732fbf59]{left:.75rem}.right-3[data-v-732fbf59]{right:.75rem}.top-1\/2[data-v-732fbf59]{top:50%}.top-full[data-v-732fbf59]{top:100%}.left-0[data-v-732fbf59]{left:0}.right-0[data-v-732fbf59]{right:0}.-translate-y-1\/2[data-v-732fbf59]{transform:translateY(-50%)}.pl-9[data-v-732fbf59]{padding-left:2.25rem}.pr-4[data-v-732fbf59]{padding-right:1rem}.px-1\.5[data-v-732fbf59]{padding-left:.375rem;padding-right:.375rem}.p-3[data-v-732fbf59]{padding:.75rem}.p-4[data-v-732fbf59]{padding:1rem}.mt-2[data-v-732fbf59]{margin-top:.5rem}.mb-1[data-v-732fbf59]{margin-bottom:.25rem}.gap-1[data-v-732fbf59]{gap:.25rem}.text-sm[data-v-732fbf59]{font-size:.875rem}.text-xs[data-v-732fbf59]{font-size:.75rem}.font-medium[data-v-732fbf59]{font-weight:500}.font-mono[data-v-732fbf59]{font-family:var(--font-mono)}.text-muted-foreground[data-v-732fbf59]{color:var(--color-muted-foreground)}.text-foreground[data-v-732fbf59]{color:var(--color-foreground)}.placeholder-muted-foreground[data-v-732fbf59]::placeholder{color:var(--color-muted-foreground)}.bg-secondary[data-v-732fbf59]{background-color:var(--color-secondary)}.bg-muted[data-v-732fbf59]{background-color:var(--color-muted)}.bg-card[data-v-732fbf59]{background-color:var(--color-card)}.bg-accent[data-v-732fbf59]{background-color:var(--color-accent)}.border[data-v-732fbf59]{border-width:1px}.border-b[data-v-732fbf59]{border-bottom-width:1px}.border-border[data-v-732fbf59]{border-color:var(--color-border)}.rounded-md[data-v-732fbf59]{border-radius:var(--radius-md)}.rounded-lg[data-v-732fbf59]{border-radius:var(--radius-lg)}.rounded[data-v-732fbf59]{border-radius:var(--radius-sm)}.shadow-lg[data-v-732fbf59]{box-shadow:var(--shadow-lg)}.z-50[data-v-732fbf59]{z-index:50}.max-h-96[data-v-732fbf59]{max-height:24rem}.overflow-y-auto[data-v-732fbf59]{overflow-y:auto}.items-center[data-v-732fbf59]{align-items:center}.text-center[data-v-732fbf59]{text-align:center}.block[data-v-732fbf59]{display:block}.hidden[data-v-732fbf59]{display:none}.inline-flex[data-v-732fbf59]{display:inline-flex}.transition-colors[data-v-732fbf59]{transition:color .2s ease,background-color .2s ease}.hover\:bg-accent[data-v-732fbf59]:hover{background-color:var(--color-accent)}.last\:border-b-0[data-v-732fbf59]:last-child{border-bottom-width:0}.line-clamp-2[data-v-732fbf59]{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.focus-outline[data-v-732fbf59]:focus{outline:none;border-color:var(--color-ring);box-shadow:0 0 0 2px #0000001a}@media (min-width: 640px){.sm\:inline-flex[data-v-732fbf59]{display:inline-flex}}.min-h-screen[data-v-073699c3]{min-height:100vh}.bg-background[data-v-073699c3]{background-color:var(--color-background)}.sticky[data-v-073699c3]{position:sticky}.top-0[data-v-073699c3]{top:0}.z-50[data-v-073699c3]{z-index:50}.z-40[data-v-073699c3]{z-index:40}.border-b[data-v-073699c3]{border-bottom:1px solid var(--color-border)}.border-r[data-v-073699c3]{border-right:1px solid var(--color-border)}.border-border[data-v-073699c3]{border-color:var(--color-border)}.backdrop-blur-sm[data-v-073699c3]{-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.flex[data-v-073699c3]{display:flex}.items-center[data-v-073699c3]{align-items:center}.justify-between[data-v-073699c3]{justify-between:space-between}.gap-2[data-v-073699c3]{gap:.5rem}.gap-4[data-v-073699c3]{gap:1rem}.h-5[data-v-073699c3]{height:1.25rem}.w-5[data-v-073699c3]{width:1.25rem}.h-7[data-v-073699c3]{height:1.75rem}.w-7[data-v-073699c3]{width:1.75rem}.h-14[data-v-073699c3]{height:3.5rem}.w-64[data-v-073699c3]{width:16rem}.px-4[data-v-073699c3]{padding-left:1rem;padding-right:1rem}.px-6[data-v-073699c3]{padding-left:1.5rem;padding-right:1.5rem}.py-10[data-v-073699c3]{padding-top:2.5rem;padding-bottom:2.5rem}.p-2[data-v-073699c3]{padding:.5rem}.p-4[data-v-073699c3]{padding:1rem}.-ml-2[data-v-073699c3]{margin-left:-.5rem}.mx-8[data-v-073699c3]{margin-left:2rem;margin-right:2rem}.mx-auto[data-v-073699c3]{margin-left:auto;margin-right:auto}.max-w-md[data-v-073699c3]{max-width:28rem}.max-w-4xl[data-v-073699c3]{max-width:56rem}.flex-1[data-v-073699c3]{flex:1}.min-w-0[data-v-073699c3]{min-width:0}.rounded-md[data-v-073699c3]{border-radius:var(--radius-md)}.font-semibold[data-v-073699c3]{font-weight:600}.font-bold[data-v-073699c3]{font-weight:700}.text-sm[data-v-073699c3]{font-size:.875rem}.text-foreground[data-v-073699c3]{color:var(--color-foreground)}.text-primary-foreground[data-v-073699c3]{color:var(--color-primary-foreground)}.text-muted-foreground[data-v-073699c3]{color:var(--color-muted-foreground)}.bg-primary[data-v-073699c3]{background-color:var(--color-primary)}.bg-background\/80[data-v-073699c3]{background-color:#fffc}.hover\:bg-accent[data-v-073699c3]:hover{background-color:var(--color-accent)}.hover\:text-foreground[data-v-073699c3]:hover{color:var(--color-foreground)}.transition-colors[data-v-073699c3]{transition:color .2s ease,background-color .2s ease}.transition-transform[data-v-073699c3]{transition:transform .3s ease}.overflow-y-auto[data-v-073699c3]{overflow-y:auto}.fixed[data-v-073699c3]{position:fixed}.inset-0[data-v-073699c3]{top:0;right:0;bottom:0;left:0}.top-14[data-v-073699c3]{top:3.5rem}.h-\[calc\(100vh-3\.5rem\)\][data-v-073699c3]{height:calc(100vh - 3.5rem)}.-translate-x-full[data-v-073699c3]{transform:translate(-100%)}.translate-x-0[data-v-073699c3]{transform:translate(0)}.hidden[data-v-073699c3]{display:none}@media (min-width: 640px){.sm\:flex[data-v-073699c3]{display:flex}}@media (min-width: 1024px){.lg\:hidden[data-v-073699c3]{display:none}.lg\:px-6[data-v-073699c3]{padding-left:1.5rem;padding-right:1.5rem}.lg\:px-8[data-v-073699c3]{padding-left:2rem;padding-right:2rem}.lg\:sticky[data-v-073699c3]{position:sticky}.lg\:translate-x-0[data-v-073699c3]{transform:translate(0)}}#app[data-v-00943de1]{min-height:100vh}.home-page[data-v-12e10d98]{max-width:1000px;margin:0 auto}.hero-section[data-v-12e10d98]{text-align:center;padding:3rem 0;margin-bottom:3rem}.hero-title[data-v-12e10d98]{font-size:3rem;font-weight:700;color:#2c3e50;margin-bottom:1rem}.hero-description[data-v-12e10d98]{font-size:1.2rem;color:#666;max-width:600px;margin:0 auto;line-height:1.6}.content-overview[data-v-12e10d98]{space-y:3rem}.stats-grid[data-v-12e10d98]{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:1.5rem;margin-bottom:3rem}.stat-card[data-v-12e10d98]{background:linear-gradient(135deg,#667eea,#764ba2);color:#fff;padding:2rem;border-radius:12px;text-align:center;box-shadow:0 4px 6px #0000001a}.stat-number[data-v-12e10d98]{font-size:2.5rem;font-weight:700;margin-bottom:.5rem}.stat-label[data-v-12e10d98]{font-size:1rem;opacity:.9}.recent-section[data-v-12e10d98],.navigation-section[data-v-12e10d98]{margin-bottom:3rem}.recent-section h2[data-v-12e10d98],.navigation-section h2[data-v-12e10d98]{font-size:1.8rem;font-weight:600;color:#2c3e50;margin-bottom:1.5rem}.recent-files[data-v-12e10d98]{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:1rem}.recent-file-card[data-v-12e10d98]{background:#fff;border:1px solid #e1e5e9;border-radius:8px;padding:1.5rem;text-decoration:none;color:inherit;transition:all .2s ease}.recent-file-card[data-v-12e10d98]:hover{transform:translateY(-2px);box-shadow:0 4px 12px #0000001a;border-color:#3182ce}.file-title[data-v-12e10d98]{font-weight:600;color:#2c3e50;margin-bottom:.5rem}.file-description[data-v-12e10d98]{color:#666;font-size:.9rem;margin-bottom:1rem;line-height:1.4}.file-meta[data-v-12e10d98]{color:#999;font-size:.8rem}.skill-grid[data-v-12e10d98]{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:1.5rem}.skill-card[data-v-12e10d98]{background:#fff;border:1px solid #e1e5e9;border-radius:8px;padding:1.5rem;text-decoration:none;color:inherit;transition:all .2s ease}.skill-card[data-v-12e10d98]:hover{transform:translateY(-2px);box-shadow:0 4px 12px #0000001a;border-color:#3182ce}.skill-name[data-v-12e10d98]{font-weight:600;color:#2c3e50;font-size:1.1rem;margin-bottom:.5rem}.skill-description[data-v-12e10d98]{color:#666;font-size:.9rem;line-height:1.4;margin-bottom:1rem}.skill-files-count[data-v-12e10d98]{color:#3182ce;font-size:.8rem;font-weight:500}@media (max-width: 768px){.hero-title[data-v-12e10d98]{font-size:2rem}.hero-description[data-v-12e10d98]{font-size:1rem}.stats-grid[data-v-12e10d98],.recent-files[data-v-12e10d98],.skill-grid[data-v-12e10d98]{grid-template-columns:1fr}}.skill-page[data-v-a95b5427]{max-width:800px;margin:0 auto}.skill-header[data-v-a95b5427]{margin-bottom:2rem;padding-bottom:1.5rem;border-bottom:1px solid #e1e5e9}.skill-title[data-v-a95b5427]{font-size:2.5rem;font-weight:700;color:#2c3e50;margin-bottom:1rem;line-height:1.2}.skill-description[data-v-a95b5427]{font-size:1.2rem;color:#666;margin-bottom:1rem;line-height:1.6}.skill-meta[data-v-a95b5427]{color:#999;font-size:.9rem}.toc[data-v-a95b5427]{background:#f8f9fa;border:1px solid #e1e5e9;border-radius:8px;padding:1.5rem;margin-bottom:2rem}.toc h3[data-v-a95b5427]{margin:0 0 1rem;color:#2c3e50;font-size:1.1rem}.toc-list[data-v-a95b5427]{list-style:none;padding:0;margin:0}.toc-list li[data-v-a95b5427]{margin-bottom:.5rem}.toc-level-1[data-v-a95b5427]{padding-left:0}.toc-level-2[data-v-a95b5427]{padding-left:1rem}.toc-level-3[data-v-a95b5427]{padding-left:2rem}.toc-level-4[data-v-a95b5427]{padding-left:3rem}.toc-level-5[data-v-a95b5427]{padding-left:4rem}.toc-level-6[data-v-a95b5427]{padding-left:5rem}.toc-link[data-v-a95b5427]{color:#555;text-decoration:none;font-size:.9rem;transition:color .2s ease}.toc-link[data-v-a95b5427]:hover{color:#3182ce}.markdown-content[data-v-a95b5427]{line-height:1.7;color:#333}.page-navigation[data-v-a95b5427]{display:flex;justify-content:space-between;margin-top:3rem;padding-top:2rem;border-top:1px solid #e1e5e9;gap:1rem}.nav-link[data-v-a95b5427]{flex:1;text-decoration:none;color:inherit;padding:1.5rem;border:1px solid #e1e5e9;border-radius:8px;transition:all .2s ease}.nav-link[data-v-a95b5427]:hover{border-color:#3182ce;box-shadow:0 2px 8px #0000001a}.nav-prev[data-v-a95b5427]{text-align:left}.nav-next[data-v-a95b5427]{text-align:right}.nav-direction[data-v-a95b5427]{color:#3182ce;font-size:.9rem;font-weight:500;margin-bottom:.25rem}.nav-title[data-v-a95b5427]{color:#2c3e50;font-weight:600}.not-found[data-v-a95b5427]{text-align:center;padding:3rem 0}.not-found h1[data-v-a95b5427]{font-size:2rem;color:#2c3e50;margin-bottom:1rem}.not-found p[data-v-a95b5427]{color:#666;margin-bottom:2rem}.back-home[data-v-a95b5427]{color:#3182ce;text-decoration:none;font-weight:500}.back-home[data-v-a95b5427]:hover{text-decoration:underline}@media (max-width: 768px){.skill-title[data-v-a95b5427]{font-size:2rem}.page-navigation[data-v-a95b5427]{flex-direction:column}.nav-next[data-v-a95b5427]{text-align:left}}.markdown-content h1,.markdown-content h2,.markdown-content h3,.markdown-content h4,.markdown-content h5,.markdown-content h6{color:#2c3e50;font-weight:600;margin-top:2rem;margin-bottom:1rem;line-height:1.3}.markdown-content h1{font-size:2rem}.markdown-content h2{font-size:1.5rem}.markdown-content h3{font-size:1.25rem}.markdown-content h4{font-size:1.1rem}.markdown-content p{margin-bottom:1rem}.markdown-content ul,.markdown-content ol{margin-bottom:1rem;padding-left:1.5rem}.markdown-content li{margin-bottom:.5rem}.markdown-content code{background:#f1f3f4;padding:.2rem .4rem;border-radius:3px;font-family:SF Mono,Consolas,monospace;font-size:.9em}.markdown-content pre{background:#f8f9fa;border:1px solid #e1e5e9;border-radius:6px;padding:1rem;overflow-x:auto;margin:1rem 0}.markdown-content pre code{background:none;padding:0;border-radius:0}.markdown-content blockquote{border-left:4px solid #3182ce;padding-left:1rem;margin:1rem 0;color:#666;font-style:italic}.markdown-content table{width:100%;border-collapse:collapse;margin:1rem 0}.markdown-content th,.markdown-content td{border:1px solid #e1e5e9;padding:.5rem;text-align:left}.markdown-content th{background:#f8f9fa;font-weight:600}:root{--color-background: #ffffff;--color-foreground: #0a0a0a;--color-muted: #f5f5f5;--color-muted-foreground: #737373;--color-border: #e5e5e5;--color-accent: #f5f5f5;--color-accent-foreground: #0a0a0a;--color-primary: #0a0a0a;--color-primary-foreground: #fafafa;--color-secondary: #f5f5f5;--color-secondary-foreground: #0a0a0a;--color-card: #ffffff;--color-card-foreground: #0a0a0a;--color-ring: #0a0a0a;--spacing-xs: .25rem;--spacing-sm: .5rem;--spacing-md: 1rem;--spacing-lg: 1.5rem;--spacing-xl: 2rem;--spacing-2xl: 3rem;--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Helvetica", "Arial", sans-serif;--font-mono: ui-monospace, "SF Mono", "Cascadia Code", "Source Code Pro", Menlo, Consolas, monospace;--radius-sm: .375rem;--radius-md: .5rem;--radius-lg: .75rem;--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / .05);--shadow-md: 0 4px 6px -1px rgb(0 0 0 / .1);--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / .1)}@media (prefers-color-scheme: dark){:root{--color-background: #0a0a0a;--color-foreground: #fafafa;--color-muted: #171717;--color-muted-foreground: #a3a3a3;--color-border: #262626;--color-accent: #171717;--color-accent-foreground: #fafafa;--color-primary: #fafafa;--color-primary-foreground: #0a0a0a;--color-secondary: #171717;--color-secondary-foreground: #fafafa;--color-card: #0a0a0a;--color-card-foreground: #fafafa;--color-ring: #fafafa}}*{margin:0;padding:0;box-sizing:border-box}html{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}body{font-family:var(--font-sans);line-height:1.6;color:var(--color-foreground);background-color:var(--color-background)}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{background:var(--color-muted)}::-webkit-scrollbar-thumb{background:var(--color-border);border-radius:4px}::-webkit-scrollbar-thumb:hover{background:var(--color-muted-foreground)}h1,h2,h3,h4,h5,h6{font-weight:600;line-height:1.2;color:var(--color-foreground)}a{color:var(--color-primary);text-decoration:none;transition:opacity .2s ease}a:hover{opacity:.8}.container{width:100%;max-width:1400px;margin:0 auto;padding:0 var(--spacing-lg)}.text-muted{color:var(--color-muted-foreground)}.text-sm{font-size:.875rem}.text-xs{font-size:.75rem}.font-medium{font-weight:500}.font-semibold{font-weight:600}.font-bold{font-weight:700}.btn{display:inline-flex;align-items:center;justify-content:center;gap:.5rem;padding:.5rem 1rem;font-size:.875rem;font-weight:500;border-radius:var(--radius-md);border:1px solid transparent;cursor:pointer;transition:all .2s ease;white-space:nowrap}.btn:disabled{opacity:.5;cursor:not-allowed}.btn-primary{background:var(--color-primary);color:var(--color-primary-foreground)}.btn-primary:hover:not(:disabled){opacity:.9}.btn-ghost{background:transparent;color:var(--color-foreground)}.btn-ghost:hover:not(:disabled){background:var(--color-accent)}.card{background:var(--color-card);border:1px solid var(--color-border);border-radius:var(--radius-lg);padding:var(--spacing-lg);transition:all .2s ease}.card:hover{border-color:var(--color-primary);box-shadow:var(--shadow-md)}.input{width:100%;padding:.5rem .75rem;font-size:.875rem;background:var(--color-secondary);border:1px solid var(--color-border);border-radius:var(--radius-md);color:var(--color-foreground);transition:all .2s ease}.input:focus{outline:none;border-color:var(--color-ring);box-shadow:0 0 0 2px #0000001a}.input::placeholder{color:var(--color-muted-foreground)}.loading{display:flex;justify-content:center;align-items:center;min-height:200px;color:var(--color-muted-foreground)}@keyframes fadeIn{0%{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.fade-in{animation:fadeIn .3s ease}@media (max-width: 1024px){.container{padding:0 var(--spacing-md)}}@media (max-width: 768px){.container{padding:0 var(--spacing-sm)}}