import fs from 'fs/promises';
import path from 'path';
import { z } from 'zod';
import { detectLanguages } from '../detectors/language.js';
import { detectFrameworks, detectDatabaseHints } from '../detectors/framework.js';
import { scanTree } from '../scanners/tree.js';
import { parseDependencies } from '../scanners/dependencies.js';
import { createError, ErrorCodes } from '../utils/errors.js';
/**
* Input schema for detect_stack tool
*/
export const detectStackSchema = {
path: z.string().describe("Path to the project directory")
};
/**
* Lightweight stack detection tool
* Faster than inspect_project, focuses only on runtime/framework info
*/
export async function detectStack({ path: projectPath }) {
// Validate path exists
try {
const stats = await fs.stat(projectPath);
if (!stats.isDirectory()) {
return createError(ErrorCodes.PATH_NOT_DIRECTORY);
}
} catch (err) {
if (err.code === 'ENOENT') {
return createError(ErrorCodes.PATH_NOT_FOUND);
}
if (err.code === 'EACCES') {
return createError(ErrorCodes.ACCESS_DENIED);
}
return createError(ErrorCodes.SCAN_ERROR, err.message);
}
try {
// Quick scan with shallow depth
const { files } = await scanTree(projectPath, {
maxDepth: 2,
maxFiles: 500
});
// Parse dependencies
const dependencies = await parseDependencies(projectPath, files);
// Detect languages
const languages = await detectLanguages(projectPath, files);
// Detect frameworks
const frameworks = await detectFrameworks(projectPath, files, languages, dependencies);
// Detect database hints
const databaseHints = await detectDatabaseHints(dependencies);
// Check for frontend
const frontendFrameworks = ['React', 'Vue.js', 'Angular', 'Svelte', 'Next.js', 'Vite'];
const frontend = frameworks
.filter(f => frontendFrameworks.some(ff => f.name.includes(ff)))
.map(f => f.name);
// Build result
const result = {
runtime: languages.map(l => l.name)
};
if (frameworks.length > 0) {
result.framework = frameworks.map(f => f.name);
}
if (databaseHints.length > 0) {
result.databaseHints = databaseHints;
}
// Only include frontend if detected
if (frontend.length > 0) {
result.frontend = frontend;
}
return result;
} catch (err) {
return createError(ErrorCodes.SCAN_ERROR, err.message);
}
}