@juspay/neurolink 9.94.6 → 9.94.7
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 +6 -0
- package/dist/cli/factories/commandFactory.d.ts +0 -2
- package/dist/cli/factories/commandFactory.js +36 -45
- package/dist/cli/loop/session.js +21 -0
- package/dist/cli/utils/inputValidation.d.ts +38 -0
- package/dist/cli/utils/inputValidation.js +143 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## [9.94.7](https://github.com/juspay/neurolink/compare/v9.94.6...v9.94.7) (2026-07-19)
|
|
2
|
+
|
|
3
|
+
### Bug Fixes
|
|
4
|
+
|
|
5
|
+
- **(cli):** validate csv-max-rows, warn on large files, and document multimodal inputs ([124f0d6](https://github.com/juspay/neurolink/commit/124f0d6ca95d7d0819ab001cb9cf753052308ed1))
|
|
6
|
+
|
|
1
7
|
## [9.94.6](https://github.com/juspay/neurolink/compare/v9.94.5...v9.94.6) (2026-07-19)
|
|
2
8
|
|
|
3
9
|
### Bug Fixes
|
|
@@ -24,8 +24,6 @@ export declare class CLICommandFactory {
|
|
|
24
24
|
private static processCliPDFFiles;
|
|
25
25
|
private static processCliFiles;
|
|
26
26
|
private static processCliVideoFiles;
|
|
27
|
-
private static isNonLocalFileReference;
|
|
28
|
-
private static validateCliInputFiles;
|
|
29
27
|
private static processOptions;
|
|
30
28
|
/**
|
|
31
29
|
* Validate Anthropic subscription options
|
|
@@ -24,6 +24,7 @@ import { initializeCliParser } from "../parser.js";
|
|
|
24
24
|
import { formatFileSize, saveAudioToFile } from "../utils/audioFileUtils.js";
|
|
25
25
|
import { playAudio } from "../utils/audioPlayer.js";
|
|
26
26
|
import { resolveFilePaths } from "../utils/pathResolver.js";
|
|
27
|
+
import { validateCliInputFiles, validateCsvMaxRows, } from "../utils/inputValidation.js";
|
|
27
28
|
import { animatedWrite } from "../utils/typewriter.js";
|
|
28
29
|
import { createStreamAbortHandler } from "../utils/abortHandler.js";
|
|
29
30
|
import { formatVideoFileSize, getVideoMetadataSummary, saveVideoToFile, } from "../utils/videoFileUtils.js";
|
|
@@ -187,7 +188,7 @@ export class CLICommandFactory {
|
|
|
187
188
|
csvMaxRows: {
|
|
188
189
|
type: "number",
|
|
189
190
|
default: 1000,
|
|
190
|
-
description: "Maximum number of CSV rows to process",
|
|
191
|
+
description: "Maximum number of CSV rows to process (positive integer, range 1-100000, default 1000)",
|
|
191
192
|
},
|
|
192
193
|
csvFormat: {
|
|
193
194
|
type: "string",
|
|
@@ -805,42 +806,6 @@ export class CLICommandFactory {
|
|
|
805
806
|
// URLs are preserved as-is by resolveFilePaths
|
|
806
807
|
return resolveFilePaths(paths);
|
|
807
808
|
}
|
|
808
|
-
static isNonLocalFileReference(filePath) {
|
|
809
|
-
const lower = filePath.toLowerCase();
|
|
810
|
-
return (lower.startsWith("http://") ||
|
|
811
|
-
lower.startsWith("https://") ||
|
|
812
|
-
lower.startsWith("file://") ||
|
|
813
|
-
lower.startsWith("data:"));
|
|
814
|
-
}
|
|
815
|
-
static validateCliInputFiles(argv) {
|
|
816
|
-
const fileArgs = [
|
|
817
|
-
{ option: "--image", value: argv.image },
|
|
818
|
-
{ option: "--csv", value: argv.csv },
|
|
819
|
-
{ option: "--pdf", value: argv.pdf },
|
|
820
|
-
{ option: "--video", value: argv.video },
|
|
821
|
-
{ option: "--file", value: argv.file },
|
|
822
|
-
];
|
|
823
|
-
const missingPaths = [];
|
|
824
|
-
for (const { option, value } of fileArgs) {
|
|
825
|
-
if (!value) {
|
|
826
|
-
continue;
|
|
827
|
-
}
|
|
828
|
-
const rawPaths = Array.isArray(value) ? value : [value];
|
|
829
|
-
const resolvedPaths = resolveFilePaths(rawPaths);
|
|
830
|
-
for (let i = 0; i < resolvedPaths.length; i++) {
|
|
831
|
-
const resolvedPath = resolvedPaths[i];
|
|
832
|
-
if (CLICommandFactory.isNonLocalFileReference(resolvedPath)) {
|
|
833
|
-
continue;
|
|
834
|
-
}
|
|
835
|
-
if (!fs.existsSync(resolvedPath)) {
|
|
836
|
-
missingPaths.push(`${option} path not found: ${rawPaths[i]} (resolved to ${resolvedPath})`);
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
}
|
|
840
|
-
if (missingPaths.length > 0) {
|
|
841
|
-
throw new Error(`One or more input files do not exist:\n${missingPaths.join("\n")}`);
|
|
842
|
-
}
|
|
843
|
-
}
|
|
844
809
|
// Helper method to process common options
|
|
845
810
|
static processOptions(argv) {
|
|
846
811
|
// Handle noColor option by disabling chalk
|
|
@@ -1538,7 +1503,12 @@ export class CLICommandFactory {
|
|
|
1538
1503
|
.example('$0 generate "Smooth camera movement" --image ./input.jpg --provider vertex --model veo-3.1-generate-001 --outputMode video --videoResolution 720p --videoLength 6 --videoAspectRatio 16:9 --videoOutput ./output.mp4', "Video generation with full options")
|
|
1539
1504
|
.example('$0 generate "AI in Healthcare" --pptPages 10', "Generate a PowerPoint presentation")
|
|
1540
1505
|
.example('$0 generate "Company Q4 Results" --pptPages 15 --pptTheme corporate --pptAudience business', "Generate presentation with options")
|
|
1541
|
-
.example('$0 generate "Machine Learning 101" --pptTheme minimal --pptTone educational --pptNoImages', "Generate educational slides without AI images")
|
|
1506
|
+
.example('$0 generate "Machine Learning 101" --pptTheme minimal --pptTone educational --pptNoImages', "Generate educational slides without AI images")
|
|
1507
|
+
.example('$0 generate "Describe this image" --image ./photo.jpg', "Analyze an image (multimodal input)")
|
|
1508
|
+
.example('$0 generate "Summarize this report" --pdf ./report.pdf', "Analyze a PDF document")
|
|
1509
|
+
.example('$0 generate "Key trends?" --csv large-data.csv --csvMaxRows 100', "Analyze a CSV with a row limit")
|
|
1510
|
+
.example('$0 generate "Compare the chart and the report" --image ./chart.png --pdf ./report.pdf', "Combine multiple file types in one prompt")
|
|
1511
|
+
.example('$0 generate "What is in this file?" --file ./data.json', "Auto-detect a file type with --file"));
|
|
1542
1512
|
},
|
|
1543
1513
|
handler: async (argv) => await CLICommandFactory.executeGenerate(argv),
|
|
1544
1514
|
};
|
|
@@ -1560,7 +1530,10 @@ export class CLICommandFactory {
|
|
|
1560
1530
|
.example('$0 stream "Explain machine learning" -p anthropic', "Stream with specific provider")
|
|
1561
1531
|
.example('$0 stream "Code walkthrough" --output story.txt', "Stream to file")
|
|
1562
1532
|
.example('echo "Live demo" | $0 stream', "Stream from stdin")
|
|
1563
|
-
.example('$0 stream "Narrate this video" --video path/to/video.mp4', "Stream video analysis")
|
|
1533
|
+
.example('$0 stream "Narrate this video" --video path/to/video.mp4', "Stream video analysis")
|
|
1534
|
+
.example('$0 stream "Describe this image" --image ./photo.jpg', "Stream image analysis (multimodal input)")
|
|
1535
|
+
.example('$0 stream "Summarize this document" --pdf ./report.pdf', "Stream PDF analysis")
|
|
1536
|
+
.example('$0 stream "Explain this dataset" --csv ./data.csv --csv-format markdown', "Stream CSV analysis"));
|
|
1564
1537
|
},
|
|
1565
1538
|
handler: async (argv) => await CLICommandFactory.executeStream(argv),
|
|
1566
1539
|
};
|
|
@@ -2277,7 +2250,11 @@ export class CLICommandFactory {
|
|
|
2277
2250
|
if (isSttOnly) {
|
|
2278
2251
|
return "";
|
|
2279
2252
|
}
|
|
2280
|
-
throw new Error("No input received from stdin"
|
|
2253
|
+
throw new Error("❌ No input received from stdin.\n" +
|
|
2254
|
+
"💡 Try this:\n" +
|
|
2255
|
+
' neurolink generate "your prompt"\n' +
|
|
2256
|
+
' echo "your prompt" | neurolink generate\n' +
|
|
2257
|
+
' neurolink generate "Describe this image" --image ./photo.jpg');
|
|
2281
2258
|
}
|
|
2282
2259
|
return trimmedData;
|
|
2283
2260
|
}
|
|
@@ -2285,7 +2262,11 @@ export class CLICommandFactory {
|
|
|
2285
2262
|
if (isSttOnly) {
|
|
2286
2263
|
return "";
|
|
2287
2264
|
}
|
|
2288
|
-
throw new Error(
|
|
2265
|
+
throw new Error("❌ Input required.\n" +
|
|
2266
|
+
"💡 Try this:\n" +
|
|
2267
|
+
' neurolink generate "your prompt"\n' +
|
|
2268
|
+
' echo "your prompt" | neurolink generate\n' +
|
|
2269
|
+
' neurolink generate "Describe this image" --image ./photo.jpg');
|
|
2289
2270
|
}
|
|
2290
2271
|
return argv.input;
|
|
2291
2272
|
}
|
|
@@ -2544,7 +2525,8 @@ export class CLICommandFactory {
|
|
|
2544
2525
|
if (options.delay) {
|
|
2545
2526
|
await new Promise((resolve) => setTimeout(resolve, options.delay));
|
|
2546
2527
|
}
|
|
2547
|
-
|
|
2528
|
+
validateCliInputFiles(argv);
|
|
2529
|
+
validateCsvMaxRows(argv);
|
|
2548
2530
|
// Process context
|
|
2549
2531
|
const { inputText, contextMetadata } = CLICommandFactory.processGenerateContext(rawInput, options);
|
|
2550
2532
|
// Handle dry-run mode for testing
|
|
@@ -3304,7 +3286,11 @@ export class CLICommandFactory {
|
|
|
3304
3286
|
argv.input = "";
|
|
3305
3287
|
return;
|
|
3306
3288
|
}
|
|
3307
|
-
throw new Error("No input received from stdin"
|
|
3289
|
+
throw new Error("❌ No input received from stdin.\n" +
|
|
3290
|
+
"💡 Try this:\n" +
|
|
3291
|
+
' neurolink stream "your prompt"\n' +
|
|
3292
|
+
' echo "your prompt" | neurolink stream\n' +
|
|
3293
|
+
' neurolink stream "Describe this image" --image ./photo.jpg');
|
|
3308
3294
|
}
|
|
3309
3295
|
}
|
|
3310
3296
|
else if (!argv.input) {
|
|
@@ -3312,7 +3298,11 @@ export class CLICommandFactory {
|
|
|
3312
3298
|
argv.input = "";
|
|
3313
3299
|
return;
|
|
3314
3300
|
}
|
|
3315
|
-
throw new Error(
|
|
3301
|
+
throw new Error("❌ Input required.\n" +
|
|
3302
|
+
"💡 Try this:\n" +
|
|
3303
|
+
' neurolink stream "your prompt"\n' +
|
|
3304
|
+
' echo "your prompt" | neurolink stream\n' +
|
|
3305
|
+
' neurolink stream "Describe this image" --image ./photo.jpg');
|
|
3316
3306
|
}
|
|
3317
3307
|
}
|
|
3318
3308
|
/**
|
|
@@ -3331,7 +3321,8 @@ export class CLICommandFactory {
|
|
|
3331
3321
|
if (options.delay) {
|
|
3332
3322
|
await new Promise((resolve) => setTimeout(resolve, options.delay));
|
|
3333
3323
|
}
|
|
3334
|
-
|
|
3324
|
+
validateCliInputFiles(argv);
|
|
3325
|
+
validateCsvMaxRows(argv);
|
|
3335
3326
|
const { inputText, contextMetadata } = await CLICommandFactory.processStreamContext(argv, options);
|
|
3336
3327
|
// Handle dry-run mode for testing
|
|
3337
3328
|
if (options.dryRun) {
|
package/dist/cli/loop/session.js
CHANGED
|
@@ -414,6 +414,22 @@ export class LoopSession {
|
|
|
414
414
|
logger.always(chalk.yellow(` ${c.cmd.padEnd(20)}`) + `${c.desc}`);
|
|
415
415
|
});
|
|
416
416
|
logger.always("\nAny other command will be executed as a standard neurolink CLI command.");
|
|
417
|
+
// #315: multimodal file flags are buried in the raw yargs dump below — call
|
|
418
|
+
// them out explicitly so loop users know PDFs/images/CSVs/video are supported.
|
|
419
|
+
logger.always(chalk.cyan("\nMultimodal file inputs (per-command flags):"));
|
|
420
|
+
[
|
|
421
|
+
["--image <path|url>", "Attach an image for analysis (repeatable)"],
|
|
422
|
+
["--pdf <path|url>", "Attach a PDF document (repeatable)"],
|
|
423
|
+
[
|
|
424
|
+
"--csv <path|url>",
|
|
425
|
+
"Attach a CSV file (see --csv-format, --csv-max-rows)",
|
|
426
|
+
],
|
|
427
|
+
["--video <path|url>", "Attach a video for analysis"],
|
|
428
|
+
["--file <path|url>", "Attach a file and auto-detect its type"],
|
|
429
|
+
].forEach(([flag, desc]) => {
|
|
430
|
+
logger.always(chalk.yellow(` ${flag.padEnd(20)}`) + `${desc}`);
|
|
431
|
+
});
|
|
432
|
+
logger.always(chalk.gray(' e.g. generate "Describe this" --image ./photo.jpg --pdf ./report.pdf'));
|
|
417
433
|
// Also show the standard help output
|
|
418
434
|
this.initializeCliParser().showHelp("log");
|
|
419
435
|
}
|
|
@@ -429,6 +445,11 @@ export class LoopSession {
|
|
|
429
445
|
logger.always(chalk.gray(` Type: ${schema.type}`));
|
|
430
446
|
}
|
|
431
447
|
}
|
|
448
|
+
// #350: multimodal file inputs are per-command flags, not session variables,
|
|
449
|
+
// so they don't appear above — point users to them explicitly.
|
|
450
|
+
logger.always(chalk.gray("\n Note: file inputs (--image/--pdf/--csv/--video/--file) are per-command\n" +
|
|
451
|
+
" flags, not session variables — pass them directly on a generate/stream line,\n" +
|
|
452
|
+
' e.g. generate "Summarize this" --pdf ./report.pdf'));
|
|
432
453
|
}
|
|
433
454
|
/**
|
|
434
455
|
* Get command input with history support using readline
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Input Validation Utilities
|
|
3
|
+
*
|
|
4
|
+
* Validates multimodal file flags (--image/--csv/--pdf/--video/--file) and
|
|
5
|
+
* --csv-max-rows before a generate/stream/batch run starts, so bad input
|
|
6
|
+
* fails fast with a clear message instead of surfacing deep inside provider
|
|
7
|
+
* calls. Exported as standalone functions (rather than private statics on
|
|
8
|
+
* CLICommandFactory) so callers — including tests — can import and invoke
|
|
9
|
+
* them directly, without reaching into the class via an `unknown` cast.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Soft (warn-only) size thresholds for CLI multimodal flags. Intentionally
|
|
13
|
+
* defined here rather than reusing `lib/processors/config/sizeLimits.ts`'s
|
|
14
|
+
* hard processor caps (e.g. PDF's 100MB hard limit): reusing those names/
|
|
15
|
+
* values would couple the CLI layer to processor internals across the
|
|
16
|
+
* CLI/SDK boundary, and would blur the line between a soft "this may be
|
|
17
|
+
* slow" warning and the actual hard cap the processor enforces.
|
|
18
|
+
*/
|
|
19
|
+
export declare const CLI_SOFT_LIMITS_MB: {
|
|
20
|
+
readonly IMAGE_MAX_MB: 10;
|
|
21
|
+
readonly CSV_MAX_MB: 50;
|
|
22
|
+
readonly PDF_MAX_MB: 100;
|
|
23
|
+
readonly VIDEO_MAX_MB: 500;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Validate --image/--csv/--pdf/--video/--file inputs before a CLI run
|
|
27
|
+
* starts: every local path must exist, must not be a directory, and — for
|
|
28
|
+
* the flags with a soft limit — triggers a size warning above the
|
|
29
|
+
* threshold. URLs/data URIs skip both existence and size checks (#319).
|
|
30
|
+
*/
|
|
31
|
+
export declare function validateCliInputFiles(argv: Record<string, unknown>): void;
|
|
32
|
+
/**
|
|
33
|
+
* #310: validate --csv-max-rows is a positive integer in the range
|
|
34
|
+
* 1-100000, matching the documented option range (the value previously
|
|
35
|
+
* flowed through silently, or — above 100000 — only warned instead of
|
|
36
|
+
* being rejected, contradicting the documented hard range).
|
|
37
|
+
*/
|
|
38
|
+
export declare function validateCsvMaxRows(argv: Record<string, unknown>): void;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Input Validation Utilities
|
|
3
|
+
*
|
|
4
|
+
* Validates multimodal file flags (--image/--csv/--pdf/--video/--file) and
|
|
5
|
+
* --csv-max-rows before a generate/stream/batch run starts, so bad input
|
|
6
|
+
* fails fast with a clear message instead of surfacing deep inside provider
|
|
7
|
+
* calls. Exported as standalone functions (rather than private statics on
|
|
8
|
+
* CLICommandFactory) so callers — including tests — can import and invoke
|
|
9
|
+
* them directly, without reaching into the class via an `unknown` cast.
|
|
10
|
+
*/
|
|
11
|
+
import fs from "node:fs";
|
|
12
|
+
import chalk from "chalk";
|
|
13
|
+
import { logger } from "../../lib/utils/logger.js";
|
|
14
|
+
import { resolveFilePaths } from "./pathResolver.js";
|
|
15
|
+
/**
|
|
16
|
+
* Soft (warn-only) size thresholds for CLI multimodal flags. Intentionally
|
|
17
|
+
* defined here rather than reusing `lib/processors/config/sizeLimits.ts`'s
|
|
18
|
+
* hard processor caps (e.g. PDF's 100MB hard limit): reusing those names/
|
|
19
|
+
* values would couple the CLI layer to processor internals across the
|
|
20
|
+
* CLI/SDK boundary, and would blur the line between a soft "this may be
|
|
21
|
+
* slow" warning and the actual hard cap the processor enforces.
|
|
22
|
+
*/
|
|
23
|
+
export const CLI_SOFT_LIMITS_MB = {
|
|
24
|
+
IMAGE_MAX_MB: 10,
|
|
25
|
+
CSV_MAX_MB: 50,
|
|
26
|
+
PDF_MAX_MB: 100,
|
|
27
|
+
VIDEO_MAX_MB: 500,
|
|
28
|
+
};
|
|
29
|
+
function isNonLocalFileReference(filePath) {
|
|
30
|
+
const lower = filePath.toLowerCase();
|
|
31
|
+
return (lower.startsWith("http://") ||
|
|
32
|
+
lower.startsWith("https://") ||
|
|
33
|
+
lower.startsWith("file://") ||
|
|
34
|
+
lower.startsWith("data:"));
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Validate --image/--csv/--pdf/--video/--file inputs before a CLI run
|
|
38
|
+
* starts: every local path must exist, must not be a directory, and — for
|
|
39
|
+
* the flags with a soft limit — triggers a size warning above the
|
|
40
|
+
* threshold. URLs/data URIs skip both existence and size checks (#319).
|
|
41
|
+
*/
|
|
42
|
+
export function validateCliInputFiles(argv) {
|
|
43
|
+
const fileArgs = [
|
|
44
|
+
{
|
|
45
|
+
option: "--image",
|
|
46
|
+
value: argv.image,
|
|
47
|
+
warnAtMB: CLI_SOFT_LIMITS_MB.IMAGE_MAX_MB,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
option: "--csv",
|
|
51
|
+
value: argv.csv,
|
|
52
|
+
warnAtMB: CLI_SOFT_LIMITS_MB.CSV_MAX_MB,
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
option: "--pdf",
|
|
56
|
+
value: argv.pdf,
|
|
57
|
+
warnAtMB: CLI_SOFT_LIMITS_MB.PDF_MAX_MB,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
option: "--video",
|
|
61
|
+
value: argv.video,
|
|
62
|
+
warnAtMB: CLI_SOFT_LIMITS_MB.VIDEO_MAX_MB,
|
|
63
|
+
},
|
|
64
|
+
{ option: "--file", value: argv.file },
|
|
65
|
+
];
|
|
66
|
+
const missingPaths = [];
|
|
67
|
+
for (const { option, value, warnAtMB } of fileArgs) {
|
|
68
|
+
if (!value) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
const rawPaths = Array.isArray(value) ? value : [value];
|
|
72
|
+
const resolvedPaths = resolveFilePaths(rawPaths);
|
|
73
|
+
for (let i = 0; i < resolvedPaths.length; i++) {
|
|
74
|
+
const resolvedPath = resolvedPaths[i];
|
|
75
|
+
// URLs / data: refs skip both existence and size checks (#319).
|
|
76
|
+
if (isNonLocalFileReference(resolvedPath)) {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
// Single statSync covers existence, directory rejection, and the
|
|
80
|
+
// size warning below — avoids a second syscall and closes the
|
|
81
|
+
// TOCTOU gap a separate existsSync()+statSync() pair would leave.
|
|
82
|
+
let stat;
|
|
83
|
+
try {
|
|
84
|
+
stat = fs.statSync(resolvedPath);
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
// Only ENOENT actually means "not found" — EACCES (permission
|
|
88
|
+
// denied), ELOOP (symlink loop), ENOTDIR, etc. are real failures
|
|
89
|
+
// that get masked (and made undebuggable) if we blanket-label
|
|
90
|
+
// every statSync error the same way.
|
|
91
|
+
const code = err?.code;
|
|
92
|
+
if (code === "ENOENT") {
|
|
93
|
+
missingPaths.push(`${option} path not found: ${rawPaths[i]} (resolved to ${resolvedPath})`);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
97
|
+
missingPaths.push(`${option} path could not be accessed: ${rawPaths[i]} (resolved to ${resolvedPath}) — ` +
|
|
98
|
+
`${code ? `${code}: ` : ""}${reason}`);
|
|
99
|
+
}
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if (stat.isDirectory()) {
|
|
103
|
+
missingPaths.push(`${option} path is a directory, not a file: ${rawPaths[i]} (resolved to ${resolvedPath})`);
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
// #319: warn (not error) when a local multimodal file is unusually
|
|
107
|
+
// large so the user isn't surprised by slow processing / token blowups.
|
|
108
|
+
if (warnAtMB !== undefined) {
|
|
109
|
+
const sizeMB = stat.size / (1024 * 1024);
|
|
110
|
+
if (sizeMB > warnAtMB) {
|
|
111
|
+
logger.always(chalk.yellow(`⚠️ ${option} file ${rawPaths[i]} is ${sizeMB.toFixed(1)}MB ` +
|
|
112
|
+
`(above the ${warnAtMB}MB soft limit) — processing may be slow ` +
|
|
113
|
+
`or exceed provider token/size limits.`));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (missingPaths.length > 0) {
|
|
119
|
+
throw new Error("❌ One or more input files are invalid:\n" +
|
|
120
|
+
`${missingPaths.join("\n")}\n` +
|
|
121
|
+
"💡 Check the path is correct and relative to your current directory, " +
|
|
122
|
+
"or pass an absolute path / URL.");
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* #310: validate --csv-max-rows is a positive integer in the range
|
|
127
|
+
* 1-100000, matching the documented option range (the value previously
|
|
128
|
+
* flowed through silently, or — above 100000 — only warned instead of
|
|
129
|
+
* being rejected, contradicting the documented hard range).
|
|
130
|
+
*/
|
|
131
|
+
export function validateCsvMaxRows(argv) {
|
|
132
|
+
const raw = argv.csvMaxRows;
|
|
133
|
+
if (raw === undefined) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const value = Number(raw);
|
|
137
|
+
if (!Number.isInteger(value) || value < 1 || value > 100000) {
|
|
138
|
+
throw new Error(`Invalid --csv-max-rows (--csvMaxRows) value: ${String(raw)}. ` +
|
|
139
|
+
`Must be a positive integer in the range 1-100000. ` +
|
|
140
|
+
`Example: --csv-max-rows 500`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=inputValidation.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "9.94.
|
|
3
|
+
"version": "9.94.7",
|
|
4
4
|
"packageManager": "pnpm@10.15.1",
|
|
5
5
|
"description": "TypeScript AI SDK with 24+ LLM providers behind one consistent API. MCP-native (connect any MCP server), voice TTS/STT/realtime, RAG, agents, memory, context compaction. OpenAI · Anthropic · Gemini · Bedrock · Azure · Ollama · DeepSeek · NVIDIA NIM and more.",
|
|
6
6
|
"author": {
|