UNPKG

@nomyx/assistant

Version:

A powerful assistant library and cli for your AI projects. works with Vertex AI (Claude and Gemini)

222 lines (221 loc) 8.56 kB
"use strict"; // LOCKED: TRUE // All content in this file is locked and cannot be edited. 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 (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.CodeEditor = void 0; const fs_1 = require("fs"); const path_1 = __importDefault(require("path")); const worker_threads_1 = require("worker_threads"); const acorn = __importStar(require("acorn")); const astring = __importStar(require("astring")); const lru_cache_1 = require("lru-cache"); const diff_1 = require("diff"); class CodeEditor { constructor(options = { maxCacheSize: 100, cacheMaxAge: 1000 * 60 * 60, workerCount: 4 }) { this.fileCache = new lru_cache_1.LRUCache({ max: options.maxCacheSize || 100 }); this.workerPool = this.createWorkerPool(options.workerCount || 4); } createWorkerPool(size) { const pool = []; for (let i = 0; i < size; i++) { const workerPath = process.env.NODE_ENV === 'production' ? path_1.default.resolve(__dirname, 'worker.js') : path_1.default.resolve(__dirname, '..', '..', 'dist', 'code-editor', 'worker.js'); const worker = new worker_threads_1.Worker(workerPath); pool.push(worker); } return pool; } getWorker() { return this.workerPool[Math.floor(Math.random() * this.workerPool.length)]; } async runWorkerTask(task, data) { return new Promise((resolve, reject) => { const worker = this.getWorker(); worker.postMessage({ task, data }); worker.once('message', resolve); worker.once('error', reject); }); } async open(filePath) { try { const content = await fs_1.promises.readFile(filePath, 'utf-8'); const ast = acorn.parse(content, { ecmaVersion: 2020, sourceType: 'module' }); this.fileCache.set(filePath, { content, ast }); } catch (error) { throw new Error(`Failed to open file ${filePath}: ${error.message}`); } } async read(filePath) { if (!this.fileCache.has(filePath)) { await this.open(filePath); } const fileHit = this.fileCache.get(filePath); return fileHit ? fileHit.content : null; } async write(filePath, content) { try { await fs_1.promises.writeFile(filePath, content, 'utf-8'); const ast = acorn.parse(content, { ecmaVersion: 2020, sourceType: 'module' }); this.fileCache.set(filePath, { content, ast }); } catch (error) { throw new Error(`Failed to write to file ${filePath}: ${error.message}`); } } async search(pattern, options = { flags: 'g' }) { try { const results = []; for (const [filePath, { content }] of this.fileCache.entries()) { const regex = new RegExp(pattern, options.flags || 'g'); const matches = content.match(regex); if (matches) { results.push({ filePath, matches }); } } return results; } catch (error) { throw new Error(`Search failed: ${error.message}`); } } async replace(pattern, replacement, options = { flags: 'g' }) { try { const results = []; for (const [filePath, { content }] of this.fileCache.entries()) { const regex = new RegExp(pattern, options.flags || 'g'); const newContent = content.replace(regex, replacement); if (newContent !== content) { await this.write(filePath, newContent); results.push({ filePath, content: newContent, changesApplied: true }); } } return results; } catch (error) { throw new Error(`Replace operation failed: ${error.message}`); } } async transform(transformation, filePath) { try { const value = this.fileCache.get(filePath); if (!value) { throw new Error(`File ${filePath} not found in cache`); } const { ast } = value; const transformedAst = transformation(ast); const transformedCode = astring.generate(transformedAst); await this.write(filePath, transformedCode); } catch (error) { throw new Error(`Transformation failed for file ${filePath}: ${error.message}`); } } async diff(filePath) { try { const originalContent = await fs_1.promises.readFile(filePath, 'utf-8'); const fileHit = this.fileCache.get(filePath); const currentContent = fileHit ? fileHit.content : null; if (!currentContent) { throw new Error(`File ${filePath} not found in cache`); } return this.generateDiff(originalContent, currentContent, filePath); } catch (error) { throw new Error(`Failed to generate diff for file ${filePath}: ${error.message}`); } } async listFiles(directory) { try { return await fs_1.promises.readdir(directory); } catch (error) { throw new Error(`Failed to list files in directory ${directory}: ${error.message}`); } } generateDiff(oldStr, newStr, filePath) { return (0, diff_1.createPatch)(filePath, oldStr, newStr); } async format(input) { try { const ast = acorn.parse(input, { ecmaVersion: 2020, sourceType: 'module' }); return this.generateFormattedCode(ast); } catch (error) { throw new Error(`Formatting failed: ${error.message}`); } } generateFormattedCode(ast) { return astring.generate(ast, { indent: ' ', lineEnd: '\n', generator: { ...astring.baseGenerator, }, }); } async applyChanges(filePath, changes) { try { const content = await this.read(filePath); if (content === null) { throw new Error(`File ${filePath} not found in cache`); } const newContent = this.applyChangesToContent(content, changes); await this.write(filePath, newContent); return { success: true, message: `Changes applied to ${filePath}` }; } catch (error) { throw new Error(`Failed to apply changes to file ${filePath}: ${error.message}`); } } applyChangesToContent(content, changes) { let newContent = content; if (typeof changes === 'string') { newContent = changes; } else if (Array.isArray(changes)) { for (const change of changes) { if (change.type === 'replace' && typeof change.start === 'number' && typeof change.end === 'number') { newContent = newContent.slice(0, change.start) + change.text + newContent.slice(change.end); } } } return newContent; } async close() { this.fileCache.clear(); for (const worker of this.workerPool) { worker.terminate(); } } } exports.CodeEditor = CodeEditor;