first commit
This commit is contained in:
commit
90482142d2
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
.env
|
||||
node_modules
|
||||
package-lock.json
|
204
README.md
Normal file
204
README.md
Normal file
@ -0,0 +1,204 @@
|
||||
# Remote Container Manager
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Features](#features)
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Installation](#installation)
|
||||
- [Configuration](#configuration)
|
||||
- [Usage](#usage)
|
||||
- [Logging](#logging)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
- [Contributing](#contributing)
|
||||
- [License](#license)
|
||||
|
||||
## Overview
|
||||
|
||||
**Remote Container Manager** is a Node.js script designed to automate the management of remote Debian/Ubuntu-based Linux containers. Leveraging AI-driven command generation and robust API integrations, this tool simplifies tasks such as package installation and service management by executing precise shell commands on remote containers.
|
||||
|
||||
## Features
|
||||
|
||||
- **AI-Powered Command Generation:** Utilizes AI to generate shell commands based on your specified goals and context.
|
||||
- **Verbose Logging:** Detailed and formatted logs make it easy to track the script's actions and outputs.
|
||||
- **API Integration:** Connects seamlessly with Groq and Discord Linux APIs to execute commands remotely.
|
||||
- **Iterative Execution:** Attempts to achieve the desired state through multiple iterations, refining commands based on previous outcomes.
|
||||
- **Environment Configuration:** Easily manage API keys and other settings via environment variables.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before you begin, ensure you have met the following requirements:
|
||||
|
||||
- **Node.js:** Version 14.0 or higher. [Download Node.js](https://nodejs.org/)
|
||||
- **Git:** For cloning the repository. [Download Git](https://git-scm.com/)
|
||||
- **API Access:**
|
||||
- **Groq API Key**
|
||||
- **Discord Linux API Key**
|
||||
|
||||
## Installation
|
||||
|
||||
1. **Clone the Repository**
|
||||
|
||||
```bash
|
||||
git clone https://github.com/yourusername/remote-container-manager.git
|
||||
cd remote-container-manager
|
||||
```
|
||||
|
||||
2. **Install Dependencies**
|
||||
|
||||
Ensure you have [Node.js](https://nodejs.org/) installed. Then, install the required packages:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
1. **Create Environment Variables**
|
||||
|
||||
The script relies on environment variables for API keys and configurations. An example file named `default.env` is provided. Follow these steps to set up your environment variables:
|
||||
|
||||
- **Copy the Example `.env` File**
|
||||
|
||||
```bash
|
||||
cp default.env .env
|
||||
```
|
||||
|
||||
- **Edit the `.env` File**
|
||||
|
||||
Open the `.env` file in your preferred text editor and replace the placeholder values with your actual API keys.
|
||||
|
||||
```env
|
||||
# .env
|
||||
|
||||
DISCORD_LINUX_API_URL=https://api.ssh.surf
|
||||
DISCORD_LINUX_API_KEY=your_discord_linux_api_key
|
||||
GROQ_API_KEY=your_groq_api_key
|
||||
```
|
||||
|
||||
- **Environment Variables Explained**
|
||||
|
||||
| Variable | Description |
|
||||
| ---------------------- | -------------------------------------------------- |
|
||||
| `DISCORD_LINUX_API_URL`| The base URL for the Discord Linux API. |
|
||||
| `DISCORD_LINUX_API_KEY`| Your API key for authenticating with Discord Linux. |
|
||||
| `GROQ_API_KEY` | Your Groq API key for AI-driven command generation.|
|
||||
|
||||
## Usage
|
||||
|
||||
To run the script, use the following command:
|
||||
|
||||
```bash
|
||||
node index.js
|
||||
```
|
||||
|
||||
**Example Goal:**
|
||||
|
||||
```javascript
|
||||
const goal = 'install apache2 (apache2) on the container and run it with service';
|
||||
```
|
||||
|
||||
**Script Flow:**
|
||||
|
||||
1. **Initialization:** Sets up the Groq client and logs the starting process.
|
||||
2. **AI Instruction Request:** Sends the current context and goal to the AI to receive shell commands.
|
||||
3. **Command Execution:** Executes each command on the remote container, logging the output.
|
||||
4. **Iteration:** Repeats the process up to a maximum number of iterations (`MAX_ITERATIONS`) until the goal is achieved or attempts are exhausted.
|
||||
|
||||
## Logging
|
||||
|
||||
The script features comprehensive and formatted logging to ensure transparency and ease of monitoring.
|
||||
|
||||
### Log Components
|
||||
|
||||
- **Headers:** Clearly marked sections indicating the start of processes and iterations.
|
||||
- **Subheaders:** Indicate specific actions like requesting AI instructions.
|
||||
- **Info Messages:** Provide status updates on command execution success or failure.
|
||||
- **Command Execution Logs:** Detailed output of each executed command, including `stdout` and `stderr`.
|
||||
|
||||
**Example Log Output:**
|
||||
|
||||
```
|
||||
════════════════════════════════════════════════════════════════════════════════════════
|
||||
═ STARTING PROCESS TO ACHIEVE GOAL: install apache2 (apache2) on the container and run it with service
|
||||
════════════════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
════════════════════════════════════════════════════════════════════════════════════════
|
||||
═ ITERATION 1 OF 5
|
||||
════════════════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
------------------------------------------------------------
|
||||
> Asking AI for instructions
|
||||
------------------------------------------------------------
|
||||
|
||||
AI PROVIDED COMMANDS:
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y apache2
|
||||
sudo service apache2 start
|
||||
|
||||
[EXECUTING COMMAND]
|
||||
$ sudo apt-get update
|
||||
|
||||
[STDOUT]:
|
||||
Get:1 http://archive.ubuntu.com/ubuntu focal InRelease [265 kB]
|
||||
...
|
||||
|
||||
[STDERR]: (empty)
|
||||
|
||||
INFO: Command executed successfully.
|
||||
|
||||
...
|
||||
|
||||
SUCCESS! The goal appears to have been achieved.
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If you encounter issues while running the script, consider the following steps:
|
||||
|
||||
1. **Check Environment Variables:**
|
||||
- Ensure all required environment variables are set correctly in the `.env` file.
|
||||
- Verify that API keys are valid and have the necessary permissions.
|
||||
|
||||
2. **API Connectivity:**
|
||||
- Confirm that the `DISCORD_LINUX_API_URL` is correct and reachable.
|
||||
- Check your internet connection and any firewall settings that might block API requests.
|
||||
|
||||
3. **Dependencies:**
|
||||
- Make sure all dependencies are installed by running `npm install`.
|
||||
- Verify that you're using a compatible Node.js version (14.0 or higher).
|
||||
|
||||
4. **Script Errors:**
|
||||
- Review the console logs for specific error messages.
|
||||
- Ensure that the remote container is accessible and configured correctly.
|
||||
|
||||
5. **AI Command Accuracy:**
|
||||
- If the AI provides incorrect or ineffective commands, consider refining the `systemPrompt` or providing more context.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome! Follow these steps to contribute:
|
||||
|
||||
1. **Fork the Repository**
|
||||
|
||||
2. **Create a Feature Branch**
|
||||
|
||||
```bash
|
||||
git checkout -b feature/YourFeature
|
||||
```
|
||||
|
||||
3. **Commit Your Changes**
|
||||
|
||||
```bash
|
||||
git commit -m "Add your feature"
|
||||
```
|
||||
|
||||
4. **Push to the Branch**
|
||||
|
||||
```bash
|
||||
git push origin feature/YourFeature
|
||||
```
|
||||
|
||||
5. **Open a Pull Request**
|
||||
|
||||
Please ensure your contributions adhere to the project's coding standards and include appropriate documentation.
|
165
agent.mjs
Normal file
165
agent.mjs
Normal file
@ -0,0 +1,165 @@
|
||||
import 'dotenv/config';
|
||||
import Groq from 'groq-sdk';
|
||||
import unirest from 'unirest';
|
||||
|
||||
const DISCORD_LINUX_API_URL = 'https://api.ssh.surf';
|
||||
const DISCORD_LINUX_API_KEY = process.env['DISCORD_LINUX_API_KEY'];
|
||||
const GROQ_API_KEY = process.env['GROQ_API_KEY'];
|
||||
|
||||
const MAX_ITERATIONS = 5;
|
||||
|
||||
// Initialize the Groq client
|
||||
const groqClient = new Groq({
|
||||
apiKey: GROQ_API_KEY,
|
||||
});
|
||||
|
||||
// A small helper for nice verbose logging:
|
||||
function logHeader(message) {
|
||||
console.log('\n' + '═'.repeat(80));
|
||||
console.log('═ ' + message);
|
||||
console.log('═'.repeat(80) + '\n');
|
||||
}
|
||||
|
||||
function logSubHeader(message) {
|
||||
console.log('\n' + '-'.repeat(60));
|
||||
console.log('> ' + message);
|
||||
console.log('-'.repeat(60) + '\n');
|
||||
}
|
||||
|
||||
function logInfo(message) {
|
||||
console.log(`INFO: ${message}`);
|
||||
}
|
||||
|
||||
function logCommandStart(cmd) {
|
||||
console.log(`\n[EXECUTING COMMAND]\n$ ${cmd}\n`);
|
||||
}
|
||||
|
||||
function logCommandResult(stdout, stderr) {
|
||||
if (stdout && stdout.trim().length > 0) {
|
||||
console.log("[STDOUT]:\n" + indentMultiline(stdout));
|
||||
} else {
|
||||
console.log("[STDOUT]: (empty)\n");
|
||||
}
|
||||
|
||||
if (stderr && stderr.trim().length > 0) {
|
||||
console.log("[STDERR]:\n" + indentMultiline(stderr));
|
||||
} else {
|
||||
console.log("[STDERR]: (empty)\n");
|
||||
}
|
||||
}
|
||||
|
||||
function indentMultiline(text) {
|
||||
return text.split('\n').map(line => ' ' + line).join('\n');
|
||||
}
|
||||
|
||||
// Helper to execute a command in the container:
|
||||
async function execCommandInContainer(cmd, pwd = '/home') {
|
||||
const response = await unirest
|
||||
.post(`${DISCORD_LINUX_API_URL}/exec`)
|
||||
.headers({
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'x-ssh-auth': DISCORD_LINUX_API_KEY
|
||||
})
|
||||
.send({ cmd, pwd });
|
||||
|
||||
return response.body;
|
||||
}
|
||||
|
||||
// This function queries the AI for instructions. It returns a series of commands to try.
|
||||
async function askAIForInstructions(context, goal) {
|
||||
const systemPrompt = `You are a world-class Linux system administration assistant, given the ability to access and run commands on a remote Debian/Ubuntu-based Linux container. Your mission is to help achieve the following goal: ${goal}.
|
||||
Rules:
|
||||
1. Return only shell commands needed, line-by-line, no explanation.
|
||||
2. If previous attempts failed, refine your approach and fix the issues based on the provided errors and output.
|
||||
3. If you need to run multiple commands, separate them by new lines.
|
||||
4. Consider common steps: updating package lists, installing packages, verifying installation.
|
||||
5. The container might be minimal, so consider installing or fixing repositories if needed.
|
||||
6. Always ensure commands are non-interactive.
|
||||
7. Do not use markdown formatting at all ever.
|
||||
8. All commands are non-interactive
|
||||
9. If installing packages, always use -y to allow for non-interactive commands
|
||||
`;
|
||||
|
||||
const userPrompt = `CONTEXT:\n${context}\n\nPlease provide the exact shell commands to achieve the goal above.`;
|
||||
|
||||
const params = {
|
||||
messages: [
|
||||
{ role: 'system', content: systemPrompt },
|
||||
{ role: 'user', content: userPrompt }
|
||||
],
|
||||
model: 'llama3-8b-8192',
|
||||
};
|
||||
|
||||
const chatCompletion = await groqClient.chat.completions.create(params);
|
||||
const aiResponse = chatCompletion.choices[0].message.content.trim();
|
||||
return aiResponse;
|
||||
}
|
||||
|
||||
function parseCommandsFromAIResponse(aiResponse) {
|
||||
const lines = aiResponse.split('\n').map(l => l.trim()).filter(l => l.length > 0);
|
||||
return lines;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const goal = 'install apache2 (apache2) on the container and run it with service';
|
||||
let context = "Initial attempt. No commands have been run yet.\n" +
|
||||
"We are working with a Debian/Ubuntu container.\n" +
|
||||
"Goal: " + goal;
|
||||
|
||||
logHeader(`STARTING PROCESS TO ACHIEVE GOAL: ${goal}`);
|
||||
|
||||
let iteration = 0;
|
||||
let success = false;
|
||||
|
||||
while (iteration < MAX_ITERATIONS && !success) {
|
||||
iteration++;
|
||||
logHeader(`ITERATION ${iteration} OF ${MAX_ITERATIONS}`);
|
||||
|
||||
logSubHeader('Asking AI for instructions');
|
||||
const instructions = await askAIForInstructions(context, goal);
|
||||
console.log("AI PROVIDED COMMANDS:\n" + indentMultiline(instructions));
|
||||
|
||||
const commands = parseCommandsFromAIResponse(instructions);
|
||||
let allCommandsSucceeded = true;
|
||||
let attemptLog = `Attempt #${iteration}:\nAI instructions:\n${instructions}\n\nCommand results:\n`;
|
||||
|
||||
for (const cmd of commands) {
|
||||
logCommandStart(cmd);
|
||||
const result = await execCommandInContainer(cmd);
|
||||
const stdout = result.stdout || '';
|
||||
const stderr = result.stderr || '';
|
||||
logCommandResult(stdout, stderr);
|
||||
|
||||
attemptLog += `\n> ${cmd}\nstdout:\n${stdout}\nstderr:\n${stderr}\n`;
|
||||
|
||||
if (stderr && stderr.trim().length > 0) {
|
||||
logInfo(`Command failed with error detected in STDERR. Will request refined instructions next iteration.`);
|
||||
allCommandsSucceeded = false;
|
||||
break;
|
||||
} else {
|
||||
logInfo(`Command executed successfully.`);
|
||||
}
|
||||
}
|
||||
|
||||
context += `\n\n${attemptLog}`;
|
||||
|
||||
if (allCommandsSucceeded) {
|
||||
logInfo("All commands executed successfully.");
|
||||
success = true;
|
||||
} else {
|
||||
logInfo("At least one command failed. The AI will refine approach in next iteration.");
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
logHeader("SUCCESS! The goal appears to have been achieved.");
|
||||
} else {
|
||||
logHeader("FAILURE TO ACHIEVE GOAL WITHIN MAX ITERATIONS");
|
||||
logInfo("Below is the final accumulated context/logs:\n" + context);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(err => {
|
||||
console.error("An error occurred:", err);
|
||||
});
|
2
default.env
Normal file
2
default.env
Normal file
@ -0,0 +1,2 @@
|
||||
DISCORD_LINUX_API_KEY=
|
||||
GROQ_API_KEY=
|
7
package.json
Normal file
7
package.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"dotenv": "^16.4.7",
|
||||
"groq-sdk": "^0.9.0",
|
||||
"unirest": "^0.6.0"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user