|
@@ -1,6 +1,8 @@
|
|
|
import { readFileSync, writeFileSync } from 'node:fs';
|
|
import { readFileSync, writeFileSync } from 'node:fs';
|
|
|
import { join } from 'node:path';
|
|
import { join } from 'node:path';
|
|
|
|
|
|
|
|
|
|
+// eslint-disable no-console
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* Extracts the first heading (# or ##) from markdown content
|
|
* Extracts the first heading (# or ##) from markdown content
|
|
|
*/
|
|
*/
|
|
@@ -27,10 +29,7 @@ function replaceFileReferences(text: string, fileToTitleMap: Map<string, string>
|
|
|
|
|
|
|
|
// Replace patterns like ./01-general.md or ./filename.md
|
|
// Replace patterns like ./01-general.md or ./filename.md
|
|
|
for (const [filename, title] of fileToTitleMap.entries()) {
|
|
for (const [filename, title] of fileToTitleMap.entries()) {
|
|
|
- const patterns = [
|
|
|
|
|
- new RegExp(`\\./${filename}`, 'g'),
|
|
|
|
|
- new RegExp(`\\b${filename}\\b`, 'g'),
|
|
|
|
|
- ];
|
|
|
|
|
|
|
+ const patterns = [new RegExp(`\\./${filename}`, 'g'), new RegExp(`\\b${filename}\\b`, 'g')];
|
|
|
|
|
|
|
|
patterns.forEach(pattern => {
|
|
patterns.forEach(pattern => {
|
|
|
result = result.replace(pattern, `the "${title}" section below`);
|
|
result = result.replace(pattern, `the "${title}" section below`);
|
|
@@ -40,6 +39,13 @@ function replaceFileReferences(text: string, fileToTitleMap: Map<string, string>
|
|
|
return result;
|
|
return result;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * Counts the number of lines in text
|
|
|
|
|
+ */
|
|
|
|
|
+function countLines(text: string): number {
|
|
|
|
|
+ return text.split('\n').length;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* Generates a migration prompt by concatenating all markdown files from the
|
|
* Generates a migration prompt by concatenating all markdown files from the
|
|
|
* vendure-dashboard-migration skill directory and inserting it into the
|
|
* vendure-dashboard-migration skill directory and inserting it into the
|
|
@@ -71,6 +77,8 @@ function generateMigrationPrompt() {
|
|
|
|
|
|
|
|
// Build a map of filenames to their section titles
|
|
// Build a map of filenames to their section titles
|
|
|
const fileToTitleMap = new Map<string, string>();
|
|
const fileToTitleMap = new Map<string, string>();
|
|
|
|
|
+ const fileLineCounts: { file: string; lines: number }[] = [];
|
|
|
|
|
+ let totalInputLines = 0;
|
|
|
|
|
|
|
|
for (const file of files) {
|
|
for (const file of files) {
|
|
|
const filePath = join(skillsDir, file);
|
|
const filePath = join(skillsDir, file);
|
|
@@ -87,9 +95,12 @@ function generateMigrationPrompt() {
|
|
|
|
|
|
|
|
// Start with instructions if found, and replace file references
|
|
// Start with instructions if found, and replace file references
|
|
|
const sections: string[] = [];
|
|
const sections: string[] = [];
|
|
|
|
|
+ let instructionsLines = 0;
|
|
|
if (instructions) {
|
|
if (instructions) {
|
|
|
const updatedInstructions = replaceFileReferences(instructions, fileToTitleMap);
|
|
const updatedInstructions = replaceFileReferences(instructions, fileToTitleMap);
|
|
|
sections.push('## Instructions\n\n' + updatedInstructions);
|
|
sections.push('## Instructions\n\n' + updatedInstructions);
|
|
|
|
|
+ instructionsLines = countLines(updatedInstructions);
|
|
|
|
|
+ totalInputLines += instructionsLines;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Read and add all content files
|
|
// Read and add all content files
|
|
@@ -97,6 +108,9 @@ function generateMigrationPrompt() {
|
|
|
const filePath = join(skillsDir, file);
|
|
const filePath = join(skillsDir, file);
|
|
|
try {
|
|
try {
|
|
|
const content = readFileSync(filePath, 'utf-8');
|
|
const content = readFileSync(filePath, 'utf-8');
|
|
|
|
|
+ const lineCount = countLines(content);
|
|
|
|
|
+ fileLineCounts.push({ file, lines: lineCount });
|
|
|
|
|
+ totalInputLines += lineCount;
|
|
|
sections.push(content.trim());
|
|
sections.push(content.trim());
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
console.error(`Warning: Could not read ${file}:`, error);
|
|
console.error(`Warning: Could not read ${file}:`, error);
|
|
@@ -105,31 +119,57 @@ function generateMigrationPrompt() {
|
|
|
|
|
|
|
|
// Join sections with double newline
|
|
// Join sections with double newline
|
|
|
const prompt = sections.join('\n\n');
|
|
const prompt = sections.join('\n\n');
|
|
|
|
|
+ const outputLines = countLines(prompt);
|
|
|
|
|
|
|
|
// Read the current index.md
|
|
// Read the current index.md
|
|
|
const indexContent = readFileSync(docsFile, 'utf-8');
|
|
const indexContent = readFileSync(docsFile, 'utf-8');
|
|
|
|
|
|
|
|
- // Find the code block after "## Full Prompt"
|
|
|
|
|
- // Support both triple and quadruple backticks
|
|
|
|
|
- const promptSectionRegex = /(## Full Prompt\s+Paste this into your AI assistant[^\n]*\n\n)(```+md\n)([\s\S]*?)(```+)/;
|
|
|
|
|
|
|
+ // Find the code block after the HTML comment marker
|
|
|
|
|
+ // Use greedy match to capture all content until the LAST closing backticks
|
|
|
|
|
+ // This is important because the content itself contains code blocks with backticks
|
|
|
|
|
+ const promptSectionRegex = /(<!-- Note: the following code block[\s\S]*?-->\n)(````md\n)([\s\S]*)(````)/;
|
|
|
|
|
|
|
|
const match = indexContent.match(promptSectionRegex);
|
|
const match = indexContent.match(promptSectionRegex);
|
|
|
if (!match) {
|
|
if (!match) {
|
|
|
- throw new Error('Could not find the "Full Prompt" section in index.md');
|
|
|
|
|
|
|
+ throw new Error('Could not find the HTML comment marker and code block in index.md');
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Replace the content inside the code block, preserving the backtick style
|
|
// Replace the content inside the code block, preserving the backtick style
|
|
|
- const updatedContent = indexContent.replace(
|
|
|
|
|
- promptSectionRegex,
|
|
|
|
|
- `$1$2${prompt}\n$4`
|
|
|
|
|
- );
|
|
|
|
|
|
|
+ const updatedContent = indexContent.replace(promptSectionRegex, `$1$2${prompt}\n$4`);
|
|
|
|
|
|
|
|
// Write back to the file
|
|
// Write back to the file
|
|
|
writeFileSync(docsFile, updatedContent, 'utf-8');
|
|
writeFileSync(docsFile, updatedContent, 'utf-8');
|
|
|
|
|
|
|
|
- console.log(' Migration prompt successfully generated and inserted into index.md');
|
|
|
|
|
- console.log(` - Concatenated ${files.length} files`);
|
|
|
|
|
- console.log(` - Total prompt length: ${prompt.length} characters`);
|
|
|
|
|
|
|
+ // Print success message and statistics
|
|
|
|
|
+ console.log('✓ Migration prompt successfully generated and inserted into index.md');
|
|
|
|
|
+ console.log(`\n📊 Line Count Report:`);
|
|
|
|
|
+ console.log(` ─────────────────────────────────────────────────────`);
|
|
|
|
|
+
|
|
|
|
|
+ if (instructionsLines > 0) {
|
|
|
|
|
+ console.log(` Instructions (SKILL.md): ${instructionsLines.toString().padStart(6)} lines`);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fileLineCounts.forEach(({ file, lines }) => {
|
|
|
|
|
+ console.log(` ${file.padEnd(30)} ${lines.toString().padStart(6)} lines`);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ console.log(` ─────────────────────────────────────────────────────`);
|
|
|
|
|
+ console.log(` Total input lines: ${totalInputLines.toString().padStart(6)} lines`);
|
|
|
|
|
+ console.log(` Output lines (concatenated): ${outputLines.toString().padStart(6)} lines`);
|
|
|
|
|
+
|
|
|
|
|
+ // Calculate the difference (should account for section separators)
|
|
|
|
|
+ const separatorLines = sections.length - 1; // Number of "\n\n" separators
|
|
|
|
|
+ const expectedOutputLines = totalInputLines + separatorLines;
|
|
|
|
|
+ const lineDifference = outputLines - expectedOutputLines;
|
|
|
|
|
+
|
|
|
|
|
+ console.log(
|
|
|
|
|
+ ` Expected (with ${separatorLines} separators): ${expectedOutputLines.toString().padStart(6)} lines`,
|
|
|
|
|
+ );
|
|
|
|
|
+ console.log(
|
|
|
|
|
+ ` Difference: ${lineDifference >= 0 ? '+' : ''}${lineDifference} lines`,
|
|
|
|
|
+ );
|
|
|
|
|
+ console.log(`\n Total files concatenated: ${files.length}`);
|
|
|
|
|
+ console.log(` Total characters: ${prompt.length.toLocaleString()}`);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Run the script
|
|
// Run the script
|