nex-code 0.3.0 → 0.3.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.
package/README.md CHANGED
@@ -13,6 +13,7 @@
13
13
  </p>
14
14
 
15
15
  <p align="center">
16
+ <a href="https://www.npmjs.com/package/nex-code"><img src="https://img.shields.io/npm/v/nex-code.svg" alt="npm version"></a>
16
17
  <a href="https://github.com/hybridpicker/nex-code/actions/workflows/ci.yml"><img src="https://github.com/hybridpicker/nex-code/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
17
18
  <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License: MIT"></a>
18
19
  <img src="https://img.shields.io/badge/node-%3E%3D18-brightgreen.svg" alt="Node >= 18">
@@ -25,10 +26,15 @@
25
26
  ## Quickstart
26
27
 
27
28
  ```bash
28
- git clone https://github.com/hybridpicker/nex-code.git
29
- cd nex-code && npm install
30
- cp .env.example .env # add at least one API key
31
- npm start # or: npm link && nex-code
29
+ npx nex-code
30
+ ```
31
+
32
+ Or install globally:
33
+
34
+ ```bash
35
+ npm install -g nex-code
36
+ cd ~/your-project
37
+ nex-code
32
38
  ```
33
39
 
34
40
  That's it. You'll see the banner, your project context, and the `>` prompt. Start typing.
@@ -55,10 +61,22 @@ That's it. You'll see the banner, your project context, and the `>` prompt. Star
55
61
  - Node.js 18+
56
62
  - At least one API key **or** a local [Ollama](https://ollama.com/download) server
57
63
 
58
- ### Installation
64
+ ### Install from npm
65
+
66
+ ```bash
67
+ npm install -g nex-code
68
+ ```
69
+
70
+ Or run directly without installing:
59
71
 
60
72
  ```bash
61
- git clone git@github.com:hybridpicker/nex-code.git
73
+ npx nex-code
74
+ ```
75
+
76
+ ### Install from source (for contributors)
77
+
78
+ ```bash
79
+ git clone https://github.com/hybridpicker/nex-code.git
62
80
  cd nex-code
63
81
  npm install
64
82
  cp .env.example .env
@@ -68,7 +86,7 @@ npm run install-hooks
68
86
 
69
87
  ### Configure a Provider
70
88
 
71
- Add one or more API keys to `.env`:
89
+ Create a `.env` file in your project directory (or set environment variables):
72
90
 
73
91
  ```bash
74
92
  # Pick any — only one is required
@@ -682,6 +700,13 @@ CI runs on GitHub Actions (Node 18/20/22).
682
700
 
683
701
  Everything else is Node.js built-in.
684
702
 
703
+ ## Installation
704
+
705
+ ```bash
706
+ npm install -g nex-code # global install
707
+ npx nex-code # or run without installing
708
+ ```
709
+
685
710
  ## License
686
711
 
687
712
  MIT
package/cli/costs.js CHANGED
@@ -33,12 +33,17 @@ const PRICING = {
33
33
  'gemini-2.0-flash-lite': { input: 0.075, output: 0.30 },
34
34
  },
35
35
  'ollama': {
36
- 'kimi-k2.5': { input: 0, output: 0 },
37
- 'qwen3-coder': { input: 0, output: 0 },
38
- 'deepseek-r1': { input: 0, output: 0 },
39
- 'llama4': { input: 0, output: 0 },
40
- 'qwen3:30b-a3b': { input: 0, output: 0 },
41
- 'devstral': { input: 0, output: 0 },
36
+ 'qwen3-coder:480b': { input: 0, output: 0 },
37
+ 'qwen3-coder-next': { input: 0, output: 0 },
38
+ 'devstral-2:123b': { input: 0, output: 0 },
39
+ 'devstral-small-2:24b': { input: 0, output: 0 },
40
+ 'kimi-k2.5': { input: 0, output: 0 },
41
+ 'kimi-k2:1t': { input: 0, output: 0 },
42
+ 'deepseek-v3.2': { input: 0, output: 0 },
43
+ 'minimax-m2.5': { input: 0, output: 0 },
44
+ 'glm-5': { input: 0, output: 0 },
45
+ 'glm-4.7': { input: 0, output: 0 },
46
+ 'gpt-oss:120b': { input: 0, output: 0 },
42
47
  },
43
48
  'local': {},
44
49
  };
package/cli/index.js CHANGED
@@ -914,18 +914,26 @@ function startREPL() {
914
914
  const { execSync } = require('child_process');
915
915
  execSync('curl -s --max-time 2 http://localhost:11434/api/tags', { encoding: 'utf-8', stdio: 'pipe' });
916
916
  setActiveModel('local:llama3');
917
- console.log(`${C.green}Local Ollama detected — using local models${C.reset}`);
918
- console.log(`${C.dim}Set API keys for cloud providers: OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY${C.reset}\n`);
917
+ console.log(`${C.green}Local Ollama detected — using local models${C.reset}`);
918
+ console.log(`${C.dim}Tip: Set API keys for cloud providers for more model options (OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.)${C.reset}\n`);
919
919
  localDetected = true;
920
920
  } catch {
921
921
  // Local Ollama not available
922
922
  }
923
923
  }
924
924
  if (!localDetected) {
925
- console.error(`${C.red}No provider configured and no local Ollama running.${C.reset}`);
926
- console.error(`${C.gray}Options:${C.reset}`);
927
- console.error(`${C.gray} 1. Install Ollama: https://ollama.com/download${C.reset}`);
928
- console.error(`${C.gray} 2. Set an API key: OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY, or OLLAMA_API_KEY${C.reset}`);
925
+ console.error(`\n${C.red}No provider configured and no local Ollama detected.${C.reset}\n`);
926
+ console.error(`${C.white}nex-code needs at least one LLM provider to work.${C.reset}\n`);
927
+ console.error(`${C.white}Option 1 Free local models (no API key needed):${C.reset}`);
928
+ console.error(`${C.gray} Install Ollama: ${C.cyan}https://ollama.com/download${C.reset}`);
929
+ console.error(`${C.gray} Pull a model: ${C.cyan}ollama pull qwen3-coder${C.reset}`);
930
+ console.error(`${C.gray} Then restart: ${C.cyan}nex-code${C.reset}\n`);
931
+ console.error(`${C.white}Option 2 — Cloud providers (set one in .env or as env var):${C.reset}`);
932
+ console.error(`${C.gray} OLLAMA_API_KEY=... ${C.dim}# Ollama Cloud (free tier available)${C.reset}`);
933
+ console.error(`${C.gray} OPENAI_API_KEY=... ${C.dim}# OpenAI${C.reset}`);
934
+ console.error(`${C.gray} ANTHROPIC_API_KEY=... ${C.dim}# Anthropic${C.reset}`);
935
+ console.error(`${C.gray} GEMINI_API_KEY=... ${C.dim}# Google Gemini${C.reset}\n`);
936
+ console.error(`${C.dim}Create a .env file in your project directory or export the variable.${C.reset}`);
929
937
  process.exit(1);
930
938
  }
931
939
  }
package/cli/ollama.js CHANGED
@@ -9,7 +9,7 @@ const registry = require('./providers/registry');
9
9
 
10
10
  const MODELS = {
11
11
  'kimi-k2.5': { id: 'kimi-k2.5', name: 'Kimi K2.5', max_tokens: 16384 },
12
- 'qwen3-coder': { id: 'qwen3-coder', name: 'Qwen3 Coder', max_tokens: 16384 },
12
+ 'qwen3-coder:480b': { id: 'qwen3-coder:480b', name: 'Qwen3 Coder 480B', max_tokens: 16384 },
13
13
  };
14
14
 
15
15
  function getActiveModel() {
@@ -7,20 +7,34 @@ const axios = require('axios');
7
7
  const { BaseProvider } = require('./base');
8
8
 
9
9
  const OLLAMA_MODELS = {
10
- // Primary: Best coding model for agentic workflows
11
- 'qwen3-coder': { id: 'qwen3-coder', name: 'Qwen3 Coder', maxTokens: 16384, contextWindow: 131072 },
10
+ // Primary: Best coding models for agentic workflows
11
+ 'qwen3-coder:480b': { id: 'qwen3-coder:480b', name: 'Qwen3 Coder 480B', maxTokens: 16384, contextWindow: 131072 },
12
12
  'qwen3-coder-next': { id: 'qwen3-coder-next', name: 'Qwen3 Coder Next', maxTokens: 16384, contextWindow: 131072 },
13
- // Reasoning specialists
14
- 'deepseek-r1': { id: 'deepseek-r1', name: 'DeepSeek R1', maxTokens: 16384, contextWindow: 131072 },
15
- 'deepseek-r1:14b': { id: 'deepseek-r1:14b', name: 'DeepSeek R1 14B', maxTokens: 8192, contextWindow: 128000 },
16
- // Agent-focused models
17
- 'devstral': { id: 'devstral', name: 'Devstral', maxTokens: 16384, contextWindow: 131072 },
13
+ 'devstral-2:123b': { id: 'devstral-2:123b', name: 'Devstral 2 123B', maxTokens: 16384, contextWindow: 131072 },
14
+ 'devstral-small-2:24b': { id: 'devstral-small-2:24b', name: 'Devstral Small 2 24B', maxTokens: 16384, contextWindow: 131072 },
15
+ // Large general-purpose models
16
+ 'kimi-k2.5': { id: 'kimi-k2.5', name: 'Kimi K2.5', maxTokens: 16384, contextWindow: 256000 },
17
+ 'kimi-k2:1t': { id: 'kimi-k2:1t', name: 'Kimi K2 1T', maxTokens: 16384, contextWindow: 256000 },
18
+ 'kimi-k2-thinking': { id: 'kimi-k2-thinking', name: 'Kimi K2 Thinking', maxTokens: 16384, contextWindow: 256000 },
19
+ 'deepseek-v3.2': { id: 'deepseek-v3.2', name: 'DeepSeek V3.2', maxTokens: 16384, contextWindow: 131072 },
20
+ 'deepseek-v3.1:671b': { id: 'deepseek-v3.1:671b', name: 'DeepSeek V3.1 671B', maxTokens: 16384, contextWindow: 131072 },
21
+ 'cogito-2.1:671b': { id: 'cogito-2.1:671b', name: 'Cogito 2.1 671B', maxTokens: 16384, contextWindow: 131072 },
22
+ // Medium models
23
+ 'qwen3-next:80b': { id: 'qwen3-next:80b', name: 'Qwen3 Next 80B', maxTokens: 16384, contextWindow: 131072 },
24
+ 'qwen3.5:397b': { id: 'qwen3.5:397b', name: 'Qwen3.5 397B', maxTokens: 16384, contextWindow: 131072 },
25
+ 'mistral-large-3:675b': { id: 'mistral-large-3:675b', name: 'Mistral Large 3 675B', maxTokens: 16384, contextWindow: 131072 },
26
+ 'gpt-oss:120b': { id: 'gpt-oss:120b', name: 'GPT-OSS 120B', maxTokens: 16384, contextWindow: 131072 },
18
27
  'minimax-m2.5': { id: 'minimax-m2.5', name: 'MiniMax M2.5', maxTokens: 16384, contextWindow: 131072 },
28
+ 'glm-5': { id: 'glm-5', name: 'GLM 5', maxTokens: 16384, contextWindow: 128000 },
19
29
  'glm-4.7': { id: 'glm-4.7', name: 'GLM 4.7', maxTokens: 16384, contextWindow: 128000 },
20
- // General purpose / large context fallback
21
- 'kimi-k2.5': { id: 'kimi-k2.5', name: 'Kimi K2.5', maxTokens: 16384, contextWindow: 256000 },
22
- 'llama4': { id: 'llama4', name: 'Llama 4 Scout', maxTokens: 16384, contextWindow: 131072 },
23
- 'qwen3:30b-a3b': { id: 'qwen3:30b-a3b', name: 'Qwen3 30B A3B', maxTokens: 16384, contextWindow: 131072 },
30
+ // Small / fast models
31
+ 'gemma3:27b': { id: 'gemma3:27b', name: 'Gemma 3 27B', maxTokens: 8192, contextWindow: 131072 },
32
+ 'gemma3:12b': { id: 'gemma3:12b', name: 'Gemma 3 12B', maxTokens: 8192, contextWindow: 131072 },
33
+ 'gemma3:4b': { id: 'gemma3:4b', name: 'Gemma 3 4B', maxTokens: 8192, contextWindow: 131072 },
34
+ 'ministral-3:14b': { id: 'ministral-3:14b', name: 'Ministral 3 14B', maxTokens: 8192, contextWindow: 131072 },
35
+ 'ministral-3:8b': { id: 'ministral-3:8b', name: 'Ministral 3 8B', maxTokens: 8192, contextWindow: 131072 },
36
+ // Special
37
+ 'gemini-3-flash-preview': { id: 'gemini-3-flash-preview', name: 'Gemini 3 Flash Preview', maxTokens: 16384, contextWindow: 131072 },
24
38
  };
25
39
 
26
40
  class OllamaProvider extends BaseProvider {
@@ -29,7 +43,7 @@ class OllamaProvider extends BaseProvider {
29
43
  name: 'ollama',
30
44
  baseUrl: config.baseUrl || 'https://ollama.com',
31
45
  models: config.models || OLLAMA_MODELS,
32
- defaultModel: config.defaultModel || 'qwen3-coder',
46
+ defaultModel: config.defaultModel || 'qwen3-coder:480b',
33
47
  ...config,
34
48
  });
35
49
  this.timeout = config.timeout || 180000;
@@ -18,9 +18,9 @@ const { checkBudget } = require('../costs');
18
18
  // Used during fallback to pick an equivalent model on a different provider.
19
19
 
20
20
  const MODEL_EQUIVALENTS = {
21
- top: { ollama: 'kimi-k2.5', openai: 'gpt-4.1', anthropic: 'claude-sonnet-4-5', gemini: 'gemini-2.5-pro' },
22
- strong: { ollama: 'qwen3-coder', openai: 'gpt-4o', anthropic: 'claude-sonnet', gemini: 'gemini-2.5-flash' },
23
- fast: { ollama: 'devstral', openai: 'gpt-4.1-mini', anthropic: 'claude-haiku', gemini: 'gemini-2.0-flash' },
21
+ top: { ollama: 'kimi-k2.5', openai: 'gpt-4.1', anthropic: 'claude-sonnet-4-5', gemini: 'gemini-2.5-pro' },
22
+ strong: { ollama: 'qwen3-coder:480b', openai: 'gpt-4o', anthropic: 'claude-sonnet', gemini: 'gemini-2.5-flash' },
23
+ fast: { ollama: 'devstral-small-2:24b', openai: 'gpt-4.1-mini', anthropic: 'claude-haiku', gemini: 'gemini-2.0-flash' },
24
24
  };
25
25
 
26
26
  // Reverse lookup: model → tier
@@ -136,9 +136,13 @@ function getActiveModel() {
136
136
  */
137
137
  function parseModelSpec(spec) {
138
138
  if (!spec) return { provider: null, model: null };
139
- const parts = spec.split(':');
140
- if (parts.length >= 2) {
141
- return { provider: parts[0], model: parts.slice(1).join(':') };
139
+ const colonIdx = spec.indexOf(':');
140
+ if (colonIdx > 0) {
141
+ const prefix = spec.slice(0, colonIdx);
142
+ // Only treat as provider:model if prefix is a known provider name
143
+ if (providers[prefix] || ['ollama', 'openai', 'anthropic', 'gemini', 'local'].includes(prefix)) {
144
+ return { provider: prefix, model: spec.slice(colonIdx + 1) };
145
+ }
142
146
  }
143
147
  return { provider: null, model: spec };
144
148
  }
package/cli/sub-agent.js CHANGED
@@ -48,6 +48,7 @@ function isRetryableError(err) {
48
48
  return false;
49
49
  }
50
50
 
51
+ <<<<<<< Updated upstream
51
52
  async function callWithRetry(messages, tools, options) {
52
53
  let lastError;
53
54
  for (let attempt = 0; attempt <= MAX_CHAT_RETRIES; attempt++) {
@@ -55,6 +56,13 @@ async function callWithRetry(messages, tools, options) {
55
56
  // Use callStream (stream:true) — more reliable than callChat (stream:false)
56
57
  // with Ollama Cloud. Silently collect the full response via no-op onToken.
57
58
  return await callStream(messages, tools, { ...options, onToken: () => {} });
59
+ =======
60
+ async function callChatWithRetry(messages, tools, options) {
61
+ let lastError;
62
+ for (let attempt = 0; attempt <= MAX_CHAT_RETRIES; attempt++) {
63
+ try {
64
+ return await callChat(messages, tools, options);
65
+ >>>>>>> Stashed changes
58
66
  } catch (err) {
59
67
  lastError = err;
60
68
  if (attempt < MAX_CHAT_RETRIES && isRetryableError(err)) {
@@ -216,7 +224,11 @@ ERROR RECOVERY:
216
224
 
217
225
  try {
218
226
  for (let i = 0; i < maxIter; i++) {
227
+ <<<<<<< Updated upstream
219
228
  const result = await callWithRetry(messages, availableTools, chatOptions);
229
+ =======
230
+ const result = await callChatWithRetry(messages, availableTools, chatOptions);
231
+ >>>>>>> Stashed changes
220
232
 
221
233
  // Guard against null/undefined responses
222
234
  if (!result || typeof result !== 'object') {
@@ -422,4 +434,8 @@ async function executeSpawnAgents(args) {
422
434
  }
423
435
  }
424
436
 
437
+ <<<<<<< Updated upstream
425
438
  module.exports = { runSubAgent, executeSpawnAgents, clearAllLocks, classifyTask, pickModelForTier, resolveSubAgentModel, isRetryableError, callWithRetry };
439
+ =======
440
+ module.exports = { runSubAgent, executeSpawnAgents, clearAllLocks, classifyTask, pickModelForTier, resolveSubAgentModel, isRetryableError, callChatWithRetry };
441
+ >>>>>>> Stashed changes
package/cli/tool-tiers.js CHANGED
@@ -23,12 +23,28 @@ const TIERS = {
23
23
  */
24
24
  const MODEL_TIERS = {
25
25
  // Ollama Cloud — tier by capability
26
+ 'qwen3-coder:480b': 'full',
27
+ 'qwen3-coder-next': 'full',
26
28
  'kimi-k2.5': 'full',
27
- 'qwen3-coder': 'full',
28
- 'devstral': 'standard',
29
- 'deepseek-r1': 'standard',
30
- 'llama4': 'standard',
31
- 'qwen3:30b-a3b': 'essential',
29
+ 'kimi-k2:1t': 'full',
30
+ 'kimi-k2-thinking': 'full',
31
+ 'deepseek-v3.2': 'full',
32
+ 'deepseek-v3.1:671b': 'full',
33
+ 'devstral-2:123b': 'full',
34
+ 'devstral-small-2:24b': 'standard',
35
+ 'cogito-2.1:671b': 'full',
36
+ 'qwen3-next:80b': 'full',
37
+ 'qwen3.5:397b': 'full',
38
+ 'mistral-large-3:675b': 'full',
39
+ 'gpt-oss:120b': 'full',
40
+ 'minimax-m2.5': 'full',
41
+ 'glm-5': 'full',
42
+ 'glm-4.7': 'standard',
43
+ 'gemma3:27b': 'standard',
44
+ 'gemma3:12b': 'essential',
45
+ 'gemma3:4b': 'essential',
46
+ 'ministral-3:14b': 'standard',
47
+ 'ministral-3:8b': 'essential',
32
48
 
33
49
  // OpenAI — all full
34
50
  'gpt-4o': 'full',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nex-code",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Nex Code — Agentic Coding CLI with Multi-Provider Support",
5
5
  "bin": {
6
6
  "nex-code": "./bin/nex-code.js"