Created
June 28, 2026 10:08
-
-
Save RahulDas-dev/0b5fc07d7a24429fd48c75d26e81b94b to your computer and use it in GitHub Desktop.
Fully functional, and production-ready unpack script that undo the remix packing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const fs = require('fs'); | |
| const path = require('path'); | |
| // Configuration: The script will search for these common output names | |
| const DEFAULT_INPUT_FILES = ['repomix-output.xml', 'repomix-output.md', 'repopack-output.xml', 'repopack-output.md']; | |
| function findInputFile() { | |
| for (const file of DEFAULT_INPUT_FILES) { | |
| if (fs.existsSync(file)) { | |
| return file; | |
| } | |
| } | |
| return null; | |
| } | |
| function unpack() { | |
| const inputFile = findInputFile(); | |
| if (!inputFile) { | |
| console.error('β Error: No packed file found in the current directory.'); | |
| console.error(`Looking for one of: ${DEFAULT_INPUT_FILES.join(', ')}`); | |
| process.exit(1); | |
| } | |
| console.log(`π Reading ${inputFile}...`); | |
| const content = fs.readFileSync(inputFile, 'utf-8'); | |
| let fileCount = 0; | |
| console.log('ποΈ Analyzing format and reconstructing...'); | |
| // Identify whether it is XML or Markdown | |
| if (content.includes('<file filePath=') || content.includes('<file path=')) { | |
| fileCount = parseXML(content); | |
| } else if (content.includes('### File:')) { | |
| fileCount = parseMarkdown(content); | |
| } else { | |
| console.error('β Error: Could not determine the packing format. The file does not seem to contain Repomix/Repopack structure.'); | |
| process.exit(1); | |
| } | |
| if (fileCount > 0) { | |
| console.log(`\nπ Success! Successfully recreated ${fileCount} files.`); | |
| } else { | |
| console.log('\nβ οΈ No files were extracted. Ensure the packed file contains intact file tags.'); | |
| } | |
| } | |
| /** | |
| * Parses XML style output: <file filePath="path/to/file">...</file> or <file path="path/to/file">...</file> | |
| * Uses string indices instead of RegExp to prevent catastrophic backtracking on large files. | |
| */ | |
| function parseXML(content) { | |
| let count = 0; | |
| let currentIndex = 0; | |
| while (true) { | |
| // Look for file opening tag | |
| let startIdx = content.indexOf('<file filePath="', currentIndex); | |
| let pathAttrLength = 16; // Length of '<file filePath="' | |
| if (startIdx === -1) { | |
| // Fallback to path="..." which is the format in your uploaded file! | |
| startIdx = content.indexOf('<file path="', currentIndex); | |
| pathAttrLength = 12; // Length of '<file path="' | |
| } | |
| if (startIdx === -1) break; // No more files found | |
| // Extract the filepath | |
| const pathStart = startIdx + pathAttrLength; | |
| const pathEnd = content.indexOf('"', pathStart); | |
| if (pathEnd === -1) break; | |
| const relativePath = content.substring(pathStart, pathEnd); | |
| // Find the end of the opening tag (could have custom attributes or just close with >) | |
| const tagEnd = content.indexOf('>', pathEnd); | |
| if (tagEnd === -1) break; | |
| // Find the closing tag | |
| const closeTagIdx = content.indexOf('</file>', tagEnd); | |
| if (closeTagIdx === -1) break; | |
| let fileContent = content.substring(tagEnd + 1, closeTagIdx); | |
| // Clean up structural formatting spacing added by Repomix | |
| if (fileContent.startsWith('\n')) fileContent = fileContent.slice(1); | |
| if (fileContent.endsWith('\n')) fileContent = fileContent.slice(0, -1); | |
| writeFile(relativePath, fileContent); | |
| count++; | |
| // Advance search index | |
| currentIndex = closeTagIdx + 7; // 7 is length of '</file>' | |
| } | |
| return count; | |
| } | |
| /** | |
| * Parses Markdown style output: | |
| * ### File: path/to/file | |
| * ``` | |
| * content | |
| * ``` | |
| */ | |
| function parseMarkdown(content) { | |
| let count = 0; | |
| const lines = content.split(/\r?\n/); | |
| let currentFile = null; | |
| let currentContent = []; | |
| let insideCodeBlock = false; | |
| for (let i = 0; i < lines.length; i++) { | |
| const line = lines[i]; | |
| if (line.startsWith('### File:')) { | |
| // Save prior file if any | |
| if (currentFile) { | |
| saveMarkdownFile(currentFile, currentContent); | |
| count++; | |
| } | |
| currentFile = line.replace('### File:', '').trim(); | |
| currentContent = []; | |
| insideCodeBlock = false; | |
| continue; | |
| } | |
| if (currentFile !== null) { | |
| // Manage skipping markdown codefence wrappers (```javascript ... ```) | |
| if (line.startsWith('```')) { | |
| if (!insideCodeBlock) { | |
| insideCodeBlock = true; | |
| continue; // Skip the opening code fence line | |
| } else { | |
| // Saving current file content on closing fence | |
| saveMarkdownFile(currentFile, currentContent); | |
| count++; | |
| currentFile = null; | |
| currentContent = []; | |
| insideCodeBlock = false; | |
| continue; | |
| } | |
| } | |
| currentContent.push(line); | |
| } | |
| } | |
| // Edgecase cleanup for files without formal closing fences | |
| if (currentFile && currentContent.length > 0) { | |
| saveMarkdownFile(currentFile, currentContent); | |
| count++; | |
| } | |
| return count; | |
| } | |
| function saveMarkdownFile(relativePath, lines) { | |
| let fileContent = lines.join('\n'); | |
| writeFile(relativePath, fileContent); | |
| } | |
| function writeFile(relativePath, fileContent) { | |
| // Guard against path traversal attacks (prevent writing files outside working directory) | |
| const safeRelativePath = path.normalize(relativePath).replace(/^(\.\.(\/|\\))+/, ''); | |
| const targetPath = path.resolve(process.cwd(), safeRelativePath); | |
| const dirName = path.dirname(targetPath); | |
| try { | |
| if (!fs.existsSync(dirName)) { | |
| fs.mkdirSync(dirName, { recursive: true }); | |
| } | |
| fs.writeFileSync(targetPath, fileContent, 'utf-8'); | |
| console.log(` + Created: ${safeRelativePath}`); | |
| } catch (err) { | |
| console.error(`β Failed to write file: ${safeRelativePath}`, err.message); | |
| } | |
| } | |
| unpack(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment