samarthya-bot 1.1.3 → 2.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.
@@ -28,13 +28,13 @@ const isServerRunning = () => {
28
28
 
29
29
  if (!command) {
30
30
  console.log(`
31
- šŸ¤– SamarthyaBot Local AI Agent
31
+ šŸ‡®šŸ‡³ SamarthyaBot — Your Local Agentic OS
32
32
  Usage:
33
- samarthya onboard - Setup your local environment
33
+ samarthya onboard - Setup + Start everything (single command!)
34
34
  samarthya model - Change your active AI provider/model
35
- samarthya gateway - Start the local server
35
+ samarthya gateway - Start the local server only
36
+ samarthya tunnel - Expose to internet & setup webhooks
36
37
  samarthya status - Check if the agent is running
37
- samarthya tunnel - Expose to internet & setup webhooks
38
38
  samarthya stop - Stop the running gateway
39
39
  samarthya restart - Restart the gateway
40
40
  `);
@@ -54,14 +54,17 @@ switch (command) {
54
54
 
55
55
  (async () => {
56
56
  console.log("\n🌐 Select your primary AI Provider:");
57
- console.log(" 1) Google Gemini (Default)");
58
- console.log(" 2) Anthropic Claude");
57
+ console.log(" 1) Google Gemini (Default, Free tier)");
58
+ console.log(" 2) Anthropic Claude (Smartest)");
59
59
  console.log(" 3) Groq (Fastest)");
60
- console.log(" 4) OpenAI");
61
- console.log(" 5) Local Ollama (Offline)");
62
- console.log(" 6) Mistral AI\n");
63
-
64
- let providerRaw = await question("Enter choice (1-6, default 1): ");
60
+ console.log(" 4) OpenAI (GPT-5)");
61
+ console.log(" 5) DeepSeek (Budget-friendly)");
62
+ console.log(" 6) Qwen (Alibaba)");
63
+ console.log(" 7) OpenRouter (100+ models via 1 key)");
64
+ console.log(" 8) Local Ollama (Offline, Private)");
65
+ console.log(" 9) Mistral AI\n");
66
+
67
+ let providerRaw = await question("Enter choice (1-9, default 1): ");
65
68
  let activeProvider = 'gemini';
66
69
  let useOllama = 'false';
67
70
 
@@ -69,11 +72,14 @@ switch (command) {
69
72
  case '2': activeProvider = 'anthropic'; break;
70
73
  case '3': activeProvider = 'groq'; break;
71
74
  case '4': activeProvider = 'openai'; break;
72
- case '5':
75
+ case '5': activeProvider = 'deepseek'; break;
76
+ case '6': activeProvider = 'qwen'; break;
77
+ case '7': activeProvider = 'openrouter'; break;
78
+ case '8':
73
79
  activeProvider = 'ollama';
74
80
  useOllama = 'true';
75
81
  break;
76
- case '6': activeProvider = 'mistral'; break;
82
+ case '9': activeProvider = 'mistral'; break;
77
83
  case '1':
78
84
  default:
79
85
  activeProvider = 'gemini';
@@ -86,7 +92,12 @@ switch (command) {
86
92
  const anthropicKey = await question('šŸ”‘ Enter Anthropic (Claude) API Key (or press Enter to skip): ');
87
93
  const groqKey = await question('šŸ”‘ Enter Groq API Key (or press Enter to skip): ');
88
94
  const openAiKey = await question('šŸ”‘ Enter OpenAI API Key (or press Enter to skip): ');
95
+ const deepseekKey = await question('šŸ”‘ Enter DeepSeek API Key (or press Enter to skip): ');
96
+ const qwenKey = await question('šŸ”‘ Enter Qwen API Key (or press Enter to skip): ');
97
+ const openrouterKey = await question('šŸ”‘ Enter OpenRouter API Key (or press Enter to skip): ');
89
98
  const telegramToken = await question('šŸ¤– Enter Telegram Bot Token (or press Enter to skip): ');
99
+ const discordToken = await question('🟣 Enter Discord Bot Token (or press Enter to skip): ');
100
+ const encKey = await question('šŸ” Enter 32-char Encryption Key (or press Enter for auto-generate): ');
90
101
 
91
102
  const envPath = path.join(backendDir, '.env');
92
103
  let envVars = {};
@@ -95,13 +106,17 @@ switch (command) {
95
106
  if (fs.existsSync(envPath)) {
96
107
  const currentEnv = fs.readFileSync(envPath, 'utf8');
97
108
  currentEnv.split('\n').forEach(line => {
98
- const [k, v] = line.split('=');
99
- if (k && v) envVars[k.trim()] = v.trim();
109
+ const eqIndex = line.indexOf('=');
110
+ if (eqIndex > 0) {
111
+ const k = line.substring(0, eqIndex).trim();
112
+ const v = line.substring(eqIndex + 1).trim();
113
+ if (k) envVars[k] = v;
114
+ }
100
115
  });
101
116
  } else {
102
117
  envVars = {
103
118
  PORT: '5000',
104
- MONGODB_URI: 'mongodb://localhost:27017/samarthya',
119
+ MONGO_URI: 'mongodb://localhost:27017/samarthya',
105
120
  JWT_SECRET: 'samarthya_secret_key_change_in_production',
106
121
  NODE_ENV: 'production',
107
122
  CORS_ORIGIN: 'http://localhost:5000',
@@ -109,7 +124,9 @@ switch (command) {
109
124
  ACTIVE_PROVIDER: activeProvider,
110
125
  ACTIVE_MODEL: activeProvider === 'gemini' ? 'gemini-2.5-flash' : '',
111
126
  OLLAMA_URL: 'http://localhost:11434',
112
- OLLAMA_MODEL: 'dolphin3:8b-llama3.1-q4_K_M'
127
+ OLLAMA_MODEL: 'dolphin3:8b-llama3.1-q4_K_M',
128
+ RESTRICT_TO_WORKSPACE: 'true',
129
+ HEARTBEAT_INTERVAL: '30'
113
130
  };
114
131
  }
115
132
 
@@ -121,7 +138,20 @@ switch (command) {
121
138
  if (anthropicKey.trim()) envVars['ANTHROPIC_API_KEY'] = anthropicKey.trim();
122
139
  if (groqKey.trim()) envVars['GROQ_API_KEY'] = groqKey.trim();
123
140
  if (openAiKey.trim()) envVars['OPENAI_API_KEY'] = openAiKey.trim();
141
+ if (deepseekKey.trim()) envVars['DEEPSEEK_API_KEY'] = deepseekKey.trim();
142
+ if (qwenKey.trim()) envVars['QWEN_API_KEY'] = qwenKey.trim();
143
+ if (openrouterKey.trim()) envVars['OPENROUTER_API_KEY'] = openrouterKey.trim();
124
144
  if (telegramToken.trim()) envVars['TELEGRAM_BOT_TOKEN'] = telegramToken.trim();
145
+ if (discordToken.trim()) envVars['DISCORD_BOT_TOKEN'] = discordToken.trim();
146
+
147
+ // Auto-generate encryption key if not provided
148
+ if (encKey.trim()) {
149
+ envVars['MEMORY_ENCRYPTION_KEY'] = encKey.trim();
150
+ } else if (!envVars['MEMORY_ENCRYPTION_KEY']) {
151
+ const crypto = require('crypto');
152
+ envVars['MEMORY_ENCRYPTION_KEY'] = crypto.randomBytes(16).toString('hex');
153
+ console.log('šŸ” Auto-generated encryption key.');
154
+ }
125
155
 
126
156
  if (!envVars['GEMINI_API_KEY']) envVars['GEMINI_API_KEY'] = 'dummy';
127
157
 
@@ -130,14 +160,67 @@ switch (command) {
130
160
  fs.writeFileSync(envPath, newEnvContent);
131
161
  console.log('\nāœ… Keys saved to .env file securely.');
132
162
 
133
- console.log('šŸ“¦ Installing backend dependencies (this might take a few seconds)...');
163
+ console.log('šŸ“¦ Installing backend dependencies...');
134
164
  try {
135
165
  execSync('npm install --production', { cwd: backendDir, stdio: 'ignore' });
136
166
  } catch (e) { /* ignore */ }
137
167
 
138
- console.log('\n✨ Onboarding complete! Run "samarthya gateway" to start your AI Operator.');
139
168
  rl.close();
140
- process.exit(0);
169
+
170
+ // ═══════ AUTO-START: Gateway + Tunnel in one command ═══════
171
+ console.log('\nšŸš€ Starting SamarthyaBot Gateway...');
172
+
173
+ // Load the .env we just wrote
174
+ try { require('dotenv').config({ path: envPath }); } catch (e) { }
175
+
176
+ const gatewayChild = spawn('node', ['server.js'], {
177
+ cwd: backendDir,
178
+ stdio: 'inherit'
179
+ });
180
+
181
+ gatewayChild.on('close', (code) => {
182
+ console.log(`Gateway exited with code ${code}`);
183
+ });
184
+
185
+ // Wait for server to boot, then start tunnel
186
+ setTimeout(() => {
187
+ if (envVars['TELEGRAM_BOT_TOKEN'] && envVars['TELEGRAM_BOT_TOKEN'] !== 'dummy') {
188
+ console.log('\nšŸš‡ Auto-starting tunnel for Telegram webhook...');
189
+ const isWin = process.platform === 'win32';
190
+ const tunnelChild = spawn('npm', ['exec', 'localtunnel', '--', '--port', '5000'], {
191
+ stdio: 'pipe',
192
+ shell: isWin
193
+ });
194
+
195
+ tunnelChild.stdout.on('data', async (data) => {
196
+ const output = data.toString();
197
+ console.log(output.trim());
198
+ const match = output.match(/your url is: (https:\/\/.+)/);
199
+ if (match && match[1]) {
200
+ const publicUrl = match[1];
201
+ console.log(`\nāœ… Public Gateway URL: ${publicUrl}`);
202
+ if (envVars['TELEGRAM_BOT_TOKEN']) {
203
+ try {
204
+ const tgUrl = `https://api.telegram.org/bot${envVars['TELEGRAM_BOT_TOKEN']}/setWebhook?url=${publicUrl}/api/telegram/webhook`;
205
+ const res = await fetch(tgUrl);
206
+ const result = await res.json();
207
+ if (result.ok) console.log('🟢 Telegram Webhook Set!');
208
+ else console.log('šŸ”“ Telegram Webhook failed:', result.description);
209
+ } catch (err) {
210
+ console.log('šŸ”“ Webhook error:', err.message);
211
+ }
212
+ }
213
+ }
214
+ });
215
+
216
+ tunnelChild.stderr.on('data', (data) => console.error('Tunnel:', data.toString()));
217
+ } else {
218
+ console.log('\nāœ… Gateway is running! Open http://localhost:5000');
219
+ console.log('ā„¹ļø No Telegram token found — skipping tunnel. Run "samarthya tunnel" later if needed.');
220
+ }
221
+ }, 3000);
222
+
223
+ // Don't exit — keep process alive
141
224
  })();
142
225
  break;
143
226
 
@@ -152,10 +235,13 @@ switch (command) {
152
235
  console.log(" 2) Anthropic Claude");
153
236
  console.log(" 3) Groq (Fastest)");
154
237
  console.log(" 4) OpenAI");
155
- console.log(" 5) Local Ollama (Offline)");
156
- console.log(" 6) Mistral AI\n");
238
+ console.log(" 5) DeepSeek");
239
+ console.log(" 6) Qwen (Alibaba)");
240
+ console.log(" 7) OpenRouter (100+ models)");
241
+ console.log(" 8) Local Ollama (Offline)");
242
+ console.log(" 9) Mistral AI\n");
157
243
 
158
- let pRaw = await qModel("Enter choice (1-6, default 1): ");
244
+ let pRaw = await qModel("Enter choice (1-9, default 1): ");
159
245
  let aProv = 'gemini';
160
246
  let uOll = 'false';
161
247
 
@@ -163,8 +249,11 @@ switch (command) {
163
249
  case '2': aProv = 'anthropic'; break;
164
250
  case '3': aProv = 'groq'; break;
165
251
  case '4': aProv = 'openai'; break;
166
- case '5': aProv = 'ollama'; uOll = 'true'; break;
167
- case '6': aProv = 'mistral'; break;
252
+ case '5': aProv = 'deepseek'; break;
253
+ case '6': aProv = 'qwen'; break;
254
+ case '7': aProv = 'openrouter'; break;
255
+ case '8': aProv = 'ollama'; uOll = 'true'; break;
256
+ case '9': aProv = 'mistral'; break;
168
257
  default: aProv = 'gemini'; break;
169
258
  }
170
259
 
@@ -26,7 +26,8 @@
26
26
  "puppeteer-core": "^24.37.5",
27
27
  "screenshot-desktop": "^1.15.3",
28
28
  "socket.io": "^4.8.3",
29
- "uuid": "^13.0.0"
29
+ "uuid": "^13.0.0",
30
+ "ws": "^8.19.0"
30
31
  },
31
32
  "bin": {
32
33
  "samarthya": "bin/samarthya.js",
@@ -1041,6 +1042,27 @@
1041
1042
  "node": ">= 0.6"
1042
1043
  }
1043
1044
  },
1045
+ "node_modules/engine.io/node_modules/ws": {
1046
+ "version": "8.18.3",
1047
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
1048
+ "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
1049
+ "license": "MIT",
1050
+ "engines": {
1051
+ "node": ">=10.0.0"
1052
+ },
1053
+ "peerDependencies": {
1054
+ "bufferutil": "^4.0.1",
1055
+ "utf-8-validate": ">=5.0.2"
1056
+ },
1057
+ "peerDependenciesMeta": {
1058
+ "bufferutil": {
1059
+ "optional": true
1060
+ },
1061
+ "utf-8-validate": {
1062
+ "optional": true
1063
+ }
1064
+ }
1065
+ },
1044
1066
  "node_modules/es-define-property": {
1045
1067
  "version": "1.0.1",
1046
1068
  "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
@@ -2643,27 +2665,6 @@
2643
2665
  "node": ">=18"
2644
2666
  }
2645
2667
  },
2646
- "node_modules/puppeteer-core/node_modules/ws": {
2647
- "version": "8.19.0",
2648
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
2649
- "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==",
2650
- "license": "MIT",
2651
- "engines": {
2652
- "node": ">=10.0.0"
2653
- },
2654
- "peerDependencies": {
2655
- "bufferutil": "^4.0.1",
2656
- "utf-8-validate": ">=5.0.2"
2657
- },
2658
- "peerDependenciesMeta": {
2659
- "bufferutil": {
2660
- "optional": true
2661
- },
2662
- "utf-8-validate": {
2663
- "optional": true
2664
- }
2665
- }
2666
- },
2667
2668
  "node_modules/qs": {
2668
2669
  "version": "6.15.0",
2669
2670
  "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz",
@@ -3031,6 +3032,27 @@
3031
3032
  "ws": "~8.18.3"
3032
3033
  }
3033
3034
  },
3035
+ "node_modules/socket.io-adapter/node_modules/ws": {
3036
+ "version": "8.18.3",
3037
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
3038
+ "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
3039
+ "license": "MIT",
3040
+ "engines": {
3041
+ "node": ">=10.0.0"
3042
+ },
3043
+ "peerDependencies": {
3044
+ "bufferutil": "^4.0.1",
3045
+ "utf-8-validate": ">=5.0.2"
3046
+ },
3047
+ "peerDependenciesMeta": {
3048
+ "bufferutil": {
3049
+ "optional": true
3050
+ },
3051
+ "utf-8-validate": {
3052
+ "optional": true
3053
+ }
3054
+ }
3055
+ },
3034
3056
  "node_modules/socket.io-parser": {
3035
3057
  "version": "4.2.5",
3036
3058
  "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.5.tgz",
@@ -3646,9 +3668,9 @@
3646
3668
  "license": "ISC"
3647
3669
  },
3648
3670
  "node_modules/ws": {
3649
- "version": "8.18.3",
3650
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
3651
- "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
3671
+ "version": "8.19.0",
3672
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
3673
+ "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==",
3652
3674
  "license": "MIT",
3653
3675
  "engines": {
3654
3676
  "node": ">=10.0.0"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "samarthya-agent",
3
- "version": "1.0.0",
3
+ "version": "2.0.0",
4
4
  "main": "server.js",
5
5
  "bin": {
6
6
  "samarthya": "./bin/samarthya.js",
@@ -33,9 +33,10 @@
33
33
  "puppeteer-core": "^24.37.5",
34
34
  "screenshot-desktop": "^1.15.3",
35
35
  "socket.io": "^4.8.3",
36
- "uuid": "^13.0.0"
36
+ "uuid": "^13.0.0",
37
+ "ws": "^8.19.0"
37
38
  },
38
39
  "devDependencies": {
39
40
  "nodemon": "^3.1.14"
40
41
  }
41
- }
42
+ }