@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
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 (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