@jmkim85/dev-flow-mcp
Version:
MCP-based Dev Flow - AI-powered development workflow management with 13 essential tools for TDD and context management
132 lines • 6.11 kB
JavaScript
// project-utils.ts - Project root detection and file utilities
import { promises as fs } from 'fs';
import { join } from 'path';
// Smart project root detection
export async function detectProjectRoot() {
console.error('🔍 Starting project root detection...');
// 1. Check environment variable (highest priority)
if (process.env.DEV_FLOW_PROJECT_ROOT) {
console.error(`✅ Using DEV_FLOW_PROJECT_ROOT: ${process.env.DEV_FLOW_PROJECT_ROOT}`);
return process.env.DEV_FLOW_PROJECT_ROOT;
}
// 2. Check VSCode workspace environment variables (most reliable)
if (process.env.VSCODE_WORKSPACE_FOLDER) {
console.error(`✅ Using VSCODE_WORKSPACE_FOLDER: ${process.env.VSCODE_WORKSPACE_FOLDER}`);
return process.env.VSCODE_WORKSPACE_FOLDER;
}
// 3. Try current working directory first (often more specific than VSCODE_CWD)
const cwd = process.cwd();
console.error(`🔍 Checking current working directory: ${cwd}`);
const projectRootFromCwd = await findProjectRoot(cwd);
if (projectRootFromCwd) {
console.error(`✅ Found project root from cwd: ${projectRootFromCwd}`);
// If we have VSCODE_CWD, compare which one is more specific
if (process.env.VSCODE_CWD) {
const vscodeCwd = process.env.VSCODE_CWD;
console.error(`🔍 Comparing with VSCODE_CWD: ${vscodeCwd}`);
// If current directory is a subdirectory of VSCODE_CWD, prefer current directory
if (cwd.startsWith(vscodeCwd) && cwd !== vscodeCwd) {
console.error(`✅ Current directory is more specific than VSCODE_CWD, using: ${projectRootFromCwd}`);
return projectRootFromCwd;
}
// If VSCODE_CWD is a subdirectory of current directory, check if it has project markers
if (vscodeCwd.startsWith(cwd)) {
const projectRootFromVscode = await findProjectRoot(vscodeCwd);
if (projectRootFromVscode) {
console.error(`✅ Found project root from VSCODE_CWD: ${projectRootFromVscode}`);
return projectRootFromVscode;
}
}
}
return projectRootFromCwd;
}
// 4. Fall back to VSCODE_CWD if current directory doesn't have project markers
if (process.env.VSCODE_CWD) {
console.error(`🔍 Checking VSCODE_CWD: ${process.env.VSCODE_CWD}`);
const projectRootFromVscode = await findProjectRoot(process.env.VSCODE_CWD);
if (projectRootFromVscode) {
console.error(`✅ Found project root from VSCODE_CWD: ${projectRootFromVscode}`);
return projectRootFromVscode;
}
else {
console.error(`⚠️ No project markers found in VSCODE_CWD, using as-is: ${process.env.VSCODE_CWD}`);
return process.env.VSCODE_CWD;
}
}
// 5. SSH environment: Check for VSCode Remote SSH specific variables
if (process.env.SSH_CLIENT || process.env.SSH_CONNECTION) {
console.error('🔗 SSH environment detected, checking VSCode Remote variables...');
// VSCode Remote SSH often sets these
if (process.env.VSCODE_IPC_HOOK_CLI) {
console.error('📡 VSCode Remote SSH detected');
}
// In SSH, VSCode might set the workspace in different variables
const remoteWorkspace = process.env.VSCODE_WORKSPACE || process.env.REMOTE_CONTAINERS_IPC;
if (remoteWorkspace) {
console.error(`✅ Using remote workspace: ${remoteWorkspace}`);
return remoteWorkspace;
}
}
// 6. Last resort: use current working directory
console.error(`⚠️ No project root found, using current directory: ${cwd}`);
return cwd;
}
// Find project root by looking for common project markers
export async function findProjectRoot(startPath) {
const projectMarkers = [
'.devflow', // Existing Dev Flow project (highest priority)
'.git', // Git repository
'package.json', // Node.js
'requirements.txt', // Python
'pyproject.toml', // Modern Python
'Cargo.toml', // Rust
'go.mod', // Go
'pom.xml', // Java Maven
'build.gradle', // Java Gradle
'composer.json', // PHP
'Gemfile', // Ruby
'mix.exs', // Elixir
'deno.json', // Deno
'tsconfig.json', // TypeScript
'.vscode', // VSCode workspace
'.idea' // IntelliJ workspace
];
let currentPath = startPath;
let searchDepth = 0;
const maxDepth = 10; // Prevent infinite loops
console.error(`🔍 Searching for project markers in: ${currentPath}`);
while (currentPath !== '/' && currentPath !== '' && !currentPath.match(/^[A-Z]:\\?$/) && searchDepth < maxDepth) {
console.error(`📁 Checking directory: ${currentPath}`);
for (const marker of projectMarkers) {
try {
const markerPath = join(currentPath, marker);
await fs.access(markerPath);
console.error(`✅ Found project marker '${marker}' at: ${currentPath}`);
return currentPath; // Found a project marker
}
catch {
// Continue searching
}
}
const parentPath = join(currentPath, '..');
if (parentPath === currentPath)
break; // Reached root
currentPath = parentPath;
searchDepth++;
}
console.error(`❌ No project markers found after searching ${searchDepth} directories`);
return null; // No project root found
}
// Get package version dynamically (deprecated - use version-manager.ts)
export async function getPackageVersion() {
try {
// Import the centralized version manager
const { getVersion } = await import('./version-manager.js');
return await getVersion();
}
catch (error) {
console.error('Warning: Could not read package version:', error);
return '0.0.0-error'; // Fallback version indicating error
}
}
//# sourceMappingURL=project-utils.js.map