ripple-ai-detector
Version:
🌊 Ripple AI Bug Detector - Built by an AI that knows its flaws. Catch AI-generated bugs before you commit.
201 lines • 7.45 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.GitManager = void 0;
const simple_git_1 = __importDefault(require("simple-git"));
const path_1 = __importDefault(require("path"));
const file_utils_1 = require("../utils/file-utils");
class GitManager {
git;
cwd;
constructor(cwd = process.cwd()) {
this.cwd = cwd;
this.git = (0, simple_git_1.default)(cwd);
}
// Check if current directory is a git repository
async isGitRepository() {
try {
await this.git.status();
return true;
}
catch {
return false;
}
}
// Get git repository information
async getGitInfo() {
try {
const isRepo = await this.isGitRepository();
if (!isRepo) {
return {
isRepository: false,
hasChanges: false,
stagedFiles: [],
modifiedFiles: []
};
}
const status = await this.git.status();
const branch = await this.git.revparse(['--abbrev-ref', 'HEAD']);
const commit = await this.git.revparse(['HEAD']).catch(() => undefined);
return {
isRepository: true,
branch: branch.trim(),
commit: commit?.trim(),
hasChanges: status.files.length > 0,
stagedFiles: status.staged,
modifiedFiles: status.modified
};
}
catch (error) {
throw new Error(`Git operation failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
// Get staged files (ready to commit)
async getStagedFiles() {
try {
const isRepo = await this.isGitRepository();
if (!isRepo) {
return [];
}
const status = await this.git.status();
// Get staged files and convert to absolute paths
const stagedFiles = status.staged
.filter(file => file_utils_1.FileUtils.isSupportedFile(file))
.map(file => path_1.default.resolve(this.cwd, file));
return stagedFiles;
}
catch (error) {
throw new Error(`Failed to get staged files: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
// Get all modified files (staged + unstaged)
async getModifiedFiles() {
try {
const isRepo = await this.isGitRepository();
if (!isRepo) {
return [];
}
const status = await this.git.status();
// Combine staged and modified files
const allModified = [...new Set([...status.staged, ...status.modified])]
.filter(file => file_utils_1.FileUtils.isSupportedFile(file))
.map(file => path_1.default.resolve(this.cwd, file));
return allModified;
}
catch (error) {
throw new Error(`Failed to get modified files: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
// Get all JavaScript/TypeScript files in repository
async getAllJSFiles() {
try {
const files = await file_utils_1.FileUtils.getJSFiles(this.cwd);
// Filter out files that are ignored by git
const filteredFiles = [];
for (const file of files) {
const relativePath = path_1.default.relative(this.cwd, file);
const isIgnored = await this.isFileIgnored(relativePath);
if (!isIgnored) {
filteredFiles.push(file);
}
}
return filteredFiles;
}
catch (error) {
throw new Error(`Failed to get JS files: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
// Check if file is ignored by git
async isFileIgnored(filePath) {
try {
const isRepo = await this.isGitRepository();
if (!isRepo) {
return false;
}
const result = await this.git.raw(['check-ignore', filePath]).catch(() => null);
return result !== null;
}
catch {
return false;
}
}
// Get diff for specific files
async getDiff(files) {
try {
const isRepo = await this.isGitRepository();
if (!isRepo) {
return '';
}
if (files && files.length > 0) {
// Get diff for specific files
const relativePaths = files.map(file => path_1.default.relative(this.cwd, file));
return await this.git.diff(['--cached', ...relativePaths]);
}
else {
// Get diff for all staged files
return await this.git.diff(['--cached']);
}
}
catch (error) {
throw new Error(`Failed to get diff: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
// Get changes for analysis
async getChanges(files) {
try {
const isRepo = await this.isGitRepository();
if (!isRepo) {
return [];
}
const status = await this.git.status();
const changes = [];
// Process staged files
for (const file of status.staged) {
if (!files || files.some(f => path_1.default.resolve(this.cwd, file) === f)) {
const diff = await this.git.diff(['--cached', '--numstat', file]);
const stats = this.parseNumstat(diff);
changes.push({
file: path_1.default.resolve(this.cwd, file),
status: 'modified', // Staged files are considered modified
additions: stats.additions,
deletions: stats.deletions
});
}
}
return changes;
}
catch (error) {
throw new Error(`Failed to get changes: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
// Parse numstat output to get additions/deletions
parseNumstat(numstat) {
const lines = numstat.trim().split('\n').filter(line => line.length > 0);
if (lines.length === 0) {
return { additions: 0, deletions: 0 };
}
const parts = lines[0].split('\t');
return {
additions: parseInt(parts[0]) || 0,
deletions: parseInt(parts[1]) || 0
};
}
// Get recent commits (for AI pattern detection)
async getRecentCommits(count = 10) {
try {
const isRepo = await this.isGitRepository();
if (!isRepo) {
return [];
}
const log = await this.git.log({ maxCount: count });
return [...log.all];
}
catch (error) {
throw new Error(`Failed to get recent commits: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
}
exports.GitManager = GitManager;
//# sourceMappingURL=git-manager.js.map