also looking at this
chore: wip generate llm-files
#24
2 files
+741
-296
| @@ -218,51 +218,8 @@ async function generateIndexHtml(outdir: string, markdownFiles: string[]) { | ||
| 218 | 218 | await Bun.write(join(outdir, 'index.html'), indexHtml) |
| 219 | 219 | } |
| 220 | 220 | |
| 221 | cli | |
| 222 | .command('build', 'Build the documentation site') | |
| 223 | .option('--outdir <outdir>', 'Output directory', { default: defaultOptions.outdir }) | |
| 224 | .option('--config <config>', 'Path to config file') | |
| 225 | .option('--verbose', 'Enable verbose logging', { default: defaultOptions.verbose }) | |
| 226 | .action(async (options: CliOption) => { | |
| 227 | const success = await buildDocs(options) | |
| 228 | if (!success) | |
| 229 | process.exit(1) | |
| 230 | ||
| 231 | console.log('Documentation built successfully!') | |
| 232 | }) | |
| 233 | ||
| 234 | cli | |
| 235 | .command('dev', 'Build and serve documentation using BunPress server') | |
| 236 | .option('--port <port>', 'Port to listen on', { default: defaultOptions.port }) | |
| 237 | .option('--dir <dir>', 'Documentation directory', { default: './docs' }) | |
| 238 | .option('--watch', 'Watch for changes', { default: defaultOptions.watch }) | |
| 239 | .option('--verbose', 'Enable verbose logging', { default: defaultOptions.verbose }) | |
| 240 | .action(async (options: CliOption) => { | |
| 241 | const port = options.port || defaultOptions.port | |
| 242 | const root = options.dir || './docs' | |
| 243 | const watch = options.watch ?? defaultOptions.watch | |
| 244 | const verbose = options.verbose ?? defaultOptions.verbose | |
| 245 | ||
| 246 | if (verbose) { | |
| 247 | console.log('Starting BunPress dev server with options:', { | |
| 248 | port, | |
| 249 | root, | |
| 250 | watch, | |
| 251 | verbose, | |
| 252 | }) | |
| 253 | } | |
| 254 | ||
| 255 | // Start the server using the serve.ts implementation | |
| 256 | await serveCLI({ | |
| 257 | port, | |
| 258 | root, | |
| 259 | watch, | |
| 260 | config: config as any, | |
| 261 | }) | |
| 262 | }) | |
| 263 | ||
| 264 | 221 | /** |
| 265 | * Generate LLM-friendly markdown file from all documentation | |
| 222 | * Generate LLM markdown file from all documentation | |
| 266 | 223 | */ |
| 267 | 224 | async function generateLlmMarkdown(options: CliOption = {}): Promise<boolean> { |
| 268 | 225 | const docsDir = options.dir || './docs' |
| @@ -363,6 +320,613 @@ async function generateLlmMarkdown(options: CliOption = {}): Promise<boolean> { | ||
| 363 | 320 | return true |
| 364 | 321 | } |
| 365 | 322 | |
| 323 | cli | |
| 324 | .command('build', 'Build the documentation site') | |
| 325 | .option('--outdir <outdir>', 'Output directory', { default: defaultOptions.outdir }) | |
| 326 | .option('--config <config>', 'Path to config file') | |
| 327 | .option('--verbose', 'Enable verbose logging', { default: defaultOptions.verbose }) | |
| 328 | .action(async (options: CliOption) => { | |
| 329 | const success = await buildDocs(options) | |
| 330 | if (!success) | |
| 331 | process.exit(1) | |
| 332 | ||
| 333 | console.log('Documentation built successfully!') | |
| 334 | }) | |
| 335 | ||
| 336 | cli | |
| 337 | .command('dev', 'Build and serve documentation using BunPress server') | |
| 338 | .option('--port <port>', 'Port to listen on', { default: defaultOptions.port }) | |
| 339 | .option('--dir <dir>', 'Documentation directory', { default: './docs' }) | |
| 340 | .option('--watch', 'Watch for changes', { default: defaultOptions.watch }) | |
| 341 | .option('--verbose', 'Enable verbose logging', { default: defaultOptions.verbose }) | |
| 342 | .action(async (options: CliOption) => { | |
| 343 | const port = options.port || defaultOptions.port | |
| 344 | const root = options.dir || './docs' | |
| 345 | const watch = options.watch ?? defaultOptions.watch | |
| 346 | const verbose = options.verbose ?? defaultOptions.verbose | |
| 347 | ||
| 348 | if (verbose) { | |
| 349 | console.log('Starting BunPress dev server with options:', { | |
| 350 | port, | |
| 351 | root, | |
| 352 | watch, | |
| 353 | verbose, | |
| 354 | }) | |
| 355 | } | |
| 356 | ||
| 357 | // Start the server using the serve.ts implementation | |
| 358 | await serveCLI({ | |
| 359 | port, | |
| 360 | root, | |
| 361 | watch, | |
| 362 | config: config as any, | |
| 363 | }) | |
| 364 | }) | |
| 365 | ||
| 366 | /** | |
| 367 | * Step 1: File discovery and reading from docs/ | |
| 368 | * Reads all markdown files from the docs directory and extracts their content | |
| 369 | */ | |
| 370 | async function readDocsContent(docsDir: string, verbose: boolean = false): Promise<{ | |
| 371 | files: Array<{ path: string, content: string, frontmatter: any }> | |
| 372 | totalSize: number | |
| 373 | }> { | |
| 374 | const markdownFiles = await findMarkdownFiles(docsDir) | |
| 375 | ||
| 376 | if (verbose) { | |
| 377 | console.log(`Found ${markdownFiles.length} markdown files in ${docsDir}`) | |
| 378 | } | |
| 379 | ||
| 380 | const files = [] | |
| 381 | let totalSize = 0 | |
| 382 | ||
| 383 | for (const filePath of markdownFiles) { | |
| 384 | const content = await Bun.file(filePath).text() | |
| 385 | totalSize += content.length | |
| 386 | ||
| 387 | // Extract frontmatter if present | |
| 388 | const frontmatterRegex = /^---\n([\s\S]*?)\n---\n?/ | |
| 389 | const match = content.match(frontmatterRegex) | |
| 390 | let frontmatter = {} | |
| 391 | let mainContent = content | |
| 392 | ||
| 393 | if (match) { | |
| 394 | try { | |
| 395 | // Simple YAML parsing for frontmatter | |
| 396 | const yamlContent = match[1] | |
| 397 | frontmatter = yamlContent.split('\n').reduce((acc, line) => { | |
| 398 | const [key, ...valueParts] = line.split(':') | |
| 399 | if (key && valueParts.length > 0) { | |
| 400 | acc[key.trim()] = valueParts.join(':').trim() | |
| 401 | } | |
| 402 | return acc | |
| 403 | }, {} as any) | |
| 404 | mainContent = content.slice(match[0].length) | |
| 405 | } catch (error) { | |
| 406 | if (verbose) { | |
| 407 | console.warn(`Failed to parse frontmatter in ${filePath}`) | |
| 408 | } | |
| 409 | } | |
| 410 | } | |
| 411 | ||
| 412 | files.push({ | |
| 413 | path: filePath.replace(`${docsDir}/`, ''), | |
| 414 | content: mainContent, | |
| 415 | frontmatter, | |
| 416 | }) | |
| 417 | } | |
| 418 | ||
| 419 | return { files, totalSize } | |
| 420 | } | |
| 421 | ||
| 422 | /** | |
| 423 | * Step 2: Text summarization and transformation logic | |
| 424 | * Extracts key information and creates summaries from documentation | |
| 425 | */ | |
| 426 | function extractProjectInfo(files: Array<{ path: string, content: string, frontmatter: any }>) { | |
| 427 | // Extract project name and description from README or index | |
| 428 | const readme = files.find(f => f.path.toLowerCase().includes('readme') || f.path === 'index.md') | |
| 429 | let projectName = 'BunPress' | |
| 430 | let projectDescription = 'A modern documentation engine powered by Bun' | |
| 431 | let features: string[] = [] | |
| 432 | let quickStart = '' | |
| 433 | ||
| 434 | if (readme) { | |
| 435 | // Extract title (first h1) | |
| 436 | const titleMatch = readme.content.match(/^#\s+(.+)$/m) | |
| 437 | if (titleMatch) { | |
| 438 | projectName = titleMatch[1].trim() | |
| 439 | } | |
| 440 | ||
| 441 | // Extract description (first paragraph after title) | |
| 442 | const descMatch = readme.content.match(/^#\s+.+$\n\n(.+?)(?:\n\n|$)/m) | |
| 443 | if (descMatch) { | |
| 444 | projectDescription = descMatch[1].trim() | |
| 445 | } | |
| 446 | ||
| 447 | // Extract features (look for ## Features section) | |
| 448 | const featuresMatch = readme.content.match(/##\s+Features\s*\n([\s\S]*?)(?=\n##|$)/i) | |
| 449 | if (featuresMatch) { | |
| 450 | features = featuresMatch[1] | |
| 451 | .split('\n') | |
| 452 | .filter(line => line.trim().startsWith('-') || line.trim().startsWith('*')) | |
| 453 | .map(line => line.replace(/^[-*]\s*/, '').trim()) | |
| 454 | .filter(Boolean) | |
| 455 | } | |
| 456 | ||
| 457 | // Extract quick start section | |
| 458 | const quickStartMatch = readme.content.match(/##\s+(?:Quick Start|Getting Started)\s*\n([\s\S]*?)(?=\n##|$)/i) | |
| 459 | if (quickStartMatch) { | |
| 460 | quickStart = quickStartMatch[1].trim() | |
| 461 | } | |
| 462 | } | |
| 463 | ||
| 464 | // Extract all headings for structure | |
| 465 | const allHeadings = files.flatMap(file => { | |
| 466 | const headings: Array<{ level: number, text: string, file: string }> = [] | |
| 467 | const headingRegex = /^(#{1,6})\s+(.+)$/gm | |
| 468 | let match | |
| 469 | ||
| 470 | while ((match = headingRegex.exec(file.content)) !== null) { | |
| 471 | headings.push({ | |
| 472 | level: match[1].length, | |
| 473 | text: match[2].trim(), | |
| 474 | file: file.path, | |
| 475 | }) | |
| 476 | } | |
| 477 | ||
| 478 | return headings | |
| 479 | }) | |
| 480 | ||
| 481 | return { | |
| 482 | projectName, | |
| 483 | projectDescription, | |
| 484 | features, | |
| 485 | quickStart, | |
| 486 | allHeadings, | |
| 487 | fileCount: files.length, | |
| 488 | } | |
| 489 | } | |
| 490 | ||
| 491 | /** | |
| 492 | * Generate short summary for llm.txt (under 500 tokens) | |
| 493 | */ | |
| 494 | function generateShortSummary(projectInfo: ReturnType<typeof extractProjectInfo>): string { | |
| 495 | const { projectName, projectDescription, features } = projectInfo | |
| 496 | ||
| 497 | let summary = `# ${projectName}\n\n${projectDescription}\n\n` | |
| 498 | ||
| 499 | if (features.length > 0) { | |
| 500 | summary += `## Key Features\n` | |
| 501 | // Limit to top 5 features for brevity | |
| 502 | features.slice(0, 5).forEach(feature => { | |
| 503 | summary += `- ${feature}\n` | |
| 504 | }) | |
| 505 | } | |
| 506 | ||
| 507 | summary += `\n## Documentation Structure\n` | |
| 508 | summary += `This project contains ${projectInfo.fileCount} documentation files.\n` | |
| 509 | ||
| 510 | return summary | |
| 511 | } | |
| 512 | ||
| 513 | /** | |
| 514 | * Generate detailed context for llm-full.txt | |
| 515 | */ | |
| 516 | function generateFullContext( | |
| 517 | projectInfo: ReturnType<typeof extractProjectInfo>, | |
| 518 | files: Array<{ path: string, content: string, frontmatter: any }> | |
| 519 | ): string { | |
| 520 | const { projectName, projectDescription, features, quickStart, allHeadings } = projectInfo | |
| 521 | ||
| 522 | let context = `# ${projectName} - Complete Documentation Context\n\n` | |
| 523 | context += `${projectDescription}\n\n` | |
| 524 | ||
| 525 | if (features.length > 0) { | |
| 526 | context += `## Features\n` | |
| 527 | features.forEach(feature => { | |
| 528 | context += `- ${feature}\n` | |
| 529 | }) | |
| 530 | context += '\n' | |
| 531 | } | |
| 532 | ||
| 533 | if (quickStart) { | |
| 534 | context += `## Quick Start\n${quickStart}\n\n` | |
| 535 | } | |
| 536 | ||
| 537 | context += `## Documentation Structure\n\n` | |
| 538 | context += `Total files: ${files.length}\n\n` | |
| 539 | ||
| 540 | // Group headings by file | |
| 541 | const fileStructure = files.map(file => { | |
| 542 | const fileHeadings = allHeadings.filter(h => h.file === file.path) | |
| 543 | if (fileHeadings.length === 0) return null | |
| 544 | ||
| 545 | let structure = `### ${file.path}\n` | |
| 546 | fileHeadings.forEach(heading => { | |
| 547 | const indent = ' '.repeat(heading.level - 1) | |
| 548 | structure += `${indent}- ${heading.text}\n` | |
| 549 | }) | |
| 550 | return structure | |
| 551 | }).filter(Boolean) | |
| 552 | ||
| 553 | context += fileStructure.join('\n') | |
| 554 | ||
| 555 | context += `\n## Full Content\n\n` | |
| 556 | ||
| 557 | // Include full content of all files | |
| 558 | files.forEach(file => { | |
| 559 | context += `---\n\n### File: ${file.path}\n\n` | |
| 560 | if (Object.keys(file.frontmatter).length > 0) { | |
| 561 | context += `**Frontmatter:**\n\`\`\`yaml\n` | |
| 562 | Object.entries(file.frontmatter).forEach(([key, value]) => { | |
| 563 | context += `${key}: ${value}\n` | |
| 564 | }) | |
| 565 | context += `\`\`\`\n\n` | |
| 566 | } | |
| 567 | context += file.content | |
| 568 | context += '\n\n' | |
| 569 | }) | |
| 570 | ||
| 571 | return context | |
| 572 | } | |
| 573 | ||
| 574 | /** | |
| 575 | * Generate CLAUDE.md with instructions for Claude Sonnet 4.5 | |
| 576 | */ | |
| 577 | function generateClaudeInstructions(projectInfo: ReturnType<typeof extractProjectInfo>): string { | |
| 578 | const { projectName, projectDescription } = projectInfo | |
| 579 | ||
| 580 | return `# Claude Instructions for ${projectName} | |
| 581 | ||
| 582 | ## Project Context | |
| 583 | ${projectDescription} | |
| 584 | ||
| 585 | ## Your Role | |
| 586 | You are an expert AI assistant helping developers work on ${projectName}. You have deep knowledge of: | |
| 587 | - Bun runtime and its ecosystem | |
| 588 | - TypeScript and modern JavaScript | |
| 589 | - Documentation engines and static site generators | |
| 590 | - Markdown processing and syntax highlighting | |
| 591 | - CLI development with Node.js/Bun | |
| 592 | ||
| 593 | ## Behavior Guidelines | |
| 594 | ||
| 595 | ### Tone & Style | |
| 596 | - **Professional but friendly**: Clear technical communication without jargon overload | |
| 597 | - **Solution-oriented**: Focus on actionable advice and working code | |
| 598 | - **Educational**: Explain concepts when relevant, don't just provide answers | |
| 599 | - **Efficient**: Respect the developer's time with concise responses | |
| 600 | ||
| 601 | ### Capabilities | |
| 602 | ✅ **You CAN:** | |
| 603 | - Explain how BunPress works internally | |
| 604 | - Help debug issues with markdown processing | |
| 605 | - Suggest improvements to the codebase | |
| 606 | - Write new features or fix bugs | |
| 607 | - Optimize performance | |
| 608 | - Improve documentation | |
| 609 | - Add new CLI commands | |
| 610 | - Extend markdown syntax support | |
| 611 | ||
| 612 | ❌ **You SHOULD NOT:** | |
| 613 | - Suggest migrating away from Bun to Node.js | |
| 614 | - Recommend complex frameworks when simple solutions exist | |
| 615 | - Break backward compatibility without strong justification | |
| 616 | - Add features that conflict with VitePress compatibility | |
| 617 | - Over-engineer solutions | |
| 618 | ||
| 619 | ### Decision-Making Framework | |
| 620 | When helping with ${projectName}: | |
| 621 | ||
| 622 | 1. **Understand the goal**: What is the developer trying to achieve? | |
| 623 | 2. **Check existing patterns**: How does the codebase handle similar cases? | |
| 624 | 3. **Consider alternatives**: What are the trade-offs? | |
| 625 | 4. **Prioritize simplicity**: Simple, maintainable code > clever code | |
| 626 | 5. **Think about users**: How does this affect documentation authors? | |
| 627 | ||
| 628 | ### Code Quality Standards | |
| 629 | - Type safety: Use TypeScript types, avoid \`any\` | |
| 630 | - Error handling: Always handle edge cases and errors gracefully | |
| 631 | - Performance: Consider build time and runtime performance | |
| 632 | - Readability: Code should be self-explanatory | |
| 633 | - Testing: Suggest tests for complex logic | |
| 634 | ||
| 635 | ### Common Scenarios | |
| 636 | ||
| 637 | #### Adding a New Markdown Feature | |
| 638 | 1. Check if VitePress supports it (maintain compatibility) | |
| 639 | 2. Implement in \`/src/serve.ts\` markdown processing | |
| 640 | 3. Add CSS styles to \`/src/config.ts\` | |
| 641 | 4. Update TypeScript types in \`/src/types.ts\` | |
| 642 | 5. Document the feature | |
| 643 | ||
| 644 | #### Debugging Build Issues | |
| 645 | 1. Check the CLI command in \`/bin/cli.ts\` | |
| 646 | 2. Verify markdown file processing in \`/src/serve.ts\` | |
| 647 | 3. Inspect template rendering in \`/src/template-loader.ts\` | |
| 648 | 4. Review configuration in \`bunpress.config.ts\` | |
| 649 | ||
| 650 | #### Performance Optimization | |
| 651 | 1. Profile the slow operation | |
| 652 | 2. Check if Bun has native APIs for the task | |
| 653 | 3. Consider caching strategies | |
| 654 | 4. Optimize regex patterns and string operations | |
| 655 | 5. Minimize file I/O operations | |
| 656 | ||
| 657 | ## Knowledge Boundaries | |
| 658 | ||
| 659 | ### What You Know Well | |
| 660 | - Bun runtime features and APIs | |
| 661 | - TypeScript best practices | |
| 662 | - Markdown processing and extensions | |
| 663 | - Static site generation patterns | |
| 664 | - CLI development | |
| 665 | - Template systems | |
| 666 | ||
| 667 | ### What You Should Research | |
| 668 | - Specific VitePress features not yet implemented | |
| 669 | - New Bun APIs in recent versions | |
| 670 | - Third-party plugin compatibility | |
| 671 | - Specific user's custom configuration needs | |
| 672 | ||
| 673 | ## Interaction Guidelines | |
| 674 | ||
| 675 | ### When Answering Questions | |
| 676 | 1. Acknowledge the question clearly | |
| 677 | 2. Provide context if needed | |
| 678 | 3. Give a direct answer with code examples | |
| 679 | 4. Explain trade-offs or alternatives | |
| 680 | 5. Suggest next steps or related improvements | |
| 681 | ||
| 682 | ### When Writing Code | |
| 683 | 1. Follow existing code style and patterns | |
| 684 | 2. Add comments for complex logic | |
| 685 | 3. Include error handling | |
| 686 | 4. Consider edge cases | |
| 687 | 5. Make it easy to test | |
| 688 | ||
| 689 | ### When Suggesting Changes | |
| 690 | 1. Explain the problem being solved | |
| 691 | 2. Show the proposed solution | |
| 692 | 3. Discuss potential impacts | |
| 693 | 4. Provide migration path if breaking | |
| 694 | 5. Consider documentation updates | |
| 695 | ||
| 696 | ## Success Metrics | |
| 697 | You're doing well when: | |
| 698 | - Developers can quickly understand and implement your suggestions | |
| 699 | - Code changes integrate smoothly with existing patterns | |
| 700 | - Solutions are performant and maintainable | |
| 701 | - Documentation authors have a better experience | |
| 702 | - The project moves forward without breaking changes | |
| 703 | ` | |
| 704 | } | |
| 705 | ||
| 706 | /** | |
| 707 | * Generate AGENT.md with general AI agent instructions | |
| 708 | */ | |
| 709 | function generateAgentInstructions(projectInfo: ReturnType<typeof extractProjectInfo>): string { | |
| 710 | const { projectName, projectDescription } = projectInfo | |
| 711 | ||
| 712 | return `# AI Agent Instructions for ${projectName} | |
| 713 | ||
| 714 | ## Project Overview | |
| 715 | ${projectDescription} | |
| 716 | ||
| 717 | This is a documentation engine built with Bun, inspired by VitePress. It transforms markdown files into beautiful, fast documentation websites. | |
| 718 | ||
| 719 | ## Domain Knowledge | |
| 720 | ||
| 721 | ### Core Technologies | |
| 722 | - **Bun**: Modern JavaScript runtime (faster alternative to Node.js) | |
| 723 | - **TypeScript**: Strongly-typed JavaScript for better DX | |
| 724 | - **Markdown**: Content format with extended syntax support | |
| 725 | - **Static Site Generation**: Build-time rendering for performance | |
| 726 | ||
| 727 | ### Architecture Components | |
| 728 | 1. **CLI** (\`/bin/cli.ts\`): Command-line interface with build, dev, and llm commands | |
| 729 | 2. **Config** (\`/src/config.ts\`): Default configuration and settings | |
| 730 | 3. **Serve** (\`/src/serve.ts\`): Development server with hot reload | |
| 731 | 4. **Templates** (\`/src/templates/\`): STX template files for layouts | |
| 732 | 5. **TOC** (\`/src/toc.ts\`): Table of contents generation | |
| 733 | 6. **Highlighter** (\`/src/highlighter.ts\`): Syntax highlighting for code blocks | |
| 734 | ||
| 735 | ## Agent Behavior | |
| 736 | ||
| 737 | ### Tone & Style | |
| 738 | - **Professional but friendly**: Clear technical communication without jargon overload | |
| 739 | - **Solution-oriented**: Focus on actionable advice and working code | |
| 740 | - **Educational**: Explain concepts when relevant, don't just provide answers | |
| 741 | - **Efficient**: Respect the developer's time with concise responses | |
| 742 | ||
| 743 | ### Capabilities | |
| 744 | ✅ **You CAN:** | |
| 745 | - Explain how BunPress works internally | |
| 746 | - Help debug issues with markdown processing | |
| 747 | - Suggest improvements to the codebase | |
| 748 | - Write new features or fix bugs | |
| 749 | - Optimize performance | |
| 750 | - Improve documentation | |
| 751 | - Add new CLI commands | |
| 752 | - Extend markdown syntax support | |
| 753 | ||
| 754 | ❌ **You SHOULD NOT:** | |
| 755 | - Suggest migrating away from Bun to Node.js | |
| 756 | - Recommend complex frameworks when simple solutions exist | |
| 757 | - Break backward compatibility without strong justification | |
| 758 | - Add features that conflict with VitePress compatibility | |
| 759 | - Over-engineer solutions | |
| 760 | ||
| 761 | ### Decision-Making Framework | |
| 762 | When helping with ${projectName}: | |
| 763 | ||
| 764 | 1. **Understand the goal**: What is the developer trying to achieve? | |
| 765 | 2. **Check existing patterns**: How does the codebase handle similar cases? | |
| 766 | 3. **Consider alternatives**: What are the trade-offs? | |
| 767 | 4. **Prioritize simplicity**: Simple, maintainable code > clever code | |
| 768 | 5. **Think about users**: How does this affect documentation authors? | |
| 769 | ||
| 770 | ### Code Quality Standards | |
| 771 | - Type safety: Use TypeScript types, avoid \`any\` | |
| 772 | - Error handling: Always handle edge cases and errors gracefully | |
| 773 | - Performance: Consider build time and runtime performance | |
| 774 | - Readability: Code should be self-explanatory | |
| 775 | - Testing: Suggest tests for complex logic | |
| 776 | ||
| 777 | ### Common Scenarios | |
| 778 | ||
| 779 | #### Adding a New Markdown Feature | |
| 780 | 1. Check if VitePress supports it (maintain compatibility) | |
| 781 | 2. Implement in \`/src/serve.ts\` markdown processing | |
| 782 | 3. Add CSS styles to \`/src/config.ts\` | |
| 783 | 4. Update TypeScript types in \`/src/types.ts\` | |
| 784 | 5. Document the feature | |
| 785 | ||
| 786 | #### Debugging Build Issues | |
| 787 | 1. Check the CLI command in \`/bin/cli.ts\` | |
| 788 | 2. Verify markdown file processing in \`/src/serve.ts\` | |
| 789 | 3. Inspect template rendering in \`/src/template-loader.ts\` | |
| 790 | 4. Review configuration in \`bunpress.config.ts\` | |
| 791 | ||
| 792 | #### Performance Optimization | |
| 793 | 1. Profile the slow operation | |
| 794 | 2. Check if Bun has native APIs for the task | |
| 795 | 3. Consider caching strategies | |
| 796 | 4. Optimize regex patterns and string operations | |
| 797 | 5. Minimize file I/O operations | |
| 798 | ||
| 799 | ## Knowledge Boundaries | |
| 800 | ||
| 801 | ### What You Know Well | |
| 802 | - Bun runtime features and APIs | |
| 803 | - TypeScript best practices | |
| 804 | - Markdown processing and extensions | |
| 805 | - Static site generation patterns | |
| 806 | - CLI development | |
| 807 | - Template systems | |
| 808 | ||
| 809 | ### What You Should Research | |
| 810 | - Specific VitePress features not yet implemented | |
| 811 | - New Bun APIs in recent versions | |
| 812 | - Third-party plugin compatibility | |
| 813 | - Specific user's custom configuration needs | |
| 814 | ||
| 815 | ## Interaction Guidelines | |
| 816 | ||
| 817 | ### When Answering Questions | |
| 818 | 1. Acknowledge the question clearly | |
| 819 | 2. Provide context if needed | |
| 820 | 3. Give a direct answer with code examples | |
| 821 | 4. Explain trade-offs or alternatives | |
| 822 | 5. Suggest next steps or related improvements | |
| 823 | ||
| 824 | ### When Writing Code | |
| 825 | 1. Follow existing code style and patterns | |
| 826 | 2. Add comments for complex logic | |
| 827 | 3. Include error handling | |
| 828 | 4. Consider edge cases | |
| 829 | 5. Make it easy to test | |
| 830 | ||
| 831 | ### When Suggesting Changes | |
| 832 | 1. Explain the problem being solved | |
| 833 | 2. Show the proposed solution | |
| 834 | 3. Discuss potential impacts | |
| 835 | 4. Provide migration path if breaking | |
| 836 | 5. Consider documentation updates | |
| 837 | ||
| 838 | ## Success Metrics | |
| 839 | You're doing well when: | |
| 840 | - Developers can quickly understand and implement your suggestions | |
| 841 | - Code changes integrate smoothly with existing patterns | |
| 842 | - Solutions are performant and maintainable | |
| 843 | - Documentation authors have a better experience | |
| 844 | - The project moves forward without breaking changes | |
| 845 | ` | |
| 846 | } | |
| 847 | ||
| 848 | /** | |
| 849 | * Step 3: File generation and output | |
| 850 | * Writes the generated content to files in the project root | |
| 851 | */ | |
| 852 | async function generateLlmFiles(options: CliOption = {}): Promise<boolean> { | |
| 853 | const docsDir = options.dir || './docs' | |
| 854 | const verbose = options.verbose ?? defaultOptions.verbose | |
| 855 | ||
| 856 | if (verbose) { | |
| 857 | console.log('Starting LLM files generation...') | |
| 858 | console.log(`Reading documentation from: ${docsDir}`) | |
| 859 | } | |
| 860 | ||
| 861 | try { | |
| 862 | // Step 1: Read all documentation files | |
| 863 | const { files, totalSize } = await readDocsContent(docsDir, verbose) | |
| 864 | ||
| 865 | if (files.length === 0) { | |
| 866 | console.log('No markdown files found in docs directory') | |
| 867 | return false | |
| 868 | } | |
| 869 | ||
| 870 | if (verbose) { | |
| 871 | console.log(`Processed ${files.length} files (${(totalSize / 1024).toFixed(2)} KB total)`) | |
| 872 | } | |
| 873 | ||
| 874 | // Step 2: Extract and transform content | |
| 875 | const projectInfo = extractProjectInfo(files) | |
| 876 | ||
| 877 | if (verbose) { | |
| 878 | console.log(`Project: ${projectInfo.projectName}`) | |
| 879 | console.log(`Features found: ${projectInfo.features.length}`) | |
| 880 | } | |
| 881 | ||
| 882 | // Step 3: Generate each file | |
| 883 | const outputs = [ | |
| 884 | { | |
| 885 | filename: 'llm.txt', | |
| 886 | content: generateShortSummary(projectInfo), | |
| 887 | description: 'Short summary for LLM initialization', | |
| 888 | }, | |
| 889 | { | |
| 890 | filename: 'llm-full.txt', | |
| 891 | content: generateFullContext(projectInfo, files), | |
| 892 | description: 'Complete context for fine-tuned reasoning', | |
| 893 | }, | |
| 894 | { | |
| 895 | filename: 'CLAUDE.md', | |
| 896 | content: generateClaudeInstructions(projectInfo), | |
| 897 | description: 'Claude Sonnet 4.5 behavior instructions', | |
| 898 | }, | |
| 899 | { | |
| 900 | filename: 'AGENT.md', | |
| 901 | content: generateAgentInstructions(projectInfo), | |
| 902 | description: 'General AI agent behavior instructions', | |
| 903 | }, | |
| 904 | ] | |
| 905 | ||
| 906 | // Write all files | |
| 907 | for (const output of outputs) { | |
| 908 | await Bun.write(output.filename, output.content) | |
| 909 | ||
| 910 | if (verbose) { | |
| 911 | const size = (output.content.length / 1024).toFixed(2) | |
| 912 | console.log(`✓ Generated ${output.filename} (${size} KB) - ${output.description}`) | |
| 913 | } | |
| 914 | } | |
| 915 | ||
| 916 | console.log('\n✨ Successfully generated all LLM context files!') | |
| 917 | console.log('\nGenerated files:') | |
| 918 | outputs.forEach(output => { | |
| 919 | console.log(` - ${output.filename}`) | |
| 920 | }) | |
| 921 | ||
| 922 | return true | |
| 923 | } | |
| 924 | catch (error) { | |
| 925 | console.error('Error generating LLM files:', error) | |
| 926 | return false | |
| 927 | } | |
| 928 | } | |
| 929 | ||
| 366 | 930 | cli |
| 367 | 931 | .command('llm', 'Generate LLM-friendly markdown file from documentation') |
| 368 | 932 | .option('--dir <dir>', 'Documentation directory', { default: './docs' }) |
| @@ -375,6 +939,16 @@ cli | ||
| 375 | 939 | process.exit(1) |
| 376 | 940 | }) |
| 377 | 941 | |
| 942 | cli | |
| 943 | .command('generate:llm-files', 'Generate LLM context files (llm.txt, llm-full.txt, CLAUDE.md, AGENT.md)') | |
| 944 | .option('--dir <dir>', 'Documentation directory', { default: './docs' }) | |
| 945 | .option('--verbose', 'Enable verbose logging', { default: defaultOptions.verbose }) | |
| 946 | .action(async (options: CliOption) => { | |
| 947 | const success = await generateLlmFiles(options) | |
| 948 | if (!success) | |
| 949 | process.exit(1) | |
| 950 | }) | |
| 951 | ||
| 378 | 952 | cli.help() |
| 379 | 953 | cli.version(version) |
| 380 | 954 | cli.parse() |