import 'reflect-metadata'; import { injectable, inject } from 'tsyringe'; import { exec } from 'child_process'; import { promisify } from 'util'; import path from 'path'; import fs from 'fs-extra'; const execAsync = promisify(exec); interface PackSummary { fileCount: number; totalLines: number; sizeKB: number; estimatedTokens: number; sampleFiles: string[]; hasMoreFiles: boolean; remainingCount: number; } interface PackResult { content: string; summary: PackSummary; } @injectable() export class RepoPackager { public projectPath: string; private outputFile: string; constructor(@inject('ProjectPath') projectPath: string) { this.projectPath = projectPath; this.outputFile = path.join(projectPath, 'repomix-output.txt'); } async pack(): Promise { try { // Check if repomix is installed await this.checkRepomixInstallation(); // Run repomix const command = `repomix --output "${this.outputFile}"`; await execAsync(command, { cwd: this.projectPath }); // Read the packed content const content = await fs.readFile(this.outputFile, 'utf-8'); // Generate summary data const summary = this.generateSummary(content); // Clean up the output file await fs.remove(this.outputFile); return { content, summary }; } catch (error: any) { if (error.message.includes('repomix: command not found')) { await this.installRepomix(); return this.pack(); // Retry after installation } throw new Error(`Failed to pack repository: ${error.message}`); } } async checkRepomixInstallation(): Promise { try { await execAsync('which repomix'); } catch { throw new Error('repomix: command not found'); } } async installRepomix(): Promise { try { await execAsync('npm install -g repomix'); } catch (error: any) { throw new Error(`Failed to install repomix: ${error.message}`); } } generateSummary(content: string): PackSummary { // Extract basic statistics from content const lines = content.split('\n'); const totalLines = lines.length; // Count files (look for new repomix format: ) const fileMatches = content.match(/ { const pathMatch = match.match(/ 3, remainingCount: Math.max(0, fileMatches.length - 3), }; } }