UNPKG

@vibe-kit/grok-cli

Version:

An open-source AI agent that brings the power of Grok directly into your terminal.

292 lines 11.1 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 (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; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.TextEditorTool = void 0; const fs = __importStar(require("fs-extra")); const path = __importStar(require("path")); class TextEditorTool { constructor() { this.editHistory = []; } async view(filePath, viewRange) { try { const resolvedPath = path.resolve(filePath); if (await fs.pathExists(resolvedPath)) { const stats = await fs.stat(resolvedPath); if (stats.isDirectory()) { const files = await fs.readdir(resolvedPath); return { success: true, output: `Directory contents of ${filePath}:\n${files.join('\n')}` }; } const content = await fs.readFile(resolvedPath, 'utf-8'); const lines = content.split('\n'); if (viewRange) { const [start, end] = viewRange; const selectedLines = lines.slice(start - 1, end); const numberedLines = selectedLines.map((line, idx) => `${start + idx}: ${line}`).join('\n'); return { success: true, output: `Lines ${start}-${end} of ${filePath}:\n${numberedLines}` }; } const totalLines = lines.length; const displayLines = totalLines > 10 ? lines.slice(0, 10) : lines; const numberedLines = displayLines.map((line, idx) => `${idx + 1}: ${line}`).join('\n'); const additionalLinesMessage = totalLines > 10 ? `\n... +${totalLines - 10} lines` : ''; return { success: true, output: `Contents of ${filePath}:\n${numberedLines}${additionalLinesMessage}` }; } else { return { success: false, error: `File or directory not found: ${filePath}` }; } } catch (error) { return { success: false, error: `Error viewing ${filePath}: ${error.message}` }; } } async strReplace(filePath, oldStr, newStr) { try { const resolvedPath = path.resolve(filePath); if (!(await fs.pathExists(resolvedPath))) { return { success: false, error: `File not found: ${filePath}` }; } const content = await fs.readFile(resolvedPath, 'utf-8'); if (!content.includes(oldStr)) { return { success: false, error: `String not found in file: "${oldStr}"` }; } const newContent = content.replace(oldStr, newStr); await fs.writeFile(resolvedPath, newContent, 'utf-8'); this.editHistory.push({ command: 'str_replace', path: filePath, old_str: oldStr, new_str: newStr }); // Generate diff output const oldLines = content.split('\n'); const newLines = newContent.split('\n'); const diff = this.generateDiff(oldLines, newLines, filePath); return { success: true, output: diff }; } catch (error) { return { success: false, error: `Error replacing text in ${filePath}: ${error.message}` }; } } async create(filePath, content) { try { const resolvedPath = path.resolve(filePath); const dir = path.dirname(resolvedPath); await fs.ensureDir(dir); await fs.writeFile(resolvedPath, content, 'utf-8'); this.editHistory.push({ command: 'create', path: filePath, content }); // Generate diff output using the same method as str_replace const oldLines = []; // Empty for new files const newLines = content.split('\n'); const diff = this.generateDiff(oldLines, newLines, filePath); return { success: true, output: diff }; } catch (error) { return { success: false, error: `Error creating ${filePath}: ${error.message}` }; } } async insert(filePath, insertLine, content) { try { const resolvedPath = path.resolve(filePath); if (!(await fs.pathExists(resolvedPath))) { return { success: false, error: `File not found: ${filePath}` }; } const fileContent = await fs.readFile(resolvedPath, 'utf-8'); const lines = fileContent.split('\n'); lines.splice(insertLine - 1, 0, content); const newContent = lines.join('\n'); await fs.writeFile(resolvedPath, newContent, 'utf-8'); this.editHistory.push({ command: 'insert', path: filePath, insert_line: insertLine, content }); return { success: true, output: `Successfully inserted content at line ${insertLine} in ${filePath}` }; } catch (error) { return { success: false, error: `Error inserting content in ${filePath}: ${error.message}` }; } } async undoEdit() { if (this.editHistory.length === 0) { return { success: false, error: 'No edits to undo' }; } const lastEdit = this.editHistory.pop(); try { switch (lastEdit.command) { case 'str_replace': if (lastEdit.path && lastEdit.old_str && lastEdit.new_str) { const content = await fs.readFile(lastEdit.path, 'utf-8'); const revertedContent = content.replace(lastEdit.new_str, lastEdit.old_str); await fs.writeFile(lastEdit.path, revertedContent, 'utf-8'); } break; case 'create': if (lastEdit.path) { await fs.remove(lastEdit.path); } break; case 'insert': if (lastEdit.path && lastEdit.insert_line) { const content = await fs.readFile(lastEdit.path, 'utf-8'); const lines = content.split('\n'); lines.splice(lastEdit.insert_line - 1, 1); await fs.writeFile(lastEdit.path, lines.join('\n'), 'utf-8'); } break; } return { success: true, output: `Successfully undid ${lastEdit.command} operation` }; } catch (error) { return { success: false, error: `Error undoing edit: ${error.message}` }; } } generateDiff(oldLines, newLines, filePath) { // Count actual changes let addedLines = 0; let removedLines = 0; let i = 0, j = 0; // Simple algorithm to detect changes while (i < oldLines.length || j < newLines.length) { if (i < oldLines.length && j < newLines.length && oldLines[i] === newLines[j]) { i++; j++; } else if (i < oldLines.length && (j >= newLines.length || oldLines[i] !== newLines[j])) { removedLines++; i++; } else if (j < newLines.length) { addedLines++; j++; } } let summary = `Updated ${filePath}`; if (addedLines > 0 && removedLines > 0) { summary += ` with ${addedLines} addition${addedLines !== 1 ? 's' : ''} and ${removedLines} removal${removedLines !== 1 ? 's' : ''}`; } else if (addedLines > 0) { summary += ` with ${addedLines} addition${addedLines !== 1 ? 's' : ''}`; } else if (removedLines > 0) { summary += ` with ${removedLines} removal${removedLines !== 1 ? 's' : ''}`; } else { summary += ' with changes'; } // Generate proper git-style diff format let diff = summary + '\n'; diff += `--- a/${filePath}\n`; diff += `+++ b/${filePath}\n`; diff += `@@ -1,${oldLines.length} +1,${newLines.length} @@\n`; // Generate unified diff i = 0; j = 0; const CONTEXT_LINES = 3; while (i < oldLines.length || j < newLines.length) { const oldLine = i < oldLines.length ? oldLines[i] : null; const newLine = j < newLines.length ? newLines[j] : null; if (oldLine === newLine && oldLine !== null) { // Context line diff += ` ${oldLine}\n`; i++; j++; } else { // Show removed lines if (oldLine !== null) { diff += `-${oldLine}\n`; i++; } // Show added lines if (newLine !== null) { diff += `+${newLine}\n`; j++; } } } return diff.trim(); } getEditHistory() { return [...this.editHistory]; } } exports.TextEditorTool = TextEditorTool; //# sourceMappingURL=textEditor.js.map