aico-pack
Version:
A tool to pack repository contents to single file for AI consumption
259 lines • 10.9 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import * as fs from 'node:fs/promises';
import path from 'node:path';
import * as prompts from '@clack/prompts';
import pc from 'picocolors';
import { getGlobalDirectory } from '../../config/globalDirectory.js';
import { logger } from '../../shared/logger.js';
/**
* Check if a file exists at the given path
*/
const fileExists = (filePath) => __awaiter(void 0, void 0, void 0, function* () {
try {
yield fs.access(filePath);
return true;
}
catch (_a) {
return false;
}
});
/**
* Replace all occurrences of 'repopack' with 'repomix' in a string
*/
const replaceRepopackString = (content) => {
return content.replace(/repopack/g, 'repomix').replace(/Repopack/g, 'Repomix');
};
/**
* Update file content by replacing 'repopack' with 'repomix'
*/
const updateFileContent = (filePath) => __awaiter(void 0, void 0, void 0, function* () {
const content = yield fs.readFile(filePath, 'utf8');
const updatedContent = replaceRepopackString(content);
// Check if content needs to be updated
if (content !== updatedContent) {
yield fs.writeFile(filePath, updatedContent, 'utf8');
const relativePath = path.relative(process.cwd(), filePath);
logger.log(`Updated repopack references in ${pc.cyan(relativePath)}`);
return true;
}
return false;
});
/**
* Parse JSON content, update instructionFilePath if exists
*/
const updateInstructionPath = (content) => {
var _a, _b;
try {
const config = JSON.parse(content);
if ((_a = config.output) === null || _a === void 0 ? void 0 : _a.instructionFilePath) {
config.output.instructionFilePath = config.output.instructionFilePath.replace('repopack', 'repomix');
}
// Also update output.filePath if it exists
if ((_b = config.output) === null || _b === void 0 ? void 0 : _b.filePath) {
config.output.filePath = config.output.filePath.replace('repopack', 'repomix');
}
return JSON.stringify(config, null, 2);
}
catch (_c) {
return content;
}
};
/**
* Get output file paths pairs
*/
const getOutputFilePaths = (rootDir) => {
const extensions = ['.txt', '.xml', '.md'];
const oldPaths = extensions.map((ext) => path.join(rootDir, `repopack-output${ext}`));
const newPaths = extensions.map((ext) => path.join(rootDir, `output${ext}`));
return { oldPaths, newPaths };
};
/**
* Migrate a single file from old path to new path
*/
const migrateFile = (oldPath_1, newPath_1, description_1, ...args_1) => __awaiter(void 0, [oldPath_1, newPath_1, description_1, ...args_1], void 0, function* (oldPath, newPath, description, isConfig = false) {
if (!(yield fileExists(oldPath))) {
return false;
}
const exists = yield fileExists(newPath);
if (exists) {
const shouldOverwrite = yield prompts.confirm({
message: `${description} already exists at ${newPath}. Do you want to overwrite it?`,
});
if (prompts.isCancel(shouldOverwrite) || !shouldOverwrite) {
logger.info(`Skipping migration of ${description}`);
return false;
}
}
try {
// Read and update content
let content = yield fs.readFile(oldPath, 'utf8');
content = replaceRepopackString(content);
// For config files, also update instructionFilePath and output.filePath
if (isConfig) {
content = updateInstructionPath(content);
}
// Ensure the target directory exists
yield fs.mkdir(path.dirname(newPath), { recursive: true });
// Write to new file
yield fs.writeFile(newPath, content, 'utf8');
// Remove old file
yield fs.unlink(oldPath);
const relativeOldPath = path.relative(process.cwd(), oldPath);
const relativeNewPath = path.relative(process.cwd(), newPath);
logger.log(`Renamed ${description} from ${relativeOldPath} to ${relativeNewPath}`);
return true;
}
catch (error) {
logger.error(`Failed to migrate ${description}:`, error);
return false;
}
});
/**
* Update content of gitignore and repomixignore files
*/
const updateIgnoreFiles = (rootDir) => __awaiter(void 0, void 0, void 0, function* () {
const gitignorePath = path.join(rootDir, '.gitignore');
const repomixignorePath = path.join(rootDir, '.repomixignore');
if (yield fileExists(gitignorePath)) {
const updated = yield updateFileContent(gitignorePath);
if (!updated) {
logger.debug('No changes needed in .gitignore');
}
}
if (yield fileExists(repomixignorePath)) {
const updated = yield updateFileContent(repomixignorePath);
if (!updated) {
logger.debug('No changes needed in .repomixignore');
}
}
});
/**
* Get all migration related file paths
*/
const getMigrationPaths = (rootDir) => {
const { oldPaths: oldOutputPaths, newPaths: newOutputPaths } = getOutputFilePaths(rootDir);
const oldGlobalDirectory = path.join(process.env.HOME || '', '.config', 'repopack');
const newGlobalDirectory = getGlobalDirectory();
return {
oldConfigPath: path.join(rootDir, 'repopack.config.json'),
newConfigPath: path.join(rootDir, 'repomix.config.json'),
oldIgnorePath: path.join(rootDir, '.repopackignore'),
newIgnorePath: path.join(rootDir, '.repomixignore'),
oldInstructionPath: path.join(rootDir, 'repopack-instruction.md'),
newInstructionPath: path.join(rootDir, 'repomix-instruction.md'),
oldOutputPaths,
newOutputPaths,
oldGlobalConfigPath: path.join(oldGlobalDirectory, 'repopack.config.json'),
newGlobalConfigPath: path.join(newGlobalDirectory, 'repomix.config.json'),
};
};
/**
* Migrate output files
*/
const migrateOutputFiles = (oldPaths, newPaths) => __awaiter(void 0, void 0, void 0, function* () {
const migratedFiles = [];
for (let i = 0; i < oldPaths.length; i++) {
const oldPath = oldPaths[i];
const newPath = newPaths[i];
const ext = path.extname(oldPath);
if (yield migrateFile(oldPath, newPath, `Output file (${ext})`)) {
migratedFiles.push(newPath);
}
}
return migratedFiles;
});
export const runMigrationAction = (rootDir) => __awaiter(void 0, void 0, void 0, function* () {
const result = {
configMigrated: false,
ignoreMigrated: false,
instructionMigrated: false,
outputFilesMigrated: [],
globalConfigMigrated: false,
};
try {
const paths = getMigrationPaths(rootDir);
// Check if migration is needed
const hasOldConfig = yield fileExists(paths.oldConfigPath);
const hasOldIgnore = yield fileExists(paths.oldIgnorePath);
const hasOldInstruction = yield fileExists(paths.oldInstructionPath);
const hasOldGlobalConfig = yield fileExists(paths.oldGlobalConfigPath);
const hasOldOutput = yield Promise.all(paths.oldOutputPaths.map(fileExists)).then((results) => results.some((exists) => exists));
if (!hasOldConfig && !hasOldIgnore && !hasOldInstruction && !hasOldOutput && !hasOldGlobalConfig) {
logger.debug('No Repopack files found to migrate.');
return result;
}
// Show migration notice based on what needs to be migrated
let migrationMessage = `Found ${pc.green('Repopack')} `;
const items = [];
if (hasOldConfig || hasOldIgnore || hasOldInstruction || hasOldOutput)
items.push('local configuration');
if (hasOldGlobalConfig)
items.push('global configuration');
migrationMessage += `${items.join(' and ')}. Would you like to migrate to ${pc.green('Repomix')}?`;
// Confirm migration with user
const shouldMigrate = yield prompts.confirm({
message: migrationMessage,
});
if (prompts.isCancel(shouldMigrate) || !shouldMigrate) {
logger.info('Migration cancelled.');
return result;
}
// Show migration notice
logger.info(pc.cyan('\nMigrating from Repopack to Repomix...'));
logger.log('');
// Migrate config file
if (hasOldConfig) {
result.configMigrated = yield migrateFile(paths.oldConfigPath, paths.newConfigPath, 'Configuration file', true);
}
// Migrate global config file
if (hasOldGlobalConfig) {
result.globalConfigMigrated = yield migrateFile(paths.oldGlobalConfigPath, paths.newGlobalConfigPath, 'Global configuration file', true);
}
// Migrate ignore file
if (hasOldIgnore) {
result.ignoreMigrated = yield migrateFile(paths.oldIgnorePath, paths.newIgnorePath, 'Ignore file');
}
// Migrate instruction file
if (hasOldInstruction) {
result.instructionMigrated = yield migrateFile(paths.oldInstructionPath, paths.newInstructionPath, 'Instruction file');
}
// Migrate output files
if (hasOldOutput) {
result.outputFilesMigrated = yield migrateOutputFiles(paths.oldOutputPaths, paths.newOutputPaths);
}
// Update content in gitignore and repomixignore
yield updateIgnoreFiles(rootDir);
// Show success message
if (result.configMigrated ||
result.ignoreMigrated ||
result.instructionMigrated ||
result.outputFilesMigrated.length > 0 ||
result.globalConfigMigrated) {
logger.log('');
logger.success('✔ Migration completed successfully!');
logger.log('');
logger.info('You can now use Repomix commands as usual. The old Repopack files have been migrated to the new format.');
logger.log('');
}
return result;
}
catch (error) {
if (error instanceof Error) {
result.error = error;
}
else {
result.error = new Error(String(error));
}
logger.error('An error occurred during migration:', error);
return result;
}
});
//# sourceMappingURL=migrationAction.js.map