autoclaw 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 AutoClaw Contributor
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,47 @@
1
+ # AutoClaw 🦞
2
+
3
+ AutoClaw is a lightweight AI agent CLI tool that brings the power of Large Language Models (LLMs) directly to your terminal. It allows you to interact with your file system and execute commands using natural language.
4
+
5
+ ## Features
6
+
7
+ - 💬 **Natural Language Interface**: Chat with your terminal to perform complex tasks.
8
+ - 🛡️ **Safe Execution**: All shell commands require user confirmation before execution.
9
+ - 📂 **File Management**: Read and write files effortlessly.
10
+ - 🧠 **Context Aware**: Automatically detects your OS, shell, and environment for accurate command generation.
11
+ - 🔌 **Model Agnostic**: Compatible with OpenAI, DeepSeek, LocalLLM, or any OpenAI-compatible API.
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm install -g autoclaw
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ 1. **Setup**: Run the setup wizard to configure your API key.
22
+ ```bash
23
+ autoclaw setup
24
+ ```
25
+ 2. **Run**: Start the agent.
26
+ ```bash
27
+ autoclaw
28
+ ```
29
+
30
+ ## Usage Examples
31
+
32
+ - "List all TypeScript files in the src folder."
33
+ - "Create a new React component named Button in `components/Button.tsx`."
34
+ - "Check my disk usage and tell me which folder is the largest."
35
+
36
+ ## Configuration
37
+
38
+ AutoClaw uses a `.env` file in the current working directory or creates one globally during setup.
39
+
40
+ Supported Environment Variables:
41
+ - `OPENAI_API_KEY`: Your API Key.
42
+ - `OPENAI_BASE_URL`: Custom Base URL (e.g., for LocalLLM or other providers).
43
+ - `OPENAI_MODEL`: Default model to use (default: `gpt-4o`).
44
+
45
+ ## License
46
+
47
+ MIT
package/dist/agent.js ADDED
@@ -0,0 +1,93 @@
1
+ import OpenAI from 'openai';
2
+ import chalk from 'chalk';
3
+ import ora from 'ora';
4
+ import * as os from 'os';
5
+ import { tools, executeTool } from './tools.js';
6
+ export class Agent {
7
+ client;
8
+ messages;
9
+ model;
10
+ constructor(apiKey, baseURL, model = 'gpt-4-turbo-preview') {
11
+ this.client = new OpenAI({
12
+ apiKey: apiKey,
13
+ baseURL: baseURL
14
+ });
15
+ this.model = model;
16
+ const systemInfo = `
17
+ System Information:
18
+ - OS: ${os.type()} ${os.release()} (${os.platform()})
19
+ - Architecture: ${os.arch()}
20
+ - Node.js Version: ${process.version}
21
+ - Current Working Directory: ${process.cwd()}
22
+ - User: ${os.userInfo().username}
23
+ - Home Directory: ${os.homedir()}
24
+ `;
25
+ this.messages = [
26
+ {
27
+ role: "system",
28
+ content: `You are AutoClaw, an advanced AI agent running in a CLI environment.
29
+ Your goal is to help the user perform tasks on their computer.
30
+ You have access to tools to execute shell commands and read/write files.
31
+
32
+ CONTEXT:
33
+ ${systemInfo}
34
+
35
+ GUIDELINES:
36
+ 1. Use the System Information above to generate platform-specific commands (e.g., use 'dir' for Windows, 'ls' for Linux).
37
+ 2. When asked to perform a task, analyze if you need to use tools.
38
+ 3. If you need to run a command, always use 'execute_shell_command' and provide a clear rationale.
39
+ 4. If you need to read a file, use 'read_file'.
40
+ 5. If you need to write a file, use 'write_file'.
41
+ 6. Be concise in your responses.
42
+ 7. If the user's request is ambiguous, ask for clarification.
43
+ 8. You are running on the user's local machine. Be careful with destructive commands (rm, etc.).
44
+ `
45
+ }
46
+ ];
47
+ }
48
+ async chat(userInput) {
49
+ this.messages.push({ role: "user", content: userInput });
50
+ let active = true;
51
+ while (active) {
52
+ const spinner = ora('Thinking...').start();
53
+ try {
54
+ const response = await this.client.chat.completions.create({
55
+ model: this.model,
56
+ messages: this.messages,
57
+ tools: tools,
58
+ tool_choice: "auto"
59
+ });
60
+ spinner.stop();
61
+ const message = response.choices[0].message;
62
+ this.messages.push(message);
63
+ if (message.content) {
64
+ console.log(chalk.blue("AutoClaw: ") + message.content);
65
+ }
66
+ if (message.tool_calls) {
67
+ for (const toolCall of message.tool_calls) {
68
+ if (toolCall.type !== 'function')
69
+ continue;
70
+ const functionName = toolCall.function.name;
71
+ const functionArgs = JSON.parse(toolCall.function.arguments);
72
+ console.log(chalk.gray(`Executing tool: ${functionName}...`));
73
+ const toolResult = await executeTool(functionName, functionArgs);
74
+ this.messages.push({
75
+ role: "tool",
76
+ tool_call_id: toolCall.id,
77
+ content: toolResult
78
+ });
79
+ // console.log(chalk.dim(`Tool Output: ${toolResult.slice(0, 100)}...`));
80
+ }
81
+ }
82
+ else {
83
+ active = false;
84
+ }
85
+ }
86
+ catch (error) {
87
+ spinner.fail('Error during processing');
88
+ console.error(chalk.red(error.message));
89
+ active = false;
90
+ }
91
+ }
92
+ }
93
+ }
package/dist/index.js ADDED
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import inquirer from 'inquirer';
4
+ import chalk from 'chalk';
5
+ import dotenv from 'dotenv';
6
+ import { Agent } from './agent.js';
7
+ import * as fs from 'fs';
8
+ import * as path from 'path';
9
+ // Load env vars
10
+ dotenv.config();
11
+ const program = new Command();
12
+ program
13
+ .name('autoclaw')
14
+ .description('A lightweight AI agent CLI tool')
15
+ .version('1.0.0');
16
+ program
17
+ .command('setup')
18
+ .description('Run the interactive setup wizard to configure API keys')
19
+ .action(async () => {
20
+ await runSetup();
21
+ });
22
+ program
23
+ .command('chat', { isDefault: true })
24
+ .description('Start the AI agent (default)')
25
+ .option('-m, --model <model>', 'Model to use')
26
+ .action(async (options) => {
27
+ await runChat(options);
28
+ });
29
+ program.parse(process.argv);
30
+ async function runSetup() {
31
+ console.log(chalk.bold.cyan("AutoClaw Setup Wizard 🦞\n"));
32
+ const answers = await inquirer.prompt([
33
+ {
34
+ type: 'password',
35
+ name: 'apiKey',
36
+ message: 'Enter your OpenAI API Key:',
37
+ mask: '*',
38
+ validate: (input) => input.length > 0 ? true : 'API Key cannot be empty.'
39
+ },
40
+ {
41
+ type: 'input',
42
+ name: 'baseUrl',
43
+ message: 'Enter API Base URL (optional, press Enter for default):',
44
+ default: 'https://api.openai.com/v1'
45
+ },
46
+ {
47
+ type: 'input',
48
+ name: 'model',
49
+ message: 'Enter default Model:',
50
+ default: 'gpt-4o'
51
+ }
52
+ ]);
53
+ const envContent = `OPENAI_API_KEY=${answers.apiKey}
54
+ OPENAI_BASE_URL=${answers.baseUrl}
55
+ OPENAI_MODEL=${answers.model}
56
+ `;
57
+ const envPath = path.resolve(process.cwd(), '.env');
58
+ fs.writeFileSync(envPath, envContent);
59
+ console.log(chalk.green(`\n✅ Configuration saved to ${envPath}`));
60
+ console.log(chalk.cyan("You can now run 'autoclaw' to start using the agent."));
61
+ }
62
+ async function runChat(options) {
63
+ console.log(chalk.bold.cyan("Welcome to AutoClaw CLI 🦞"));
64
+ let apiKey = process.env.OPENAI_API_KEY;
65
+ let baseURL = process.env.OPENAI_BASE_URL;
66
+ // Priority: CLI arg > Env var > Default
67
+ const model = options.model || process.env.OPENAI_MODEL || 'gpt-4o';
68
+ if (!apiKey) {
69
+ console.log(chalk.yellow("API Key not found."));
70
+ const { doSetup } = await inquirer.prompt([
71
+ {
72
+ type: 'confirm',
73
+ name: 'doSetup',
74
+ message: 'Would you like to run the setup wizard now?',
75
+ default: true
76
+ }
77
+ ]);
78
+ if (doSetup) {
79
+ await runSetup();
80
+ // Reload env
81
+ dotenv.config({ override: true });
82
+ apiKey = process.env.OPENAI_API_KEY;
83
+ baseURL = process.env.OPENAI_BASE_URL;
84
+ }
85
+ else {
86
+ console.error(chalk.red("API Key is required to proceed."));
87
+ process.exit(1);
88
+ }
89
+ }
90
+ // Double check if apiKey is present after potential setup
91
+ if (!apiKey) {
92
+ console.error(chalk.red("API Key is still missing. Exiting."));
93
+ process.exit(1);
94
+ }
95
+ const agent = new Agent(apiKey, baseURL, model);
96
+ console.log(chalk.green(`Agent initialized with model: ${model}`));
97
+ console.log(chalk.gray("Type 'exit' or 'quit' to leave."));
98
+ while (true) {
99
+ const { userInput } = await inquirer.prompt([
100
+ {
101
+ type: 'input',
102
+ name: 'userInput',
103
+ message: 'You >'
104
+ }
105
+ ]);
106
+ if (userInput.toLowerCase() === 'exit' || userInput.toLowerCase() === 'quit') {
107
+ console.log(chalk.cyan("Goodbye!"));
108
+ break;
109
+ }
110
+ if (userInput.trim() === '')
111
+ continue;
112
+ await agent.chat(userInput);
113
+ }
114
+ }
package/dist/tools.js ADDED
@@ -0,0 +1,130 @@
1
+ import { exec } from 'child_process';
2
+ import * as fs from 'fs/promises';
3
+ import * as path from 'path';
4
+ import inquirer from 'inquirer';
5
+ import chalk from 'chalk';
6
+ import util from 'util';
7
+ const execAsync = util.promisify(exec);
8
+ export const tools = [
9
+ {
10
+ type: "function",
11
+ function: {
12
+ name: "execute_shell_command",
13
+ description: "Execute a shell command on the host machine. Use this to run scripts, list files, or interact with the system.",
14
+ parameters: {
15
+ type: "object",
16
+ properties: {
17
+ command: {
18
+ type: "string",
19
+ description: "The shell command to execute (e.g., 'ls -la', 'npm install')."
20
+ },
21
+ rationale: {
22
+ type: "string",
23
+ description: "Explain why you are running this command."
24
+ }
25
+ },
26
+ required: ["command", "rationale"]
27
+ }
28
+ }
29
+ },
30
+ {
31
+ type: "function",
32
+ function: {
33
+ name: "read_file",
34
+ description: "Read the content of a file.",
35
+ parameters: {
36
+ type: "object",
37
+ properties: {
38
+ path: {
39
+ type: "string",
40
+ description: "The path to the file to read."
41
+ }
42
+ },
43
+ required: ["path"]
44
+ }
45
+ }
46
+ },
47
+ {
48
+ type: "function",
49
+ function: {
50
+ name: "write_file",
51
+ description: "Write content to a file. Overwrites existing files.",
52
+ parameters: {
53
+ type: "object",
54
+ properties: {
55
+ path: {
56
+ type: "string",
57
+ description: "The path to the file to write."
58
+ },
59
+ content: {
60
+ type: "string",
61
+ description: "The content to write to the file."
62
+ }
63
+ },
64
+ required: ["path", "content"]
65
+ }
66
+ }
67
+ }
68
+ ];
69
+ export async function executeTool(name, args) {
70
+ try {
71
+ switch (name) {
72
+ case 'execute_shell_command':
73
+ return await executeShellCommand(args.command, args.rationale);
74
+ case 'read_file':
75
+ return await readFile(args.path);
76
+ case 'write_file':
77
+ return await writeFile(args.path, args.content);
78
+ default:
79
+ return `Error: Unknown tool ${name}`;
80
+ }
81
+ }
82
+ catch (error) {
83
+ return `Error executing ${name}: ${error.message}`;
84
+ }
85
+ }
86
+ async function executeShellCommand(command, rationale) {
87
+ console.log(chalk.yellow(`
88
+ AI wants to execute: `) + chalk.bold(command));
89
+ console.log(chalk.dim(`Reason: ${rationale}`));
90
+ const { confirm } = await inquirer.prompt([
91
+ {
92
+ type: 'confirm',
93
+ name: 'confirm',
94
+ message: 'Do you want to run this command?',
95
+ default: false
96
+ }
97
+ ]);
98
+ if (!confirm) {
99
+ return "User denied command execution.";
100
+ }
101
+ try {
102
+ const { stdout, stderr } = await execAsync(command);
103
+ return stdout + (stderr ? `
104
+ Stderr: ${stderr}` : '');
105
+ }
106
+ catch (error) {
107
+ return `Command failed: ${error.message}
108
+ Stdout: ${error.stdout}
109
+ Stderr: ${error.stderr}`;
110
+ }
111
+ }
112
+ async function readFile(filePath) {
113
+ try {
114
+ const content = await fs.readFile(filePath, 'utf-8');
115
+ return content;
116
+ }
117
+ catch (error) {
118
+ return `Error reading file: ${error.message}`;
119
+ }
120
+ }
121
+ async function writeFile(filePath, content) {
122
+ try {
123
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
124
+ await fs.writeFile(filePath, content, 'utf-8');
125
+ return `Successfully wrote to ${filePath}`;
126
+ }
127
+ catch (error) {
128
+ return `Error writing file: ${error.message}`;
129
+ }
130
+ }
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "autoclaw",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "autoclaw": "./dist/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "start": "node dist/index.js",
12
+ "dev": "node --loader ts-node/esm src/index.ts",
13
+ "test": "echo \"Error: no test specified\" && exit 1",
14
+ "prepublishOnly": "npm run build"
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "README.md",
19
+ "package.json",
20
+ "LICENSE"
21
+ ],
22
+ "keywords": [
23
+ "ai",
24
+ "cli",
25
+ "agent",
26
+ "automation",
27
+ "openai",
28
+ "tool"
29
+ ],
30
+ "author": "AutoClaw Contributor",
31
+ "license": "MIT",
32
+ "description": "A lightweight AI agent CLI tool that brings the power of LLMs to your terminal.",
33
+ "dependencies": {
34
+ "chalk": "^5.6.2",
35
+ "commander": "^14.0.3",
36
+ "dotenv": "^17.2.4",
37
+ "inquirer": "^13.2.2",
38
+ "openai": "^6.18.0",
39
+ "ora": "^9.3.0"
40
+ },
41
+ "devDependencies": {
42
+ "@types/inquirer": "^9.0.9",
43
+ "@types/node": "^25.2.1",
44
+ "ts-node": "^10.9.2",
45
+ "typescript": "^5.9.3"
46
+ }
47
+ }