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 +32 -7
- package/cli/costs.js +11 -6
- package/cli/index.js +14 -6
- package/cli/ollama.js +1 -1
- package/cli/providers/ollama.js +26 -12
- package/cli/providers/registry.js +10 -6
- package/cli/sub-agent.js +16 -0
- package/cli/tool-tiers.js +21 -5
- package/package.json +1 -1
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
###
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
'
|
|
37
|
-
'qwen3-coder':
|
|
38
|
-
'
|
|
39
|
-
'
|
|
40
|
-
'
|
|
41
|
-
'
|
|
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
|
|
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(
|
|
926
|
-
console.error(`${C.
|
|
927
|
-
console.error(`${C.
|
|
928
|
-
console.error(`${C.gray}
|
|
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() {
|
package/cli/providers/ollama.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
14
|
-
'
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
'
|
|
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
|
-
//
|
|
21
|
-
'
|
|
22
|
-
'
|
|
23
|
-
'
|
|
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',
|
|
22
|
-
strong: { ollama: 'qwen3-coder', openai: 'gpt-4o', anthropic: 'claude-sonnet', gemini: 'gemini-2.5-flash' },
|
|
23
|
-
fast: { ollama: 'devstral',
|
|
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
|
|
140
|
-
if (
|
|
141
|
-
|
|
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
|
-
'
|
|
28
|
-
'
|
|
29
|
-
'deepseek-
|
|
30
|
-
'
|
|
31
|
-
'
|
|
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',
|