@xelauvas/xela-cli 0.1.1 → 0.1.2

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/xela.js +82 -43
  2. package/package.json +1 -1
package/bin/xela.js CHANGED
@@ -4,67 +4,98 @@ import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
4
4
  import { join } from 'path';
5
5
  import { fileURLToPath } from 'url';
6
6
  import { homedir } from 'os';
7
+ import { createInterface } from 'readline';
7
8
 
8
9
  const __dirname = fileURLToPath(new URL('.', import.meta.url));
9
10
  const INSTALL_DIR = join(__dirname, '..');
10
11
  const XELA_HOME = join(homedir(), '.xela');
11
12
  const XELA_CONFIG = join(XELA_HOME, 'config.json');
12
13
 
13
- // Create config on first run
14
- if (!existsSync(XELA_CONFIG)) {
14
+ const PROVIDERS = {
15
+ openrouter: { baseUrl: 'https://openrouter.ai/api/v1', model: 'qwen/qwen3.6-plus-preview:free' },
16
+ groq: { baseUrl: 'https://api.groq.com/openai/v1', model: 'qwen-qwq-32b' },
17
+ ollama: { baseUrl: 'http://localhost:11434/v1', model: 'qwen2.5-coder:7b' },
18
+ deepseek: { baseUrl: 'https://api.deepseek.com', model: 'deepseek-chat' },
19
+ openai: { baseUrl: undefined, model: 'gpt-4o' },
20
+ cerebras: { baseUrl: 'https://api.cerebras.ai/v1', model: 'llama-3.3-70b' },
21
+ sambanova: { baseUrl: 'https://api.sambanova.ai/v1', model: 'Meta-Llama-3.3-70B-Instruct' },
22
+ };
23
+
24
+ function ask(question) {
25
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
26
+ return new Promise(resolve => rl.question(question, answer => { rl.close(); resolve(answer.trim()); }));
27
+ }
28
+
29
+ async function setup() {
30
+ console.log('');
31
+ console.log(' Welcome to Xela! Let\'s get you set up.');
32
+ console.log('');
33
+
34
+ // Pick provider
35
+ const providerNames = Object.keys(PROVIDERS);
36
+ console.log(' Providers:');
37
+ providerNames.forEach((p, i) => console.log(` ${i + 1}. ${p}`));
38
+ console.log('');
39
+ const choice = await ask(' Pick a provider [1]: ');
40
+ const idx = (parseInt(choice) || 1) - 1;
41
+ const provider = providerNames[Math.min(idx, providerNames.length - 1)];
42
+
43
+ // Get API key (skip for ollama)
44
+ let apiKey = '';
45
+ if (provider === 'ollama') {
46
+ apiKey = 'ollama';
47
+ } else {
48
+ console.log('');
49
+ if (provider === 'openrouter') {
50
+ console.log(' Get a free key at: https://openrouter.ai/keys');
51
+ } else if (provider === 'groq') {
52
+ console.log(' Get a free key at: https://console.groq.com/keys');
53
+ } else if (provider === 'deepseek') {
54
+ console.log(' Get a key at: https://platform.deepseek.com/api_keys');
55
+ }
56
+ apiKey = await ask(' API key: ');
57
+ if (!apiKey) {
58
+ console.log(' No key provided. You can add it later in ~/.xela/config.json');
59
+ apiKey = '';
60
+ }
61
+ }
62
+
15
63
  mkdirSync(XELA_HOME, { recursive: true });
16
- writeFileSync(XELA_CONFIG, JSON.stringify({
17
- provider: 'openrouter',
18
- apiKey: 'sk-or-your-key-here',
19
- model: '',
20
- baseUrl: '',
21
- }, null, 2));
64
+ const config = { provider, apiKey, model: '', baseUrl: '' };
65
+ writeFileSync(XELA_CONFIG, JSON.stringify(config, null, 2));
22
66
  console.log('');
23
- console.log(' Welcome to Xela!');
24
- console.log(` Config created at ${XELA_CONFIG}`);
25
- console.log(` Edit it to add your API key`);
67
+ console.log(` Saved to ${XELA_CONFIG}`);
68
+ console.log(' You can edit it anytime: nano ~/.xela/config.json');
26
69
  console.log('');
70
+ return config;
27
71
  }
28
72
 
29
- // Load config
73
+ // Load or create config
30
74
  let config = {};
31
- try {
32
- config = JSON.parse(readFileSync(XELA_CONFIG, 'utf-8'));
33
- } catch {}
75
+ if (!existsSync(XELA_CONFIG)) {
76
+ config = await setup();
77
+ } else {
78
+ try {
79
+ config = JSON.parse(readFileSync(XELA_CONFIG, 'utf-8'));
80
+ } catch {}
81
+ // If key is still placeholder, run setup again
82
+ if (!config.apiKey || config.apiKey === 'sk-or-your-key-here') {
83
+ config = await setup();
84
+ }
85
+ }
34
86
 
35
87
  const provider = config.provider || 'openrouter';
88
+ const providerInfo = PROVIDERS[provider] || PROVIDERS.openrouter;
36
89
 
37
- // Set env vars from config
38
- if (config.apiKey && config.apiKey !== 'sk-or-your-key-here') {
90
+ // Set env vars
91
+ if (config.apiKey) {
39
92
  process.env.OPENAI_API_KEY = config.apiKey;
40
93
  }
41
-
42
- // Auto-detect base URL
43
94
  if (!process.env.OPENAI_BASE_URL) {
44
- const baseUrls = {
45
- openrouter: 'https://openrouter.ai/api/v1',
46
- groq: 'https://api.groq.com/openai/v1',
47
- ollama: 'http://localhost:11434/v1',
48
- deepseek: 'https://api.deepseek.com',
49
- openai: undefined,
50
- cerebras: 'https://api.cerebras.ai/v1',
51
- sambanova: 'https://api.sambanova.ai/v1',
52
- };
53
- if (baseUrls[provider]) process.env.OPENAI_BASE_URL = config.baseUrl || baseUrls[provider];
95
+ process.env.OPENAI_BASE_URL = config.baseUrl || providerInfo.baseUrl;
54
96
  }
55
-
56
- // Auto-detect model
57
97
  if (!process.env.OPENAI_MODEL) {
58
- const defaultModels = {
59
- openrouter: 'qwen/qwen3.6-plus-preview:free',
60
- groq: 'qwen-qwq-32b',
61
- ollama: 'qwen2.5-coder:7b',
62
- deepseek: 'deepseek-chat',
63
- openai: 'gpt-4o',
64
- cerebras: 'llama-3.3-70b',
65
- sambanova: 'Meta-Llama-3.3-70B-Instruct',
66
- };
67
- process.env.OPENAI_MODEL = config.model || defaultModels[provider] || 'gpt-4o';
98
+ process.env.OPENAI_MODEL = config.model || providerInfo.model || 'gpt-4o';
68
99
  }
69
100
 
70
101
  // Handle -m/--model flag
@@ -77,5 +108,13 @@ for (let i = 0; i < args.length; i++) {
77
108
  }
78
109
  }
79
110
 
80
- // Import and run the CLI
81
- await import(join(INSTALL_DIR, 'src', 'entrypoints', 'cli.tsx'));
111
+ // Launch node with the TSX loader shim
112
+ try {
113
+ execFileSync(process.execPath, [
114
+ '--import', join(INSTALL_DIR, 'src', '_shims', 'register.js'),
115
+ join(INSTALL_DIR, 'start.js'),
116
+ ...args,
117
+ ], { stdio: 'inherit', env: process.env });
118
+ } catch (e) {
119
+ process.exit(e.status || 1);
120
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xelauvas/xela-cli",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Xela — AI coding assistant powered by any model (OpenRouter, Groq, Ollama, DeepSeek, OpenAI)",
5
5
  "author": "xelauvas",
6
6
  "license": "MIT",