avg-nexus 1.0.7 → 1.0.10

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.
Files changed (2) hide show
  1. package/bin/avg-nexus.js +92 -161
  2. package/package.json +2 -5
package/bin/avg-nexus.js CHANGED
@@ -6,7 +6,6 @@ const http = require('http');
6
6
  const path = require('path');
7
7
  const fs = require('fs');
8
8
 
9
- // ── Ranglar ──
10
9
  const C = {
11
10
  reset: '\x1b[0m',
12
11
  green: '\x1b[32m',
@@ -21,72 +20,76 @@ function log(icon, msg, color = C.reset) {
21
20
  console.log(`${color}${icon} ${msg}${C.reset}`);
22
21
  }
23
22
 
24
- // ── Ollama topish (barcha disklar) ──
23
+ function sleep(ms) {
24
+ return new Promise(r => setTimeout(r, ms));
25
+ }
26
+
27
+ // ── Ollama topish — PATH + barcha disklar ──
25
28
  function findOllama() {
26
- // 1. PATH dan
27
29
  try {
28
30
  const r = execSync('where ollama', { encoding: 'utf8', stdio: ['pipe','pipe','pipe'] }).trim();
29
31
  if (r) return r.split('\n')[0].trim();
30
32
  } catch {}
31
33
 
32
- // 2. Barcha disklarda qidirish
33
34
  const drives = ['A','B','C','D','E','F','G','H','I','J'];
34
35
  const locations = [
35
36
  'Ollama\\ollama.exe',
36
37
  'Program Files\\Ollama\\ollama.exe',
37
38
  `Users\\${process.env.USERNAME || 'user'}\\AppData\\Local\\Programs\\Ollama\\ollama.exe`,
38
- 'AppData\\Local\\Programs\\Ollama\\ollama.exe',
39
39
  ];
40
40
 
41
- for (const drive of drives) {
42
- for (const loc of locations) {
43
- const full = `${drive}:\\${loc}`;
44
- try {
45
- if (fs.existsSync(full)) return full;
46
- } catch {}
41
+ for (const d of drives) {
42
+ for (const l of locations) {
43
+ const p = `${d}:\\${l}`;
44
+ try { if (fs.existsSync(p)) return p; } catch {}
47
45
  }
48
46
  }
49
47
  return null;
50
48
  }
51
49
 
52
- // ── Model topish (barcha disklar) ──
53
- async function findBestModel() {
54
- // 10 marta urinib ko'rish
55
- for (let i = 0; i < 10; i++) {
56
- await sleep(4000);
57
- try {
58
- const res = await fetch('http://localhost:11434/api/tags');
59
- const data = await res.json();
60
- const models = data.models || [];
61
- if (models.length > 0) {
62
- const preferred = ['gemma4', 'gemma3', 'gemma2', 'qwen', 'llama', 'mistral', 'deepseek', 'phi'];
63
- for (const pref of preferred) {
64
- const found = models.find(m => m.name.toLowerCase().includes(pref));
65
- if (found) {
66
- log('✅', `Model topildi: ${found.name}`, C.green);
67
- return found.name;
68
- }
50
+ // ── Model topish ollama list CLI orqali ──
51
+ function findBestModel() {
52
+ const preferred = ['gemma4', 'gemma3', 'gemma2', 'qwen', 'llama', 'mistral', 'deepseek', 'phi'];
53
+ try {
54
+ const result = execSync('ollama list', {
55
+ encoding: 'utf8',
56
+ stdio: ['pipe', 'pipe', 'pipe'],
57
+ timeout: 10000,
58
+ });
59
+ const lines = result
60
+ .split('\n')
61
+ .filter(l => l.trim() && !l.toLowerCase().startsWith('name'));
62
+
63
+ if (lines.length > 0) {
64
+ for (const pref of preferred) {
65
+ const found = lines.find(l => l.toLowerCase().includes(pref));
66
+ if (found) {
67
+ const name = found.split(/\s+/)[0].trim();
68
+ log('✅', `Model topildi: ${name}`, C.green);
69
+ return name;
69
70
  }
70
- return models[0].name;
71
71
  }
72
- log('⏳', `Model kutilmoqda... (${i+1}/10)`, C.yellow);
73
- } catch {
74
- log('⏳', `Ollama kutilmoqda... (${i+1}/10)`, C.yellow);
72
+ const name = lines[0].split(/\s+/)[0].trim();
73
+ log('✅', `Model: ${name}`, C.green);
74
+ return name;
75
75
  }
76
+ } catch (e) {
77
+ log('⚠️', `ollama list xatosi: ${e.message}`, C.yellow);
76
78
  }
77
- log('📥', 'Model topilmadi, gemma4:e4b yuklanmoqda...', C.yellow);
79
+
80
+ // Model topilmadi — gemma4:e4b yuklab olish
81
+ log('📥', 'Model topilmadi. gemma4:e4b yuklanmoqda...', C.yellow);
78
82
  execSync('ollama pull gemma4:e4b', { stdio: 'inherit' });
79
83
  return 'gemma4:e4b';
80
84
  }
81
85
 
82
- // ── Ollama ishga tushirish ──
86
+ // ── Ollama serve ishga tushirish ──
83
87
  function startOllama(ollamaPath) {
84
88
  try {
85
- execSync('curl -s http://localhost:11434', { timeout: 1000, stdio: 'pipe' });
89
+ execSync('curl -s http://localhost:11434', { timeout: 2000, stdio: 'pipe' });
86
90
  log('✅', 'Ollama allaqachon ishlamoqda', C.green);
87
91
  return;
88
92
  } catch {}
89
-
90
93
  log('🚀', 'Ollama ishga tushirilmoqda...', C.cyan);
91
94
  const proc = spawn(ollamaPath, ['serve'], {
92
95
  detached: true,
@@ -97,27 +100,19 @@ function startOllama(ollamaPath) {
97
100
  log('✅', 'Ollama serve ishga tushdi', C.green);
98
101
  }
99
102
 
100
- // ── OpenRouter Proxy ──
103
+ // ── OpenRouter → Ollama Proxy ──
101
104
  function startProxy(model) {
102
- const PROXY_PORT = 11435;
103
-
105
+ const PORT = 11435;
104
106
  const server = http.createServer(async (req, res) => {
105
107
  res.setHeader('Access-Control-Allow-Origin', '*');
106
108
  res.setHeader('Access-Control-Allow-Headers', '*');
107
109
  res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS');
108
110
 
109
- if (req.method === 'OPTIONS') {
110
- res.writeHead(200);
111
- res.end();
112
- return;
113
- }
111
+ if (req.method === 'OPTIONS') { res.writeHead(200); res.end(); return; }
114
112
 
115
- // Models endpoint
116
113
  if (req.url && req.url.includes('/models')) {
117
114
  res.writeHead(200, { 'Content-Type': 'application/json' });
118
- res.end(JSON.stringify({
119
- data: [{ id: model, name: model, context_length: 8192 }]
120
- }));
115
+ res.end(JSON.stringify({ data: [{ id: model, name: model, context_length: 8192 }] }));
121
116
  return;
122
117
  }
123
118
 
@@ -125,151 +120,104 @@ function startProxy(model) {
125
120
  req.on('data', c => body += c);
126
121
  req.on('end', async () => {
127
122
  try {
128
- let reqData = {};
129
- try { reqData = JSON.parse(body); } catch {}
130
-
123
+ let d = {};
124
+ try { d = JSON.parse(body); } catch {}
131
125
  const ollamaRes = await fetch('http://localhost:11434/api/chat', {
132
126
  method: 'POST',
133
127
  headers: { 'Content-Type': 'application/json' },
134
- body: JSON.stringify({
135
- model: reqData.model || model,
136
- messages: reqData.messages || [],
137
- stream: true,
138
- }),
128
+ body: JSON.stringify({ model: d.model || model, messages: d.messages || [], stream: true }),
139
129
  });
140
-
141
130
  res.writeHead(200, { 'Content-Type': 'text/event-stream' });
142
-
143
131
  const reader = ollamaRes.body.getReader();
144
- const decoder = new TextDecoder();
145
-
132
+ const dec = new TextDecoder();
146
133
  while (true) {
147
134
  const { done, value } = await reader.read();
148
135
  if (done) break;
149
- const text = decoder.decode(value);
150
- for (const line of text.split('\n').filter(l => l.trim())) {
136
+ for (const line of dec.decode(value).split('\n').filter(l => l.trim())) {
151
137
  try {
152
- const json = JSON.parse(line);
153
- const content = json.message?.content || '';
154
- const isDone = json.done || false;
138
+ const j = JSON.parse(line);
155
139
  res.write('data: ' + JSON.stringify({
156
140
  id: 'chatcmpl-' + Date.now(),
157
141
  object: 'chat.completion.chunk',
158
- choices: [{ delta: { content }, finish_reason: isDone ? 'stop' : null }],
142
+ choices: [{ delta: { content: j.message?.content || '' }, finish_reason: j.done ? 'stop' : null }],
159
143
  }) + '\n\n');
160
144
  } catch {}
161
145
  }
162
146
  }
163
147
  res.write('data: [DONE]\n\n');
164
148
  res.end();
165
- } catch (err) {
166
- res.writeHead(500);
167
- res.end(JSON.stringify({ error: err.message }));
168
- }
149
+ } catch (e) { res.writeHead(500); res.end(JSON.stringify({ error: e.message })); }
169
150
  });
170
151
  });
171
-
172
- server.listen(PROXY_PORT, () => {
173
- log('✅', `OpenRouter proxy: http://localhost:${PROXY_PORT}`, C.green);
174
- });
175
-
152
+ server.listen(PORT, () => log('✅', `Proxy: http://localhost:${PORT}`, C.green));
176
153
  return server;
177
154
  }
178
155
 
179
- // ── NexusAI loyihasini topish ──
156
+ // ── NexusAI loyiha topish ──
180
157
  function findProject() {
158
+ const cfgs = ['next.config.js', 'next.config.ts', 'next.config.mjs'];
181
159
  const cwd = process.cwd();
182
-
183
- // Hozirgi papkada next.config bormi?
184
- const nextConfigs = ['next.config.js', 'next.config.ts', 'next.config.mjs'];
185
- for (const cfg of nextConfigs) {
186
- if (fs.existsSync(path.join(cwd, cfg))) return cwd;
160
+ for (const c of cfgs) {
161
+ if (fs.existsSync(path.join(cwd, c))) return cwd;
187
162
  }
188
-
189
- // Barcha disklarda qidirish
190
- const drives = ['E', 'D', 'C', 'F', 'G'];
191
- const names = ['nexusai-team', 'NexusAi-team', 'NexusAI-team', 'nexus-team', 'nexusai'];
192
-
193
- for (const drive of drives) {
194
- for (const name of names) {
195
- const p = `${drive}:\\${name}`;
163
+ const drives = ['E','D','C','F','G'];
164
+ const names = ['nexusai-team','NexusAi-team','NexusAI-team','nexus-team','nexusai'];
165
+ for (const d of drives) {
166
+ for (const n of names) {
167
+ const p = `${d}:\\${n}`;
196
168
  try {
197
- if (fs.existsSync(p) && nextConfigs.some(c => fs.existsSync(path.join(p, c)))) {
198
- return p;
199
- }
169
+ if (fs.existsSync(p) && cfgs.some(c => fs.existsSync(path.join(p, c)))) return p;
200
170
  } catch {}
201
171
  }
202
172
  }
203
173
  return null;
204
174
  }
205
175
 
206
- // ── .env.local sozlash ──
207
- function setupEnv(projectDir) {
208
- const envPath = path.join(projectDir, '.env.local');
176
+ // ── .env.local yozish ──
177
+ function setupEnv(dir) {
178
+ const envPath = path.join(dir, '.env.local');
209
179
  const content = [
210
180
  'OPENROUTER_BASE_URL=http://localhost:11435/api/v1',
211
181
  'OPENROUTER_API_KEY_1=ollama-local',
212
182
  'OPENROUTER_API_KEY_2=ollama-local',
213
183
  'OPENROUTER_API_KEY_3=ollama-local',
214
184
  ].join('\n');
215
-
216
- // Agar mavjud bo'lsa OpenRouter kalitlarini saqlab qolamiz
217
185
  if (fs.existsSync(envPath)) {
218
- const existing = fs.readFileSync(envPath, 'utf8');
219
- if (existing.includes('OLLAMA') || existing.includes('ollama-local')) return;
220
- // OpenRouter kalitlari bor bo'lsa ularga proxy qo'shamiz
221
- fs.writeFileSync(envPath, content + '\n' + existing);
186
+ const ex = fs.readFileSync(envPath, 'utf8');
187
+ if (ex.includes('ollama-local')) return;
188
+ fs.writeFileSync(envPath, content + '\n' + ex);
222
189
  } else {
223
190
  fs.writeFileSync(envPath, content);
224
191
  }
225
192
  log('✅', '.env.local sozlandi', C.green);
226
193
  }
227
194
 
228
- // ── Next.js serverni ishga tushirish ──
229
- function startNextJS(projectDir) {
230
- return new Promise((resolve) => {
231
- setupEnv(projectDir);
232
-
233
- // node_modules bormi?
234
- if (!fs.existsSync(path.join(projectDir, 'node_modules'))) {
195
+ // ── Next.js ishga tushirish ──
196
+ function startNextJS(dir) {
197
+ return new Promise(resolve => {
198
+ setupEnv(dir);
199
+ if (!fs.existsSync(path.join(dir, 'node_modules'))) {
235
200
  log('📦', 'npm install...', C.yellow);
236
- execSync('npm install', { cwd: projectDir, stdio: 'inherit' });
201
+ execSync('npm install', { cwd: dir, stdio: 'inherit' });
237
202
  }
238
-
239
- log('🌐', 'NexusAI sayt ishga tushmoqda...', C.cyan);
240
-
203
+ log('🌐', 'NexusAI ishga tushmoqda...', C.cyan);
241
204
  const dev = spawn('npm', ['run', 'dev'], {
242
- cwd: projectDir,
243
- shell: true,
205
+ cwd: dir, shell: true,
244
206
  stdio: ['ignore', 'pipe', 'pipe'],
245
- env: {
246
- ...process.env,
247
- PORT: '3000',
248
- OPENROUTER_BASE_URL: 'http://localhost:11435/api/v1',
249
- OPENROUTER_API_KEY_1: 'ollama-local',
250
- },
207
+ env: { ...process.env, PORT: '3000', OPENROUTER_BASE_URL: 'http://localhost:11435/api/v1', OPENROUTER_API_KEY_1: 'ollama-local' },
251
208
  });
252
-
253
- dev.stdout.on('data', (data) => {
254
- const text = data.toString();
255
- if (text.includes('Ready') || text.includes('ready') || text.includes('localhost:3000')) {
209
+ dev.stdout.on('data', d => {
210
+ const t = d.toString();
211
+ if (t.includes('Ready') || t.includes('ready') || t.includes('localhost:3000')) {
256
212
  log('✅', 'Sayt tayyor: http://localhost:3000', C.green);
257
213
  setTimeout(resolve, 500);
258
214
  }
259
215
  });
260
-
261
- dev.stderr.on('data', () => {});
262
- dev.on('error', (err) => log('❌', err.message, C.red));
263
-
264
- // Max 60 sekund
216
+ dev.on('error', e => log('❌', e.message, C.red));
265
217
  setTimeout(resolve, 60000);
266
218
  });
267
219
  }
268
220
 
269
- function sleep(ms) {
270
- return new Promise(r => setTimeout(r, ms));
271
- }
272
-
273
221
  // ── MAIN ──
274
222
  async function main() {
275
223
  console.log(`\n${C.bold}${C.cyan}
@@ -281,54 +229,37 @@ async function main() {
281
229
  ╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝╚═╝
282
230
  ${C.reset}${C.dim} TEAM v3.0 — 15 AI Agents${C.reset}\n`);
283
231
 
284
- // 1. Ollama topish
285
232
  log('🔍', 'Ollama qidirilmoqda...', C.cyan);
286
233
  const ollamaPath = findOllama();
287
-
288
234
  if (!ollamaPath) {
289
- log('❌', 'Ollama topilmadi!', C.red);
290
- log('💡', 'Yuklab oling: https://ollama.com/download', C.yellow);
235
+ log('❌', 'Ollama topilmadi! https://ollama.com/download', C.red);
291
236
  process.exit(1);
292
237
  }
293
238
  log('✅', `Ollama: ${ollamaPath}`, C.green);
294
239
 
295
- // 2. Ollama ishga tushirish
296
240
  startOllama(ollamaPath);
297
241
  await sleep(2000);
298
242
 
299
- // 3. Model topish
300
243
  log('🔍', 'AI model qidirilmoqda...', C.cyan);
301
- const model = await findBestModel();
244
+ const model = findBestModel();
302
245
 
303
- // 4. Proxy
304
246
  startProxy(model);
305
247
 
306
- // 5. Loyiha topish
307
248
  log('🔍', 'NexusAI loyiha qidirilmoqda...', C.cyan);
308
- const projectDir = findProject();
309
-
310
- if (!projectDir) {
249
+ const dir = findProject();
250
+ if (!dir) {
311
251
  log('❌', 'NexusAI loyiha topilmadi!', C.red);
312
- log('💡', 'Loyiha papkasida turib avg-nexus buyrug\'ini bering', C.yellow);
252
+ log('💡', 'nexusai-team papkasida turib avg-nexus bering', C.yellow);
313
253
  process.exit(1);
314
254
  }
315
- log('✅', `Loyiha: ${projectDir}`, C.green);
255
+ log('✅', `Loyiha: ${dir}`, C.green);
316
256
 
317
- // 6. Next.js ishga tushirish
318
- await startNextJS(projectDir);
257
+ await startNextJS(dir);
319
258
 
320
- log('', `\n${C.bold}${C.green}🎉 NexusAI tayyor!${C.reset}`, '');
321
- log('🌐', 'http://localhost:3000', C.cyan);
322
- log('', `${C.dim}To\'xtatish uchun: Ctrl+C${C.reset}\n`, '');
259
+ log('', `\n${C.bold}${C.green}🎉 NexusAI tayyor! http://localhost:3000${C.reset}\n`, '');
260
+ log('', `${C.dim}To'xtatish: Ctrl+C${C.reset}\n`, '');
323
261
 
324
- // Jarayon tirik qolsin
325
- process.on('SIGINT', () => {
326
- log('👋', 'NexusAI to\'xtatildi', C.yellow);
327
- process.exit(0);
328
- });
262
+ process.on('SIGINT', () => { log('👋', 'To\'xtatildi', C.yellow); process.exit(0); });
329
263
  }
330
264
 
331
- main().catch(err => {
332
- log('❌', `Xato: ${err.message}`, C.red);
333
- process.exit(1);
334
- });
265
+ main().catch(e => { log('❌', e.message, C.red); process.exit(1); });
package/package.json CHANGED
@@ -1,18 +1,15 @@
1
1
  {
2
2
  "name": "avg-nexus",
3
- "version": "1.0.7",
3
+ "version": "1.0.10",
4
4
  "description": "Offline/Online proxy for NexusAI Team — runs with local Ollama",
5
5
  "main": "bin/avg-nexus.js",
6
6
  "type": "commonjs",
7
7
  "bin": {
8
- "avg-nexus": "./bin/avg-nexus.js"
8
+ "avgnexus": "./bin/avg-nexus.js"
9
9
  },
10
10
  "scripts": {
11
11
  "start": "node bin/avg-nexus.js"
12
12
  },
13
- "dependencies": {
14
- "node-fetch": "^2.7.0"
15
- },
16
13
  "keywords": [
17
14
  "ollama",
18
15
  "openrouter",