neuro-cli 4.1.0 → 4.1.1
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/dist/core/engine.js +2 -2
- package/dist/core/sandbox.js +14 -3
- package/dist/index.js +4 -4
- package/dist/tools/file.js +8 -7
- package/dist/utils/crosspath.d.ts +28 -0
- package/dist/utils/crosspath.js +81 -0
- package/package.json +1 -1
package/dist/core/engine.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// ============================================================
|
|
2
|
-
// NeuroCLI - NeuroEngine v4.1.
|
|
2
|
+
// NeuroCLI - NeuroEngine v4.1.1
|
|
3
3
|
// The main engine that ties everything together
|
|
4
4
|
// Now with: Sandbox, Plugin SDK, Enhanced MCP, Enhanced Approval,
|
|
5
5
|
// Model Router, Prompt Cache, Undo/Redo, Output Styles,
|
|
@@ -483,7 +483,7 @@ export class NeuroEngine {
|
|
|
483
483
|
this.gitWorktree = new GitWorktreeManager(process.cwd());
|
|
484
484
|
// Auto-Updater
|
|
485
485
|
this.updater = new AutoUpdater({
|
|
486
|
-
currentVersion: '4.1.
|
|
486
|
+
currentVersion: '4.1.1',
|
|
487
487
|
autoCheck: true,
|
|
488
488
|
autoUpdate: false,
|
|
489
489
|
});
|
package/dist/core/sandbox.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import { join, resolve, relative, normalize } from 'path';
|
|
7
7
|
import { existsSync, mkdirSync, readFileSync, writeFileSync, copyFileSync } from 'fs';
|
|
8
8
|
import chalk from 'chalk';
|
|
9
|
+
import { normalizeCrossPlatformPath, isWindowsAbsolutePath } from '../utils/crosspath.js';
|
|
9
10
|
export const DEFAULT_SANDBOX_CONFIG = {
|
|
10
11
|
enabled: false,
|
|
11
12
|
rootDir: process.cwd(),
|
|
@@ -312,11 +313,21 @@ export class Sandbox {
|
|
|
312
313
|
}
|
|
313
314
|
// --- Private Helpers ---
|
|
314
315
|
resolvePath(filePath) {
|
|
316
|
+
// Expand home directory
|
|
317
|
+
if (filePath.startsWith('~/') || filePath === '~') {
|
|
318
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE || require('os').homedir();
|
|
319
|
+
const expanded = filePath === '~' ? homeDir : join(homeDir, filePath.slice(2));
|
|
320
|
+
return normalize(expanded);
|
|
321
|
+
}
|
|
322
|
+
// Windows absolute path (C:\... or C:/...)
|
|
323
|
+
if (isWindowsAbsolutePath(filePath)) {
|
|
324
|
+
return normalizeCrossPlatformPath(filePath);
|
|
325
|
+
}
|
|
326
|
+
// POSIX absolute path
|
|
315
327
|
if (filePath.startsWith('/'))
|
|
316
328
|
return normalize(filePath);
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
return normalize(resolve(this.config.rootDir, filePath));
|
|
329
|
+
// Relative path - resolve against rootDir
|
|
330
|
+
return normalize(resolve(this.config.rootDir, normalizeCrossPlatformPath(filePath)));
|
|
320
331
|
}
|
|
321
332
|
isUnderRootDir(absPath) {
|
|
322
333
|
const relativePath = relative(this.config.rootDir, absPath);
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// ============================================================
|
|
3
3
|
// NeuroCLI - Advanced AI Terminal Coding Assistant
|
|
4
|
-
// Main Entry Point - v4.1.
|
|
4
|
+
// Main Entry Point - v4.1.1 with cross-platform path fix
|
|
5
5
|
// ============================================================
|
|
6
6
|
import { Command } from 'commander';
|
|
7
7
|
import { createInterface } from 'readline';
|
|
@@ -16,7 +16,7 @@ import { HeadlessMode } from './core/headless.js';
|
|
|
16
16
|
import { ShellCompletionGenerator } from './core/shell-completion.js';
|
|
17
17
|
import chalk from 'chalk';
|
|
18
18
|
import { AutoUpdater } from './core/updater.js';
|
|
19
|
-
const VERSION = '4.1.
|
|
19
|
+
const VERSION = '4.1.1';
|
|
20
20
|
// ---- CLI Setup ----
|
|
21
21
|
const program = new Command();
|
|
22
22
|
program
|
|
@@ -909,7 +909,7 @@ async function startInteractive(options) {
|
|
|
909
909
|
}
|
|
910
910
|
break;
|
|
911
911
|
case 'doctor':
|
|
912
|
-
console.log(chalk.bold('\nNeuroCLI v4.1.
|
|
912
|
+
console.log(chalk.bold('\nNeuroCLI v4.1.1 Health Check:\n'));
|
|
913
913
|
console.log(` API Key: ${config.apiKey ? chalk.green('configured') : chalk.red('MISSING')}`);
|
|
914
914
|
console.log(` Default Model: ${chalk.cyan(config.defaultModel)} ${MODELS[config.defaultModel] ? chalk.green('valid') : chalk.red('INVALID')}`);
|
|
915
915
|
console.log(` MCP Servers: ${chalk.cyan(String(engine.mcpClient.listServers().length))}`);
|
|
@@ -1128,7 +1128,7 @@ async function startInteractive(options) {
|
|
|
1128
1128
|
}
|
|
1129
1129
|
function printHelp(engine) {
|
|
1130
1130
|
const t = engine.ui.theme;
|
|
1131
|
-
console.log(`\n ${t.bold('NeuroCLI v4.1.
|
|
1131
|
+
console.log(`\n ${t.bold('NeuroCLI v4.1.1 Commands:')}\n`);
|
|
1132
1132
|
console.log(` ${t.tool('/help')} Show this help message`);
|
|
1133
1133
|
console.log(` ${t.tool('/model [id]')} Switch or list models`);
|
|
1134
1134
|
console.log(` ${t.tool('/agent [name]')} Switch or list agents`);
|
package/dist/tools/file.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync, statSync, readdirSync } from 'fs';
|
|
6
6
|
import { join, relative, extname } from 'path';
|
|
7
7
|
import { execSync } from 'child_process';
|
|
8
|
+
import { resolvePath } from '../utils/crosspath.js';
|
|
8
9
|
const MAX_FILE_SIZE = 1024 * 1024; // 1MB
|
|
9
10
|
const MAX_OUTPUT_LENGTH = 50000;
|
|
10
11
|
function truncateOutput(output, maxLength = MAX_OUTPUT_LENGTH) {
|
|
@@ -32,7 +33,7 @@ export const readFileTool = {
|
|
|
32
33
|
definition: readFileDef,
|
|
33
34
|
risk: 'low',
|
|
34
35
|
async execute(args, context) {
|
|
35
|
-
const filePath =
|
|
36
|
+
const filePath = resolvePath(context.workingDirectory, args.path);
|
|
36
37
|
if (!existsSync(filePath))
|
|
37
38
|
return `Error: File not found: ${args.path}`;
|
|
38
39
|
const stat = statSync(filePath);
|
|
@@ -78,7 +79,7 @@ export const writeFileTool = {
|
|
|
78
79
|
};
|
|
79
80
|
},
|
|
80
81
|
async execute(args, context) {
|
|
81
|
-
const filePath =
|
|
82
|
+
const filePath = resolvePath(context.workingDirectory, args.path);
|
|
82
83
|
const dir = join(filePath, '..');
|
|
83
84
|
if (!existsSync(dir)) {
|
|
84
85
|
mkdirSync(dir, { recursive: true });
|
|
@@ -114,7 +115,7 @@ export const editFileTool = {
|
|
|
114
115
|
};
|
|
115
116
|
},
|
|
116
117
|
async execute(args, context) {
|
|
117
|
-
const filePath =
|
|
118
|
+
const filePath = resolvePath(context.workingDirectory, args.path);
|
|
118
119
|
if (!existsSync(filePath))
|
|
119
120
|
return `Error: File not found: ${args.path}`;
|
|
120
121
|
let content = readFileSync(filePath, 'utf-8');
|
|
@@ -157,7 +158,7 @@ export const deleteFileTool = {
|
|
|
157
158
|
};
|
|
158
159
|
},
|
|
159
160
|
async execute(args, context) {
|
|
160
|
-
const filePath =
|
|
161
|
+
const filePath = resolvePath(context.workingDirectory, args.path);
|
|
161
162
|
if (!existsSync(filePath))
|
|
162
163
|
return `Error: File not found: ${args.path}`;
|
|
163
164
|
unlinkSync(filePath);
|
|
@@ -183,7 +184,7 @@ export const listDirectoryTool = {
|
|
|
183
184
|
definition: listDirDef,
|
|
184
185
|
risk: 'low',
|
|
185
186
|
async execute(args, context) {
|
|
186
|
-
const dirPath =
|
|
187
|
+
const dirPath = resolvePath(context.workingDirectory, args.path || '.');
|
|
187
188
|
if (!existsSync(dirPath))
|
|
188
189
|
return `Error: Directory not found: ${args.path}`;
|
|
189
190
|
const stat = statSync(dirPath);
|
|
@@ -259,7 +260,7 @@ export const searchFilesTool = {
|
|
|
259
260
|
risk: 'low',
|
|
260
261
|
async execute(args, context) {
|
|
261
262
|
const pattern = args.pattern;
|
|
262
|
-
const searchPath =
|
|
263
|
+
const searchPath = resolvePath(context.workingDirectory, args.path || '.');
|
|
263
264
|
const fileType = args.file_type;
|
|
264
265
|
const maxResults = args.max_results || 50;
|
|
265
266
|
const caseInsensitive = args.case_insensitive || false;
|
|
@@ -332,7 +333,7 @@ export const applyDiffTool = {
|
|
|
332
333
|
};
|
|
333
334
|
},
|
|
334
335
|
async execute(args, context) {
|
|
335
|
-
const filePath =
|
|
336
|
+
const filePath = resolvePath(context.workingDirectory, args.path);
|
|
336
337
|
if (!existsSync(filePath))
|
|
337
338
|
return `Error: File not found: ${args.path}`;
|
|
338
339
|
try {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check if a path looks like a Windows absolute path (drive letter)
|
|
3
|
+
* Matches: C:\, C:/, D:\foo, etc.
|
|
4
|
+
*/
|
|
5
|
+
export declare function isWindowsAbsolutePath(p: string): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Normalize a path for cross-platform compatibility:
|
|
8
|
+
* 1. Convert backslashes to forward slashes
|
|
9
|
+
* 2. Detect Windows absolute paths (C:\...) and treat them as absolute
|
|
10
|
+
* 3. Resolve ~ to home directory
|
|
11
|
+
* 4. Handle relative paths correctly
|
|
12
|
+
*/
|
|
13
|
+
export declare function normalizeCrossPlatformPath(inputPath: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Resolve a path relative to a working directory with cross-platform support.
|
|
16
|
+
* This is the main function to use in file tools.
|
|
17
|
+
*
|
|
18
|
+
* - Absolute paths (POSIX or Windows) are used as-is after normalization
|
|
19
|
+
* - Relative paths are resolved against workingDirectory
|
|
20
|
+
* - Home directory (~) is expanded
|
|
21
|
+
* - Backslashes are normalized to forward slashes
|
|
22
|
+
*/
|
|
23
|
+
export declare function resolvePath(workingDirectory: string, inputPath: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* Check if a path is absolute on any platform (POSIX or Windows)
|
|
26
|
+
*/
|
|
27
|
+
export declare function isAnyAbsolutePath(p: string): boolean;
|
|
28
|
+
//# sourceMappingURL=crosspath.d.ts.map
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// NeuroCLI - Cross-Platform Path Utility
|
|
3
|
+
// Handles Windows, macOS, and Linux path differences
|
|
4
|
+
// ============================================================
|
|
5
|
+
import { join, resolve, isAbsolute, normalize } from 'path';
|
|
6
|
+
/**
|
|
7
|
+
* Check if a path looks like a Windows absolute path (drive letter)
|
|
8
|
+
* Matches: C:\, C:/, D:\foo, etc.
|
|
9
|
+
*/
|
|
10
|
+
export function isWindowsAbsolutePath(p) {
|
|
11
|
+
return /^[A-Za-z]:[/\\]/.test(p);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Normalize a path for cross-platform compatibility:
|
|
15
|
+
* 1. Convert backslashes to forward slashes
|
|
16
|
+
* 2. Detect Windows absolute paths (C:\...) and treat them as absolute
|
|
17
|
+
* 3. Resolve ~ to home directory
|
|
18
|
+
* 4. Handle relative paths correctly
|
|
19
|
+
*/
|
|
20
|
+
export function normalizeCrossPlatformPath(inputPath) {
|
|
21
|
+
let p = inputPath;
|
|
22
|
+
// Step 1: Expand home directory
|
|
23
|
+
if (p.startsWith('~/') || p === '~') {
|
|
24
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE || '';
|
|
25
|
+
p = p === '~' ? homeDir : join(homeDir, p.slice(2));
|
|
26
|
+
return normalize(p);
|
|
27
|
+
}
|
|
28
|
+
// Step 2: Detect Windows absolute path with drive letter
|
|
29
|
+
if (isWindowsAbsolutePath(p)) {
|
|
30
|
+
// Normalize backslashes to forward slashes, then let Node normalize
|
|
31
|
+
p = p.replace(/\\/g, '/');
|
|
32
|
+
// On Windows, Node's path.resolve handles drive letters natively
|
|
33
|
+
// On non-Windows, we still need to handle this for the case where
|
|
34
|
+
// the LLM sends a Windows path from a user's context
|
|
35
|
+
if (process.platform === 'win32') {
|
|
36
|
+
return normalize(p);
|
|
37
|
+
}
|
|
38
|
+
// On non-Windows systems, a Windows path like C:/Users/foo
|
|
39
|
+
// won't resolve. This likely means the LLM is confused about
|
|
40
|
+
// the OS. We still normalize it so it can be used as-is.
|
|
41
|
+
return normalize(p);
|
|
42
|
+
}
|
|
43
|
+
// Step 3: Convert backslashes to forward slashes for mixed paths
|
|
44
|
+
// (handles cases where LLM or user provides backslash paths on any OS)
|
|
45
|
+
p = p.replace(/\\/g, '/');
|
|
46
|
+
// Step 4: If already absolute (POSIX), normalize directly
|
|
47
|
+
if (isAbsolute(p)) {
|
|
48
|
+
return normalize(p);
|
|
49
|
+
}
|
|
50
|
+
// Step 5: Relative path - return as-is (caller will resolve against working dir)
|
|
51
|
+
return normalize(p);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Resolve a path relative to a working directory with cross-platform support.
|
|
55
|
+
* This is the main function to use in file tools.
|
|
56
|
+
*
|
|
57
|
+
* - Absolute paths (POSIX or Windows) are used as-is after normalization
|
|
58
|
+
* - Relative paths are resolved against workingDirectory
|
|
59
|
+
* - Home directory (~) is expanded
|
|
60
|
+
* - Backslashes are normalized to forward slashes
|
|
61
|
+
*/
|
|
62
|
+
export function resolvePath(workingDirectory, inputPath) {
|
|
63
|
+
const normalized = normalizeCrossPlatformPath(inputPath);
|
|
64
|
+
// If it's already an absolute path after normalization, use it directly
|
|
65
|
+
if (isAbsolute(normalized)) {
|
|
66
|
+
return normalized;
|
|
67
|
+
}
|
|
68
|
+
// Windows absolute paths that became normalized (C:/...)
|
|
69
|
+
if (isWindowsAbsolutePath(normalized)) {
|
|
70
|
+
return normalized;
|
|
71
|
+
}
|
|
72
|
+
// Relative path: resolve against working directory
|
|
73
|
+
return resolve(workingDirectory, normalized);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Check if a path is absolute on any platform (POSIX or Windows)
|
|
77
|
+
*/
|
|
78
|
+
export function isAnyAbsolutePath(p) {
|
|
79
|
+
return isAbsolute(p) || isWindowsAbsolutePath(p);
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=crosspath.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neuro-cli",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.1",
|
|
4
4
|
"description": "Advanced AI-powered terminal coding assistant with multi-agent orchestration, sub-agent spawning, ACP protocol, OS-level sandboxing, spec-driven development, smart monitoring, multi-model routing, MCP Apps, auto-updater, and 23+ free models",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|