@juspay/neurolink 7.47.2 → 7.48.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.
- package/CHANGELOG.md +8 -0
- package/dist/cli/loop/session.d.ts +13 -0
- package/dist/cli/loop/session.js +78 -17
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
## [7.48.0](https://github.com/juspay/neurolink/compare/v7.47.3...v7.48.0) (2025-09-30)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
- **(cli):** add command history support on up/down ([5aa3c2d](https://github.com/juspay/neurolink/commit/5aa3c2db04714019b34af0fd69106a8fd21ac252))
|
|
6
|
+
|
|
7
|
+
## [7.47.3](https://github.com/juspay/neurolink/compare/v7.47.2...v7.47.3) (2025-09-26)
|
|
8
|
+
|
|
1
9
|
## [7.47.2](https://github.com/juspay/neurolink/compare/v7.47.1...v7.47.2) (2025-09-26)
|
|
2
10
|
|
|
3
11
|
### Bug Fixes
|
|
@@ -5,6 +5,7 @@ export declare class LoopSession {
|
|
|
5
5
|
private initializeCliParser;
|
|
6
6
|
private isRunning;
|
|
7
7
|
private sessionId?;
|
|
8
|
+
private commandHistory;
|
|
8
9
|
private sessionVariablesSchema;
|
|
9
10
|
constructor(initializeCliParser: () => Argv, conversationMemoryConfig?: ConversationMemoryConfig | undefined);
|
|
10
11
|
start(): Promise<void>;
|
|
@@ -12,4 +13,16 @@ export declare class LoopSession {
|
|
|
12
13
|
private parseValue;
|
|
13
14
|
private showHelp;
|
|
14
15
|
private showSetHelp;
|
|
16
|
+
/**
|
|
17
|
+
* Load command history from the global history file
|
|
18
|
+
*/
|
|
19
|
+
private loadHistory;
|
|
20
|
+
/**
|
|
21
|
+
* Save a command to the global history file
|
|
22
|
+
*/
|
|
23
|
+
private saveCommand;
|
|
24
|
+
/**
|
|
25
|
+
* Get command input with history support using readline
|
|
26
|
+
*/
|
|
27
|
+
private getCommandWithHistory;
|
|
15
28
|
}
|
package/dist/cli/loop/session.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import inquirer from "inquirer";
|
|
2
1
|
import chalk from "chalk";
|
|
2
|
+
import readline from "readline";
|
|
3
|
+
import fs from "fs/promises";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import os from "os";
|
|
3
6
|
import { logger } from "../../lib/utils/logger.js";
|
|
4
7
|
import { globalSession } from "../../lib/session/globalSessionState.js";
|
|
5
8
|
import { textGenerationOptionsSchema } from "./optionsSchema.js";
|
|
@@ -11,11 +14,14 @@ const NEUROLINK_BANNER = `
|
|
|
11
14
|
▐▌ ▝▜▌▐▛▀▀▘▐▌ ▐▌▐▛▀▚▖▐▌ ▐▌▐▌ █ ▐▌ ▝▜▌▐▛▚▖
|
|
12
15
|
▐▌ ▐▌▐▙▄▄▖▝▚▄▞▘▐▌ ▐▌▝▚▄▞▘▐▙▄▄▖▗▄█▄▖▐▌ ▐▌▐▌ ▐▌
|
|
13
16
|
`;
|
|
17
|
+
// Global command history file
|
|
18
|
+
const HISTORY_FILE = path.join(os.homedir(), ".neurolink_history");
|
|
14
19
|
export class LoopSession {
|
|
15
20
|
conversationMemoryConfig;
|
|
16
21
|
initializeCliParser;
|
|
17
22
|
isRunning = false;
|
|
18
23
|
sessionId;
|
|
24
|
+
commandHistory = [];
|
|
19
25
|
sessionVariablesSchema = textGenerationOptionsSchema;
|
|
20
26
|
constructor(initializeCliParser, conversationMemoryConfig) {
|
|
21
27
|
this.conversationMemoryConfig = conversationMemoryConfig;
|
|
@@ -24,6 +30,8 @@ export class LoopSession {
|
|
|
24
30
|
async start() {
|
|
25
31
|
// Initialize global session state
|
|
26
32
|
this.sessionId = globalSession.setLoopSession(this.conversationMemoryConfig);
|
|
33
|
+
// Load command history from global file, reverse once for most recent first
|
|
34
|
+
this.commandHistory = (await this.loadHistory()).reverse();
|
|
27
35
|
this.isRunning = true;
|
|
28
36
|
logger.always(chalk.bold.green(NEUROLINK_BANNER));
|
|
29
37
|
logger.always(chalk.bold.green("Welcome to NeuroLink Loop Mode!"));
|
|
@@ -37,21 +45,8 @@ export class LoopSession {
|
|
|
37
45
|
logger.always(chalk.gray('Type "exit", "quit", or ":q" to leave the loop.'));
|
|
38
46
|
while (this.isRunning) {
|
|
39
47
|
try {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
{
|
|
43
|
-
type: "input",
|
|
44
|
-
name: "command",
|
|
45
|
-
message: chalk.blue.bold("neurolink"),
|
|
46
|
-
prefix: chalk.blue.green("⎔"),
|
|
47
|
-
suffix: chalk.blue.green(" »"),
|
|
48
|
-
},
|
|
49
|
-
])
|
|
50
|
-
.catch(() => {
|
|
51
|
-
// This catch block handles the interruption of inquirer
|
|
52
|
-
return { command: "" };
|
|
53
|
-
});
|
|
54
|
-
const command = answers.command.trim();
|
|
48
|
+
// Use readline with history support instead of inquirer
|
|
49
|
+
const command = await this.getCommandWithHistory();
|
|
55
50
|
if (command.toLowerCase() === "exit" ||
|
|
56
51
|
command.toLowerCase() === "quit" ||
|
|
57
52
|
command.toLowerCase() === ":q") {
|
|
@@ -63,6 +58,11 @@ export class LoopSession {
|
|
|
63
58
|
}
|
|
64
59
|
// Handle session variable commands first
|
|
65
60
|
if (await this.handleSessionCommands(command)) {
|
|
61
|
+
// Save session commands to history (both memory and file)
|
|
62
|
+
if (command && command.trim()) {
|
|
63
|
+
this.commandHistory.unshift(command);
|
|
64
|
+
await this.saveCommand(command);
|
|
65
|
+
}
|
|
66
66
|
continue;
|
|
67
67
|
}
|
|
68
68
|
// Execute the command
|
|
@@ -78,9 +78,14 @@ export class LoopSession {
|
|
|
78
78
|
})
|
|
79
79
|
.exitProcess(false)
|
|
80
80
|
.parse(command);
|
|
81
|
+
// Save command to history (both memory and file)
|
|
82
|
+
if (command && command.trim()) {
|
|
83
|
+
this.commandHistory.unshift(command);
|
|
84
|
+
await this.saveCommand(command);
|
|
85
|
+
}
|
|
81
86
|
}
|
|
82
87
|
catch (error) {
|
|
83
|
-
// Catch errors from the main loop (e.g.,
|
|
88
|
+
// Catch errors from the main loop (e.g., readline prompt itself failing)
|
|
84
89
|
handleError(error, "An unexpected error occurred");
|
|
85
90
|
}
|
|
86
91
|
}
|
|
@@ -249,4 +254,60 @@ export class LoopSession {
|
|
|
249
254
|
}
|
|
250
255
|
}
|
|
251
256
|
}
|
|
257
|
+
/**
|
|
258
|
+
* Load command history from the global history file
|
|
259
|
+
*/
|
|
260
|
+
async loadHistory() {
|
|
261
|
+
try {
|
|
262
|
+
const content = await fs.readFile(HISTORY_FILE, "utf8");
|
|
263
|
+
return content.split("\n").filter((line) => line.trim());
|
|
264
|
+
}
|
|
265
|
+
catch {
|
|
266
|
+
// File doesn't exist yet or can't be read
|
|
267
|
+
return [];
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Save a command to the global history file
|
|
272
|
+
*/
|
|
273
|
+
async saveCommand(command) {
|
|
274
|
+
try {
|
|
275
|
+
// Skip potentially sensitive commands
|
|
276
|
+
const sensitivePattern = /\b(api[-_]?key|token|password|secret|authorization)\b/i;
|
|
277
|
+
if (sensitivePattern.test(command)) {
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
// Use writeFile with flag 'a' and mode 0o600 to ensure permissions on creation
|
|
281
|
+
await fs.writeFile(HISTORY_FILE, command + "\n", { flag: "a", mode: 0o600 });
|
|
282
|
+
// Ensure existing file remains private (best-effort)
|
|
283
|
+
await fs.chmod(HISTORY_FILE, 0o600);
|
|
284
|
+
}
|
|
285
|
+
catch (error) {
|
|
286
|
+
// Log file write errors as warnings, but do not interrupt CLI flow
|
|
287
|
+
logger.warn("Warning: Could not save command to history:", error);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Get command input with history support using readline
|
|
292
|
+
*/
|
|
293
|
+
async getCommandWithHistory() {
|
|
294
|
+
return new Promise((resolve) => {
|
|
295
|
+
const rl = readline.createInterface({
|
|
296
|
+
input: process.stdin,
|
|
297
|
+
output: process.stdout,
|
|
298
|
+
history: [...this.commandHistory], // most recent first
|
|
299
|
+
prompt: `${chalk.blue.green("⎔")} ${chalk.blue.bold("neurolink")} ${chalk.blue.green("»")} `,
|
|
300
|
+
});
|
|
301
|
+
rl.prompt();
|
|
302
|
+
rl.on("line", (input) => {
|
|
303
|
+
rl.close();
|
|
304
|
+
resolve(input.trim());
|
|
305
|
+
});
|
|
306
|
+
rl.on("SIGINT", () => {
|
|
307
|
+
rl.close();
|
|
308
|
+
this.isRunning = false;
|
|
309
|
+
resolve("exit");
|
|
310
|
+
});
|
|
311
|
+
});
|
|
312
|
+
}
|
|
252
313
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.48.0",
|
|
4
4
|
"description": "Universal AI Development Platform with working MCP integration, multi-provider support, and professional CLI. Built-in tools operational, 58+ external MCP servers discoverable. Connect to filesystem, GitHub, database operations, and more. Build, test, and deploy AI applications with 9 major providers: OpenAI, Anthropic, Google AI, AWS Bedrock, Azure, Hugging Face, Ollama, and Mistral AI.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Juspay Technologies",
|