simple-task-master
Version:
A simple command-line task management tool
237 lines • 10.2 kB
JavaScript
;
/**
* 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