add first file
This commit is contained in:
@@ -0,0 +1,610 @@
|
|||||||
|
const fs = require('fs').promises;
|
||||||
|
const path = require('path');
|
||||||
|
const readline = require('readline');
|
||||||
|
const { exec } = require('child_process');
|
||||||
|
|
||||||
|
class LMStudioFileAgent {
|
||||||
|
constructor(options = {}) {
|
||||||
|
this.lmStudioUrl = options.lmStudioUrl || 'http://localhost:1234/v1';
|
||||||
|
this.workspaceDir = path.resolve(options.workspaceDir || './workspace');
|
||||||
|
this.modelName = options.modelName || 'local-model';
|
||||||
|
this.conversationHistory = [];
|
||||||
|
|
||||||
|
// Create workspace directory
|
||||||
|
this._ensureDirectory(this.workspaceDir);
|
||||||
|
|
||||||
|
// Test connection
|
||||||
|
this._testConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
async _ensureDirectory(dir) {
|
||||||
|
try {
|
||||||
|
await fs.mkdir(dir, { recursive: true });
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error creating directory ${dir}:`, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async _testConnection() {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${this.lmStudioUrl}/models`);
|
||||||
|
if (response.ok) {
|
||||||
|
const models = await response.json();
|
||||||
|
console.log(`✓ Connected to LM Studio at ${this.lmStudioUrl}`);
|
||||||
|
console.log(`✓ Available models:`, models);
|
||||||
|
} else {
|
||||||
|
console.log(`⚠ Warning: Could not connect to LM Studio (Status: ${response.status})`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(`⚠ Warning: LM Studio connection failed: ${error.message}`);
|
||||||
|
console.log(' Make sure LM Studio is running with the local server enabled');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async queryLLM(prompt, systemPrompt = null, maxTokens = 2000) {
|
||||||
|
const messages = [];
|
||||||
|
|
||||||
|
if (systemPrompt) {
|
||||||
|
messages.push({ role: 'system', content: systemPrompt });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add recent conversation history (last 10 messages)
|
||||||
|
messages.push(...this.conversationHistory.slice(-10));
|
||||||
|
messages.push({ role: 'user', content: prompt });
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${this.lmStudioUrl}/chat/completions`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
model: this.modelName,
|
||||||
|
messages: messages,
|
||||||
|
temperature: 0.7,
|
||||||
|
max_tokens: maxTokens,
|
||||||
|
stream: false
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
const content = result.choices[0].message.content;
|
||||||
|
|
||||||
|
// Update conversation history
|
||||||
|
this.conversationHistory.push({ role: 'user', content: prompt });
|
||||||
|
this.conversationHistory.push({ role: 'assistant', content: content });
|
||||||
|
|
||||||
|
return content;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error querying LLM:', error.message);
|
||||||
|
return `Error: ${error.message}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============ FILE OPERATIONS ============
|
||||||
|
|
||||||
|
async readFile(filepath) {
|
||||||
|
try {
|
||||||
|
const fullPath = this._resolvePath(filepath);
|
||||||
|
const content = await fs.readFile(fullPath, 'utf-8');
|
||||||
|
return content;
|
||||||
|
} catch (error) {
|
||||||
|
if (error.code === 'ENOENT') {
|
||||||
|
return `Error: File '${filepath}' not found`;
|
||||||
|
}
|
||||||
|
return `Error reading file: ${error.message}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async writeFile(filepath, content, mode = 'w') {
|
||||||
|
try {
|
||||||
|
const fullPath = this._resolvePath(filepath);
|
||||||
|
await this._ensureDirectory(path.dirname(fullPath));
|
||||||
|
|
||||||
|
if (mode === 'a') {
|
||||||
|
await fs.appendFile(fullPath, content, 'utf-8');
|
||||||
|
} else {
|
||||||
|
await fs.writeFile(fullPath, content, 'utf-8');
|
||||||
|
}
|
||||||
|
|
||||||
|
return `✓ Successfully wrote to '${filepath}'`;
|
||||||
|
} catch (error) {
|
||||||
|
return `Error writing file: ${error.message}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async editFile(filepath, oldContent, newContent) {
|
||||||
|
try {
|
||||||
|
const fullPath = this._resolvePath(filepath);
|
||||||
|
const content = await fs.readFile(fullPath, 'utf-8');
|
||||||
|
|
||||||
|
if (!content.includes(oldContent)) {
|
||||||
|
return `Error: Could not find the specified content in '${filepath}'`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedContent = content.replace(oldContent, newContent);
|
||||||
|
|
||||||
|
await fs.writeFile(fullPath, updatedContent, 'utf-8');
|
||||||
|
|
||||||
|
return `✓ Successfully edited '${filepath}'`;
|
||||||
|
} catch (error) {
|
||||||
|
return `Error editing file: ${error.message}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async applyCodeChanges(filepath, changes) {
|
||||||
|
try {
|
||||||
|
const fullPath = this._resolvePath(filepath);
|
||||||
|
let content = await fs.readFile(fullPath, 'utf-8');
|
||||||
|
|
||||||
|
let applied = 0;
|
||||||
|
for (const change of changes) {
|
||||||
|
const oldContent = change.old || '';
|
||||||
|
const newContent = change.new || '';
|
||||||
|
|
||||||
|
if (content.includes(oldContent)) {
|
||||||
|
content = content.replace(oldContent, newContent);
|
||||||
|
applied++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await fs.writeFile(fullPath, content, 'utf-8');
|
||||||
|
|
||||||
|
return `✓ Applied ${applied}/${changes.length} changes to '${filepath}'`;
|
||||||
|
} catch (error) {
|
||||||
|
return `Error applying changes: ${error.message}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async createFile(filepath, content = '', fileType = null) {
|
||||||
|
try {
|
||||||
|
const fullPath = this._resolvePath(filepath);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await fs.access(fullPath);
|
||||||
|
return `Error: File '${filepath}' already exists`;
|
||||||
|
} catch {
|
||||||
|
// File doesn't exist, continue
|
||||||
|
}
|
||||||
|
|
||||||
|
await this._ensureDirectory(path.dirname(fullPath));
|
||||||
|
|
||||||
|
let fileContent = content;
|
||||||
|
if (fileType) {
|
||||||
|
fileContent = this._getTemplate(fileType) + content;
|
||||||
|
}
|
||||||
|
|
||||||
|
await fs.writeFile(fullPath, fileContent, 'utf-8');
|
||||||
|
|
||||||
|
return `✓ Created new file '${filepath}'`;
|
||||||
|
} catch (error) {
|
||||||
|
return `Error creating file: ${error.message}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteFile(filepath) {
|
||||||
|
try {
|
||||||
|
const fullPath = this._resolvePath(filepath);
|
||||||
|
await fs.unlink(fullPath);
|
||||||
|
return `✓ Deleted '${filepath}'`;
|
||||||
|
} catch (error) {
|
||||||
|
if (error.code === 'ENOENT') {
|
||||||
|
return `Error: File '${filepath}' not found`;
|
||||||
|
}
|
||||||
|
return `Error deleting file: ${error.message}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============ DIRECTORY OPERATIONS ============
|
||||||
|
|
||||||
|
async listDirectory(directory = '.') {
|
||||||
|
try {
|
||||||
|
const fullPath = this._resolvePath(directory);
|
||||||
|
const items = await fs.readdir(fullPath, { withFileTypes: true });
|
||||||
|
|
||||||
|
const result = [];
|
||||||
|
for (const item of items) {
|
||||||
|
const itemPath = path.join(fullPath, item.name);
|
||||||
|
const stats = await fs.stat(itemPath);
|
||||||
|
|
||||||
|
if (item.isDirectory()) {
|
||||||
|
result.push(`📁 ${item.name}/`);
|
||||||
|
} else {
|
||||||
|
result.push(`📄 ${item.name} (${this._formatSize(stats.size)})`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.sort();
|
||||||
|
} catch (error) {
|
||||||
|
return [`Error listing directory: ${error.message}`];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async searchFiles(pattern, directory = '.', recursive = true) {
|
||||||
|
try {
|
||||||
|
const fullPath = this._resolvePath(directory);
|
||||||
|
const results = [];
|
||||||
|
|
||||||
|
const searchRecursive = async (dir) => {
|
||||||
|
const items = await fs.readdir(dir, { withFileTypes: true });
|
||||||
|
|
||||||
|
for (const item of items) {
|
||||||
|
const itemPath = path.join(dir, item.name);
|
||||||
|
|
||||||
|
if (item.isDirectory() && recursive) {
|
||||||
|
await searchRecursive(itemPath);
|
||||||
|
} else if (item.isFile()) {
|
||||||
|
// Simple glob pattern matching
|
||||||
|
if (this._matchPattern(item.name, pattern)) {
|
||||||
|
results.push(path.relative(this.workspaceDir, itemPath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
await searchRecursive(fullPath);
|
||||||
|
|
||||||
|
return results.length > 0 ? results : ['No files found'];
|
||||||
|
} catch (error) {
|
||||||
|
return [`Error searching files: ${error.message}`];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async searchContent(searchText, directory = '.', filePattern = '*') {
|
||||||
|
try {
|
||||||
|
const fullPath = this._resolvePath(directory);
|
||||||
|
const matches = [];
|
||||||
|
const textExtensions = ['.js', '.jsx', '.ts', '.tsx', '.py', '.txt', '.md', '.json', '.html', '.css', '.yaml', '.yml', '.xml', '.sql'];
|
||||||
|
|
||||||
|
const searchRecursive = async (dir) => {
|
||||||
|
const items = await fs.readdir(dir, { withFileTypes: true });
|
||||||
|
|
||||||
|
for (const item of items) {
|
||||||
|
const itemPath = path.join(dir, item.name);
|
||||||
|
|
||||||
|
if (item.isDirectory()) {
|
||||||
|
await searchRecursive(itemPath);
|
||||||
|
} else if (item.isFile() && textExtensions.includes(path.extname(item.name))) {
|
||||||
|
try {
|
||||||
|
const content = await fs.readFile(itemPath, 'utf-8');
|
||||||
|
const lines = content.split('\n');
|
||||||
|
|
||||||
|
lines.forEach((line, index) => {
|
||||||
|
if (line.toLowerCase().includes(searchText.toLowerCase())) {
|
||||||
|
matches.push({
|
||||||
|
file: path.relative(this.workspaceDir, itemPath),
|
||||||
|
line: index + 1,
|
||||||
|
content: line.trim()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
// Skip files that can't be read
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
await searchRecursive(fullPath);
|
||||||
|
|
||||||
|
return matches;
|
||||||
|
} catch (error) {
|
||||||
|
return [{ error: error.message }];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============ AGENT INTELLIGENCE ============
|
||||||
|
|
||||||
|
async processRequest(userRequest) {
|
||||||
|
const systemPrompt = `You are a file management agent. You can help with:
|
||||||
|
1. Reading files - Use read_file(filepath)
|
||||||
|
2. Writing files - Use write_file(filepath, content)
|
||||||
|
3. Editing files - Use edit_file(filepath, old_content, new_content)
|
||||||
|
4. Creating files - Use create_file(filepath, content)
|
||||||
|
5. Deleting files - Use delete_file(filepath)
|
||||||
|
6. Listing directories - Use list_directory(directory)
|
||||||
|
7. Searching files - Use search_files(pattern, directory)
|
||||||
|
8. Searching content - Use search_content(text, directory)
|
||||||
|
|
||||||
|
Parse user requests and identify which operations to perform.
|
||||||
|
Return a JSON response with the operations to execute.`;
|
||||||
|
|
||||||
|
const prompt = `User request: ${userRequest}
|
||||||
|
|
||||||
|
Available operations:
|
||||||
|
${JSON.stringify({
|
||||||
|
read_file: "Read file contents",
|
||||||
|
write_file: "Write to file",
|
||||||
|
edit_file: "Edit file content",
|
||||||
|
create_file: "Create new file",
|
||||||
|
delete_file: "Delete file",
|
||||||
|
list_directory: "List directory contents",
|
||||||
|
search_files: "Search for files",
|
||||||
|
search_content: "Search within files"
|
||||||
|
}, null, 2)}
|
||||||
|
|
||||||
|
Respond with a JSON array of operations to perform:
|
||||||
|
[{"operation": "read_file", "args": {"filepath": "example.txt"}}]`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const llmResponse = await this.queryLLM(prompt, systemPrompt);
|
||||||
|
|
||||||
|
// Try to parse JSON from response
|
||||||
|
const jsonMatch = llmResponse.match(/\[.*\]/s);
|
||||||
|
if (jsonMatch) {
|
||||||
|
const operations = JSON.parse(jsonMatch[0]);
|
||||||
|
|
||||||
|
const results = [];
|
||||||
|
for (const op of operations) {
|
||||||
|
const result = await this._executeOperation(op);
|
||||||
|
results.push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return results.join('\n');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// Fall back to manual parsing
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manual operation parsing
|
||||||
|
return this._manualOperation(userRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
async _executeOperation(operation) {
|
||||||
|
const opType = operation.operation;
|
||||||
|
const args = operation.args || {};
|
||||||
|
|
||||||
|
const operationMap = {
|
||||||
|
read_file: () => this.readFile(args.filepath),
|
||||||
|
write_file: () => this.writeFile(args.filepath, args.content, args.mode),
|
||||||
|
edit_file: () => this.editFile(args.filepath, args.old_content, args.new_content),
|
||||||
|
create_file: () => this.createFile(args.filepath, args.content, args.file_type),
|
||||||
|
delete_file: () => this.deleteFile(args.filepath),
|
||||||
|
list_directory: () => this.listDirectory(args.directory),
|
||||||
|
search_files: () => this.searchFiles(args.pattern, args.directory),
|
||||||
|
search_content: () => this.searchContent(args.text, args.directory)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (operationMap[opType]) {
|
||||||
|
try {
|
||||||
|
const result = await operationMap[opType]();
|
||||||
|
if (Array.isArray(result)) {
|
||||||
|
return result.join('\n');
|
||||||
|
}
|
||||||
|
return String(result);
|
||||||
|
} catch (error) {
|
||||||
|
return `Error executing ${opType}: ${error.message}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return `Unknown operation: ${opType}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async _manualOperation(request) {
|
||||||
|
const requestLower = request.toLowerCase();
|
||||||
|
const results = [];
|
||||||
|
|
||||||
|
// Read file
|
||||||
|
if (requestLower.includes('read') && requestLower.includes('file')) {
|
||||||
|
const match = request.match(/["']([^"']+)["']/);
|
||||||
|
if (match) {
|
||||||
|
results.push(`Reading file: ${match[1]}`);
|
||||||
|
results.push(await this.readFile(match[1]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// List directory
|
||||||
|
if (requestLower.includes('list') || requestLower.includes('show')) {
|
||||||
|
if (requestLower.includes('directory') || requestLower.includes('folder') || requestLower.includes('files')) {
|
||||||
|
results.push('Directory contents:');
|
||||||
|
const items = await this.listDirectory();
|
||||||
|
results.push(...items);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search files
|
||||||
|
if (requestLower.includes('search') || requestLower.includes('find')) {
|
||||||
|
if (requestLower.includes('file')) {
|
||||||
|
const match = request.match(/["']([^"']+)["']/);
|
||||||
|
if (match) {
|
||||||
|
results.push(`Search results for: ${match[1]}`);
|
||||||
|
const files = await this.searchFiles(match[1]);
|
||||||
|
results.push(...files);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create file
|
||||||
|
if (requestLower.includes('create') || requestLower.includes('new file')) {
|
||||||
|
const match = request.match(/(?:create|new file)\s+["']?([^"']+)["']?/);
|
||||||
|
if (match) {
|
||||||
|
const filename = match[1].trim();
|
||||||
|
results.push(`Creating file: ${filename}`);
|
||||||
|
results.push(await this.createFile(filename));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no manual operations matched, use LLM
|
||||||
|
if (results.length === 0) {
|
||||||
|
results.push(await this.queryLLM(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
return results.join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============ UTILITY FUNCTIONS ============
|
||||||
|
|
||||||
|
_resolvePath(filepath) {
|
||||||
|
return path.isAbsolute(filepath) ? filepath : path.join(this.workspaceDir, filepath);
|
||||||
|
}
|
||||||
|
|
||||||
|
_formatSize(bytes) {
|
||||||
|
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||||
|
let size = bytes;
|
||||||
|
let unitIndex = 0;
|
||||||
|
|
||||||
|
while (size >= 1024 && unitIndex < units.length - 1) {
|
||||||
|
size /= 1024;
|
||||||
|
unitIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${size.toFixed(1)} ${units[unitIndex]}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
_matchPattern(filename, pattern) {
|
||||||
|
// Convert glob pattern to regex
|
||||||
|
const regexPattern = pattern
|
||||||
|
.replace(/\./g, '\\.')
|
||||||
|
.replace(/\*/g, '.*')
|
||||||
|
.replace(/\?/g, '.');
|
||||||
|
|
||||||
|
const regex = new RegExp(`^${regexPattern}$`);
|
||||||
|
return regex.test(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
_getTemplate(fileType) {
|
||||||
|
const templates = {
|
||||||
|
javascript: "// JavaScript file\n\n",
|
||||||
|
python: "#!/usr/bin/env python3\n\n",
|
||||||
|
html: "<!DOCTYPE html>\n<html>\n<head>\n <title>Document</title>\n</head>\n<body>\n \n</body>\n</html>",
|
||||||
|
css: "/* CSS file */\n\n",
|
||||||
|
json: "{\n \n}",
|
||||||
|
markdown: "# Title\n\n",
|
||||||
|
text: ""
|
||||||
|
};
|
||||||
|
|
||||||
|
return templates[fileType.toLowerCase()] || '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============ CLI INTERFACE ============
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
console.log('🤖 LM Studio File Agent (Node.js)');
|
||||||
|
console.log('='.repeat(50));
|
||||||
|
|
||||||
|
// Initialize agent
|
||||||
|
const agent = new LMStudioFileAgent({
|
||||||
|
workspaceDir: './workspace'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create readline interface
|
||||||
|
const rl = readline.createInterface({
|
||||||
|
input: process.stdin,
|
||||||
|
output: process.stdout
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('\nCommands:');
|
||||||
|
console.log(' read <file> - Read a file');
|
||||||
|
console.log(' list - List directory contents');
|
||||||
|
console.log(' create <file> - Create a new file');
|
||||||
|
console.log(' search <pattern> - Search for files');
|
||||||
|
console.log(' write <file> - Write content to file');
|
||||||
|
console.log(' edit <file> - Edit a file');
|
||||||
|
console.log(' help - Show this help');
|
||||||
|
console.log(' exit - Quit the program\n');
|
||||||
|
|
||||||
|
const promptUser = () => {
|
||||||
|
rl.question('You: ', async (input) => {
|
||||||
|
const trimmedInput = input.trim();
|
||||||
|
|
||||||
|
if (['exit', 'quit', 'q'].includes(trimmedInput.toLowerCase())) {
|
||||||
|
console.log('Goodbye!');
|
||||||
|
rl.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trimmedInput.toLowerCase() === 'help') {
|
||||||
|
console.log('\nAvailable commands:');
|
||||||
|
console.log(' read <file> - Read a file');
|
||||||
|
console.log(' list - List directory contents');
|
||||||
|
console.log(' create <file> - Create a new file');
|
||||||
|
console.log(' search <pattern> - Search for files');
|
||||||
|
console.log(' write <file> - Write content to file');
|
||||||
|
console.log(' edit <file> - Edit a file');
|
||||||
|
console.log(' delete <file> - Delete a file');
|
||||||
|
console.log(' search content <text> - Search within files');
|
||||||
|
console.log(' exit - Quit the program\n');
|
||||||
|
promptUser();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!trimmedInput) {
|
||||||
|
promptUser();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Parse command
|
||||||
|
const [command, ...args] = trimmedInput.split(' ');
|
||||||
|
const arg = args.join(' ');
|
||||||
|
|
||||||
|
let result;
|
||||||
|
switch (command.toLowerCase()) {
|
||||||
|
case 'read':
|
||||||
|
result = await agent.readFile(arg);
|
||||||
|
break;
|
||||||
|
case 'list':
|
||||||
|
const items = await agent.listDirectory();
|
||||||
|
result = items.join('\n');
|
||||||
|
break;
|
||||||
|
case 'create':
|
||||||
|
result = await agent.createFile(arg);
|
||||||
|
break;
|
||||||
|
case 'write':
|
||||||
|
const [filepath, ...contentParts] = args;
|
||||||
|
const content = contentParts.join(' ');
|
||||||
|
if (filepath && content) {
|
||||||
|
result = await agent.writeFile(filepath, content);
|
||||||
|
} else {
|
||||||
|
result = 'Usage: write <file> <content>';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'edit':
|
||||||
|
const [editFile, oldContent, newContent] = arg.split('|').map(s => s.trim());
|
||||||
|
if (editFile && oldContent && newContent) {
|
||||||
|
result = await agent.editFile(editFile, oldContent, newContent);
|
||||||
|
} else {
|
||||||
|
result = 'Usage: edit <file> | <old content> | <new content>';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'delete':
|
||||||
|
result = await agent.deleteFile(arg);
|
||||||
|
break;
|
||||||
|
case 'search':
|
||||||
|
if (args[0] === 'content') {
|
||||||
|
const searchResults = await agent.searchContent(args[1] || '');
|
||||||
|
result = searchResults.map(r => `${r.file}:${r.line} - ${r.content}`).join('\n');
|
||||||
|
} else {
|
||||||
|
const files = await agent.searchFiles(arg);
|
||||||
|
result = files.join('\n');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Process as natural language request
|
||||||
|
result = await agent.processRequest(trimmedInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`\nAgent:\n${result}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error: ${error.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
promptUser();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
promptUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run if this file is executed directly
|
||||||
|
if (require.main === module) {
|
||||||
|
main().catch(console.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export for use as a module
|
||||||
|
module.exports = LMStudioFileAgent;
|
||||||
Reference in New Issue
Block a user