generate-migration-prompt.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import { readFileSync, writeFileSync } from 'node:fs';
  2. import { join } from 'node:path';
  3. /**
  4. * Extracts the first heading (# or ##) from markdown content
  5. */
  6. function extractTitle(content: string): string {
  7. const titleRegex = /^##?\s+(.+)$/m;
  8. const match = content.match(titleRegex);
  9. return match ? match[1].trim() : '';
  10. }
  11. /**
  12. * Extracts the Instructions section from SKILL.md
  13. */
  14. function extractInstructions(content: string): string {
  15. const instructionsRegex = /## Instructions\s+([\s\S]*?)(?=\n##|$)/;
  16. const match = content.match(instructionsRegex);
  17. return match ? match[1].trim() : '';
  18. }
  19. /**
  20. * Replaces file references with section references
  21. */
  22. function replaceFileReferences(text: string, fileToTitleMap: Map<string, string>): string {
  23. let result = text;
  24. // Replace patterns like ./01-general.md or ./filename.md
  25. for (const [filename, title] of fileToTitleMap.entries()) {
  26. const patterns = [
  27. new RegExp(`\\./${filename}`, 'g'),
  28. new RegExp(`\\b${filename}\\b`, 'g'),
  29. ];
  30. patterns.forEach(pattern => {
  31. result = result.replace(pattern, `the "${title}" section below`);
  32. });
  33. }
  34. return result;
  35. }
  36. /**
  37. * Generates a migration prompt by concatenating all markdown files from the
  38. * vendure-dashboard-migration skill directory and inserting it into the
  39. * migration index.md documentation file.
  40. */
  41. function generateMigrationPrompt() {
  42. const skillsDir = join(__dirname, '../../.claude/skills/vendure-dashboard-migration');
  43. const docsFile = join(__dirname, '../docs/guides/extending-the-dashboard/migration/index.md');
  44. // Read the SKILL.md to extract instructions
  45. const skillContent = readFileSync(join(skillsDir, 'SKILL.md'), 'utf-8');
  46. const instructions = extractInstructions(skillContent);
  47. // Files to concatenate in order
  48. const files = [
  49. '01-general.md',
  50. '01a-common-tasks.md',
  51. '01b-tsconfig-setup.md',
  52. '02-forms.md',
  53. '03-custom-field-inputs.md',
  54. '04-list-pages.md',
  55. '05-detail-pages.md',
  56. '06-adding-nav-menu-items.md',
  57. '07-action-bar-items.md',
  58. '08-custom-detail-components.md',
  59. '09-page-tabs.md',
  60. '10-widgets.md',
  61. ];
  62. // Build a map of filenames to their section titles
  63. const fileToTitleMap = new Map<string, string>();
  64. for (const file of files) {
  65. const filePath = join(skillsDir, file);
  66. try {
  67. const content = readFileSync(filePath, 'utf-8');
  68. const title = extractTitle(content);
  69. if (title) {
  70. fileToTitleMap.set(file, title);
  71. }
  72. } catch (error) {
  73. console.error(`Warning: Could not read ${file}:`, error);
  74. }
  75. }
  76. // Start with instructions if found, and replace file references
  77. const sections: string[] = [];
  78. if (instructions) {
  79. const updatedInstructions = replaceFileReferences(instructions, fileToTitleMap);
  80. sections.push('## Instructions\n\n' + updatedInstructions);
  81. }
  82. // Read and add all content files
  83. for (const file of files) {
  84. const filePath = join(skillsDir, file);
  85. try {
  86. const content = readFileSync(filePath, 'utf-8');
  87. sections.push(content.trim());
  88. } catch (error) {
  89. console.error(`Warning: Could not read ${file}:`, error);
  90. }
  91. }
  92. // Join sections with double newline
  93. const prompt = sections.join('\n\n');
  94. // Read the current index.md
  95. const indexContent = readFileSync(docsFile, 'utf-8');
  96. // Find the code block after "## Full Prompt"
  97. // Support both triple and quadruple backticks
  98. const promptSectionRegex = /(## Full Prompt\s+Paste this into your AI assistant[^\n]*\n\n)(```+md\n)([\s\S]*?)(```+)/;
  99. const match = indexContent.match(promptSectionRegex);
  100. if (!match) {
  101. throw new Error('Could not find the "Full Prompt" section in index.md');
  102. }
  103. // Replace the content inside the code block, preserving the backtick style
  104. const updatedContent = indexContent.replace(
  105. promptSectionRegex,
  106. `$1$2${prompt}\n$4`
  107. );
  108. // Write back to the file
  109. writeFileSync(docsFile, updatedContent, 'utf-8');
  110. console.log(' Migration prompt successfully generated and inserted into index.md');
  111. console.log(` - Concatenated ${files.length} files`);
  112. console.log(` - Total prompt length: ${prompt.length} characters`);
  113. }
  114. // Run the script
  115. generateMigrationPrompt();