nex-code 0.3.2 → 0.3.4
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 +11 -3
- package/cli/context.js +18 -1
- package/cli/git.js +9 -0
- package/cli/sub-agent.js +0 -16
- package/cli/ui.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -18,9 +18,15 @@
|
|
|
18
18
|
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License: MIT"></a>
|
|
19
19
|
<img src="https://img.shields.io/badge/node-%3E%3D18-brightgreen.svg" alt="Node >= 18">
|
|
20
20
|
<img src="https://img.shields.io/badge/dependencies-2-green.svg" alt="Dependencies: 2">
|
|
21
|
-
<img src="https://img.shields.io/badge/tests-
|
|
21
|
+
<img src="https://img.shields.io/badge/tests-1783-blue.svg" alt="Tests: 1783">
|
|
22
22
|
</p>
|
|
23
23
|
|
|
24
|
+
---
|
|
25
|
+
## Demo
|
|
26
|
+
|
|
27
|
+
https://github.com/user-attachments/assets/634e70eb-645c-42f7-a604-824f17e49840
|
|
28
|
+
|
|
29
|
+
|
|
24
30
|
---
|
|
25
31
|
|
|
26
32
|
## Quickstart
|
|
@@ -49,7 +55,7 @@ That's it. You'll see the banner, your project context, and the `>` prompt. Star
|
|
|
49
55
|
| **Multi-provider** | 5 providers, swap at runtime | Anthropic only | Multi-provider | Multi-provider |
|
|
50
56
|
| **Free local models** | Ollama (no API key) | — | Ollama | — |
|
|
51
57
|
| **Runtime dependencies** | 2 (axios, dotenv) | Heavy | Heavy | Electron |
|
|
52
|
-
| **Test coverage** |
|
|
58
|
+
| **Test coverage** | 1783 tests, 90% coverage | — | — | — |
|
|
53
59
|
| **Tool tiers** | Auto-adapts tools per model | Fixed | Fixed | Fixed |
|
|
54
60
|
| **No lock-in** | `/model openai:gpt-4o` ↔ `/model local:llama3` | Anthropic only | Config change | Config change |
|
|
55
61
|
|
|
@@ -321,6 +327,7 @@ On startup, the CLI reads your project and injects context into the system promp
|
|
|
321
327
|
- `README.md` — first 50 lines
|
|
322
328
|
- Git info — branch, status, recent commits
|
|
323
329
|
- `.gitignore` content
|
|
330
|
+
- **Merge conflicts** — detected and shown as a red warning; included in LLM context so the agent avoids editing conflicted files
|
|
324
331
|
|
|
325
332
|
### Context Engine
|
|
326
333
|
Automatic token management with compression when the context window gets full. Tracks token usage across system prompt, conversation, tool results, and tool definitions.
|
|
@@ -332,6 +339,7 @@ Three tiers of protection:
|
|
|
332
339
|
- **SSH read-only safe list**: Common read-only SSH commands (`systemctl status`, `journalctl`, `tail`, `cat`, `git pull`, etc.) skip the dangerous-command confirmation
|
|
333
340
|
- **Path protection**: Sensitive paths (`.ssh/`, `.aws/`, `.env`, credentials) are blocked from file operations
|
|
334
341
|
- **Pre-push secret detection**: Git hook scans diffs for API keys, private keys, hardcoded secrets, SSH+IP patterns, and `.env` leaks before allowing push
|
|
342
|
+
- **Post-merge automation**: Auto-bumps patch version on `devel→main` merge; runs `npm install` when `package.json` changes
|
|
335
343
|
|
|
336
344
|
### Sessions
|
|
337
345
|
Save and restore conversations:
|
|
@@ -681,7 +689,7 @@ npm test # Run all tests with coverage
|
|
|
681
689
|
npm run test:watch # Watch mode
|
|
682
690
|
```
|
|
683
691
|
|
|
684
|
-
43 test suites,
|
|
692
|
+
43 test suites, 1783 tests, 90% statement / 83% branch coverage.
|
|
685
693
|
|
|
686
694
|
CI runs on GitHub Actions (Node 18/20/22).
|
|
687
695
|
|
package/cli/context.js
CHANGED
|
@@ -6,6 +6,7 @@ const fs = require('fs');
|
|
|
6
6
|
const path = require('path');
|
|
7
7
|
const { execSync } = require('child_process');
|
|
8
8
|
const { C } = require('./ui');
|
|
9
|
+
const { getMergeConflicts } = require('./git');
|
|
9
10
|
|
|
10
11
|
function safe(fn) {
|
|
11
12
|
try {
|
|
@@ -50,6 +51,13 @@ function gatherProjectContext(cwd) {
|
|
|
50
51
|
);
|
|
51
52
|
if (log) parts.push(`RECENT COMMITS:\n${log}`);
|
|
52
53
|
|
|
54
|
+
// Merge conflicts
|
|
55
|
+
const conflicts = getMergeConflicts();
|
|
56
|
+
if (conflicts.length > 0) {
|
|
57
|
+
const conflictFiles = conflicts.map(c => ` ${c.file}`).join('\n');
|
|
58
|
+
parts.push(`MERGE CONFLICTS (resolve before editing these files):\n${conflictFiles}`);
|
|
59
|
+
}
|
|
60
|
+
|
|
53
61
|
// .gitignore
|
|
54
62
|
const giPath = path.join(cwd, '.gitignore');
|
|
55
63
|
if (fs.existsSync(giPath)) {
|
|
@@ -72,9 +80,18 @@ function printContext(cwd) {
|
|
|
72
80
|
|
|
73
81
|
const branch = safe(() => execSync('git branch --show-current', { cwd, encoding: 'utf-8', stdio: 'pipe' }).trim());
|
|
74
82
|
|
|
75
|
-
console.log(`${C.dim} cwd: ${cwd}${C.reset}`);
|
|
76
83
|
if (project) console.log(`${C.dim} project: ${project}${C.reset}`);
|
|
77
84
|
if (branch) console.log(`${C.dim} branch: ${branch}${C.reset}`);
|
|
85
|
+
|
|
86
|
+
const conflicts = getMergeConflicts();
|
|
87
|
+
if (conflicts.length > 0) {
|
|
88
|
+
console.log(`${C.red} ⚠ ${conflicts.length} unresolved merge conflict(s):${C.reset}`);
|
|
89
|
+
for (const c of conflicts) {
|
|
90
|
+
console.log(`${C.red} ${c.file}${C.reset}`);
|
|
91
|
+
}
|
|
92
|
+
console.log(`${C.yellow} → Resolve conflicts before starting tasks${C.reset}`);
|
|
93
|
+
}
|
|
94
|
+
|
|
78
95
|
console.log();
|
|
79
96
|
}
|
|
80
97
|
|
package/cli/git.js
CHANGED
|
@@ -168,6 +168,14 @@ function formatDiffSummary() {
|
|
|
168
168
|
return lines.join('\n');
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
+
/**
|
|
172
|
+
* Get files with unresolved merge conflicts (UU, AA, DD)
|
|
173
|
+
*/
|
|
174
|
+
function getMergeConflicts() {
|
|
175
|
+
const status = getStatus();
|
|
176
|
+
return status.filter(s => s.status === 'UU' || s.status === 'AA' || s.status === 'DD');
|
|
177
|
+
}
|
|
178
|
+
|
|
171
179
|
/**
|
|
172
180
|
* Get diff-aware context (only changed files' content)
|
|
173
181
|
* For use when the user is working on git-related tasks
|
|
@@ -199,4 +207,5 @@ module.exports = {
|
|
|
199
207
|
commit,
|
|
200
208
|
formatDiffSummary,
|
|
201
209
|
getDiffContext,
|
|
210
|
+
getMergeConflicts,
|
|
202
211
|
};
|
package/cli/sub-agent.js
CHANGED
|
@@ -48,7 +48,6 @@ function isRetryableError(err) {
|
|
|
48
48
|
return false;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
<<<<<<< Updated upstream
|
|
52
51
|
async function callWithRetry(messages, tools, options) {
|
|
53
52
|
let lastError;
|
|
54
53
|
for (let attempt = 0; attempt <= MAX_CHAT_RETRIES; attempt++) {
|
|
@@ -56,13 +55,6 @@ async function callWithRetry(messages, tools, options) {
|
|
|
56
55
|
// Use callStream (stream:true) — more reliable than callChat (stream:false)
|
|
57
56
|
// with Ollama Cloud. Silently collect the full response via no-op onToken.
|
|
58
57
|
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
|
|
66
58
|
} catch (err) {
|
|
67
59
|
lastError = err;
|
|
68
60
|
if (attempt < MAX_CHAT_RETRIES && isRetryableError(err)) {
|
|
@@ -224,11 +216,7 @@ ERROR RECOVERY:
|
|
|
224
216
|
|
|
225
217
|
try {
|
|
226
218
|
for (let i = 0; i < maxIter; i++) {
|
|
227
|
-
<<<<<<< Updated upstream
|
|
228
219
|
const result = await callWithRetry(messages, availableTools, chatOptions);
|
|
229
|
-
=======
|
|
230
|
-
const result = await callChatWithRetry(messages, availableTools, chatOptions);
|
|
231
|
-
>>>>>>> Stashed changes
|
|
232
220
|
|
|
233
221
|
// Guard against null/undefined responses
|
|
234
222
|
if (!result || typeof result !== 'object') {
|
|
@@ -434,8 +422,4 @@ async function executeSpawnAgents(args) {
|
|
|
434
422
|
}
|
|
435
423
|
}
|
|
436
424
|
|
|
437
|
-
<<<<<<< Updated upstream
|
|
438
425
|
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/ui.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nex-code",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "Nex Code — Agentic Coding CLI with Multi-Provider Support",
|
|
5
5
|
"bin": {
|
|
6
6
|
"nex-code": "./bin/nex-code.js"
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"test": "jest --coverage",
|
|
20
20
|
"test:watch": "jest --watch",
|
|
21
21
|
"format": "prettier --write .",
|
|
22
|
-
"install-hooks": "ln -sf ../../hooks/pre-push .git/hooks/pre-push && chmod +x .git/hooks/pre-push && echo 'pre-push
|
|
22
|
+
"install-hooks": "ln -sf ../../hooks/pre-push .git/hooks/pre-push && chmod +x .git/hooks/pre-push && ln -sf ../../hooks/post-merge .git/hooks/post-merge && chmod +x .git/hooks/post-merge && echo 'Hooks installed (pre-push, post-merge).'",
|
|
23
23
|
"prepublishOnly": "npm test"
|
|
24
24
|
},
|
|
25
25
|
"keywords": [
|