locker-mcp
Version:
MCP server for file locking and access control for AI code tools
163 lines • 5.91 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Locker = void 0;
const crypto_1 = require("crypto");
const metadata_1 = require("./metadata");
const file_manager_1 = require("./file-manager");
class Locker {
constructor(projectRoot) {
this.metadataManager = new metadata_1.MetadataManager(projectRoot);
}
getFileState(params) {
const { filePath } = params;
const entry = this.metadataManager.getEntry(filePath);
if (!entry) {
return {
filePath,
state: 'unlocked',
context: '',
id: '',
history: []
};
}
return {
filePath: entry.filePath,
state: entry.state,
context: entry.context,
id: entry.id,
history: [...entry.history]
};
}
lockFile(params) {
const { filePath, context } = params;
if (!context.trim()) {
throw new Error('Context cannot be empty');
}
const existingEntry = this.metadataManager.getEntry(filePath);
if (existingEntry) {
throw new Error(`File is already tracked: ${filePath}`);
}
const id = (0, crypto_1.randomUUID)();
const state = 'locked-context';
try {
// Add lock comment to file
file_manager_1.FileManager.addLockComment(filePath, id, state);
// Create metadata entry
const entry = this.metadataManager.createEntry(filePath, id, context, state);
return {
filePath: entry.filePath,
state: entry.state,
context: entry.context,
id: entry.id,
history: [...entry.history]
};
}
catch (error) {
// Cleanup on failure
try {
file_manager_1.FileManager.removeLockComment(filePath);
}
catch {
// Ignore cleanup errors
}
throw error;
}
}
unlockFile(params) {
const { filePath } = params;
const existingEntry = this.metadataManager.getEntry(filePath);
if (!existingEntry) {
throw new Error(`File is not tracked: ${filePath}`);
}
try {
// Remove lock comment from file
file_manager_1.FileManager.removeLockComment(filePath);
// Remove entry from metadata completely
this.metadataManager.removeEntry(filePath);
return {
filePath: existingEntry.filePath,
state: 'unlocked',
context: existingEntry.context,
id: existingEntry.id,
history: [...existingEntry.history, {
state: 'unlocked',
timestamp: new Date().toISOString()
}]
};
}
catch (error) {
throw new Error(`Failed to unlock file: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
updateFile(params) {
const { filePath, context, state } = params;
if (!context.trim()) {
throw new Error('Context cannot be empty');
}
const existingEntry = this.metadataManager.getEntry(filePath);
if (!existingEntry) {
throw new Error(`File is not tracked: ${filePath}`);
}
try {
// Update file comment if state changed
if (state !== existingEntry.state) {
file_manager_1.FileManager.updateLockComment(filePath, existingEntry.id, state);
}
// Update metadata
const updatedEntry = this.metadataManager.updateEntry(filePath, { state, context });
return {
filePath: updatedEntry.filePath,
state: updatedEntry.state,
context: updatedEntry.context,
id: updatedEntry.id,
history: [...updatedEntry.history]
};
}
catch (error) {
throw new Error(`Failed to update file: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
finalizeFile(filePath) {
const existingEntry = this.metadataManager.getEntry(filePath);
if (!existingEntry) {
throw new Error(`File is not tracked: ${filePath}`);
}
if (existingEntry.state === 'locked') {
return {
filePath: existingEntry.filePath,
state: existingEntry.state,
context: existingEntry.context,
id: existingEntry.id,
history: [...existingEntry.history]
};
}
try {
// Update file comment to locked state
file_manager_1.FileManager.updateLockComment(filePath, existingEntry.id, 'locked');
// Update metadata to locked state
const updatedEntry = this.metadataManager.updateEntry(filePath, { state: 'locked' });
return {
filePath: updatedEntry.filePath,
state: updatedEntry.state,
context: updatedEntry.context,
id: updatedEntry.id,
history: [...updatedEntry.history]
};
}
catch (error) {
throw new Error(`Failed to finalize file: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
getAllTrackedFiles() {
const entries = this.metadataManager.getAllEntries();
return entries.map(entry => ({
filePath: entry.filePath,
state: entry.state,
context: entry.context,
id: entry.id,
history: [...entry.history]
}));
}
}
exports.Locker = Locker;
//# sourceMappingURL=locker.js.map