UNPKG

simple-task-master

Version:
237 lines 10.2 kB
"use strict"; /** * Initialize STM repository command */ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.initCommand = void 0; const commander_1 = require("commander"); const fs = __importStar(require("fs/promises")); const path = __importStar(require("path")); const lock_manager_1 = require("../lib/lock-manager"); const utils_1 = require("../lib/utils"); const output_1 = require("../lib/output"); const errors_1 = require("../lib/errors"); const constants_1 = require("../lib/constants"); const path_validation_1 = require("../lib/path-validation"); /** * Initialize STM repository in the current directory */ async function initializeRepository(options) { const lockManager = new lock_manager_1.LockManager(process.cwd()); try { await lockManager.acquire(); const projectRoot = process.cwd(); const baseDir = constants_1.PATHS.getBaseDir(projectRoot); const configPath = constants_1.PATHS.getConfigPath(projectRoot); // Validate the custom tasks directory BEFORE checking if initialized // This ensures validation errors are caught even on already-initialized workspaces let validatedPath; if (options.tasksDir) { validatedPath = (0, path_validation_1.validateTasksDir)(options.tasksDir); } // Check if already initialized const isInitialized = await (0, utils_1.fileExists)(configPath); if (isInitialized) { (0, output_1.printWarning)('STM repository is already initialized'); return; } // Determine tasks directory let tasksDir; let customTasksDir; if (options.tasksDir && validatedPath) { // Use the already validated path // Convert to absolute path if relative if (!path.isAbsolute(validatedPath)) { tasksDir = path.join(projectRoot, validatedPath); // Store relative path in config, preserving ./ prefix if it was provided customTasksDir = options.tasksDir.startsWith('./') && !validatedPath.startsWith('./') ? './' + validatedPath : validatedPath; } else { tasksDir = validatedPath; // Store as relative path in config for portability // Use resolved real paths to handle symlinks properly const fs = require('fs'); const realProjectRoot = fs.realpathSync(projectRoot); // For the target path, resolve the parent directory since the path might not exist yet const validatedDir = path.dirname(validatedPath); let realValidatedDir; try { realValidatedDir = fs.realpathSync(validatedDir); } catch { // If parent doesn't exist, just use path.resolve realValidatedDir = path.resolve(validatedDir); } const realValidatedPath = path.join(realValidatedDir, path.basename(validatedPath)); customTasksDir = path.relative(realProjectRoot, realValidatedPath); } // Additional validation - ensure it's not inside .simple-task-master const relativeToBase = path.relative(baseDir, tasksDir); if (!relativeToBase.startsWith('..') && relativeToBase !== '') { throw new errors_1.ValidationError('Custom tasks directory cannot be inside .simple-task-master directory'); } // Check if the directory already exists and has files try { const stats = await fs.stat(tasksDir); if (stats.isDirectory()) { const files = await fs.readdir(tasksDir); if (files.length > 0) { (0, output_1.printWarning)(`Directory ${options.tasksDir} already exists and contains files`); } } } catch { // Directory doesn't exist, which is fine } } else { // Use default tasks directory tasksDir = constants_1.PATHS.getTasksDir(projectRoot); } // Create directories await (0, utils_1.ensureDirectory)(baseDir); await (0, utils_1.ensureDirectory)(tasksDir); // Create configuration with optional custom tasks directory const config = { schema: constants_1.DEFAULT_CONFIG.SCHEMA_VERSION, lockTimeoutMs: constants_1.DEFAULT_CONFIG.LOCK_TIMEOUT_MS, maxTaskSizeBytes: constants_1.DEFAULT_CONFIG.MAX_TASK_SIZE_BYTES }; // Only add tasksDir to config if it's custom if (customTasksDir) { config.tasksDir = customTasksDir; } await fs.writeFile(configPath, JSON.stringify(config, null, 2), 'utf8'); // Update .gitignore if it exists const isAbsolutePath = options.tasksDir ? path.isAbsolute((0, path_validation_1.validateTasksDir)(options.tasksDir)) : false; await updateGitignore(projectRoot, customTasksDir, isAbsolutePath); (0, output_1.printSuccess)('Initialized STM repository'); (0, output_1.printSuccess)(`Created ${path.relative(projectRoot, baseDir)}/`); (0, output_1.printSuccess)(`Created ${path.relative(projectRoot, tasksDir)}/`); (0, output_1.printSuccess)(`Created ${path.relative(projectRoot, configPath)}`); if (customTasksDir) { (0, output_1.printSuccess)(`Using custom tasks directory: ${customTasksDir}`); } } catch (error) { if (error instanceof errors_1.ValidationError || error instanceof errors_1.FileSystemError || error instanceof errors_1.ConfigurationError) { (0, output_1.printError)(error.message); process.exit(1); } throw error; } finally { await lockManager.release(); } } /** * Updates .gitignore to ignore task files but track config */ async function updateGitignore(projectRoot, customTasksDir, isAbsolutePath) { const gitignorePath = path.join(projectRoot, '.gitignore'); try { // Check if .gitignore exists const gitignoreExists = await (0, utils_1.fileExists)(gitignorePath); let gitignoreContent = ''; if (gitignoreExists) { gitignoreContent = await fs.readFile(gitignorePath, 'utf8'); } // Determine patterns to check/add let stmTasksPattern; if (customTasksDir) { // Warn if user provided an absolute path if (isAbsolutePath) { (0, output_1.printWarning)('Absolute paths in .gitignore may not work as expected across different systems'); } // Use the relative path (customTasksDir is always relative at this point) stmTasksPattern = customTasksDir.endsWith('/') ? customTasksDir : customTasksDir + '/'; } else { // Default pattern stmTasksPattern = '.simple-task-master/tasks/'; } const stmLockPattern = '.simple-task-master/lock'; const hasTasksIgnore = gitignoreContent.includes(stmTasksPattern); const hasLockIgnore = gitignoreContent.includes(stmLockPattern); if (!hasTasksIgnore || !hasLockIgnore) { const linesToAdd = []; if (!hasTasksIgnore || !hasLockIgnore) { linesToAdd.push(''); linesToAdd.push('# Simple Task Master - User tasks are git-ignored'); } if (!hasTasksIgnore) { linesToAdd.push(stmTasksPattern); } if (!hasLockIgnore) { linesToAdd.push(stmLockPattern); } const updatedContent = gitignoreContent + linesToAdd.join('\n') + '\n'; await fs.writeFile(gitignorePath, updatedContent, 'utf8'); if (gitignoreExists) { (0, output_1.printSuccess)('Updated .gitignore'); } else { (0, output_1.printSuccess)('Created .gitignore'); } } } catch (error) { // Non-fatal error (0, output_1.printWarning)(`Could not update .gitignore: ${error.message}`); } } /** * Create the init command */ exports.initCommand = new commander_1.Command('init') .description('Initialize STM repository in the current directory') .option('--tasks-dir <path>', 'Custom directory for storing task files') .action(async (options) => { try { await initializeRepository(options); } catch (error) { (0, output_1.printError)(error); process.exit(1); } }); //# sourceMappingURL=init.js.map