UNPKG

@pimzino/claude-code-spec-workflow

Version:

Automated workflows for Claude Code. Includes spec-driven development (Requirements → Design → Tasks → Implementation) with intelligent task execution, optional steering documents and streamlined bug fix workflow (Report → Analyze → Fix → Verify). We have

173 lines 5.37 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.detectProjectType = detectProjectType; exports.validateClaudeCode = validateClaudeCode; exports.fileExists = fileExists; exports.ensureDirectory = ensureDirectory; exports.isPortAvailable = isPortAvailable; exports.findAvailablePort = findAvailablePort; exports.getBestAvailablePort = getBestAvailablePort; const fs_1 = require("fs"); const path_1 = require("path"); const child_process_1 = require("child_process"); const util_1 = require("util"); const net_1 = require("net"); const execAsync = (0, util_1.promisify)(child_process_1.exec); /** * Detects project type(s) based on files present in the project directory. * Supports multiple project types including Node.js, Python, Java, C#, Go, Rust, PHP, and Ruby. * * @param projectPath - Path to the project directory to analyze * @returns Promise resolving to array of detected project type names * * @example * ```typescript * const types = await detectProjectType('/path/to/project'); * console.log(types); // ['Node.js', 'TypeScript'] * ``` */ async function detectProjectType(projectPath) { const indicators = { 'Node.js': ['package.json', 'node_modules'], Python: ['requirements.txt', 'setup.py', 'pyproject.toml', '__pycache__'], Java: ['pom.xml', 'build.gradle'], 'C#': ['*.csproj', '*.sln'], Go: ['go.mod', 'go.sum'], Rust: ['Cargo.toml', 'Cargo.lock'], PHP: ['composer.json', 'vendor'], Ruby: ['Gemfile', 'Gemfile.lock'], }; const detected = []; for (const [projectType, files] of Object.entries(indicators)) { for (const file of files) { try { if (file.includes('*')) { // Handle glob patterns - simplified check const dirContents = await fs_1.promises.readdir(projectPath); const extension = file.replace('*', ''); if (dirContents.some((f) => f.endsWith(extension))) { detected.push(projectType); break; } } else { await fs_1.promises.access((0, path_1.join)(projectPath, file)); detected.push(projectType); break; } } catch { // File doesn't exist, continue } } } return detected; } /** * Validates that Claude Code CLI is installed and accessible. * * @returns Promise resolving to true if Claude Code is available, false otherwise * * @example * ```typescript * const isInstalled = await validateClaudeCode(); * if (!isInstalled) { * console.log('Please install Claude Code first'); * } * ``` */ async function validateClaudeCode() { try { await execAsync('claude --version'); return true; } catch { return false; } } /** * Checks if a file exists at the given path. * * @param filePath - Path to the file to check * @returns Promise resolving to true if file exists, false otherwise * * @example * ```typescript * const exists = await fileExists('package.json'); * if (exists) { * console.log('Found package.json'); * } * ``` */ async function fileExists(filePath) { try { await fs_1.promises.access(filePath); return true; } catch { return false; } } /** * Ensures a directory exists by creating it recursively if needed. * * @param dirPath - Path to the directory to create * @throws Error if directory creation fails for reasons other than already existing * * @example * ```typescript * await ensureDirectory('.claude/specs/my-feature'); * // Directory structure is now guaranteed to exist * ``` */ async function ensureDirectory(dirPath) { try { await fs_1.promises.mkdir(dirPath, { recursive: true }); } catch (error) { if (error instanceof Error && 'code' in error && error.code !== 'EEXIST') { throw error; } } } /** * Check if a port is available */ async function isPortAvailable(port) { return new Promise((resolve) => { const server = (0, net_1.createServer)(); server.listen(port, () => { server.close(() => resolve(true)); }); server.on('error', () => { resolve(false); }); }); } /** * Find an available port starting from a given port number */ async function findAvailablePort(startPort = 3000, maxAttempts = 100) { for (let port = startPort; port < startPort + maxAttempts; port++) { if (await isPortAvailable(port)) { return port; } } throw new Error(`Could not find an available port after checking ${maxAttempts} ports starting from ${startPort}`); } /** * Get the best available port from a list of preferred ports, with fallback */ async function getBestAvailablePort(preferredPorts = [3000, 3001, 3002, 8080, 8000, 4000]) { // First try the preferred ports for (const port of preferredPorts) { if (await isPortAvailable(port)) { return port; } } // Fall back to finding any available port starting from 3000 return findAvailablePort(3000); } //# sourceMappingURL=utils.js.map