ccguard
Version:
Automated enforcement of net-negative LOC, complexity constraints, and quality standards for Claude code
248 lines • 8.81 kB
JavaScript
;
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