UNPKG

tdd-guard

Version:

TDD Guard enforces Test-Driven Development principles using Claude Code hooks

97 lines (96 loc) 3.72 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Config = void 0; const path_1 = __importDefault(require("path")); const TEST_RESULTS_FILENAME = 'test.json'; const TODOS_FILENAME = 'todos.json'; const MODIFICATIONS_FILENAME = 'modifications.json'; const LINT_FILENAME = 'lint.json'; const CONFIG_FILENAME = 'config.json'; class Config { static DEFAULT_DATA_DIR = '.claude/tdd-guard/data'; dataDir; useSystemClaude; anthropicApiKey; modelType; linterType; constructor(options) { const mode = options?.mode ?? 'production'; this.dataDir = this.getDataDir(options); this.useSystemClaude = this.getUseSystemClaude(options); this.anthropicApiKey = this.getAnthropicApiKey(options); this.modelType = this.getModelType(options, mode); this.linterType = this.getLinterType(options); } getDataDir(options) { // Determine the base directory const baseDir = options?.projectRoot ?? this.getValidatedClaudeProjectDir(); // If we have a base directory, construct the full path if (baseDir) { return path_1.default.join(baseDir, ...Config.DEFAULT_DATA_DIR.split('/')); } // Default to relative path return Config.DEFAULT_DATA_DIR; } getUseSystemClaude(options) { return options?.useSystemClaude ?? process.env.USE_SYSTEM_CLAUDE === 'true'; } getAnthropicApiKey(options) { return options?.anthropicApiKey ?? process.env.TDD_GUARD_ANTHROPIC_API_KEY; } getModelType(options, mode) { return (options?.modelType ?? this.getEnvironmentModelType(mode) ?? 'claude_cli'); } getEnvironmentModelType(mode) { if (mode === 'test' && process.env.TEST_MODEL_TYPE) { return process.env.TEST_MODEL_TYPE; } return process.env.MODEL_TYPE; } get testResultsFilePath() { return path_1.default.join(this.dataDir, TEST_RESULTS_FILENAME); } get todosFilePath() { return path_1.default.join(this.dataDir, TODOS_FILENAME); } get modificationsFilePath() { return path_1.default.join(this.dataDir, MODIFICATIONS_FILENAME); } get lintFilePath() { return path_1.default.join(this.dataDir, LINT_FILENAME); } get configFilePath() { return path_1.default.join(this.dataDir, CONFIG_FILENAME); } getLinterType(options) { if (options?.linterType) { return options.linterType.toLowerCase(); } const envValue = process.env.LINTER_TYPE?.toLowerCase(); return envValue && envValue.trim() !== '' ? envValue : undefined; } getValidatedClaudeProjectDir() { const projectDir = process.env.CLAUDE_PROJECT_DIR; if (!projectDir) { return null; } // Validate that CLAUDE_PROJECT_DIR is an absolute path if (!path_1.default.isAbsolute(projectDir)) { throw new Error('CLAUDE_PROJECT_DIR must be an absolute path'); } // Validate that CLAUDE_PROJECT_DIR does not contain path traversal if (projectDir.includes('..')) { throw new Error('CLAUDE_PROJECT_DIR must not contain path traversal'); } // Validate that current working directory is within CLAUDE_PROJECT_DIR const cwd = process.cwd(); if (!cwd.startsWith(projectDir)) { throw new Error('CLAUDE_PROJECT_DIR must contain the current working directory'); } return projectDir; } } exports.Config = Config;