rentabots-sdk 1.6.4 → 1.7.1

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/cli.js CHANGED
@@ -1,19 +1,26 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * šŸ¦€ RENTABOTS MASTER CONTROLLER (v1.5.8)
4
+ * šŸ¦€ RENTABOTS MASTER CONTROLLER (v1.7.0)
5
5
  * The all-in-one CLI for managing autonomous agents.
6
6
  * Cross-Platform Support: Windows, Linux, Mac
7
+ *
8
+ * NEW: Interactive LLM Provider Selection (OpenClaw or Custom API)
7
9
  */
8
10
 
9
11
  const { execSync, spawn } = require('child_process');
10
12
  const path = require('path');
11
13
  const fs = require('fs');
14
+ const readline = require('readline');
12
15
 
13
16
  const args = process.argv.slice(2);
14
17
  const command = args[0];
15
18
 
16
- // Helper: Run shell command and stream output
19
+ // --- Helper Utilities ---
20
+
21
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
22
+ const ask = (q) => new Promise((r) => rl.question(q, r));
23
+
17
24
  function run(cmd, desc) {
18
25
  console.log(`\nšŸš€ ${desc}...`);
19
26
  try {
@@ -24,56 +31,183 @@ function run(cmd, desc) {
24
31
  }
25
32
  }
26
33
 
27
- // Helper: Check if OpenClaw is installed and ready
34
+ // --- LLM Provider Selection ---
35
+
36
+ const LLM_PROVIDERS = [
37
+ { key: 'openai', name: 'OpenAI', models: 'gpt-4o, gpt-4o-mini' },
38
+ { key: 'anthropic', name: 'Anthropic', models: 'claude-sonnet-4, claude-3.5-haiku' },
39
+ { key: 'google', name: 'Google', models: 'gemini-2.0-flash, gemini-2.5-pro' },
40
+ { key: 'groq', name: 'Groq', models: 'llama-3.3-70b, mixtral-8x7b' },
41
+ { key: 'mistral', name: 'Mistral', models: 'mistral-large, mistral-small' },
42
+ { key: 'custom', name: 'Custom URL', models: 'any OpenAI-compatible endpoint' },
43
+ ];
44
+
28
45
  function checkOpenClaw() {
29
- console.log("\nšŸ¦ž Checking OpenClaw Brain Connection...");
30
46
  try {
31
- // Just checking version is enough to know if it's in PATH and runnable
32
47
  const version = execSync('openclaw --version', { stdio: 'pipe' }).toString().trim();
33
- console.log(`āœ… OpenClaw Intelligence detected (v${version}). Agent is ready for autonomous work.`);
34
- return true;
48
+ return version;
35
49
  } catch (e) {
36
- console.warn(`\nāš ļø OPENCLAW NOT FOUND!`);
37
- console.warn(` Your agent will lack autonomous reasoning capabilities.`);
38
- console.warn(` Please install OpenClaw to enable full intelligence:`);
39
- console.warn(` > npm install -g openclaw\n`);
40
-
41
- // We don't exit(1) here because maybe they want to run a dumb bot,
42
- // but for RentaBots standards, it's highly recommended.
43
- // Uncomment next line to enforce:
44
- // process.exit(1);
45
- return false;
50
+ return null;
46
51
  }
47
52
  }
48
53
 
49
- async function handleDeploy() {
50
- // 0. Pre-Flight Checks
51
- checkOpenClaw();
54
+ async function installOpenClaw() {
55
+ console.log('\nšŸ“¦ Installing OpenClaw...');
56
+ try {
57
+ execSync('npm install -g openclaw', { stdio: 'inherit' });
58
+ const version = checkOpenClaw();
59
+ if (version) {
60
+ console.log(`āœ… OpenClaw installed successfully (v${version})`);
61
+ return true;
62
+ }
63
+ } catch (e) {
64
+ console.error('āŒ OpenClaw installation failed.');
65
+ }
66
+ return false;
67
+ }
68
+
69
+ async function selectLLMProvider(nonInteractiveFlag) {
70
+ // Support non-interactive mode via --llm flag
71
+ if (nonInteractiveFlag) {
72
+ const key = nonInteractiveFlag.toLowerCase();
73
+ if (key === 'openclaw') {
74
+ const version = checkOpenClaw();
75
+ if (!version) {
76
+ console.error('āŒ OpenClaw is not installed. Run without --llm flag for interactive setup.');
77
+ process.exit(1);
78
+ }
79
+ return { provider: 'openclaw' };
80
+ }
81
+ const found = LLM_PROVIDERS.find(p => p.key === key);
82
+ if (found) return { provider: found.key };
83
+ console.error(`āŒ Unknown provider: ${key}. Valid: openclaw, ${LLM_PROVIDERS.map(p => p.key).join(', ')}`);
84
+ process.exit(1);
85
+ }
86
+
87
+ console.log(`
88
+ ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
89
+ │ 🧠 SELECT YOUR AGENT'S BRAIN │
90
+ │ │
91
+ │ 1. OpenClaw (Recommended - local AI runtime) │
92
+ │ 2. Custom API (OpenAI, Anthropic, Google, etc.) │
93
+ ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜`);
94
+
95
+ const choice = await ask('\n Select [1/2]: ');
96
+
97
+ if (choice.trim() === '1') {
98
+ // --- OpenClaw Path ---
99
+ const version = checkOpenClaw();
100
+ if (version) {
101
+ console.log(`\nāœ… OpenClaw detected (v${version}). Your agent will use local AI intelligence.`);
102
+ return { provider: 'openclaw' };
103
+ }
104
+
105
+ console.log('\nāš ļø OpenClaw is not installed on this system.');
106
+ const install = await ask(' Install OpenClaw now? [Y/n]: ');
107
+
108
+ if (!install.trim() || install.trim().toLowerCase() === 'y') {
109
+ const success = await installOpenClaw();
110
+ if (success) return { provider: 'openclaw' };
111
+ console.log('\nāš ļø Falling back to Custom API selection...');
112
+ } else {
113
+ console.log('\nāš ļø Skipping OpenClaw. Switching to Custom API selection...\n');
114
+ }
115
+ // Fall through to custom API selection
116
+ }
117
+
118
+ // --- Custom API Path ---
119
+ console.log('\n šŸ“” Available LLM Providers:\n');
120
+ LLM_PROVIDERS.forEach((p, i) => {
121
+ console.log(` ${i + 1}. ${p.name.padEnd(12)} (${p.models})`);
122
+ });
123
+
124
+ const providerChoice = await ask('\n Select provider [1-6]: ');
125
+ const idx = parseInt(providerChoice.trim()) - 1;
126
+ const selected = LLM_PROVIDERS[idx];
127
+
128
+ if (!selected) {
129
+ console.error('āŒ Invalid selection. Defaulting to OpenAI.');
130
+ return await collectApiKey('openai');
131
+ }
132
+
133
+ return await collectApiKey(selected.key);
134
+ }
135
+
136
+ async function collectApiKey(providerKey) {
137
+ const result = { provider: providerKey };
138
+
139
+ const apiKey = await ask(`\n šŸ”‘ Enter your ${providerKey.toUpperCase()} API Key: `);
140
+ if (!apiKey.trim()) {
141
+ console.error('āŒ API Key is required.');
142
+ process.exit(1);
143
+ }
144
+ result.apiKey = apiKey.trim();
145
+
146
+ if (providerKey === 'custom') {
147
+ const baseUrl = await ask(' 🌐 Enter your API Base URL (e.g. https://my-api.com/v1): ');
148
+ if (!baseUrl.trim()) {
149
+ console.error('āŒ Base URL is required for custom provider.');
150
+ process.exit(1);
151
+ }
152
+ result.baseUrl = baseUrl.trim();
153
+
154
+ const model = await ask(' šŸ¤– Enter model name (e.g. gpt-4o-mini): ');
155
+ if (model.trim()) result.model = model.trim();
156
+ }
157
+
158
+ return result;
159
+ }
52
160
 
161
+ function buildEnvContent(apiKey, llmConfig) {
162
+ let env = `RENTABOTS_API_KEY=${apiKey}\nRENTABOTS_SECRET_KEY=${apiKey}\nRENTABOTS_API_URL=https://rentabots.com/api\nRENTABOTS_SOCKET_URL=https://rentabots-relay-production.up.railway.app\n`;
163
+ env += `LLM_PROVIDER=${llmConfig.provider}\n`;
164
+
165
+ if (llmConfig.apiKey) env += `LLM_API_KEY=${llmConfig.apiKey}\n`;
166
+ if (llmConfig.baseUrl) env += `LLM_BASE_URL=${llmConfig.baseUrl}\n`;
167
+ if (llmConfig.model) env += `LLM_MODEL=${llmConfig.model}\n`;
168
+
169
+ return env;
170
+ }
171
+
172
+ // --- Main Commands ---
173
+
174
+ async function handleDeploy() {
175
+ // Parse API key
53
176
  const keyArgIndex = args.findIndex(a => a === '--key' || a === '-k' || a === '-key');
54
177
  const API_KEY = (keyArgIndex !== -1 && args[keyArgIndex + 1]) ? args[keyArgIndex + 1] : process.env.RENTABOTS_API_KEY;
55
178
 
56
179
  if (!API_KEY) {
57
- console.error("āŒ Error: API Key required for one-line deployment.");
180
+ console.error("āŒ Error: API Key required for deployment.");
58
181
  console.log("Usage: npx rentabots-sdk deploy --key YOUR_API_KEY");
182
+ console.log(" npx rentabots-sdk deploy --key YOUR_API_KEY --llm openclaw");
59
183
  process.exit(1);
60
184
  }
61
185
 
186
+ // Parse --llm flag for non-interactive mode
187
+ const llmArgIndex = args.findIndex(a => a === '--llm');
188
+ const llmFlag = (llmArgIndex !== -1 && args[llmArgIndex + 1]) ? args[llmArgIndex + 1] : null;
189
+
190
+ // 0. Pre-Flight: LLM Provider Selection
191
+ console.log('\nšŸ¦€ RENTABOTS AGENT DEPLOYMENT WIZARD\n');
192
+ const llmConfig = await selectLLMProvider(llmFlag);
193
+
194
+ console.log(`\nāœ… Brain configured: ${llmConfig.provider.toUpperCase()}`);
195
+
62
196
  const projectDir = 'my-rentabot-agent';
63
-
197
+
64
198
  // 1. Create project if missing
65
199
  if (!fs.existsSync(projectDir)) {
66
200
  console.log(`\nšŸ“‚ Project folder '${projectDir}' not found. Initializing...`);
67
201
  fs.mkdirSync(projectDir);
68
202
  process.chdir(projectDir);
69
-
70
- // Generate necessary files (Minimal v1.5.7 templates)
203
+
204
+ // Write .env with LLM config
205
+ fs.writeFileSync('.env', buildEnvContent(API_KEY, llmConfig));
206
+
207
+ // Generate package.json
71
208
  const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf8'));
72
209
  const ver = pkg.version;
73
-
74
- fs.writeFileSync('.env', `RENTABOTS_API_KEY=${API_KEY}\nRENTABOTS_API_URL=https://rentabots.com/api\n`);
75
-
76
- // Universal Scripts: Use 'node' or 'npx' instead of OS-specific commands
210
+
77
211
  const pkgJson = {
78
212
  name: "my-rentabot-agent",
79
213
  version: "1.0.0",
@@ -85,28 +219,97 @@ async function handleDeploy() {
85
219
  "logs": "npx pm2 logs my-rentabot-agent",
86
220
  "status": "node -e \"console.log(require('fs').readFileSync('RENTABOT_STATUS.md', 'utf8'))\""
87
221
  },
88
- dependencies: {
89
- "rentabots-sdk": `^${ver}`,
222
+ dependencies: {
223
+ "rentabots-sdk": `^${ver}`,
90
224
  "dotenv": "^16.3.1",
91
- "pm2": "^5.3.0"
225
+ "pm2": "^5.3.0"
92
226
  }
93
227
  };
94
228
  fs.writeFileSync('package.json', JSON.stringify(pkgJson, null, 2));
95
229
 
96
- // Generate Queen & Worker
97
- const initScript = require('./init_templates');
230
+ // Generate Queen & Worker templates
231
+ const initScript = require('./init_templates');
98
232
  fs.writeFileSync('agent.js', initScript.queenTemplate);
99
233
  fs.writeFileSync('worker.js', initScript.workerTemplate);
100
-
234
+
101
235
  run('npm install', 'Installing dependencies');
102
236
  } else {
103
237
  process.chdir(projectDir);
238
+
239
+ // Update .env with new LLM config if it changed
240
+ if (fs.existsSync('.env')) {
241
+ const existing = fs.readFileSync('.env', 'utf8');
242
+ if (!existing.includes('LLM_PROVIDER')) {
243
+ fs.appendFileSync('.env', `\nLLM_PROVIDER=${llmConfig.provider}\n`);
244
+ if (llmConfig.apiKey) fs.appendFileSync('.env', `LLM_API_KEY=${llmConfig.apiKey}\n`);
245
+ if (llmConfig.baseUrl) fs.appendFileSync('.env', `LLM_BASE_URL=${llmConfig.baseUrl}\n`);
246
+ if (llmConfig.model) fs.appendFileSync('.env', `LLM_MODEL=${llmConfig.model}\n`);
247
+ }
248
+ }
104
249
  }
105
250
 
106
- // 2. Deploy with PM2 (Cross-Platform via NPX)
251
+ // 2. Deploy with PM2
107
252
  run('npm run deploy', 'Deploying agent to RentaBots Grid (24/7 Mode)');
108
253
  console.log("\n✨ DEPLOYMENT SUCCESSFUL!");
109
254
  console.log("šŸ“Š Run 'npx rentabots-sdk status' to see your live dashboard.");
255
+ rl.close();
256
+ }
257
+
258
+ async function handleInit() {
259
+ console.log('\nšŸ¦€ RENTABOTS INTERACTIVE SETUP\n');
260
+
261
+ const apiKey = await ask("šŸ”‘ Enter Agent API Key: ");
262
+ if (!apiKey.startsWith('sk_agent_')) {
263
+ console.error("āŒ Invalid API Key. Must start with 'sk_agent_'");
264
+ process.exit(1);
265
+ }
266
+
267
+ // LLM Provider Selection
268
+ const llmConfig = await selectLLMProvider(null);
269
+
270
+ const projectDir = 'my-rentabot-agent';
271
+ if (!fs.existsSync(projectDir)) fs.mkdirSync(projectDir);
272
+ process.chdir(projectDir);
273
+
274
+ // Write .env
275
+ fs.writeFileSync('.env', buildEnvContent(apiKey, llmConfig));
276
+
277
+ // Generate package.json
278
+ const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf8'));
279
+ const ver = pkg.version;
280
+
281
+ const pkgJson = {
282
+ name: "my-rentabot-agent",
283
+ version: "1.0.0",
284
+ main: "agent.js",
285
+ scripts: {
286
+ "start": "node agent.js",
287
+ "deploy": "npx pm2 start agent.js --name my-rentabot-agent --update-env",
288
+ "stop": "npx pm2 stop my-rentabot-agent",
289
+ "logs": "npx pm2 logs my-rentabot-agent",
290
+ "status": "node -e \"console.log(require('fs').readFileSync('RENTABOT_STATUS.md', 'utf8'))\""
291
+ },
292
+ dependencies: {
293
+ "rentabots-sdk": `^${ver}`,
294
+ "dotenv": "^16.3.1",
295
+ "pm2": "^5.3.0"
296
+ }
297
+ };
298
+ fs.writeFileSync('package.json', JSON.stringify(pkgJson, null, 2));
299
+
300
+ // Generate Queen & Worker templates
301
+ const initScript = require('./init_templates');
302
+ fs.writeFileSync('agent.js', initScript.queenTemplate);
303
+ fs.writeFileSync('worker.js', initScript.workerTemplate);
304
+
305
+ console.log("\nšŸ“¦ Installing core dependencies...");
306
+ try {
307
+ execSync('npm install', { stdio: 'inherit' });
308
+ } catch (e) { }
309
+
310
+ console.log(`\nāœ… Brain: ${llmConfig.provider.toUpperCase()}`);
311
+ console.log("šŸš€ PROJECT READY: cd my-rentabot-agent && npm start");
312
+ rl.close();
110
313
  }
111
314
 
112
315
  async function main() {
@@ -118,18 +321,17 @@ async function main() {
118
321
 
119
322
  switch (command) {
120
323
  case 'init':
121
- require('./init.js'); // Proxy to existing interactive init
324
+ await handleInit();
122
325
  break;
123
-
326
+
124
327
  case 'deploy':
125
328
  await handleDeploy();
126
329
  break;
127
330
 
128
331
  case 'status':
129
- // Try to find status file in current or subdirectory
130
332
  const statusPath = path.join(process.cwd(), 'my-rentabot-agent', 'RENTABOT_STATUS.md');
131
333
  const localStatusPath = path.join(process.cwd(), 'RENTABOT_STATUS.md');
132
-
334
+
133
335
  if (fs.existsSync(statusPath)) {
134
336
  console.log(fs.readFileSync(statusPath, 'utf8'));
135
337
  } else if (fs.existsSync(localStatusPath)) {
@@ -149,14 +351,15 @@ async function main() {
149
351
 
150
352
  default:
151
353
  console.log(`
152
- šŸ¦€ RENTABOTS MASTER CLI v1.5.8 (Universal)
354
+ šŸ¦€ RENTABOTS MASTER CLI v1.7.0 (Universal)
153
355
  ------------------------------
154
356
  Usage:
155
- npx rentabots-sdk init - Interactive setup for a new agent.
156
- npx rentabots-sdk deploy --key - One-line command to launch (Win/Linux/Mac).
157
- npx rentabots-sdk status - See your live agent dashboard.
158
- npx rentabots-sdk logs - Stream real-time telemetry.
159
- npx rentabots-sdk stop - Shutdown your agent.
357
+ npx rentabots-sdk init - Interactive setup wizard
358
+ npx rentabots-sdk deploy --key X - Deploy (interactive LLM selection)
359
+ npx rentabots-sdk deploy --key X --llm Y - Deploy (non-interactive, Y = openclaw|openai|anthropic|google|groq|mistral|custom)
360
+ npx rentabots-sdk status - Live agent dashboard
361
+ npx rentabots-sdk logs - Stream real-time telemetry
362
+ npx rentabots-sdk stop - Shutdown your agent
160
363
  `);
161
364
  }
162
365
  }