UNPKG

ccguard

Version:

Automated enforcement of net-negative LOC, complexity constraints, and quality standards for Claude code

248 lines 8.81 kB
"use strict"; 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.GuardManager = void 0; const HotConfigLoader_1 = require("../config/HotConfigLoader"); const SnapshotManager_1 = require("../snapshot/SnapshotManager"); const HistoryManager_1 = require("../history/HistoryManager"); const path = __importStar(require("path")); class GuardManager { storage; configLoader; rootDir; snapshotManager; hotConfigLoader; historyManager; constructor(storage, configLoader, rootDir = process.cwd()) { this.storage = storage; this.configLoader = configLoader; this.rootDir = rootDir; this.historyManager = new HistoryManager_1.HistoryManager(storage); if (configLoader) { this.hotConfigLoader = new HotConfigLoader_1.HotConfigLoader(configLoader, storage); } } async isEnabled() { const state = await this.storage.getGuardState(); return state?.enabled ?? false; // Default to disabled } async enable() { const state = { enabled: true, lastUpdated: new Date().toISOString(), }; await this.storage.saveGuardState(state); } async disable() { const state = { enabled: false, lastUpdated: new Date().toISOString(), }; await this.storage.saveGuardState(state); } async getSessionStats() { return await this.storage.getSessionStats(); } async updateSessionStats(linesAdded, linesRemoved) { const current = await this.storage.getSessionStats(); const updated = { totalLinesAdded: (current?.totalLinesAdded ?? 0) + linesAdded, totalLinesRemoved: (current?.totalLinesRemoved ?? 0) + linesRemoved, netChange: 0, // Will calculate below operationCount: (current?.operationCount ?? 0) + 1, lastUpdated: new Date().toISOString(), }; updated.netChange = updated.totalLinesAdded - updated.totalLinesRemoved; await this.storage.saveSessionStats(updated); return updated; } async resetStats() { const stats = { totalLinesAdded: 0, totalLinesRemoved: 0, netChange: 0, operationCount: 0, lastUpdated: new Date().toISOString(), }; await this.storage.saveSessionStats(stats); } async takeSnapshot(sessionId) { // Initialize snapshot manager if not already done if (!this.snapshotManager) { const config = this.configLoader?.getConfig() ?? { enforcement: { ignoreEmptyLines: true } }; this.snapshotManager = new SnapshotManager_1.SnapshotManager(this.rootDir, this.storage, config.enforcement.ignoreEmptyLines); } // Use a default session ID if not provided const effectiveSessionId = sessionId ?? 'default'; // Take a new baseline snapshot const snapshot = await this.snapshotManager.initializeBaseline(effectiveSessionId); return { totalLoc: snapshot.totalLoc, fileCount: snapshot.files.size, timestamp: snapshot.timestamp, }; } /** * Check if the system is configured for snapshot mode */ isSnapshotMode() { const config = this.configLoader?.getConfig(); return config?.enforcement.strategy === 'snapshot'; } /** * Get the snapshot manager instance */ getSnapshotManager() { if (!this.snapshotManager) { const config = this.configLoader?.getConfig() ?? { enforcement: { ignoreEmptyLines: true } }; this.snapshotManager = new SnapshotManager_1.SnapshotManager(this.rootDir, this.storage, config.enforcement.ignoreEmptyLines); } return this.snapshotManager; } /** * Get the current configuration (including hot config overrides) */ async getConfig() { if (this.hotConfigLoader) { return await this.hotConfigLoader.getConfig(); } return this.configLoader?.getConfig() ?? { enforcement: { mode: 'session-wide', strategy: 'cumulative', ignoreEmptyLines: true, limitType: 'hard' }, whitelist: { patterns: [], extensions: [] }, thresholds: { allowedPositiveLines: 0 } }; } /** * Update hot configuration */ async updateHotConfig(updates) { if (!this.hotConfigLoader) { throw new Error('Hot config loader not initialized'); } await this.hotConfigLoader.updateConfig(updates); } /** * Get hot configuration */ async getHotConfig() { return await this.storage.getHotConfig(); } /** * Add operation to history */ async addOperationToHistory(record) { await this.historyManager.addOperation(record); } /** * Get recent operations from history */ async getRecentOperations(limit) { return await this.historyManager.getRecentOperations(limit); } /** * Clear operation history */ async clearHistory() { await this.historyManager.clearHistory(); } /** * Lock a file from modifications */ async lockFile(filePath) { // Normalize the file path to absolute const absolutePath = path.isAbsolute(filePath) ? filePath : path.resolve(process.cwd(), filePath); const lockedFiles = await this.storage.getLockedFiles(); const files = lockedFiles?.files ?? []; // Check if already locked if (files.includes(absolutePath)) { throw new Error(`File is already locked: ${absolutePath}`); } // Add to locked files files.push(absolutePath); await this.storage.saveLockedFiles({ files, lastUpdated: new Date().toISOString(), }); } /** * Unlock a file */ async unlockFile(filePath) { // Normalize the file path to absolute const absolutePath = path.isAbsolute(filePath) ? filePath : path.resolve(process.cwd(), filePath); const lockedFiles = await this.storage.getLockedFiles(); const files = lockedFiles?.files ?? []; // Check if file is locked const index = files.indexOf(absolutePath); if (index === -1) { throw new Error(`File is not locked: ${absolutePath}`); } // Remove from locked files files.splice(index, 1); await this.storage.saveLockedFiles({ files, lastUpdated: new Date().toISOString(), }); } /** * Check if a file is locked */ async isFileLocked(filePath) { // Normalize the file path to absolute const absolutePath = path.isAbsolute(filePath) ? filePath : path.resolve(process.cwd(), filePath); const lockedFiles = await this.storage.getLockedFiles(); const files = lockedFiles?.files ?? []; return files.includes(absolutePath); } /** * Get all locked files */ async getLockedFiles() { const lockedFiles = await this.storage.getLockedFiles(); return lockedFiles?.files ?? []; } } exports.GuardManager = GuardManager; //# sourceMappingURL=GuardManager.js.map