UNPKG

@jjdenhertog/ai-driven-development

Version:

AI-driven development workflow with learning capabilities for Claude

165 lines 9.09 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.executeTaskCommand = executeTaskCommand; const fs_extra_1 = require("fs-extra"); const checkGitAuth_1 = require("../utils/git/checkGitAuth"); /* eslint-disable @typescript-eslint/restrict-template-expressions */ const claude_wrapper_1 = require("../../claude-wrapper"); const addHooks_1 = __importDefault(require("../utils/claude/addHooks")); const removeHooks_1 = __importDefault(require("../utils/claude/removeHooks")); const checkGitInitialized_1 = require("../utils/git/checkGitInitialized"); const createCommit_1 = require("../utils/git/createCommit"); const ensureBranch_1 = require("../utils/git/ensureBranch"); const ensureWorktree_1 = require("../utils/git/ensureWorktree"); const getGitInstance_1 = require("../utils/git/getGitInstance"); const isInWorktree_1 = require("../utils/git/isInWorktree"); const pullBranch_1 = require("../utils/git/pullBranch"); const pushBranch_1 = require("../utils/git/pushBranch"); const stageAllFiles_1 = require("../utils/git/stageAllFiles"); const logger_1 = require("../utils/logger"); const createSession_1 = require("../utils/storage/createSession"); const createSessionReport_1 = require("../utils/storage/createSessionReport"); const createTaskPR_1 = require("../utils/tasks/createTaskPR"); const getBranchName_1 = require("../utils/tasks/getBranchName"); const updateTaskFile_1 = require("../utils/tasks/updateTaskFile"); const validateTaskForExecution_1 = require("../utils/tasks/validateTaskForExecution"); function executeTaskCommand(options) { return __awaiter(this, void 0, void 0, function* () { const { taskId, dryRun, force, dangerouslySkipPermission } = options; // Ensure git auth if (!(yield (0, checkGitInitialized_1.checkGitInitialized)())) throw new Error('Git is not initialized. Please run `git init` in the root of the repository.'); // Check if we are in a worktree if (yield (0, isInWorktree_1.isInWorktree)()) throw new Error('This command must be run from the root of the repository.'); const { logsDir, logPath } = (0, createSession_1.createSession)(taskId); // Validate the task - expecting pending or in-progress status const task = yield (0, validateTaskForExecution_1.validateTaskForExecution)({ taskId, expectedStatuses: ['pending', 'in-progress'], force, refresh: true }); /////////////////////////////////////////////////////////// // Goal: // 1. Ensure the branch for the task exists // 2. Ensure the worktree for the task exists // 3. Ensure the worktree branh is pulled /////////////////////////////////////////////////////////// (0, logger_1.log)(`Preparing git branch...`, 'success', undefined, logPath); const branchName = (0, getBranchName_1.getBranchName)(task); yield (0, ensureBranch_1.ensureBranch)(branchName); const worktreeFolder = branchName.split('/').at(-1) || branchName; const worktreePath = `.aidev-${worktreeFolder}`; yield (0, ensureWorktree_1.ensureWorktree)(branchName, worktreePath); yield (0, pullBranch_1.pullBranch)(branchName, worktreePath); (0, logger_1.log)(`Executing Task: ${task.id} - ${task.name}`, 'info', undefined, logPath); if (dryRun) { (0, logger_1.log)('Dry Run Mode - No changes will be made', 'warn', undefined, logPath); (0, logger_1.log)(` Task File: ${task.path}`, 'info', undefined, logPath); (0, logger_1.log)(` Branch Name: ${(0, getBranchName_1.getBranchName)(task)}`, 'info', undefined, logPath); return; } // Create session (0, logger_1.log)(`Starting execution of task ${task.id}`, 'info', undefined, logPath); // Update task file with execution metadata (0, updateTaskFile_1.updateTaskFile)(task.path, { branch: branchName, started_at: new Date().toISOString() }); // Step 3: Execute Claude (0, logger_1.log)('Starting Claude with aidev-code-task command...', 'success', undefined, logPath); const args = []; if (dangerouslySkipPermission) args.push('--dangerously-skip-permissions'); // Add hooks for claude (0, addHooks_1.default)(worktreePath); // Execute Claude and wait for completion const result = yield (0, claude_wrapper_1.executeClaudeCommand)({ cwd: worktreePath, command: `/aidev-code-task ${task.id}-${task.name}`, args, }); // We no longer capture output - hooks will handle logging (0, logger_1.log)(`\nClaude command exited with code: ${result.exitCode}`, 'info', undefined, logPath); // Create session report from debug logs and transcript (0, logger_1.log)('Creating session report...', 'info', undefined, logPath); const sessionReport = yield (0, createSessionReport_1.createSessionReport)({ taskId: task.id, taskName: task.name, worktreePath, logsDir, exitCode: result.exitCode }); // Remove hooks for claude (0, removeHooks_1.default)(worktreePath); if (!sessionReport.success) { (0, logger_1.log)(`Claude command failed`, 'error', undefined, logPath); (0, updateTaskFile_1.updateTaskFile)(task.path, { status: 'failed' }); (0, logger_1.log)(`Removing worktree...`, 'info', undefined, logPath); const git = (0, getGitInstance_1.getGitInstance)(); try { yield git.raw(['worktree', 'remove', '--force', worktreePath]); } catch (_error) { (0, fs_extra_1.rmSync)(worktreePath, { force: true, recursive: true }); } yield git.raw(['branch', '-D', branchName, '--force']); return; } /////////////////////////////////////////////////////////// // Update task status and create PR /////////////////////////////////////////////////////////// try { (0, logger_1.log)(`Claude command success...`, 'success', undefined, logPath); // Then immediately to completed for PR creation (0, updateTaskFile_1.updateTaskFile)(task.path, { status: 'completed' }); (0, logger_1.log)(`Committing and pushing changes...`, 'info', undefined, logPath); yield (0, stageAllFiles_1.stageAllFiles)(worktreePath); yield (0, createCommit_1.createCommit)(`complete task ${task.id} - ${task.name} (AI-generated)`, { prefix: 'feat', cwd: worktreePath }); const pushResult = yield (0, pushBranch_1.pushBranch)(branchName, worktreePath); if (!pushResult.success) (0, logger_1.log)(`Failed to push changes to remote: ${pushResult.error}`, 'error', undefined, logPath); // Create PR if ((0, checkGitAuth_1.checkGitAuth)()) { (0, logger_1.log)(`Creating PR...`, 'info', undefined, logPath); yield (0, createTaskPR_1.createTaskPR)(task, branchName, worktreePath); } /////////////////////////////////////////////////////////// // Remove work tree /////////////////////////////////////////////////////////// (0, logger_1.log)(`Removing worktree...`, 'info', undefined, logPath); const git = (0, getGitInstance_1.getGitInstance)(); try { yield git.raw(['worktree', 'remove', '--force', worktreePath]); } catch (_error) { (0, fs_extra_1.rmSync)(worktreePath, { force: true, recursive: true }); } yield git.raw(['branch', '-D', branchName, '--force']); } catch (error) { (0, logger_1.log)(`Failed to finish task ${task.id} - ${task.name}: ${error instanceof Error ? error.message : 'Unknown error'}`, 'error'); } }); } //# sourceMappingURL=executeTaskCommand.js.map