aico-pack
Version:
A tool to pack repository contents to single file for AI consumption
165 lines • 8.16 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 os from 'node:os';
import path from 'node:path';
import pc from 'picocolors';
import { execGitShallowClone } from '../../core/git/gitCommand.js';
import { downloadGitHubArchive, isArchiveDownloadSupported } from '../../core/git/gitHubArchive.js';
import { getRemoteRefs } from '../../core/git/gitRemoteHandle.js';
import { isGitHubRepository, parseGitHubRepoInfo, parseRemoteValue } from '../../core/git/gitRemoteParse.js';
import { isGitInstalled } from '../../core/git/gitRepositoryHandle.js';
import { RepomixError } from '../../shared/errorHandle.js';
import { logger } from '../../shared/logger.js';
import { Spinner } from '../cliSpinner.js';
import { runDefaultAction } from './defaultAction.js';
export const runRemoteAction = (repoUrl_1, cliOptions_1, ...args_1) => __awaiter(void 0, [repoUrl_1, cliOptions_1, ...args_1], void 0, function* (repoUrl, cliOptions, deps = {
isGitInstalled,
execGitShallowClone,
getRemoteRefs,
runDefaultAction,
downloadGitHubArchive,
isGitHubRepository,
parseGitHubRepoInfo,
isArchiveDownloadSupported,
}) {
var _a;
let tempDirPath = yield createTempDirectory();
let result;
let downloadMethod = 'git';
try {
// Check if this is a GitHub repository and archive download is supported
const githubRepoInfo = deps.parseGitHubRepoInfo(repoUrl);
const shouldTryArchive = githubRepoInfo && deps.isArchiveDownloadSupported(githubRepoInfo);
if (shouldTryArchive) {
// Try GitHub archive download first
const spinner = new Spinner('Downloading repository archive...', cliOptions);
try {
spinner.start();
// Override ref with CLI option if provided
const repoInfoWithBranch = Object.assign(Object.assign({}, githubRepoInfo), { ref: (_a = cliOptions.remoteBranch) !== null && _a !== void 0 ? _a : githubRepoInfo.ref });
yield deps.downloadGitHubArchive(repoInfoWithBranch, tempDirPath, {
timeout: 60000, // 1 minute timeout for large repos
retries: 2,
}, (progress) => {
if (progress.percentage !== null) {
spinner.update(`Downloading repository archive... (${progress.percentage}%)`);
}
else {
// Show downloaded bytes when percentage is not available
const downloadedMB = (progress.downloaded / 1024 / 1024).toFixed(1);
spinner.update(`Downloading repository archive... (${downloadedMB} MB)`);
}
});
downloadMethod = 'archive';
spinner.succeed('Repository archive downloaded successfully!');
logger.log('');
}
catch (archiveError) {
spinner.fail('Archive download failed, trying git clone...');
logger.trace('Archive download error:', archiveError.message);
// Clear the temp directory for git clone attempt
yield cleanupTempDirectory(tempDirPath);
tempDirPath = yield createTempDirectory();
// Fall back to git clone
yield performGitClone(repoUrl, tempDirPath, cliOptions, deps);
downloadMethod = 'git';
}
}
else {
// Use git clone directly
yield performGitClone(repoUrl, tempDirPath, cliOptions, deps);
downloadMethod = 'git';
}
// Run the default action on the downloaded/cloned repository
result = yield deps.runDefaultAction([tempDirPath], tempDirPath, cliOptions);
// Copy output file only when not in stdout mode
// In stdout mode, output is written directly to stdout without creating a file,
// so attempting to copy a non-existent file would cause an error and exit code 1
if (!cliOptions.stdout) {
yield copyOutputToCurrentDirectory(tempDirPath, process.cwd(), result.config.output.filePath);
}
logger.trace(`Repository obtained via ${downloadMethod} method`);
}
finally {
// Cleanup the temporary directory
yield cleanupTempDirectory(tempDirPath);
}
return result;
});
/**
* Performs git clone operation with spinner and error handling
*/
const performGitClone = (repoUrl, tempDirPath, cliOptions, deps) => __awaiter(void 0, void 0, void 0, function* () {
// Check if git is installed only when we actually need to use git
if (!(yield deps.isGitInstalled())) {
throw new RepomixError('Git is not installed or not in the system PATH.');
}
// Get remote refs
let refs = [];
try {
refs = yield deps.getRemoteRefs(parseRemoteValue(repoUrl).repoUrl);
logger.trace(`Retrieved ${refs.length} refs from remote repository`);
}
catch (error) {
logger.trace('Failed to get remote refs, proceeding without them:', error.message);
}
// Parse the remote URL with the refs information
const parsedFields = parseRemoteValue(repoUrl, refs);
const spinner = new Spinner('Cloning repository...', cliOptions);
try {
spinner.start();
// Clone the repository
yield cloneRepository(parsedFields.repoUrl, tempDirPath, cliOptions.remoteBranch || parsedFields.remoteBranch, {
execGitShallowClone: deps.execGitShallowClone,
});
spinner.succeed('Repository cloned successfully!');
logger.log('');
}
catch (error) {
spinner.fail('Error during repository cloning. cleanup...');
throw error;
}
});
export const createTempDirectory = () => __awaiter(void 0, void 0, void 0, function* () {
const tempDir = yield fs.mkdtemp(path.join(os.tmpdir(), 'repomix-'));
logger.trace(`Created temporary directory. (path: ${pc.dim(tempDir)})`);
return tempDir;
});
export const cloneRepository = (url_1, directory_1, remoteBranch_1, ...args_1) => __awaiter(void 0, [url_1, directory_1, remoteBranch_1, ...args_1], void 0, function* (url, directory, remoteBranch, deps = {
execGitShallowClone,
}) {
logger.log(`Clone repository: ${url} to temporary directory. ${pc.dim(`path: ${directory}`)}`);
logger.log('');
try {
yield deps.execGitShallowClone(url, directory, remoteBranch);
}
catch (error) {
throw new RepomixError(`Failed to clone repository: ${error.message}`);
}
});
export const cleanupTempDirectory = (directory) => __awaiter(void 0, void 0, void 0, function* () {
logger.trace(`Cleaning up temporary directory: ${directory}`);
yield fs.rm(directory, { recursive: true, force: true });
});
export const copyOutputToCurrentDirectory = (sourceDir, targetDir, outputFileName) => __awaiter(void 0, void 0, void 0, function* () {
const sourcePath = path.resolve(sourceDir, outputFileName);
const targetPath = path.resolve(targetDir, outputFileName);
try {
logger.trace(`Copying output file from: ${sourcePath} to: ${targetPath}`);
// Create target directory if it doesn't exist
yield fs.mkdir(path.dirname(targetPath), { recursive: true });
yield fs.copyFile(sourcePath, targetPath);
}
catch (error) {
throw new RepomixError(`Failed to copy output file: ${error.message}`);
}
});
//# sourceMappingURL=remoteAction.js.map