import fs from 'fs';
import path from 'path';
import { execSync } from 'child_process';
import { ApiRoute } from './crawler/api';
import { ComponentInfo } from './crawler/components';
import { PageAnalysis } from './mcp/pageAnalyzer';
import { suggestHookImplementation, suggestPageProps, loadMCPConfig } from './ai/mcpAgent';
/**
* Utility: Get diffs between generated code and current repo state
*/
function getDiff(filePath: string): string | null {
try {
const diff = execSync(`git diff HEAD -- ${filePath}`, { encoding: 'utf-8' });
return diff.trim() || null;
} catch {
return null;
}
}
/**
* Save snapshot of generated files for future diff checks
*/
export function saveSnapshot(filePath: string) {
const snapshotDir = path.join('.mcp-snapshots');
if (!fs.existsSync(snapshotDir)) fs.mkdirSync(snapshotDir);
const fileName = path.basename(filePath);
const content = fs.readFileSync(filePath, 'utf-8');
fs.writeFileSync(path.join(snapshotDir, fileName), content, 'utf-8');
}
/**
* Load snapshot content
*/
function loadSnapshot(filePath: string): string | null {
const snapshotPath = path.join('.mcp-snapshots', path.basename(filePath));
if (!fs.existsSync(snapshotPath)) return null;
return fs.readFileSync(snapshotPath, 'utf-8');
}
/**
* Check hooks for potential breakages
*/
export async function checkHooksDiff(
hooks: ApiRoute[],
hooksDir: string,
aiAgent: 'none' | 'copilot' | 'openai' | 'custom' = 'none',
) {
for (const route of hooks) {
const hookFile = path.join(hooksDir, 'hooks.ts'); // Assuming single hooks.ts
const snapshot = loadSnapshot(hookFile);
const diff = getDiff(hookFile);
if (!diff) continue;
console.log(`🔍 Detected changes in hooks: ${route.methods.join(', ')}`);
if (aiAgent !== 'none') {
for (const method of route.methods) {
const suggestion = await suggestHookImplementation(method, route, aiAgent);
console.log(`🤖 AI Suggestion for ${method}:\n${suggestion}`);
}
}
}
}
/**
* Check components for potential breakages
*/
export async function checkComponentsDiff(
components: ComponentInfo[],
componentsDir: string,
aiAgent: 'none' | 'copilot' | 'openai' | 'custom' = 'none',
) {
for (const comp of components) {
const compFile = path.join(componentsDir, path.basename(comp.filePath));
const snapshot = loadSnapshot(compFile);
const diff = getDiff(compFile);
if (!diff) continue;
console.log(`🔍 Detected changes in component: ${comp.name}`);
if (aiAgent !== 'none') {
// For demo, we reuse enrichComponents logic
const enriched = await enrichComponentDiff(comp, aiAgent);
console.log(`🤖 AI Suggestion for ${comp.name}:\n${enriched.usage}`);
}
}
}
/**
* Check pages for potential breakages
*/
export async function checkPagesDiff(
pages: PageAnalysis[],
pagesDir: string,
aiAgent: 'none' | 'copilot' | 'openai' | 'custom' = 'none',
) {
for (const page of pages) {
const pageFile = path.join(pagesDir, path.basename(page.pagePath));
const snapshot = loadSnapshot(pageFile);
const diff = getDiff(pageFile);
if (!diff) continue;
console.log(`🔍 Detected changes in page: ${page.pagePath}`);
if (aiAgent !== 'none') {
const suggestion = await suggestPageProps(page.pagePath, page, aiAgent);
console.log(`🤖 AI Suggestion for ${page.pagePath}:\n${suggestion}`);
}
}
}
/**
* Placeholder: enrich a component for diff checking
*/
async function enrichComponentDiff(
comp: ComponentInfo,
aiAgent: 'none' | 'copilot' | 'openai' | 'custom',
) {
// Here you can reuse your enrichComponents logic or AI agent
return {
...comp,
usage: `AI usage example for ${comp.name} (${aiAgent})`,
};
}