@juspay/neurolink 7.33.4 → 7.34.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.
Files changed (93) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +37 -0
  3. package/dist/cli/errorHandler.d.ts +1 -0
  4. package/dist/cli/errorHandler.js +28 -0
  5. package/dist/cli/factories/commandFactory.d.ts +23 -0
  6. package/dist/cli/factories/commandFactory.js +375 -60
  7. package/dist/cli/factories/ollamaCommandFactory.js +7 -1
  8. package/dist/cli/index.d.ts +1 -1
  9. package/dist/cli/index.js +9 -164
  10. package/dist/cli/loop/optionsSchema.d.ts +15 -0
  11. package/dist/cli/loop/optionsSchema.js +59 -0
  12. package/dist/cli/loop/session.d.ts +15 -0
  13. package/dist/cli/loop/session.js +252 -0
  14. package/dist/cli/parser.d.ts +1 -0
  15. package/dist/cli/parser.js +158 -0
  16. package/dist/cli/utils/ollamaUtils.js +6 -0
  17. package/dist/config/{conversationMemoryConfig.d.ts → conversationMemory.d.ts} +1 -1
  18. package/dist/core/baseProvider.js +17 -3
  19. package/dist/core/conversationMemoryFactory.d.ts +23 -0
  20. package/dist/core/conversationMemoryFactory.js +144 -0
  21. package/dist/core/conversationMemoryInitializer.d.ts +14 -0
  22. package/dist/core/conversationMemoryInitializer.js +127 -0
  23. package/dist/core/conversationMemoryManager.d.ts +3 -2
  24. package/dist/core/conversationMemoryManager.js +4 -3
  25. package/dist/core/redisConversationMemoryManager.d.ts +73 -0
  26. package/dist/core/redisConversationMemoryManager.js +483 -0
  27. package/dist/core/types.d.ts +1 -1
  28. package/dist/lib/config/{conversationMemoryConfig.d.ts → conversationMemory.d.ts} +1 -1
  29. package/dist/lib/core/baseProvider.js +17 -3
  30. package/dist/lib/core/conversationMemoryFactory.d.ts +23 -0
  31. package/dist/lib/core/conversationMemoryFactory.js +144 -0
  32. package/dist/lib/core/conversationMemoryInitializer.d.ts +14 -0
  33. package/dist/lib/core/conversationMemoryInitializer.js +127 -0
  34. package/dist/lib/core/conversationMemoryManager.d.ts +3 -2
  35. package/dist/lib/core/conversationMemoryManager.js +4 -3
  36. package/dist/lib/core/redisConversationMemoryManager.d.ts +73 -0
  37. package/dist/lib/core/redisConversationMemoryManager.js +483 -0
  38. package/dist/lib/core/types.d.ts +1 -1
  39. package/dist/lib/neurolink.d.ts +15 -9
  40. package/dist/lib/neurolink.js +218 -67
  41. package/dist/lib/providers/amazonBedrock.d.ts +4 -4
  42. package/dist/lib/providers/anthropic.d.ts +4 -4
  43. package/dist/lib/providers/azureOpenai.d.ts +4 -4
  44. package/dist/lib/providers/googleAiStudio.d.ts +4 -4
  45. package/dist/lib/providers/googleAiStudio.js +1 -1
  46. package/dist/lib/providers/huggingFace.d.ts +4 -4
  47. package/dist/lib/providers/litellm.d.ts +1 -1
  48. package/dist/lib/providers/mistral.d.ts +4 -4
  49. package/dist/lib/providers/mistral.js +2 -2
  50. package/dist/lib/providers/openAI.d.ts +4 -4
  51. package/dist/lib/session/globalSessionState.d.ts +27 -0
  52. package/dist/lib/session/globalSessionState.js +77 -0
  53. package/dist/lib/types/{conversationTypes.d.ts → conversation.d.ts} +32 -0
  54. package/dist/lib/types/generateTypes.d.ts +1 -1
  55. package/dist/lib/types/streamTypes.d.ts +1 -1
  56. package/dist/lib/utils/conversationMemory.d.ts +22 -0
  57. package/dist/lib/utils/conversationMemory.js +121 -0
  58. package/dist/lib/utils/conversationMemoryUtils.d.ts +1 -1
  59. package/dist/lib/utils/conversationMemoryUtils.js +2 -2
  60. package/dist/lib/utils/messageBuilder.d.ts +1 -1
  61. package/dist/lib/utils/messageBuilder.js +1 -1
  62. package/dist/lib/utils/redis.d.ts +42 -0
  63. package/dist/lib/utils/redis.js +263 -0
  64. package/dist/neurolink.d.ts +15 -9
  65. package/dist/neurolink.js +218 -67
  66. package/dist/providers/amazonBedrock.d.ts +4 -4
  67. package/dist/providers/anthropic.d.ts +4 -4
  68. package/dist/providers/azureOpenai.d.ts +4 -4
  69. package/dist/providers/googleAiStudio.d.ts +4 -4
  70. package/dist/providers/googleAiStudio.js +1 -1
  71. package/dist/providers/huggingFace.d.ts +4 -4
  72. package/dist/providers/litellm.d.ts +1 -1
  73. package/dist/providers/mistral.d.ts +4 -4
  74. package/dist/providers/mistral.js +2 -2
  75. package/dist/providers/openAI.d.ts +4 -4
  76. package/dist/session/globalSessionState.d.ts +27 -0
  77. package/dist/session/globalSessionState.js +77 -0
  78. package/dist/types/{conversationTypes.d.ts → conversation.d.ts} +32 -0
  79. package/dist/types/generateTypes.d.ts +1 -1
  80. package/dist/types/streamTypes.d.ts +1 -1
  81. package/dist/utils/conversationMemory.d.ts +22 -0
  82. package/dist/utils/conversationMemory.js +121 -0
  83. package/dist/utils/conversationMemoryUtils.d.ts +1 -1
  84. package/dist/utils/conversationMemoryUtils.js +2 -2
  85. package/dist/utils/messageBuilder.d.ts +1 -1
  86. package/dist/utils/messageBuilder.js +1 -1
  87. package/dist/utils/redis.d.ts +42 -0
  88. package/dist/utils/redis.js +263 -0
  89. package/package.json +3 -1
  90. /package/dist/config/{conversationMemoryConfig.js → conversationMemory.js} +0 -0
  91. /package/dist/lib/config/{conversationMemoryConfig.js → conversationMemory.js} +0 -0
  92. /package/dist/lib/types/{conversationTypes.js → conversation.js} +0 -0
  93. /package/dist/types/{conversationTypes.js → conversation.js} +0 -0
package/dist/cli/index.js CHANGED
@@ -5,15 +5,8 @@
5
5
  * Professional CLI experience with minimal maintenance overhead.
6
6
  * Features: Spinners, colors, batch processing, provider testing, rich help
7
7
  */
8
- import yargs from "yargs";
9
- import { hideBin } from "yargs/helpers";
8
+ import { initializeCliParser } from "./parser.js";
10
9
  import chalk from "chalk";
11
- import _fs from "fs";
12
- import path from "path";
13
- import { fileURLToPath } from "url";
14
- import { CLICommandFactory } from "./factories/commandFactory.js";
15
- import { AuthenticationError, AuthorizationError, NetworkError, RateLimitError, } from "../lib/types/errors.js";
16
- import { logger } from "../lib/utils/logger.js";
17
10
  // Clean up pnpm-specific environment variables that cause npm warnings
18
11
  // These variables are set by pnpm but cause "Unknown env config" warnings in npm
19
12
  if (process.env.npm_config_verify_deps_before_run) {
@@ -22,11 +15,6 @@ if (process.env.npm_config_verify_deps_before_run) {
22
15
  if (process.env.npm_config__jsr_registry) {
23
16
  delete process.env.npm_config__jsr_registry;
24
17
  }
25
- // Get version from package.json
26
- const __filename = fileURLToPath(import.meta.url);
27
- const __dirname = path.dirname(__filename);
28
- const packageJson = JSON.parse(_fs.readFileSync(path.resolve(__dirname, "../../package.json"), "utf-8"));
29
- const cliVersion = packageJson.version;
30
18
  // Load environment variables from .env file
31
19
  try {
32
20
  // Try to import and configure dotenv
@@ -37,158 +25,8 @@ catch {
37
25
  // dotenv is not available (dev dependency only) - this is fine for production
38
26
  // Environment variables should be set externally in production
39
27
  }
40
- // Utility Functions (Simple, Zero Maintenance)
41
- export function handleError(_error, context) {
42
- logger.error(chalk.red(`❌ ${context} failed: ${_error.message}`));
43
- if (_error instanceof AuthenticationError) {
44
- logger.error(chalk.yellow("💡 Set Google AI Studio API key (RECOMMENDED): export GOOGLE_AI_API_KEY=AIza-..."));
45
- logger.error(chalk.yellow("💡 Or set OpenAI API key: export OPENAI_API_KEY=sk-..."));
46
- logger.error(chalk.yellow("💡 Or set AWS Bedrock credentials: export AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... AWS_REGION=us-east-1"));
47
- logger.error(chalk.yellow("💡 Or set Google Vertex AI credentials: export GOOGLE_APPLICATION_CREDENTIALS=/path/to/key.json"));
48
- logger.error(chalk.yellow("💡 Or set Anthropic API key: export ANTHROPIC_API_KEY=sk-ant-..."));
49
- logger.error(chalk.yellow("💡 Or set Azure OpenAI credentials: export AZURE_OPENAI_API_KEY=... AZURE_OPENAI_ENDPOINT=..."));
50
- }
51
- else if (_error instanceof RateLimitError) {
52
- logger.error(chalk.yellow("💡 Try again in a few moments or use --provider vertex"));
53
- }
54
- else if (_error instanceof AuthorizationError) {
55
- logger.error(chalk.yellow("💡 Check your account permissions for the selected model/service."));
56
- logger.error(chalk.yellow("💡 For AWS Bedrock, ensure you have permissions for the specific model and consider using inference profile ARNs."));
57
- }
58
- else if (_error instanceof NetworkError) {
59
- logger.error(chalk.yellow("💡 Check your internet connection and the provider's status page."));
60
- }
61
- process.exit(1);
62
- }
63
- // Manual pre-validation for unknown flags
64
- const args = hideBin(process.argv);
65
28
  // Enhanced CLI with Professional UX
66
- const cli = yargs(args)
67
- .scriptName("neurolink")
68
- .usage("Usage: $0 <command> [options]")
69
- .version(cliVersion)
70
- .help()
71
- .alias("h", "help")
72
- .alias("V", "version")
73
- .strictOptions()
74
- .strictCommands()
75
- .demandCommand(1, "")
76
- .epilogue("For more info: https://github.com/juspay/neurolink")
77
- .showHelpOnFail(true, "Specify --help for available options")
78
- .middleware((argv) => {
79
- // Handle no-color option globally
80
- if (argv.noColor || process.env.NO_COLOR || !process.stdout.isTTY) {
81
- process.env.FORCE_COLOR = "0";
82
- }
83
- // Handle custom config file
84
- if (argv.configFile) {
85
- process.env.NEUROLINK_CONFIG_FILE = argv.configFile;
86
- }
87
- // Control SDK logging based on debug flag
88
- if (argv.debug) {
89
- process.env.NEUROLINK_DEBUG = "true";
90
- }
91
- else {
92
- // Always set to false when debug is not enabled (including when not provided)
93
- process.env.NEUROLINK_DEBUG = "false";
94
- }
95
- // Keep existing quiet middleware
96
- if (process.env.NEUROLINK_QUIET === "true" &&
97
- typeof argv.quiet === "undefined") {
98
- argv.quiet = true;
99
- }
100
- })
101
- .fail((msg, err, yargsInstance) => {
102
- const exitProcess = () => {
103
- if (!process.exitCode) {
104
- process.exit(1);
105
- }
106
- };
107
- if (err) {
108
- // Error likely from an async command handler (e.g., via _handleError)
109
- // _handleError already prints and calls process.exit(1).
110
- // If we're here, it means _handleError's process.exit might not have been caught by the top-level async IIFE.
111
- // Or, it's a synchronous yargs error during parsing that yargs itself throws.
112
- const alreadyExitedByHandleError = err?.exitCode !== undefined;
113
- // A simple heuristic: if the error message doesn't look like one of our handled generic messages,
114
- // it might be a direct yargs parsing error.
115
- const isLikelyYargsInternalError = err.message && // Ensure err.message exists
116
- !err.message.includes("Authentication error") &&
117
- !err.message.includes("Network error") &&
118
- !err.message.includes("Authorization error") &&
119
- !err.message.includes("Permission denied") && // from config export
120
- !err.message.includes("Invalid or unparseable JSON"); // from config import
121
- if (!alreadyExitedByHandleError) {
122
- process.stderr.write(chalk.red(`CLI Error: ${err.message || msg || "An unexpected error occurred."}\n`));
123
- // If it's a yargs internal parsing error, show help.
124
- if (isLikelyYargsInternalError && msg) {
125
- yargsInstance.showHelp((h) => {
126
- process.stderr.write(h + "\n");
127
- exitProcess();
128
- });
129
- return;
130
- }
131
- exitProcess();
132
- }
133
- return; // Exit was already called or error handled
134
- }
135
- // Yargs parsing/validation error (msg is present, err is null)
136
- if (msg) {
137
- let processedMsg = `Error: ${msg}\n`;
138
- if (msg.includes("Not enough non-option arguments") ||
139
- msg.includes("Missing required argument") ||
140
- msg.includes("Unknown command")) {
141
- process.stderr.write(chalk.red(processedMsg)); // Print error first
142
- yargsInstance.showHelp((h) => {
143
- process.stderr.write("\n" + h + "\n");
144
- exitProcess();
145
- });
146
- return; // Exit happens in callback
147
- }
148
- else if (msg.includes("Unknown argument") ||
149
- msg.includes("Invalid values")) {
150
- processedMsg = `Error: ${msg}\nUse --help to see available options.\n`;
151
- }
152
- process.stderr.write(chalk.red(processedMsg));
153
- }
154
- else {
155
- // No specific message, but failure occurred (e.g. demandCommand failed silently)
156
- yargsInstance.showHelp((h) => {
157
- process.stderr.write(h + "\n");
158
- exitProcess();
159
- });
160
- return; // Exit happens in callback
161
- }
162
- exitProcess(); // Default exit
163
- })
164
- // Generate Command (Primary) - Using CLICommandFactory
165
- .command(CLICommandFactory.createGenerateCommand())
166
- // Stream Text Command - Using CLICommandFactory
167
- .command(CLICommandFactory.createStreamCommand())
168
- // Batch Processing Command - Using CLICommandFactory
169
- .command(CLICommandFactory.createBatchCommand())
170
- // Provider Command Group - Using CLICommandFactory
171
- .command(CLICommandFactory.createProviderCommands())
172
- // Status command alias - Using CLICommandFactory
173
- .command(CLICommandFactory.createStatusCommand())
174
- // Models Command Group - Using CLICommandFactory
175
- .command(CLICommandFactory.createModelsCommands())
176
- // MCP Command Group - Using CLICommandFactory
177
- .command(CLICommandFactory.createMCPCommands())
178
- // Discover Command - Using CLICommandFactory
179
- .command(CLICommandFactory.createDiscoverCommand())
180
- // Configuration Command Group - Using CLICommandFactory
181
- .command(CLICommandFactory.createConfigCommands())
182
- // Get Best Provider Command - Using CLICommandFactory
183
- .command(CLICommandFactory.createBestProviderCommand())
184
- // Validate Command (alias for config validate)
185
- .command(CLICommandFactory.createValidateCommand())
186
- // Completion Command - Using CLICommandFactory
187
- .command(CLICommandFactory.createCompletionCommand())
188
- // Ollama Command Group - Using CLICommandFactory
189
- .command(CLICommandFactory.createOllamaCommands())
190
- // SageMaker Command Group - Using CLICommandFactory
191
- .command(CLICommandFactory.createSageMakerCommands());
29
+ const cli = initializeCliParser();
192
30
  // Execute CLI
193
31
  (async () => {
194
32
  try {
@@ -201,3 +39,10 @@ const cli = yargs(args)
201
39
  process.exit(1);
202
40
  }
203
41
  })();
42
+ // Cleanup on exit
43
+ process.on("SIGINT", () => {
44
+ process.exit(0);
45
+ });
46
+ process.on("SIGTERM", () => {
47
+ process.exit(0);
48
+ });
@@ -0,0 +1,15 @@
1
+ import { type TextGenerationOptions } from "../../lib/core/types.js";
2
+ /**
3
+ * Defines the schema for a session variable or a generation option.
4
+ */
5
+ export interface OptionSchema {
6
+ type: "string" | "boolean" | "number";
7
+ description: string;
8
+ allowedValues?: string[];
9
+ }
10
+ /**
11
+ * Master schema for all text generation options.
12
+ * This object provides metadata for validation and help text in the CLI loop.
13
+ * It is derived from the main TextGenerationOptions interface to ensure consistency.
14
+ */
15
+ export declare const textGenerationOptionsSchema: Record<keyof Omit<TextGenerationOptions, "prompt" | "input" | "schema" | "tools" | "context" | "conversationHistory" | "conversationMessages" | "conversationMemoryConfig" | "originalPrompt" | "middleware" | "expectedOutcome" | "evaluationCriteria">, OptionSchema>;
@@ -0,0 +1,59 @@
1
+ import { AIProviderName, } from "../../lib/core/types.js";
2
+ /**
3
+ * Master schema for all text generation options.
4
+ * This object provides metadata for validation and help text in the CLI loop.
5
+ * It is derived from the main TextGenerationOptions interface to ensure consistency.
6
+ */
7
+ export const textGenerationOptionsSchema = {
8
+ provider: {
9
+ type: "string",
10
+ description: "The AI provider to use.",
11
+ allowedValues: Object.values(AIProviderName)
12
+ .filter((p) => typeof p === "string")
13
+ .filter((p) => p !== AIProviderName.AUTO),
14
+ },
15
+ model: {
16
+ type: "string",
17
+ description: "The specific model to use from the provider.",
18
+ },
19
+ temperature: {
20
+ type: "number",
21
+ description: "Controls randomness of the output (e.g., 0.2, 0.8).",
22
+ },
23
+ maxTokens: {
24
+ type: "number",
25
+ description: "The maximum number of tokens to generate.",
26
+ },
27
+ systemPrompt: {
28
+ type: "string",
29
+ description: "The system prompt to guide the AI's behavior.",
30
+ },
31
+ timeout: {
32
+ type: "number",
33
+ description: "Timeout for the generation request in milliseconds.",
34
+ },
35
+ disableTools: {
36
+ type: "boolean",
37
+ description: "Disable all tool usage for the AI.",
38
+ },
39
+ maxSteps: {
40
+ type: "number",
41
+ description: "Maximum number of tool execution steps.",
42
+ },
43
+ enableAnalytics: {
44
+ type: "boolean",
45
+ description: "Enable or disable analytics for responses.",
46
+ },
47
+ enableEvaluation: {
48
+ type: "boolean",
49
+ description: "Enable or disable AI-powered evaluation of responses.",
50
+ },
51
+ evaluationDomain: {
52
+ type: "string",
53
+ description: 'Domain expertise for evaluation (e.g., "general AI assistant").',
54
+ },
55
+ toolUsageContext: {
56
+ type: "string",
57
+ description: "Context about tools/MCPs used in the interaction.",
58
+ },
59
+ };
@@ -0,0 +1,15 @@
1
+ import type { Argv } from "yargs";
2
+ import type { ConversationMemoryConfig } from "../../lib/types/conversation.js";
3
+ export declare class LoopSession {
4
+ private conversationMemoryConfig?;
5
+ private initializeCliParser;
6
+ private isRunning;
7
+ private sessionId?;
8
+ private sessionVariablesSchema;
9
+ constructor(initializeCliParser: () => Argv, conversationMemoryConfig?: ConversationMemoryConfig | undefined);
10
+ start(): Promise<void>;
11
+ private handleSessionCommands;
12
+ private parseValue;
13
+ private showHelp;
14
+ private showSetHelp;
15
+ }
@@ -0,0 +1,252 @@
1
+ import inquirer from "inquirer";
2
+ import chalk from "chalk";
3
+ import { logger } from "../../lib/utils/logger.js";
4
+ import { globalSession } from "../../lib/session/globalSessionState.js";
5
+ import { textGenerationOptionsSchema } from "./optionsSchema.js";
6
+ import { handleError } from "../errorHandler.js";
7
+ // Banner Art
8
+ const NEUROLINK_BANNER = `
9
+ ▗▖ ▗▖▗▄▄▄▖▗▖ ▗▖▗▄▄▖ ▗▄▖ ▗▖ ▗▄▄▄▖▗▖ ▗▖▗▖ ▗▖
10
+ ▐▛▚▖▐▌▐▌ ▐▌ ▐▌▐▌ ▐▌▐▌ ▐▌▐▌ █ ▐▛▚▖▐▌▐▌▗▞▘
11
+ ▐▌ ▝▜▌▐▛▀▀▘▐▌ ▐▌▐▛▀▚▖▐▌ ▐▌▐▌ █ ▐▌ ▝▜▌▐▛▚▖
12
+ ▐▌ ▐▌▐▙▄▄▖▝▚▄▞▘▐▌ ▐▌▝▚▄▞▘▐▙▄▄▖▗▄█▄▖▐▌ ▐▌▐▌ ▐▌
13
+ `;
14
+ export class LoopSession {
15
+ conversationMemoryConfig;
16
+ initializeCliParser;
17
+ isRunning = false;
18
+ sessionId;
19
+ sessionVariablesSchema = textGenerationOptionsSchema;
20
+ constructor(initializeCliParser, conversationMemoryConfig) {
21
+ this.conversationMemoryConfig = conversationMemoryConfig;
22
+ this.initializeCliParser = initializeCliParser;
23
+ }
24
+ async start() {
25
+ // Initialize global session state
26
+ this.sessionId = globalSession.setLoopSession(this.conversationMemoryConfig);
27
+ this.isRunning = true;
28
+ logger.always(chalk.bold.green(NEUROLINK_BANNER));
29
+ logger.always(chalk.bold.green("Welcome to NeuroLink Loop Mode!"));
30
+ if (this.conversationMemoryConfig?.enabled) {
31
+ logger.always(chalk.gray(`Session ID: ${this.sessionId}`));
32
+ logger.always(chalk.gray("Conversation memory enabled"));
33
+ logger.always(chalk.gray(`Max sessions: ${this.conversationMemoryConfig.maxSessions}`));
34
+ logger.always(chalk.gray(`Max turns per session: ${this.conversationMemoryConfig.maxTurnsPerSession}\n`));
35
+ }
36
+ logger.always(chalk.gray('Type "help" for a list of commands.'));
37
+ logger.always(chalk.gray('Type "exit", "quit", or ":q" to leave the loop.'));
38
+ while (this.isRunning) {
39
+ 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();
55
+ if (command.toLowerCase() === "exit" ||
56
+ command.toLowerCase() === "quit" ||
57
+ command.toLowerCase() === ":q") {
58
+ this.isRunning = false;
59
+ continue;
60
+ }
61
+ if (!command) {
62
+ continue;
63
+ }
64
+ // Handle session variable commands first
65
+ if (await this.handleSessionCommands(command)) {
66
+ continue;
67
+ }
68
+ // Execute the command
69
+ // The .fail() handler in cli.ts is now session-aware and will
70
+ // handle all parsing and validation errors without exiting the loop.
71
+ // We create a fresh instance for each command to prevent state pollution.
72
+ const yargsInstance = this.initializeCliParser();
73
+ await yargsInstance
74
+ .scriptName("")
75
+ .fail((msg, err) => {
76
+ // Re-throw the error to be caught by the outer catch block
77
+ throw err || new Error(msg);
78
+ })
79
+ .exitProcess(false)
80
+ .parse(command);
81
+ }
82
+ catch (error) {
83
+ // Catch errors from the main loop (e.g., inquirer prompt itself failing)
84
+ handleError(error, "An unexpected error occurred");
85
+ }
86
+ }
87
+ // Cleanup on exit
88
+ globalSession.clearLoopSession();
89
+ logger.always(chalk.yellow("Loop session ended."));
90
+ }
91
+ async handleSessionCommands(command) {
92
+ const parts = command.split(" ");
93
+ const cmd = parts[0].toLowerCase();
94
+ switch (cmd) {
95
+ case "help":
96
+ this.showHelp();
97
+ return true;
98
+ case "set":
99
+ if (parts.length === 2 && parts[1].toLowerCase() === "help") {
100
+ this.showSetHelp();
101
+ }
102
+ else if (parts.length >= 3) {
103
+ const key = parts[1];
104
+ const schema = this.sessionVariablesSchema[key];
105
+ if (!schema) {
106
+ logger.always(chalk.red(`Error: Unknown session variable "${key}".`));
107
+ logger.always(chalk.gray('Use "set help" to see available variables.'));
108
+ return true;
109
+ }
110
+ const valueStr = parts.slice(2).join(" ");
111
+ let value = this.parseValue(valueStr);
112
+ // Validate type
113
+ if (schema.type === "boolean" && typeof value !== "boolean") {
114
+ logger.always(chalk.red(`Error: Invalid value for "${key}". Expected a boolean (true/false).`));
115
+ return true;
116
+ }
117
+ if (schema.type === "string") {
118
+ if (typeof value === "number" || typeof value === "boolean") {
119
+ value = String(value);
120
+ }
121
+ else if (typeof value !== "string") {
122
+ logger.always(chalk.red(`Error: Invalid value for "${key}". Expected a string.`));
123
+ return true;
124
+ }
125
+ }
126
+ if (schema.type === "number" && typeof value !== "number") {
127
+ logger.always(chalk.red(`Error: Invalid value for "${key}". Expected a number.`));
128
+ return true;
129
+ }
130
+ // Validate allowedValues
131
+ if (schema.allowedValues &&
132
+ !schema.allowedValues.includes(String(value))) {
133
+ logger.always(chalk.red(`Error: Invalid value for "${key}".`));
134
+ logger.always(chalk.gray(`Allowed values are: ${schema.allowedValues.join(", ")}`));
135
+ return true;
136
+ }
137
+ globalSession.setSessionVariable(key, value);
138
+ logger.always(chalk.green(`✓ ${key} set to ${value}`));
139
+ }
140
+ else {
141
+ logger.always(chalk.red("Usage: set <key> <value> or set help"));
142
+ }
143
+ return true;
144
+ case "get":
145
+ if (parts.length >= 2) {
146
+ const key = parts[1];
147
+ const value = globalSession.getSessionVariable(key);
148
+ if (value !== undefined) {
149
+ logger.always(chalk.cyan(`${key}: ${value}`));
150
+ }
151
+ else {
152
+ logger.always(chalk.yellow(`${key} is not set`));
153
+ }
154
+ }
155
+ else {
156
+ logger.always(chalk.red("Usage: get <key>"));
157
+ }
158
+ return true;
159
+ case "unset":
160
+ if (parts.length >= 2) {
161
+ const key = parts[1];
162
+ if (globalSession.unsetSessionVariable(key)) {
163
+ logger.always(chalk.green(`✓ ${key} unset`));
164
+ }
165
+ else {
166
+ logger.always(chalk.yellow(`${key} was not set`));
167
+ }
168
+ }
169
+ else {
170
+ logger.always(chalk.red("Usage: unset <key>"));
171
+ }
172
+ return true;
173
+ case "show": {
174
+ const variables = globalSession.getSessionVariables();
175
+ if (Object.keys(variables).length > 0) {
176
+ logger.always(chalk.cyan("Session Variables:"));
177
+ for (const [key, value] of Object.entries(variables)) {
178
+ logger.always(chalk.gray(` ${key}: ${value}`));
179
+ }
180
+ }
181
+ else {
182
+ logger.always(chalk.yellow("No session variables set"));
183
+ }
184
+ return true;
185
+ }
186
+ case "clear":
187
+ globalSession.clearSessionVariables();
188
+ logger.always(chalk.green("✓ All session variables cleared"));
189
+ return true;
190
+ default:
191
+ return false;
192
+ }
193
+ }
194
+ parseValue(value) {
195
+ // Try to parse as number
196
+ if (!isNaN(Number(value))) {
197
+ return Number(value);
198
+ }
199
+ // Try to parse as boolean
200
+ if (value.toLowerCase() === "true") {
201
+ return true;
202
+ }
203
+ if (value.toLowerCase() === "false") {
204
+ return false;
205
+ }
206
+ // Return as string
207
+ return value;
208
+ }
209
+ showHelp() {
210
+ logger.always(chalk.cyan("Available Loop Mode Commands:"));
211
+ const commands = [
212
+ {
213
+ cmd: "help",
214
+ desc: "Show this help message.",
215
+ },
216
+ {
217
+ cmd: "set <key> <value>",
218
+ desc: "Set a session variable. Use 'set help' for details.",
219
+ },
220
+ { cmd: "get <key>", desc: "Get a session variable." },
221
+ { cmd: "unset <key>", desc: "Unset a session variable." },
222
+ {
223
+ cmd: "show",
224
+ desc: "Show all currently set session variables.",
225
+ },
226
+ { cmd: "clear", desc: "Clear all session variables." },
227
+ {
228
+ cmd: "exit / quit / :q",
229
+ desc: "Exit the loop mode.",
230
+ },
231
+ ];
232
+ commands.forEach((c) => {
233
+ logger.always(chalk.yellow(` ${c.cmd.padEnd(20)}`) + `${c.desc}`);
234
+ });
235
+ logger.always("\nAny other command will be executed as a standard neurolink CLI command.");
236
+ // Also show the standard help output
237
+ this.initializeCliParser().showHelp("log");
238
+ }
239
+ showSetHelp() {
240
+ logger.always(chalk.cyan("Available Session Variables to Set:"));
241
+ for (const [key, schema] of Object.entries(this.sessionVariablesSchema)) {
242
+ logger.always(chalk.yellow(` ${key}`));
243
+ logger.always(` ${schema.description}`);
244
+ if (schema.allowedValues) {
245
+ logger.always(chalk.gray(` Allowed: ${schema.allowedValues.join(", ")}`));
246
+ }
247
+ else {
248
+ logger.always(chalk.gray(` Type: ${schema.type}`));
249
+ }
250
+ }
251
+ }
252
+ }
@@ -0,0 +1 @@
1
+ export declare function initializeCliParser(): import("yargs").Argv<{}>;