repomix
Version:
A tool to pack repository contents to single file for AI consumption
155 lines (144 loc) ⢠5.12 kB
JavaScript
import crypto from 'node:crypto';
import fs from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';
import { generateTreeString } from '../../core/file/fileTreeGenerate.js';
const outputFileRegistry = new Map();
export const registerOutputFile = (id, filePath) => {
outputFileRegistry.set(id, filePath);
};
export const getOutputFilePath = (id) => {
return outputFileRegistry.get(id);
};
export const createToolWorkspace = async () => {
try {
const tmpBaseDir = path.join(os.tmpdir(), 'repomix', 'mcp-outputs');
await fs.mkdir(tmpBaseDir, { recursive: true });
const tempDir = await fs.mkdtemp(`${tmpBaseDir}/`);
return tempDir;
}
catch (error) {
const message = error instanceof Error ? error.message : String(error);
throw new Error(`Failed to create temporary directory: ${message}`);
}
};
export const generateOutputId = () => {
return crypto.randomBytes(8).toString('hex');
};
export const formatPackToolResponse = async (context, metrics, outputFilePath, topFilesLen = 5) => {
const outputId = generateOutputId();
registerOutputFile(outputId, outputFilePath);
const outputContent = await fs.readFile(outputFilePath, 'utf8');
const totalLines = outputContent.split('\n').length;
const topFiles = Object.entries(metrics.fileCharCounts)
.map(([filePath, charCount]) => ({
path: filePath,
charCount,
tokenCount: metrics.fileTokenCounts[filePath] || 0,
}))
.sort((a, b) => b.charCount - a.charCount)
.slice(0, topFilesLen);
const directoryStructure = generateTreeString(metrics.safeFilePaths, []);
const jsonResult = JSON.stringify({
...(context.directory ? { directory: context.directory } : {}),
...(context.repository ? { repository: context.repository } : {}),
outputFilePath,
outputId,
metrics: {
totalFiles: metrics.totalFiles,
totalCharacters: metrics.totalCharacters,
totalTokens: metrics.totalTokens,
totalLines,
topFiles,
},
}, null, 2);
return buildMcpToolSuccessResponse({
description: `
š Successfully packed codebase!\nPlease review the metrics below and consider adjusting compress/includePatterns/ignorePatterns if the token count is too high and you need to reduce it before reading the file content.
For environments with direct file system access, you can read the file directly using path: ${outputFilePath}
For environments without direct file access (e.g., web browsers or sandboxed apps), use the \`read_repomix_output\` tool with this outputId: ${outputId} to access the packed codebase contents.
The output retrieved with \`read_repomix_output\` has the following structure:
\`\`\`xml
This file is a merged representation of the entire codebase, combining all repository files into a single document.
<file_summary>
(Metadata and usage AI instructions)
</file_summary>
<directory_structure>
src/
cli/
cliOutput.ts
index.ts
(...remaining directories)
</directory_structure>
<files>
<file path="src/index.js">
// File contents here
</file>
(...remaining files)
</files>
<instruction>
(Custom instructions from output.instructionFilePath)
</instruction>
\`\`\`
You can use grep with \`path="<file-path>"\` to locate specific files within the output.
`,
result: jsonResult,
directoryStructure: directoryStructure,
outputId: outputId,
outputFilePath: outputFilePath,
totalFiles: metrics.totalFiles,
totalTokens: metrics.totalTokens,
});
};
export const convertErrorToJson = (error) => {
const timestamp = new Date().toISOString();
if (error instanceof Error) {
return {
errorMessage: error.message,
details: {
stack: error.stack,
name: error.name,
cause: error.cause,
code: 'code' in error
? error.code
: 'errno' in error
? error.errno
: undefined,
timestamp,
type: 'Error',
},
};
}
return {
errorMessage: String(error),
details: {
name: 'UnknownError',
timestamp,
type: 'Unknown',
},
};
};
export const buildMcpToolSuccessResponse = (structuredContent) => {
const textContent = structuredContent !== undefined ? JSON.stringify(structuredContent, null, 2) : 'null';
return {
content: [
{
type: 'text',
text: textContent,
},
],
structuredContent: structuredContent,
};
};
export const buildMcpToolErrorResponse = (structuredContent) => {
const textContent = structuredContent !== undefined ? JSON.stringify(structuredContent, null, 2) : 'null';
return {
isError: true,
content: [
{
type: 'text',
text: textContent,
},
],
};
};