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

320 lines 12.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SpecWorkflowSetup = void 0; const fs_1 = require("fs"); const path_1 = require("path"); const task_generator_1 = require("./task-generator"); // CLAUDE.md generation removed - all workflow instructions now in individual commands // Script imports removed in v1.2.5 - task command generation now uses NPX command /** * Main class that orchestrates the entire spec workflow setup process. * Creates directory structure, commands, templates, and configuration files. * * @example * ```typescript * const setup = new SpecWorkflowSetup('/my/project'); * await setup.setupWorkflow(); * ``` */ class SpecWorkflowSetup { constructor(projectRoot = process.cwd()) { this.projectRoot = projectRoot; this.claudeDir = (0, path_1.join)(projectRoot, '.claude'); this.commandsDir = (0, path_1.join)(this.claudeDir, 'commands'); this.specsDir = (0, path_1.join)(this.claudeDir, 'specs'); this.templatesDir = (0, path_1.join)(this.claudeDir, 'templates'); // scriptsDir initialization removed in v1.2.5 this.steeringDir = (0, path_1.join)(this.claudeDir, 'steering'); this.bugsDir = (0, path_1.join)(this.claudeDir, 'bugs'); this.agentsDir = (0, path_1.join)(this.claudeDir, 'agents'); // Agents are now mandatory - no longer configurable // Initialize source markdown directories this.markdownDir = (0, path_1.join)(__dirname, 'markdown'); this.markdownCommandsDir = (0, path_1.join)(this.markdownDir, 'commands'); this.markdownTemplatesDir = (0, path_1.join)(this.markdownDir, 'templates'); this.markdownAgentsDir = (0, path_1.join)(this.markdownDir, 'agents'); } async claudeDirectoryExists() { try { await fs_1.promises.access(this.claudeDir); return true; } catch { return false; } } /** * Check if the installation is complete by verifying all required files and directories exist * This prevents treating incomplete installations as complete ones */ async isInstallationComplete() { try { // First check if .claude directory exists if (!await this.claudeDirectoryExists()) { return false; } // Check all required directories const requiredDirectories = [ this.commandsDir, this.specsDir, this.templatesDir, this.steeringDir, this.bugsDir ]; // Agents are now mandatory requiredDirectories.push(this.agentsDir); for (const dir of requiredDirectories) { try { await fs_1.promises.access(dir); } catch { return false; } } // Check all required command files const requiredCommands = [ 'spec-create.md', 'spec-execute.md', 'spec-status.md', 'spec-list.md', 'spec-steering-setup.md', 'bug-create.md', 'bug-analyze.md', 'bug-fix.md', 'bug-verify.md', 'bug-status.md' ]; for (const commandFile of requiredCommands) { try { await fs_1.promises.access((0, path_1.join)(this.commandsDir, commandFile)); } catch { return false; } } // Check all required template files const requiredTemplates = [ 'requirements-template.md', 'design-template.md', 'tasks-template.md', 'product-template.md', 'tech-template.md', 'structure-template.md', 'bug-report-template.md', 'bug-analysis-template.md', 'bug-verification-template.md' ]; for (const templateFile of requiredTemplates) { try { await fs_1.promises.access((0, path_1.join)(this.templatesDir, templateFile)); } catch { return false; } } // Check required agent files (agents are now mandatory) const requiredAgents = [ 'spec-requirements-validator.md', 'spec-design-validator.md', 'spec-task-validator.md', 'spec-task-executor.md', ]; for (const agentFile of requiredAgents) { try { await fs_1.promises.access((0, path_1.join)(this.agentsDir, agentFile)); } catch { return false; } } return true; } catch { return false; } } async setupDirectories() { const directories = [ this.claudeDir, this.commandsDir, this.specsDir, this.templatesDir, // scriptsDir removed from directory creation this.steeringDir, this.bugsDir ]; // Agents are now mandatory directories.push(this.agentsDir); for (const dir of directories) { await fs_1.promises.mkdir(dir, { recursive: true }); } } async createSlashCommands() { const commandNames = [ 'spec-create', 'spec-execute', 'spec-status', 'spec-list', 'spec-steering-setup', 'bug-create', 'bug-analyze', 'bug-fix', 'bug-verify', 'bug-status' ]; for (const commandName of commandNames) { const sourceFile = (0, path_1.join)(this.markdownCommandsDir, `${commandName}.md`); const destFile = (0, path_1.join)(this.commandsDir, `${commandName}.md`); try { // Delete existing file if it exists to ensure clean replacement try { await fs_1.promises.unlink(destFile); } catch { // File might not exist, which is fine } const commandContent = await fs_1.promises.readFile(sourceFile, 'utf-8'); await fs_1.promises.writeFile(destFile, commandContent, 'utf-8'); } catch (error) { console.error(`Failed to copy command ${commandName}:`, error); throw error; } } } async createTemplates() { const templateNames = [ 'requirements-template.md', 'design-template.md', 'tasks-template.md', 'product-template.md', 'tech-template.md', 'structure-template.md', 'bug-report-template.md', 'bug-analysis-template.md', 'bug-verification-template.md' ]; for (const templateName of templateNames) { const sourceFile = (0, path_1.join)(this.markdownTemplatesDir, templateName); const destFile = (0, path_1.join)(this.templatesDir, templateName); try { // Delete existing file if it exists to ensure clean replacement try { await fs_1.promises.unlink(destFile); } catch { // File might not exist, which is fine } const templateContent = await fs_1.promises.readFile(sourceFile, 'utf-8'); await fs_1.promises.writeFile(destFile, templateContent, 'utf-8'); } catch (error) { console.error(`Failed to copy template ${templateName}:`, error); throw error; } } } // NOTE: Script creation removed in v1.2.5 - task command generation now uses NPX command async setupAgents() { // Agents are now mandatory - always create them const agentFiles = [ 'spec-requirements-validator.md', 'spec-design-validator.md', 'spec-task-validator.md', 'spec-task-executor.md', ]; for (const agentFile of agentFiles) { const sourceFile = (0, path_1.join)(this.markdownAgentsDir, agentFile); const destFile = (0, path_1.join)(this.agentsDir, agentFile); try { // Delete existing file if it exists to ensure clean replacement try { await fs_1.promises.unlink(destFile); } catch { // File might not exist, which is fine } const agentContent = await fs_1.promises.readFile(sourceFile, 'utf-8'); await fs_1.promises.writeFile(destFile, agentContent, 'utf-8'); } catch (error) { console.error(`Failed to copy agent ${agentFile}:`, error); throw error; } } } // CLAUDE.md creation removed - all workflow instructions now in individual commands /** * Auto-generate task commands for all existing specs */ async autoGenerateTaskCommands() { try { // Check if specs directory exists await fs_1.promises.access(this.specsDir); } catch { // No specs directory, nothing to generate return; } try { const specsEntries = await fs_1.promises.readdir(this.specsDir, { withFileTypes: true }); const specDirs = specsEntries .filter(entry => entry.isDirectory()) .map(entry => entry.name); if (specDirs.length === 0) { return; } console.log(`Auto-generating task commands for ${specDirs.length} existing spec(s)...`); for (const specName of specDirs) { const tasksFile = (0, path_1.join)(this.specsDir, specName, 'tasks.md'); const commandsSpecDir = (0, path_1.join)(this.commandsDir, specName); try { // Check if tasks.md exists await fs_1.promises.access(tasksFile); // Read tasks.md const tasksContent = await fs_1.promises.readFile(tasksFile, 'utf8'); // Parse tasks and generate commands const tasks = (0, task_generator_1.parseTasksFromMarkdown)(tasksContent); if (tasks.length === 0) { continue; } // Delete existing task commands for this spec try { await fs_1.promises.rm(commandsSpecDir, { recursive: true }); } catch { // Directory might not exist } // Create spec commands directory await fs_1.promises.mkdir(commandsSpecDir, { recursive: true }); // Generate commands for (const task of tasks) { await (0, task_generator_1.generateTaskCommand)(commandsSpecDir, specName, task); } console.log(` Generated ${tasks.length} task commands for spec: ${specName}`); } catch { // tasks.md doesn't exist for this spec, skip continue; } } } catch { // Error reading specs directory, skip return; } } async runSetup() { await this.setupDirectories(); await this.createSlashCommands(); await this.createTemplates(); await this.setupAgents(); // Script creation removed in v1.2.5 - using NPX command instead // spec-config.json creation removed - not required // CLAUDE.md creation removed - all workflow instructions now in individual commands // Auto-generate task commands for existing specs await this.autoGenerateTaskCommands(); } } exports.SpecWorkflowSetup = SpecWorkflowSetup; //# sourceMappingURL=setup.js.map