@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 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
  }
@@ -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
- const answers = await inquirer
41
- .prompt([
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., inquirer prompt itself failing)
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.47.2",
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",