@dastageer_44/eco-code 1.1.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.
Files changed (42) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +105 -0
  3. package/dist/config.d.ts +44 -0
  4. package/dist/config.js +111 -0
  5. package/dist/config.js.map +1 -0
  6. package/dist/harness/agent.d.ts +51 -0
  7. package/dist/harness/agent.js +168 -0
  8. package/dist/harness/agent.js.map +1 -0
  9. package/dist/harness/context.d.ts +17 -0
  10. package/dist/harness/context.js +77 -0
  11. package/dist/harness/context.js.map +1 -0
  12. package/dist/index.d.ts +2 -0
  13. package/dist/index.js +414 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/services/openrouter.d.ts +21 -0
  16. package/dist/services/openrouter.js +106 -0
  17. package/dist/services/openrouter.js.map +1 -0
  18. package/dist/services/updater.d.ts +6 -0
  19. package/dist/services/updater.js +61 -0
  20. package/dist/services/updater.js.map +1 -0
  21. package/dist/taste/engine.d.ts +10 -0
  22. package/dist/taste/engine.js +80 -0
  23. package/dist/taste/engine.js.map +1 -0
  24. package/dist/tools/file-ops.d.ts +18 -0
  25. package/dist/tools/file-ops.js +89 -0
  26. package/dist/tools/file-ops.js.map +1 -0
  27. package/dist/tools/index.d.ts +5 -0
  28. package/dist/tools/index.js +235 -0
  29. package/dist/tools/index.js.map +1 -0
  30. package/dist/tools/search-ops.d.ts +5 -0
  31. package/dist/tools/search-ops.js +55 -0
  32. package/dist/tools/search-ops.js.map +1 -0
  33. package/dist/tools/shell-ops.d.ts +18 -0
  34. package/dist/tools/shell-ops.js +140 -0
  35. package/dist/tools/shell-ops.js.map +1 -0
  36. package/dist/tools/types.d.ts +11 -0
  37. package/dist/tools/types.js +2 -0
  38. package/dist/tools/types.js.map +1 -0
  39. package/dist/ui/banner.d.ts +2 -0
  40. package/dist/ui/banner.js +31 -0
  41. package/dist/ui/banner.js.map +1 -0
  42. package/package.json +53 -0
package/dist/index.js ADDED
@@ -0,0 +1,414 @@
1
+ #!/usr/bin/env node
2
+ // Suppress punycode deprecation noise from legacy sub-dependencies
3
+ process.removeAllListeners('warning');
4
+ process.on('warning', (warning) => {
5
+ if (warning.name === 'DeprecationWarning' && warning.message.includes('punycode')) {
6
+ return;
7
+ }
8
+ });
9
+ import * as fs from 'fs';
10
+ import * as path from 'path';
11
+ import * as readline from 'readline';
12
+ import * as p from '@clack/prompts';
13
+ import chalk from 'chalk';
14
+ import ora from 'ora';
15
+ import { ConfigManager } from './config.js';
16
+ import { OpenRouterService } from './services/openrouter.js';
17
+ import { AgentHarness } from './harness/agent.js';
18
+ import { printBanner, printHelp } from './ui/banner.js';
19
+ import { runCommand } from './tools/shell-ops.js';
20
+ import { checkAndPromptUpdate } from './services/updater.js';
21
+ const SPINNER_VERBS = [
22
+ 'Thinking', 'Reasoning', 'Analyzing', 'Synthesizing',
23
+ 'Drafting', 'Evaluating', 'Planning', 'Processing'
24
+ ];
25
+ function getRandomVerb() {
26
+ return SPINNER_VERBS[Math.floor(Math.random() * SPINNER_VERBS.length)];
27
+ }
28
+ function getPackageVersion() {
29
+ try {
30
+ const pkgPath = path.resolve(path.dirname(new URL(import.meta.url).pathname.replace(/^\/([A-Z]:)/, '$1')), '../package.json');
31
+ if (fs.existsSync(pkgPath)) {
32
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
33
+ return pkg.version || '1.0.0';
34
+ }
35
+ }
36
+ catch { }
37
+ return '1.0.0';
38
+ }
39
+ const config = new ConfigManager();
40
+ /**
41
+ * Robust Readline Prompt Manager that stays alive on Windows/macOS/Linux
42
+ * and catches instant '/' keypress without requiring Enter.
43
+ */
44
+ class PromptManager {
45
+ rl;
46
+ constructor() {
47
+ this.rl = readline.createInterface({
48
+ input: process.stdin,
49
+ output: process.stdout,
50
+ terminal: true,
51
+ });
52
+ }
53
+ ask(promptStr) {
54
+ return new Promise((resolve) => {
55
+ this.rl.resume();
56
+ const onData = (chunk) => {
57
+ const str = chunk.toString();
58
+ // If line is empty and user pressed '/', trigger instant slash menu
59
+ if (this.rl.line.trim() === '' && str === '/') {
60
+ process.stdin.removeListener('data', onData);
61
+ readline.clearLine(process.stdout, 0);
62
+ readline.cursorTo(process.stdout, 0);
63
+ this.rl.pause();
64
+ resolve('/');
65
+ }
66
+ };
67
+ process.stdin.on('data', onData);
68
+ this.rl.question(promptStr, (answer) => {
69
+ process.stdin.removeListener('data', onData);
70
+ resolve(answer);
71
+ });
72
+ });
73
+ }
74
+ pause() {
75
+ this.rl.pause();
76
+ }
77
+ resume() {
78
+ this.rl.resume();
79
+ }
80
+ close() {
81
+ this.rl.close();
82
+ }
83
+ }
84
+ async function promptOnboardingApiKey() {
85
+ p.intro(chalk.bgGreen.black(' eco-code Setup '));
86
+ const method = await p.select({
87
+ message: 'How would you like to configure your OpenRouter API Key?',
88
+ options: [
89
+ { value: 'interactive', label: '1. Paste API Key here in terminal (Recommended)' },
90
+ { value: 'env', label: '2. Show how to set OPENROUTER_API_KEY environment variable' },
91
+ { value: 'config', label: `3. Show config file path (~/.eco-code/config.json)` },
92
+ ],
93
+ });
94
+ if (p.isCancel(method)) {
95
+ p.outro('Setup cancelled.');
96
+ process.exit(0);
97
+ }
98
+ if (method === 'env') {
99
+ p.note(`Windows (PowerShell):\n $env:OPENROUTER_API_KEY="sk-or-v1-..."\n\nLinux / macOS / Bash:\n export OPENROUTER_API_KEY="sk-or-v1-..."\n\nGet a free key at: https://openrouter.ai/keys`, 'Environment Variable Setup');
100
+ }
101
+ else if (method === 'config') {
102
+ p.note(`File location:\n ${config.getConfigPath()}\n\nContent:\n {\n "apiKey": "sk-or-v1-..."\n }`, 'Config File Setup');
103
+ }
104
+ const entered = await p.password({
105
+ message: 'Enter your OpenRouter API Key:',
106
+ validate: (val) => (!val || !val.trim() ? 'API key cannot be empty' : undefined),
107
+ });
108
+ if (p.isCancel(entered)) {
109
+ p.outro('Setup cancelled.');
110
+ process.exit(0);
111
+ }
112
+ const key = entered.trim();
113
+ config.setApiKey(key);
114
+ p.note(`Saved API key to: ${config.getConfigPath()}`, 'Key Saved');
115
+ return key;
116
+ }
117
+ async function selectModelInteractive(models, currentModel) {
118
+ const options = models.slice(0, 15).map((m) => {
119
+ const isCurrent = m.id === currentModel;
120
+ const tag = isCurrent ? chalk.green(' [active]') : '';
121
+ return {
122
+ value: m.id,
123
+ label: `${m.name || m.id}${tag}`,
124
+ hint: `Context: ${m.contextLength.toLocaleString()} tokens`,
125
+ };
126
+ });
127
+ const chosen = await p.select({
128
+ message: 'Select an active free AI model from OpenRouter:',
129
+ options,
130
+ });
131
+ if (p.isCancel(chosen)) {
132
+ return models.find((m) => m.id === currentModel) || models[0];
133
+ }
134
+ return models.find((m) => m.id === chosen) || models[0];
135
+ }
136
+ async function handleSlashCommandMenu(stats) {
137
+ let compactLabel = `/compact - Compact history ${chalk.dim(stats.progressBar)} ${chalk.green(`${stats.percentage}% used`)}`;
138
+ if (stats.isCritical) {
139
+ compactLabel = `/compact - Compact history ${chalk.red.bold(stats.progressBar)} ${chalk.red.bold(`${stats.percentage}% used (⚠️ Recommended now!)`)}`;
140
+ }
141
+ else if (stats.isWarning) {
142
+ compactLabel = `/compact - Compact history ${chalk.yellow(stats.progressBar)} ${chalk.yellow(`${stats.percentage}% used (Consider compacting)`)}`;
143
+ }
144
+ const action = await p.select({
145
+ message: 'Select command:',
146
+ options: [
147
+ { value: '/compact', label: compactLabel },
148
+ { value: '/models', label: '/models - Browse & switch free models' },
149
+ { value: '/refresh', label: '/refresh - Check for latest free models' },
150
+ { value: '/resume', label: '/resume - Restore previous session context' },
151
+ { value: '/taste', label: '/taste - View or add project coding style rules' },
152
+ { value: '/key', label: '/key - Update OpenRouter API Key' },
153
+ { value: '/clear', label: '/clear - Reset conversation history' },
154
+ { value: '/help', label: '/help - Show help summary' },
155
+ { value: '/exit', label: '/exit - Quit the agent' },
156
+ ],
157
+ });
158
+ if (p.isCancel(action))
159
+ return null;
160
+ return action;
161
+ }
162
+ function printContextUsageHint(stats) {
163
+ const usedK = (stats.usedTokens / 1000).toFixed(1);
164
+ const maxK = (stats.maxTokens / 1000).toFixed(1);
165
+ if (stats.isCritical) {
166
+ console.log(chalk.red(` ⚠️ Context Usage: ${chalk.bold(`${stats.percentage}%`)} (${usedK}k / ${maxK}k tokens) — Press ${chalk.bold('/')} and choose /compact to save tokens.`));
167
+ }
168
+ else if (stats.isWarning) {
169
+ console.log(chalk.yellow(` 💡 Context Usage: ${stats.percentage}% (${usedK}k / ${maxK}k tokens) — Press ${chalk.cyan('/')} and run /compact when ready.`));
170
+ }
171
+ }
172
+ async function main() {
173
+ const version = getPackageVersion();
174
+ printBanner(version);
175
+ // Auto-check for updates on launch
176
+ await checkAndPromptUpdate(version, 'eco-code');
177
+ let apiKey = config.getApiKey();
178
+ if (!apiKey) {
179
+ apiKey = await promptOnboardingApiKey();
180
+ }
181
+ let openRouter = new OpenRouterService(apiKey, config);
182
+ const spinner = ora({ text: 'Checking models...', color: 'green' }).start();
183
+ let freeModels = [];
184
+ try {
185
+ const result = await openRouter.getOrFetchFreeModels(false);
186
+ freeModels = result.models;
187
+ if (freeModels.length === 0) {
188
+ spinner.fail('No free models found on OpenRouter.');
189
+ console.log(chalk.yellow('\nPlease check your API key or visit https://openrouter.ai/models?max_price=0'));
190
+ process.exit(1);
191
+ }
192
+ spinner.succeed(chalk.green('Models updated'));
193
+ }
194
+ catch (err) {
195
+ spinner.fail('Failed to connect to OpenRouter.');
196
+ console.error(chalk.red(err.message));
197
+ console.log(chalk.yellow(`\nCheck your API key in ${config.getConfigPath()} or run /key.`));
198
+ process.exit(1);
199
+ }
200
+ let currentModelInfo = freeModels.find((m) => m.id === config.getDefaultModel()) || freeModels[0];
201
+ let activeModel = currentModelInfo.id;
202
+ config.setDefaultModel(activeModel);
203
+ console.log(` ${chalk.dim('Active Model:')} ${chalk.green.bold(activeModel)} ${chalk.dim(`(${currentModelInfo.contextLength.toLocaleString()} tokens)`)}`);
204
+ console.log(` ${chalk.dim('Press / for commands menu, /exit to quit.')}\n`);
205
+ const harness = new AgentHarness(openRouter.getClient(), activeModel, currentModelInfo.contextLength, config, process.cwd());
206
+ const promptMgr = new PromptManager();
207
+ // Main interactive loop
208
+ while (true) {
209
+ const promptStr = `${chalk.green.bold('eco-code')} ${chalk.cyan('❯')} `;
210
+ const rawInput = await promptMgr.ask(promptStr);
211
+ if (rawInput === null || rawInput === undefined) {
212
+ console.log('\nHappy coding! 👋');
213
+ promptMgr.close();
214
+ process.exit(0);
215
+ }
216
+ let prompt = rawInput.trim();
217
+ if (!prompt)
218
+ continue;
219
+ // INSTANT TRIGGER: If user pressed '/' or typed '/menu'
220
+ if (prompt === '/' || prompt === '/menu') {
221
+ promptMgr.pause();
222
+ const stats = harness.getContextStats();
223
+ const chosenCmd = await handleSlashCommandMenu(stats);
224
+ promptMgr.resume();
225
+ if (!chosenCmd)
226
+ continue;
227
+ prompt = chosenCmd;
228
+ }
229
+ // --- Slash Commands Execution ---
230
+ if (prompt === '/exit' || prompt === 'exit' || prompt === 'quit') {
231
+ console.log('\nHappy coding! 👋\n');
232
+ promptMgr.close();
233
+ process.exit(0);
234
+ }
235
+ if (prompt === '/help') {
236
+ printHelp();
237
+ const stats = harness.getContextStats();
238
+ console.log(` ${chalk.bold('Current Context:')} ${stats.progressBar} ${chalk.green(`${stats.percentage}%`)} (${(stats.usedTokens / 1000).toFixed(1)}k / ${(stats.maxTokens / 1000).toFixed(1)}k tokens)\n`);
239
+ continue;
240
+ }
241
+ if (prompt === '/model' || prompt === '/models') {
242
+ promptMgr.pause();
243
+ const selected = await selectModelInteractive(freeModels, activeModel);
244
+ promptMgr.resume();
245
+ activeModel = selected.id;
246
+ currentModelInfo = selected;
247
+ config.setDefaultModel(activeModel);
248
+ harness.setModel(activeModel, selected.contextLength);
249
+ console.log(`\n ${chalk.green('✔')} Switched active model to: ${chalk.green.bold(activeModel)} (${selected.contextLength.toLocaleString()} tokens)\n`);
250
+ continue;
251
+ }
252
+ if (prompt === '/refresh') {
253
+ const refSpinner = ora('Checking for latest free models...').start();
254
+ try {
255
+ const res = await openRouter.getOrFetchFreeModels(true);
256
+ freeModels = res.models;
257
+ refSpinner.succeed(chalk.green('Models updated'));
258
+ if (!freeModels.some((m) => m.id === activeModel)) {
259
+ const fallback = freeModels[0];
260
+ activeModel = fallback.id;
261
+ currentModelInfo = fallback;
262
+ config.setDefaultModel(activeModel);
263
+ harness.setModel(activeModel, fallback.contextLength);
264
+ console.log(chalk.yellow(` Previous model is no longer free. Switched to ${activeModel}`));
265
+ }
266
+ }
267
+ catch (err) {
268
+ refSpinner.fail(`Failed to refresh: ${err.message}`);
269
+ }
270
+ console.log();
271
+ continue;
272
+ }
273
+ if (prompt === '/compact') {
274
+ const { before, after } = harness.compactContext();
275
+ const newStats = harness.getContextStats();
276
+ console.log(`\n ${chalk.green('✔')} Compacted context from ${chalk.yellow(before)} to ${chalk.green(after)} messages.`);
277
+ console.log(` ${chalk.cyan('Context Status:')} ${newStats.progressBar} ${chalk.green(`${newStats.percentage}% used`)} (${(newStats.usedTokens / 1000).toFixed(1)}k / ${(newStats.maxTokens / 1000).toFixed(1)}k tokens)\n`);
278
+ continue;
279
+ }
280
+ if (prompt === '/resume') {
281
+ const session = config.loadLatestSession();
282
+ if (session && session.messages && session.messages.length > 1) {
283
+ harness.setHistory(session.messages);
284
+ if (session.model) {
285
+ activeModel = session.model;
286
+ const found = freeModels.find((m) => m.id === activeModel);
287
+ harness.setModel(activeModel, found?.contextLength);
288
+ }
289
+ const stats = harness.getContextStats();
290
+ console.log(`\n ${chalk.green('✔')} Restored previous session (${chalk.green(session.messages.length)} messages, model: ${chalk.cyan(session.model)}).`);
291
+ console.log(` ${chalk.cyan('Context Status:')} ${stats.progressBar} ${chalk.green(`${stats.percentage}% used`)}\n`);
292
+ }
293
+ else {
294
+ console.log(`\n ${chalk.yellow('ℹ')} No previous session found to resume.\n`);
295
+ }
296
+ continue;
297
+ }
298
+ if (prompt === '/taste') {
299
+ const tasteEngine = harness.getContextManager().getTasteEngine();
300
+ console.log(chalk.cyan('\n--- Project Taste & Directives ---'));
301
+ console.log(chalk.dim(tasteEngine.getTastePrompt()));
302
+ promptMgr.pause();
303
+ const newRule = await p.text({
304
+ message: 'Add a new directive (or press Enter to skip):',
305
+ placeholder: 'e.g., Prefer Tailwind CSS, Use strict TypeScript',
306
+ });
307
+ promptMgr.resume();
308
+ if (!p.isCancel(newRule) && newRule.trim()) {
309
+ tasteEngine.addDirective(newRule.trim());
310
+ harness.resetContext();
311
+ console.log(`\n ${chalk.green('✔')} Added directive to .agent/taste.md\n`);
312
+ }
313
+ continue;
314
+ }
315
+ if (prompt === '/key') {
316
+ promptMgr.pause();
317
+ const newKey = await p.password({
318
+ message: 'Enter new OpenRouter API Key:',
319
+ });
320
+ promptMgr.resume();
321
+ if (!p.isCancel(newKey) && newKey.trim()) {
322
+ apiKey = newKey.trim();
323
+ config.setApiKey(apiKey);
324
+ openRouter = new OpenRouterService(apiKey, config);
325
+ console.log(`\n ${chalk.green('✔')} API key updated.\n`);
326
+ try {
327
+ const res = await openRouter.getOrFetchFreeModels(true);
328
+ freeModels = res.models;
329
+ }
330
+ catch { }
331
+ }
332
+ continue;
333
+ }
334
+ if (prompt === '/clear') {
335
+ harness.resetContext();
336
+ console.log(`\n ${chalk.green('✔')} Context and conversation history cleared.\n`);
337
+ continue;
338
+ }
339
+ // Safeguard for typos on slash commands (e.g. /mode;)
340
+ if (prompt.startsWith('/')) {
341
+ console.log(chalk.yellow(`\n Unrecognized command "${prompt}". Opening command options:\n`));
342
+ promptMgr.pause();
343
+ const stats = harness.getContextStats();
344
+ const chosenCmd = await handleSlashCommandMenu(stats);
345
+ promptMgr.resume();
346
+ if (chosenCmd) {
347
+ if (chosenCmd === '/compact') {
348
+ const { before, after } = harness.compactContext();
349
+ const newStats = harness.getContextStats();
350
+ console.log(`\n ${chalk.green('✔')} Compacted context from ${chalk.yellow(before)} to ${chalk.green(after)} messages (${newStats.percentage}% used).\n`);
351
+ }
352
+ else if (chosenCmd === '/help') {
353
+ printHelp();
354
+ }
355
+ else if (chosenCmd === '/exit') {
356
+ console.log('\nHappy coding! 👋\n');
357
+ promptMgr.close();
358
+ process.exit(0);
359
+ }
360
+ }
361
+ continue;
362
+ }
363
+ // Direct Bash Escape: !command
364
+ if (prompt.startsWith('!')) {
365
+ const cmd = prompt.slice(1).trim();
366
+ if (cmd) {
367
+ const cmdSpinner = ora(`Executing: ${chalk.cyan(cmd)}`).start();
368
+ const out = await runCommand({ command: cmd }, process.cwd());
369
+ cmdSpinner.stop();
370
+ console.log(`\n${chalk.dim(out)}\n`);
371
+ }
372
+ continue;
373
+ }
374
+ // --- Run Agent Turn with Tool Calling ---
375
+ const turnSpinner = ora({ text: `${getRandomVerb()}...`, color: 'cyan' }).start();
376
+ // Optionally cycle the verb every 3 seconds if not running a tool
377
+ let isToolRunning = false;
378
+ const verbInterval = setInterval(() => {
379
+ if (!isToolRunning) {
380
+ turnSpinner.text = `${getRandomVerb()}...`;
381
+ }
382
+ }, 3000);
383
+ try {
384
+ const result = await harness.runTurn(prompt, {
385
+ onToolStart: (toolName, args) => {
386
+ isToolRunning = true;
387
+ const detail = args.path || args.command || args.query || '';
388
+ turnSpinner.text = `Running ${chalk.yellow(toolName)} ${chalk.dim(detail ? `(${detail})` : '')}...`;
389
+ },
390
+ onToolEnd: (toolName) => {
391
+ isToolRunning = false;
392
+ turnSpinner.text = `Tool ${chalk.yellow(toolName)} finished. ${getRandomVerb()}...`;
393
+ },
394
+ });
395
+ clearInterval(verbInterval);
396
+ turnSpinner.stop();
397
+ console.log(`\n${result}\n`);
398
+ // Print context usage reminder if usage is moderate/high
399
+ const stats = harness.getContextStats();
400
+ printContextUsageHint(stats);
401
+ console.log(chalk.dim(` Total Session Tokens: ${stats.sessionTotalTokens.toLocaleString()}`));
402
+ }
403
+ catch (err) {
404
+ clearInterval(verbInterval);
405
+ turnSpinner.fail(chalk.red('Error'));
406
+ console.error(chalk.red(`\n${err.message}\n`));
407
+ }
408
+ }
409
+ }
410
+ main().catch((err) => {
411
+ console.error(chalk.red(`Fatal Error: ${err.message}`));
412
+ process.exit(1);
413
+ });
414
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import OpenAI from 'openai';
2
+ import { ConfigManager, FreeModelInfo } from '../config.js';
3
+ export declare class OpenRouterService {
4
+ private apiKey;
5
+ private client;
6
+ private configManager;
7
+ constructor(apiKey: string, configManager: ConfigManager);
8
+ getClient(): OpenAI;
9
+ /**
10
+ * Fetches free models from OpenRouter or returns the cached list if fresh today (< 24h).
11
+ */
12
+ getOrFetchFreeModels(forceRefresh?: boolean): Promise<{
13
+ models: FreeModelInfo[];
14
+ fromCache: boolean;
15
+ }>;
16
+ /**
17
+ * Scans OpenRouter for all active zero-cost / free models.
18
+ */
19
+ private fetchFreeModelsFromApi;
20
+ validateKey(): Promise<boolean>;
21
+ }
@@ -0,0 +1,106 @@
1
+ import axios from 'axios';
2
+ import OpenAI from 'openai';
3
+ // Models that are known to have restricted access, 403 on standard API keys, or require whitelists
4
+ const RESTRICTED_MODELS = new Set([
5
+ 'thinkingmachines/inkling-small:free',
6
+ 'thinkingmachines/inkling-small',
7
+ ]);
8
+ export class OpenRouterService {
9
+ apiKey;
10
+ client;
11
+ configManager;
12
+ constructor(apiKey, configManager) {
13
+ this.apiKey = apiKey;
14
+ this.configManager = configManager;
15
+ this.client = new OpenAI({
16
+ baseURL: 'https://openrouter.ai/api/v1',
17
+ apiKey: this.apiKey,
18
+ defaultHeaders: {
19
+ 'HTTP-Referer': 'https://github.com/eco-code/eco-code',
20
+ 'X-Title': 'eco-code CLI Agent',
21
+ },
22
+ });
23
+ }
24
+ getClient() {
25
+ return this.client;
26
+ }
27
+ /**
28
+ * Fetches free models from OpenRouter or returns the cached list if fresh today (< 24h).
29
+ */
30
+ async getOrFetchFreeModels(forceRefresh = false) {
31
+ if (!forceRefresh) {
32
+ const cached = this.configManager.getCachedModels();
33
+ if (cached && cached.length > 0) {
34
+ return { models: cached, fromCache: true };
35
+ }
36
+ }
37
+ const liveModels = await this.fetchFreeModelsFromApi();
38
+ this.configManager.setCachedModels(liveModels);
39
+ return { models: liveModels, fromCache: false };
40
+ }
41
+ /**
42
+ * Scans OpenRouter for all active zero-cost / free models.
43
+ */
44
+ async fetchFreeModelsFromApi() {
45
+ const res = await axios.get('https://openrouter.ai/api/v1/models', {
46
+ headers: {
47
+ Authorization: `Bearer ${this.apiKey}`,
48
+ },
49
+ timeout: 15000,
50
+ });
51
+ const models = res.data?.data || [];
52
+ const freeList = models.filter((m) => {
53
+ // Exclude restricted models
54
+ if (RESTRICTED_MODELS.has(m.id))
55
+ return false;
56
+ const promptCost = parseFloat(m.pricing?.prompt || '1');
57
+ const completionCost = parseFloat(m.pricing?.completion || '1');
58
+ const isZeroCost = promptCost === 0 && completionCost === 0;
59
+ const isFreeTag = typeof m.id === 'string' && m.id.endsWith(':free');
60
+ return isZeroCost || isFreeTag;
61
+ });
62
+ const parsed = freeList.map((m) => {
63
+ let score = 1;
64
+ const idLower = (m.id || '').toLowerCase();
65
+ const nameLower = (m.name || '').toLowerCase();
66
+ // Prioritize top coding models
67
+ if (idLower.includes('coder') || nameLower.includes('coder'))
68
+ score += 15;
69
+ if (idLower.includes('qwen-2.5') || idLower.includes('qwen'))
70
+ score += 12;
71
+ if (idLower.includes('deepseek-chat') || idLower.includes('deepseek-r1') || idLower.includes('deepseek'))
72
+ score += 10;
73
+ if (idLower.includes('llama-3.3') || idLower.includes('llama-3.1'))
74
+ score += 8;
75
+ if (idLower.includes('gemini-2.0') || idLower.includes('gemini'))
76
+ score += 7;
77
+ if (idLower.includes('mistral'))
78
+ score += 6;
79
+ if (idLower.includes('minimax'))
80
+ score += 5;
81
+ return {
82
+ id: m.id,
83
+ name: m.name || m.id,
84
+ contextLength: m.context_length || 8192,
85
+ description: m.description || '',
86
+ score,
87
+ };
88
+ });
89
+ // Sort by score first, then by context length descending
90
+ parsed.sort((a, b) => b.score - a.score || b.contextLength - a.contextLength);
91
+ return parsed;
92
+ }
93
+ async validateKey() {
94
+ try {
95
+ const res = await axios.get('https://openrouter.ai/api/v1/models', {
96
+ headers: { Authorization: `Bearer ${this.apiKey}` },
97
+ timeout: 8000,
98
+ });
99
+ return res.status === 200;
100
+ }
101
+ catch {
102
+ return false;
103
+ }
104
+ }
105
+ }
106
+ //# sourceMappingURL=openrouter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openrouter.js","sourceRoot":"","sources":["../../src/services/openrouter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export declare function isNewerVersion(latest: string, current: string): boolean;
2
+ /**
3
+ * Checks NPM registry for a newer version of eco-code.
4
+ * If available, prompts the user to auto-download and update immediately.
5
+ */
6
+ export declare function checkAndPromptUpdate(currentVersion: string, packageName?: string): Promise<void>;
@@ -0,0 +1,61 @@
1
+ import axios from 'axios';
2
+ import { exec } from 'child_process';
3
+ import { promisify } from 'util';
4
+ import * as p from '@clack/prompts';
5
+ import chalk from 'chalk';
6
+ import ora from 'ora';
7
+ const execAsync = promisify(exec);
8
+ export function isNewerVersion(latest, current) {
9
+ try {
10
+ const parse = (v) => v.replace(/^v/, '').split('.').map((x) => parseInt(x, 10) || 0);
11
+ const [lMaj = 0, lMin = 0, lPatch = 0] = parse(latest);
12
+ const [cMaj = 0, cMin = 0, cPatch = 0] = parse(current);
13
+ if (lMaj > cMaj)
14
+ return true;
15
+ if (lMaj === cMaj && lMin > cMin)
16
+ return true;
17
+ if (lMaj === cMaj && lMin === cMin && lPatch > cPatch)
18
+ return true;
19
+ }
20
+ catch { }
21
+ return false;
22
+ }
23
+ /**
24
+ * Checks NPM registry for a newer version of eco-code.
25
+ * If available, prompts the user to auto-download and update immediately.
26
+ */
27
+ export async function checkAndPromptUpdate(currentVersion, packageName = 'eco-code') {
28
+ try {
29
+ const res = await axios.get(`https://registry.npmjs.org/${packageName}/latest`, {
30
+ timeout: 3000,
31
+ });
32
+ const latestVersion = res.data?.version;
33
+ if (!latestVersion)
34
+ return;
35
+ if (isNewerVersion(latestVersion, currentVersion)) {
36
+ console.log(`\n ${chalk.yellow.bold('✨ New version available:')} ${chalk.dim(`v${currentVersion}`)} ➔ ${chalk.green.bold(`v${latestVersion}`)}`);
37
+ const shouldUpdate = await p.confirm({
38
+ message: `A new version (v${latestVersion}) is available. Would you like to update now?`,
39
+ initialValue: true,
40
+ });
41
+ if (!p.isCancel(shouldUpdate) && shouldUpdate) {
42
+ const spinner = ora({ text: `Downloading and updating to v${latestVersion}...`, color: 'cyan' }).start();
43
+ try {
44
+ await execAsync(`npm install -g ${packageName}@latest`);
45
+ spinner.succeed(chalk.green(`Updated successfully to v${latestVersion}!`));
46
+ console.log(`\n ${chalk.bold('Please restart eco-code to use the new version:')}`);
47
+ console.log(` ${chalk.cyan.bold('eco-code')}\n`);
48
+ process.exit(0);
49
+ }
50
+ catch (err) {
51
+ spinner.fail(chalk.red(`Auto-update failed: ${err.message}`));
52
+ console.log(chalk.dim(` You can manually update anytime with: npm update -g ${packageName}\n`));
53
+ }
54
+ }
55
+ }
56
+ }
57
+ catch {
58
+ // Offline or package not yet published on registry; continue seamlessly
59
+ }
60
+ }
61
+ //# sourceMappingURL=updater.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"updater.js","sourceRoot":"","sources":["../../src/services/updater.ts"],"names":[],"mappings":"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"}