@aethermind/setup 0.1.4 → 0.1.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aethermind/setup",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "CLI setup tool for Aethermind AgentOS — configures your project with one command",
5
5
  "bin": {
6
6
  "aethermind-setup": "./bin/setup.js"
package/src/detect.js CHANGED
@@ -15,15 +15,26 @@ function checkNodeVersion() {
15
15
  return version;
16
16
  }
17
17
 
18
+ /**
19
+ * Detect the project language/runtime.
20
+ * Returns 'node', 'python', or 'unknown'.
21
+ */
22
+ function detectLanguage(cwd) {
23
+ if (fs.existsSync(path.join(cwd, 'package.json'))) return 'node';
24
+ if (
25
+ fs.existsSync(path.join(cwd, 'requirements.txt')) ||
26
+ fs.existsSync(path.join(cwd, 'pyproject.toml')) ||
27
+ fs.existsSync(path.join(cwd, 'setup.py')) ||
28
+ fs.existsSync(path.join(cwd, 'Pipfile'))
29
+ ) return 'python';
30
+ return 'unknown';
31
+ }
32
+
18
33
  function detectPackageJson(cwd) {
19
34
  const pkgPath = path.join(cwd, 'package.json');
20
- if (!fs.existsSync(pkgPath)) {
21
- fail('No se encontro package.json en el directorio actual');
22
- console.log(' Ejecuta este comando desde la raiz de tu proyecto.');
23
- process.exit(1);
24
- }
35
+ if (!fs.existsSync(pkgPath)) return null;
25
36
  const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
26
- ok(`Proyecto: ${pkg.name || path.basename(cwd)} (package.json encontrado)`);
37
+ ok(`Proyecto: ${pkg.name || path.basename(cwd)}`);
27
38
  return pkg;
28
39
  }
29
40
 
@@ -49,7 +60,7 @@ function detectInstalledSDKs(cwd) {
49
60
  if (found.length > 0) {
50
61
  ok(`SDKs detectados: ${found.join(', ')}`);
51
62
  } else {
52
- info('No se detectaron SDKs de IA instalados (openai, anthropic, gemini, ollama)');
63
+ info('No se detectaron SDKs de IA instalados');
53
64
  }
54
65
  return found;
55
66
  }
@@ -61,4 +72,32 @@ function detectPackageManager(cwd) {
61
72
  return 'npm';
62
73
  }
63
74
 
64
- module.exports = { checkNodeVersion, detectPackageJson, detectInstalledSDKs, detectPackageManager };
75
+ /**
76
+ * Detect if Ollama is installed (binary on PATH or running on default port).
77
+ */
78
+ function detectOllama() {
79
+ const { execSync } = require('child_process');
80
+
81
+ // Check if ollama binary exists
82
+ try {
83
+ execSync('ollama --version', { stdio: 'pipe', timeout: 5000 });
84
+ ok('Ollama detectado');
85
+ return true;
86
+ } catch (_) {
87
+ // not on PATH
88
+ }
89
+
90
+ // Check if something is listening on port 11434 (default Ollama port)
91
+ const http = require('http');
92
+ return new Promise((resolve) => {
93
+ const req = http.get('http://localhost:11434', { timeout: 2000 }, (res) => {
94
+ req.destroy();
95
+ ok('Ollama detectado (puerto 11434 activo)');
96
+ resolve(true);
97
+ });
98
+ req.on('error', () => resolve(false));
99
+ req.on('timeout', () => { req.destroy(); resolve(false); });
100
+ });
101
+ }
102
+
103
+ module.exports = { checkNodeVersion, detectLanguage, detectPackageJson, detectInstalledSDKs, detectPackageManager, detectOllama };
package/src/env.js CHANGED
@@ -4,61 +4,100 @@ const fs = require('fs');
4
4
  const path = require('path');
5
5
  const { ok, info } = require('./ui.js');
6
6
 
7
- const ENV_KEYS = {
8
- AETHERMIND_API_KEY: null,
9
- NODE_OPTIONS: '--require @aethermind/providers/register',
10
- };
7
+ const GATEWAY_URL = 'https://aethermind-agentos-production.up.railway.app/gateway/v1';
11
8
 
12
- function updateEnvFile(cwd, apiKey) {
9
+ /**
10
+ * Update .env file for a Node.js project.
11
+ * Adds AETHERMIND_API_KEY and NODE_OPTIONS=--require @aethermind/agent/register
12
+ */
13
+ function updateEnvForNode(cwd, apiKey) {
13
14
  const envPath = path.join(cwd, '.env');
14
- const backupPath = path.join(cwd, '.env.aethermind.backup');
15
- let existing = '';
15
+ backupEnv(cwd, envPath);
16
+
17
+ let content = readEnvOrEmpty(envPath);
18
+
19
+ content = setEnvVar(content, 'AETHERMIND_API_KEY', apiKey);
20
+ content = setEnvVar(content, 'NODE_OPTIONS', buildNodeOptions(content));
21
+
22
+ fs.writeFileSync(envPath, content, 'utf-8');
23
+ ok('.env actualizado (AETHERMIND_API_KEY + NODE_OPTIONS)');
24
+ }
25
+
26
+ /**
27
+ * Add Ollama proxy env vars.
28
+ * Sets OLLAMA_HOST to point to the local Aethermind proxy instead of Ollama directly.
29
+ */
30
+ function addOllamaEnv(cwd) {
31
+ const envPath = path.join(cwd, '.env');
32
+ let content = readEnvOrEmpty(envPath);
33
+
34
+ content = setEnvVar(content, 'OLLAMA_HOST', 'http://localhost:11435');
35
+
36
+ fs.writeFileSync(envPath, content, 'utf-8');
37
+ ok('.env actualizado (OLLAMA_HOST → proxy en puerto 11435)');
38
+ }
39
+
40
+ /**
41
+ * Update .env file for a Python or generic project.
42
+ * Sets OPENAI_BASE_URL, OPENAI_API_KEY (= SDK key), and ANTHROPIC_BASE_URL.
43
+ * The gateway authenticates via the SDK key and uses stored provider keys.
44
+ */
45
+ function updateEnvForGateway(cwd, apiKey) {
46
+ const envPath = path.join(cwd, '.env');
47
+ backupEnv(cwd, envPath);
48
+
49
+ let content = readEnvOrEmpty(envPath);
50
+
51
+ content = setEnvVar(content, 'AETHERMIND_API_KEY', apiKey);
52
+ content = setEnvVar(content, 'OPENAI_BASE_URL', GATEWAY_URL);
53
+ content = setEnvVar(content, 'OPENAI_API_KEY', apiKey);
54
+ content = setEnvVar(content, 'ANTHROPIC_BASE_URL', GATEWAY_URL);
55
+ content = setEnvVar(content, 'ANTHROPIC_API_KEY', apiKey);
16
56
 
17
- // Backup existing .env
57
+ fs.writeFileSync(envPath, content, 'utf-8');
58
+ ok('.env actualizado (OPENAI_BASE_URL + ANTHROPIC_BASE_URL + API keys)');
59
+ }
60
+
61
+ // ─── Helpers ────────────────────────────────────────
62
+
63
+ function readEnvOrEmpty(envPath) {
64
+ if (fs.existsSync(envPath)) {
65
+ return fs.readFileSync(envPath, 'utf-8');
66
+ }
67
+ return '';
68
+ }
69
+
70
+ function backupEnv(cwd, envPath) {
71
+ const backupPath = path.join(cwd, '.env.aethermind.backup');
18
72
  if (fs.existsSync(envPath)) {
19
- existing = fs.readFileSync(envPath, 'utf-8');
20
73
  fs.copyFileSync(envPath, backupPath);
21
74
  ok('Backup guardado en .env.aethermind.backup');
22
75
  }
76
+ }
23
77
 
24
- const lines = existing ? existing.split('\n') : [];
25
- const updates = {
26
- AETHERMIND_API_KEY: apiKey,
27
- NODE_OPTIONS: buildNodeOptions(lines),
28
- };
29
-
30
- let content = existing;
31
-
32
- for (const [key, value] of Object.entries(updates)) {
33
- const regex = new RegExp(`^${key}=.*$`, 'm');
34
- const newLine = `${key}=${value}`;
35
-
36
- if (regex.test(content)) {
37
- content = content.replace(regex, newLine);
38
- } else {
39
- if (content && !content.endsWith('\n')) {
40
- content += '\n';
41
- }
42
- content += newLine + '\n';
43
- }
44
- }
78
+ function setEnvVar(content, key, value) {
79
+ const regex = new RegExp(`^${key}=.*$`, 'm');
80
+ const newLine = `${key}=${value}`;
45
81
 
46
- fs.writeFileSync(envPath, content, 'utf-8');
47
- ok('.env actualizado');
82
+ if (regex.test(content)) {
83
+ return content.replace(regex, newLine);
84
+ }
85
+ if (content && !content.endsWith('\n')) {
86
+ content += '\n';
87
+ }
88
+ return content + newLine + '\n';
48
89
  }
49
90
 
50
- function buildNodeOptions(lines) {
51
- const requireFlag = '--require @aethermind/providers/register';
91
+ function buildNodeOptions(content) {
92
+ const requireFlag = '--require @aethermind/agent/register';
93
+ const lines = content.split('\n');
52
94
  const existingLine = lines.find((l) => l.startsWith('NODE_OPTIONS='));
53
95
 
54
96
  if (existingLine) {
55
97
  const existingValue = existingLine.replace('NODE_OPTIONS=', '');
56
- if (existingValue.includes(requireFlag)) {
57
- return existingValue;
58
- }
98
+ if (existingValue.includes(requireFlag)) return existingValue;
59
99
  return existingValue ? `${existingValue} ${requireFlag}` : requireFlag;
60
100
  }
61
-
62
101
  return requireFlag;
63
102
  }
64
103
 
@@ -71,13 +110,12 @@ function restoreEnvFile(cwd) {
71
110
  fs.unlinkSync(backupPath);
72
111
  ok('.env restaurado desde backup');
73
112
  } else if (fs.existsSync(envPath)) {
74
- // Remove our additions from .env
75
113
  let content = fs.readFileSync(envPath, 'utf-8');
76
114
  content = content.replace(/^AETHERMIND_API_KEY=.*\n?/m, '');
77
- // Remove our require from NODE_OPTIONS
78
- content = content.replace(/ ?--require @aethermind\/providers\/register/g, '');
79
- // Remove empty NODE_OPTIONS line
115
+ content = content.replace(/ ?--require @aethermind\/agent\/register/g, '');
80
116
  content = content.replace(/^NODE_OPTIONS=\s*\n?/m, '');
117
+ content = content.replace(/^OPENAI_BASE_URL=.*\n?/m, '');
118
+ content = content.replace(/^ANTHROPIC_BASE_URL=.*\n?/m, '');
81
119
  fs.writeFileSync(envPath, content, 'utf-8');
82
120
  ok('Entradas de Aethermind removidas del .env');
83
121
  } else {
@@ -85,4 +123,4 @@ function restoreEnvFile(cwd) {
85
123
  }
86
124
  }
87
125
 
88
- module.exports = { updateEnvFile, restoreEnvFile };
126
+ module.exports = { updateEnvForNode, updateEnvForGateway, addOllamaEnv, restoreEnvFile };
package/src/index.js CHANGED
@@ -2,10 +2,10 @@
2
2
 
3
3
  const readline = require('readline');
4
4
  const { banner, ok, info, separator, summary, c } = require('./ui.js');
5
- const { checkNodeVersion, detectPackageJson, detectInstalledSDKs, detectPackageManager } = require('./detect.js');
5
+ const { checkNodeVersion, detectLanguage, detectPackageJson, detectInstalledSDKs, detectPackageManager, detectOllama } = require('./detect.js');
6
6
  const { validateApiKey } = require('./validate.js');
7
- const { installProviders, uninstallProviders } = require('./install.js');
8
- const { updateEnvFile, restoreEnvFile } = require('./env.js');
7
+ const { installAgent, uninstallAgent, installOllamaProxy } = require('./install.js');
8
+ const { updateEnvForNode, updateEnvForGateway, addOllamaEnv, restoreEnvFile } = require('./env.js');
9
9
 
10
10
  function prompt(question) {
11
11
  return new Promise((resolve) => {
@@ -21,7 +21,7 @@ function prompt(question) {
21
21
  }
22
22
 
23
23
  function confirm(question) {
24
- return prompt(`${question} (s/n): `).then((a) => a.toLowerCase() === 's' || a.toLowerCase() === 'y');
24
+ return prompt(`${question} (y/n): `).then((a) => a.toLowerCase() === 's' || a.toLowerCase() === 'y');
25
25
  }
26
26
 
27
27
  async function runSetup() {
@@ -29,26 +29,30 @@ async function runSetup() {
29
29
 
30
30
  banner();
31
31
 
32
- // 1. Check Node version
32
+ // 1. Check Node version (needed to run this script)
33
33
  checkNodeVersion();
34
34
 
35
- // 2. Detect package.json
36
- const pkg = detectPackageJson(cwd);
35
+ // 2. Detect project language
36
+ const language = detectLanguage(cwd);
37
+ ok(`Proyecto detectado: ${language === 'node' ? 'Node.js' : language === 'python' ? 'Python' : 'Otro'}`);
37
38
 
38
- // 3. Detect installed SDKs
39
- const sdks = detectInstalledSDKs(cwd);
39
+ // 3. Detect project details
40
+ if (language === 'node') {
41
+ detectPackageJson(cwd);
42
+ detectInstalledSDKs(cwd);
43
+ }
40
44
 
41
- // 4. Detect package manager
42
- const pm = detectPackageManager(cwd);
45
+ // 4. Detect Ollama
46
+ const hasOllama = await detectOllama();
43
47
 
44
48
  separator();
45
49
 
46
50
  // 5. Ask for API key
47
- const apiKey = await prompt(c.cyan(' ? ') + 'Ingresa tu AETHERMIND_API_KEY: ');
51
+ const apiKey = await prompt(c.cyan(' ? ') + 'Pega tu SDK API Key (la encontras en el dashboard): ');
48
52
 
49
53
  if (!apiKey) {
50
54
  console.log(c.red('\n API key no puede estar vacia.'));
51
- console.log(' Obtene tu key en: https://aethermind-agent-os-dashboard.vercel.app/settings\n');
55
+ console.log(' Obtene tu key en: https://aethermind-agent-os-dashboard.vercel.app\n');
52
56
  process.exit(1);
53
57
  }
54
58
 
@@ -57,12 +61,31 @@ async function runSetup() {
57
61
 
58
62
  separator();
59
63
 
60
- // 7. Show what will be modified and confirm
64
+ // 7. Show plan and confirm
61
65
  console.log('');
62
66
  console.log(c.bold(' Se realizaran los siguientes cambios:'));
63
- console.log(` - Instalar @aethermind/providers (via ${pm})`);
64
- console.log(' - Agregar AETHERMIND_API_KEY al .env');
65
- console.log(' - Agregar --require @aethermind/providers/register a NODE_OPTIONS');
67
+
68
+ if (language === 'node') {
69
+ const pm = detectPackageManager(cwd);
70
+ console.log(` - Instalar @aethermind/agent (via ${pm})`);
71
+ console.log(' - Agregar AETHERMIND_API_KEY al .env');
72
+ console.log(' - Agregar --require @aethermind/agent/register a NODE_OPTIONS');
73
+ } else {
74
+ console.log(' - Agregar AETHERMIND_API_KEY al .env');
75
+ console.log(' - Configurar OPENAI_BASE_URL -> Aethermind Gateway');
76
+ console.log(' - Configurar ANTHROPIC_BASE_URL -> Aethermind Gateway');
77
+ }
78
+
79
+ if (hasOllama) {
80
+ console.log(' - Configurar OLLAMA_HOST -> proxy local (puerto 11435)');
81
+ if (language === 'node') {
82
+ const pm = detectPackageManager(cwd);
83
+ console.log(` - Instalar @aethermind/proxy (via ${pm})`);
84
+ }
85
+ }
86
+
87
+ console.log('');
88
+ console.log(c.dim(' Tu codigo NO se modifica.'));
66
89
  console.log('');
67
90
 
68
91
  const proceed = await confirm(c.cyan(' ? ') + 'Continuar?');
@@ -73,25 +96,35 @@ async function runSetup() {
73
96
 
74
97
  console.log('');
75
98
 
76
- // 8. Install @aethermind/providers
77
- installProviders(pm);
78
-
79
- // 9. Update .env
80
- updateEnvFile(cwd, apiKey);
99
+ // 8. Execute
100
+ if (language === 'node') {
101
+ const pm = detectPackageManager(cwd);
102
+ installAgent(pm);
103
+ updateEnvForNode(cwd, apiKey);
104
+ if (hasOllama) {
105
+ installOllamaProxy(pm);
106
+ addOllamaEnv(cwd);
107
+ }
108
+ } else {
109
+ updateEnvForGateway(cwd, apiKey);
110
+ if (hasOllama) {
111
+ addOllamaEnv(cwd);
112
+ }
113
+ }
81
114
 
82
- // 10. Show summary
83
- summary();
115
+ // 9. Done
116
+ summary(language, hasOllama);
84
117
  }
85
118
 
86
119
  async function runUninstall() {
87
120
  const cwd = process.cwd();
88
121
 
89
122
  banner();
90
- console.log(c.yellow(' Desinstalando Aethermind AgentOS...\n'));
123
+ console.log(c.yellow(' Desinstalando Aethermind...\n'));
91
124
 
92
- const pm = detectPackageManager(cwd);
125
+ const language = detectLanguage(cwd);
93
126
 
94
- const proceed = await confirm(c.cyan(' ? ') + 'Desinstalar @aethermind/providers y restaurar .env?');
127
+ const proceed = await confirm(c.cyan(' ? ') + 'Desinstalar Aethermind y restaurar .env?');
95
128
  if (!proceed) {
96
129
  console.log('\n Cancelado.\n');
97
130
  process.exit(0);
@@ -99,13 +132,14 @@ async function runUninstall() {
99
132
 
100
133
  console.log('');
101
134
 
102
- // Uninstall package
103
- uninstallProviders(pm);
135
+ if (language === 'node') {
136
+ const pm = detectPackageManager(cwd);
137
+ uninstallAgent(pm);
138
+ }
104
139
 
105
- // Restore .env
106
140
  restoreEnvFile(cwd);
107
141
 
108
- console.log(c.green('\n Aethermind AgentOS desinstalado correctamente.\n'));
142
+ console.log(c.green('\n Aethermind desinstalado correctamente.\n'));
109
143
  }
110
144
 
111
145
  async function main({ uninstall = false } = {}) {
package/src/install.js CHANGED
@@ -3,42 +3,61 @@
3
3
  const { execSync } = require('child_process');
4
4
  const { ok, fail } = require('./ui.js');
5
5
 
6
- function installProviders(packageManager) {
6
+ function installAgent(packageManager) {
7
7
  const cmds = {
8
- npm: 'npm install @aethermind/providers --legacy-peer-deps',
9
- pnpm: 'pnpm add @aethermind/providers',
10
- yarn: 'yarn add @aethermind/providers',
11
- bun: 'bun add @aethermind/providers',
8
+ npm: 'npm install @aethermind/agent --legacy-peer-deps',
9
+ pnpm: 'pnpm add @aethermind/agent',
10
+ yarn: 'yarn add @aethermind/agent',
11
+ bun: 'bun add @aethermind/agent',
12
12
  };
13
13
 
14
14
  const cmd = cmds[packageManager] || cmds.npm;
15
15
 
16
16
  try {
17
17
  execSync(cmd, { stdio: 'pipe', timeout: 120000 });
18
- ok('@aethermind/providers instalado');
18
+ ok('@aethermind/agent instalado');
19
19
  } catch (err) {
20
- fail(`Error instalando @aethermind/providers con ${packageManager}`);
20
+ fail(`Error instalando @aethermind/agent con ${packageManager}`);
21
21
  console.log(` Intenta manualmente: ${cmd}`);
22
22
  throw new Error(`Fallo la instalacion: ${err.message}`);
23
23
  }
24
24
  }
25
25
 
26
- function uninstallProviders(packageManager) {
26
+ function uninstallAgent(packageManager) {
27
27
  const cmds = {
28
- npm: 'npm uninstall @aethermind/providers',
29
- pnpm: 'pnpm remove @aethermind/providers',
30
- yarn: 'yarn remove @aethermind/providers',
31
- bun: 'bun remove @aethermind/providers',
28
+ npm: 'npm uninstall @aethermind/agent',
29
+ pnpm: 'pnpm remove @aethermind/agent',
30
+ yarn: 'yarn remove @aethermind/agent',
31
+ bun: 'bun remove @aethermind/agent',
32
32
  };
33
33
 
34
34
  const cmd = cmds[packageManager] || cmds.npm;
35
35
 
36
36
  try {
37
37
  execSync(cmd, { stdio: 'pipe', timeout: 120000 });
38
- ok('@aethermind/providers desinstalado');
38
+ ok('@aethermind/agent desinstalado');
39
39
  } catch (_) {
40
40
  // may not be installed, that's ok
41
41
  }
42
42
  }
43
43
 
44
- module.exports = { installProviders, uninstallProviders };
44
+ function installOllamaProxy(packageManager) {
45
+ const cmds = {
46
+ npm: 'npm install @aethermind/proxy --legacy-peer-deps',
47
+ pnpm: 'pnpm add @aethermind/proxy',
48
+ yarn: 'yarn add @aethermind/proxy',
49
+ bun: 'bun add @aethermind/proxy',
50
+ };
51
+
52
+ const cmd = cmds[packageManager] || cmds.npm;
53
+
54
+ try {
55
+ execSync(cmd, { stdio: 'pipe', timeout: 120000 });
56
+ ok('@aethermind/proxy instalado');
57
+ } catch (err) {
58
+ fail(`Error instalando @aethermind/proxy con ${packageManager}`);
59
+ console.log(` Intenta manualmente: ${cmd}`);
60
+ }
61
+ }
62
+
63
+ module.exports = { installAgent, uninstallAgent, installOllamaProxy };
package/src/ui.js CHANGED
@@ -36,17 +36,28 @@ function separator() {
36
36
  console.log(c.dim(' ' + '-'.repeat(35)));
37
37
  }
38
38
 
39
- function summary() {
39
+ function summary(language, hasOllama) {
40
40
  console.log('');
41
- console.log(c.dim(' ' + '='.repeat(35)));
42
- console.log(c.green(c.bold(' Listo. Tu app esta siendo monitoreada.')));
41
+ console.log(c.dim(' ' + '='.repeat(40)));
42
+ console.log(c.green(c.bold(' Listo! Tu app esta siendo monitoreada.')));
43
43
  console.log('');
44
44
  console.log(' Corre tu app normalmente:');
45
- console.log(c.cyan(' node index.js'));
45
+ if (language === 'python') {
46
+ console.log(c.cyan(' python app.py'));
47
+ } else {
48
+ console.log(c.cyan(' node app.js'));
49
+ }
50
+ if (hasOllama) {
51
+ console.log('');
52
+ console.log(' Para modelos Ollama, antes inicia el proxy:');
53
+ console.log(c.cyan(' npx @aethermind/proxy'));
54
+ }
55
+ console.log('');
56
+ console.log(' No necesitas cambiar tu codigo.');
46
57
  console.log('');
47
58
  console.log(' Mira tu dashboard:');
48
59
  console.log(c.cyan(' https://aethermind-agent-os-dashboard.vercel.app'));
49
- console.log(c.dim(' ' + '='.repeat(35)));
60
+ console.log(c.dim(' ' + '='.repeat(40)));
50
61
  console.log('');
51
62
  }
52
63