@juspay/neurolink 9.35.0 → 9.36.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,9 @@
|
|
|
1
|
+
## [9.36.0](https://github.com/juspay/neurolink/compare/v9.35.0...v9.36.0) (2026-03-28)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
- **(proxy):** add auto-update with traffic-aware graceful restart ([4a11a78](https://github.com/juspay/neurolink/commit/4a11a783adb4424d7a303b298c6cf9989cd4ed63))
|
|
6
|
+
|
|
1
7
|
## [9.35.0](https://github.com/juspay/neurolink/compare/v9.34.0...v9.35.0) (2026-03-28)
|
|
2
8
|
|
|
3
9
|
### Features
|
|
@@ -934,16 +934,21 @@ export const proxyGuardCommand = {
|
|
|
934
934
|
const UPDATE_CHECK_INTERVAL_MS = 2 * 60 * 60 * 1000; // 2 hours
|
|
935
935
|
const QUIET_THRESHOLD_MS = 120 * 1000; // 2 minutes of silence
|
|
936
936
|
const UPDATE_TIMEOUT_MS = 30 * 1000; // 30 seconds to come healthy
|
|
937
|
-
// Get running version from /health endpoint
|
|
937
|
+
// Get running version from /health endpoint (with timeout to avoid hanging)
|
|
938
938
|
let runningVersion = PROXY_VERSION; // fallback
|
|
939
939
|
try {
|
|
940
|
-
const healthResp = await fetch(`http://${host}:${port}/health
|
|
940
|
+
const healthResp = await fetch(`http://${host}:${port}/health`, {
|
|
941
|
+
signal: AbortSignal.timeout(5_000),
|
|
942
|
+
});
|
|
941
943
|
const healthData = (await healthResp.json());
|
|
942
944
|
runningVersion = healthData.version ?? PROXY_VERSION;
|
|
943
945
|
}
|
|
944
946
|
catch {
|
|
945
947
|
/* use fallback */
|
|
946
948
|
}
|
|
949
|
+
// Auto-update only works on macOS with launchd. On other platforms,
|
|
950
|
+
// there's no restart mechanism, so skip the update loop entirely.
|
|
951
|
+
const canAutoUpdate = process.platform === "darwin" && (await isLaunchdManaging());
|
|
947
952
|
let updateInProgress = false;
|
|
948
953
|
let updateRestartInProgress = false;
|
|
949
954
|
const runUpdateCheck = async () => {
|
|
@@ -1014,7 +1019,7 @@ export const proxyGuardCommand = {
|
|
|
1014
1019
|
logger.always(`[guard] restarting proxy via launchctl...`);
|
|
1015
1020
|
const uid = process.getuid?.() ?? 501;
|
|
1016
1021
|
try {
|
|
1017
|
-
execFileSync("launchctl", ["kickstart", "-k", `gui/${uid}
|
|
1022
|
+
execFileSync("launchctl", ["kickstart", "-k", `gui/${uid}/${PLIST_LABEL}`], {
|
|
1018
1023
|
timeout: 10_000,
|
|
1019
1024
|
stdio: "pipe",
|
|
1020
1025
|
});
|
|
@@ -1065,8 +1070,10 @@ export const proxyGuardCommand = {
|
|
|
1065
1070
|
}
|
|
1066
1071
|
};
|
|
1067
1072
|
// Run first check after a short delay, then on interval
|
|
1068
|
-
|
|
1069
|
-
|
|
1073
|
+
if (canAutoUpdate) {
|
|
1074
|
+
setTimeout(runUpdateCheck, 30_000);
|
|
1075
|
+
setInterval(runUpdateCheck, UPDATE_CHECK_INTERVAL_MS);
|
|
1076
|
+
}
|
|
1070
1077
|
const startedAt = Date.now();
|
|
1071
1078
|
let parentStatus = getProcessStatus(parentPid);
|
|
1072
1079
|
let consecutiveUnhealthy = 0;
|
|
@@ -12,12 +12,25 @@ const DEFAULT_QUIET_THRESHOLD_MS = 120_000;
|
|
|
12
12
|
/** Maximum bytes to read from the tail of the log file. */
|
|
13
13
|
const TAIL_READ_SIZE = 4096;
|
|
14
14
|
/**
|
|
15
|
-
* Build the path to
|
|
15
|
+
* Build the path to a proxy debug log file for a given date.
|
|
16
16
|
* Format: ~/.neurolink/logs/proxy-debug-YYYY-MM-DD.jsonl
|
|
17
17
|
*/
|
|
18
|
-
function
|
|
19
|
-
const
|
|
20
|
-
return join(homedir(), ".neurolink", "logs", `proxy-debug-${
|
|
18
|
+
function getLogPathForDate(date) {
|
|
19
|
+
const dateStr = date.toISOString().split("T")[0];
|
|
20
|
+
return join(homedir(), ".neurolink", "logs", `proxy-debug-${dateStr}.jsonl`);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Get the most relevant log file path. Uses today's log if it exists,
|
|
24
|
+
* otherwise falls back to yesterday's to handle the midnight rollover case
|
|
25
|
+
* (last request at 23:59, update check at 00:01).
|
|
26
|
+
*/
|
|
27
|
+
function getActiveLogPath() {
|
|
28
|
+
const todayPath = getLogPathForDate(new Date());
|
|
29
|
+
if (existsSync(todayPath)) {
|
|
30
|
+
return todayPath;
|
|
31
|
+
}
|
|
32
|
+
const yesterday = new Date(Date.now() - 86_400_000);
|
|
33
|
+
return getLogPathForDate(yesterday);
|
|
21
34
|
}
|
|
22
35
|
/**
|
|
23
36
|
* Read the last complete line(s) from a file efficiently.
|
|
@@ -82,7 +95,7 @@ export function checkTrafficQuiet(quietThresholdMs = DEFAULT_QUIET_THRESHOLD_MS)
|
|
|
82
95
|
lastActivityAt: null,
|
|
83
96
|
silenceDurationMs: Infinity,
|
|
84
97
|
};
|
|
85
|
-
const logPath =
|
|
98
|
+
const logPath = getActiveLogPath();
|
|
86
99
|
if (!existsSync(logPath)) {
|
|
87
100
|
return noActivityResult;
|
|
88
101
|
}
|
|
@@ -67,9 +67,12 @@ export function loadUpdateState(stateFilePath) {
|
|
|
67
67
|
const content = fs.readFileSync(filePath, "utf8");
|
|
68
68
|
const parsed = JSON.parse(content);
|
|
69
69
|
// Minimal shape check — reject valid JSON that isn't an UpdateState
|
|
70
|
+
// Note: typeof null === "object", so we check both
|
|
70
71
|
if (typeof parsed !== "object" ||
|
|
71
72
|
parsed === null ||
|
|
72
73
|
typeof parsed.suppressedVersions !== "object" ||
|
|
74
|
+
parsed.suppressedVersions === null ||
|
|
75
|
+
Array.isArray(parsed.suppressedVersions) ||
|
|
73
76
|
typeof parsed.lastCheckAt !== "string") {
|
|
74
77
|
return getDefaultUpdateState();
|
|
75
78
|
}
|
|
@@ -12,12 +12,25 @@ const DEFAULT_QUIET_THRESHOLD_MS = 120_000;
|
|
|
12
12
|
/** Maximum bytes to read from the tail of the log file. */
|
|
13
13
|
const TAIL_READ_SIZE = 4096;
|
|
14
14
|
/**
|
|
15
|
-
* Build the path to
|
|
15
|
+
* Build the path to a proxy debug log file for a given date.
|
|
16
16
|
* Format: ~/.neurolink/logs/proxy-debug-YYYY-MM-DD.jsonl
|
|
17
17
|
*/
|
|
18
|
-
function
|
|
19
|
-
const
|
|
20
|
-
return join(homedir(), ".neurolink", "logs", `proxy-debug-${
|
|
18
|
+
function getLogPathForDate(date) {
|
|
19
|
+
const dateStr = date.toISOString().split("T")[0];
|
|
20
|
+
return join(homedir(), ".neurolink", "logs", `proxy-debug-${dateStr}.jsonl`);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Get the most relevant log file path. Uses today's log if it exists,
|
|
24
|
+
* otherwise falls back to yesterday's to handle the midnight rollover case
|
|
25
|
+
* (last request at 23:59, update check at 00:01).
|
|
26
|
+
*/
|
|
27
|
+
function getActiveLogPath() {
|
|
28
|
+
const todayPath = getLogPathForDate(new Date());
|
|
29
|
+
if (existsSync(todayPath)) {
|
|
30
|
+
return todayPath;
|
|
31
|
+
}
|
|
32
|
+
const yesterday = new Date(Date.now() - 86_400_000);
|
|
33
|
+
return getLogPathForDate(yesterday);
|
|
21
34
|
}
|
|
22
35
|
/**
|
|
23
36
|
* Read the last complete line(s) from a file efficiently.
|
|
@@ -82,7 +95,7 @@ export function checkTrafficQuiet(quietThresholdMs = DEFAULT_QUIET_THRESHOLD_MS)
|
|
|
82
95
|
lastActivityAt: null,
|
|
83
96
|
silenceDurationMs: Infinity,
|
|
84
97
|
};
|
|
85
|
-
const logPath =
|
|
98
|
+
const logPath = getActiveLogPath();
|
|
86
99
|
if (!existsSync(logPath)) {
|
|
87
100
|
return noActivityResult;
|
|
88
101
|
}
|
|
@@ -67,9 +67,12 @@ export function loadUpdateState(stateFilePath) {
|
|
|
67
67
|
const content = fs.readFileSync(filePath, "utf8");
|
|
68
68
|
const parsed = JSON.parse(content);
|
|
69
69
|
// Minimal shape check — reject valid JSON that isn't an UpdateState
|
|
70
|
+
// Note: typeof null === "object", so we check both
|
|
70
71
|
if (typeof parsed !== "object" ||
|
|
71
72
|
parsed === null ||
|
|
72
73
|
typeof parsed.suppressedVersions !== "object" ||
|
|
74
|
+
parsed.suppressedVersions === null ||
|
|
75
|
+
Array.isArray(parsed.suppressedVersions) ||
|
|
73
76
|
typeof parsed.lastCheckAt !== "string") {
|
|
74
77
|
return getDefaultUpdateState();
|
|
75
78
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.36.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 13 providers: OpenAI, Anthropic, Google AI, AWS Bedrock, Azure, Hugging Face, Ollama, and Mistral AI.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Juspay Technologies",
|