@livedesk/client 0.1.123 → 0.1.124
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/bin/livedesk-client-node.js +201 -69
- package/package.json +1 -1
|
@@ -18,8 +18,9 @@ const MAX_LIVE_FPS = 30;
|
|
|
18
18
|
const MAX_FRAME_BASE64_CHARS = 3 * 1024 * 1024;
|
|
19
19
|
const MAX_AI_OUTPUT_CHARS = 6000;
|
|
20
20
|
const MAX_FILE_TRANSFER_FILES = 24;
|
|
21
|
-
const MAX_FILE_TRANSFER_BYTES = 24 * 1024 * 1024;
|
|
22
|
-
const MAX_AGENT_OUTPUT_CHARS = 32000;
|
|
21
|
+
const MAX_FILE_TRANSFER_BYTES = 24 * 1024 * 1024;
|
|
22
|
+
const MAX_AGENT_OUTPUT_CHARS = 32000;
|
|
23
|
+
const launchedProcessRegistry = new Map();
|
|
23
24
|
|
|
24
25
|
function printHelp() {
|
|
25
26
|
console.log(`
|
|
@@ -888,21 +889,51 @@ function startLiveStream(socket, options, message, nextFrameSeq, activeStreams)
|
|
|
888
889
|
return { streamId, fps, intervalMs };
|
|
889
890
|
}
|
|
890
891
|
|
|
891
|
-
function isSensitiveAgentPath(value) {
|
|
892
|
+
function isSensitiveAgentPath(value) {
|
|
892
893
|
const normalized = String(value || '').replaceAll('\\', '/').toLowerCase();
|
|
893
|
-
return normalized.includes('/.codex/') || normalized.endsWith('/auth.json') || normalized.includes('/.ssh/') || normalized.includes('/id_rsa') || normalized.endsWith('.pem') || normalized.endsWith('.key') || normalized.endsWith('/.env') || normalized.includes('/credential') || normalized.includes('/secret') || normalized.includes('/password');
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
function
|
|
897
|
-
const
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
894
|
+
return normalized.includes('/.codex/') || normalized.endsWith('/auth.json') || normalized.includes('/.ssh/') || normalized.includes('/id_rsa') || normalized.endsWith('.pem') || normalized.endsWith('.key') || normalized.endsWith('/.env') || normalized.includes('/credential') || normalized.includes('/secret') || normalized.includes('/password');
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
function isPathWithinAgentRoot(root, candidate) {
|
|
898
|
+
const relative = path.relative(root, candidate);
|
|
899
|
+
return relative === '' || (relative !== '..' && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative));
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
async function assertAgentPathDoesNotTraverseLink(base, resolved) {
|
|
903
|
+
await fs.mkdir(base, { recursive: true });
|
|
904
|
+
const canonicalRoot = await fs.realpath(base);
|
|
905
|
+
let current = resolved;
|
|
906
|
+
while (true) {
|
|
907
|
+
try {
|
|
908
|
+
const stat = await fs.lstat(current);
|
|
909
|
+
if (stat.isSymbolicLink()) {
|
|
910
|
+
throw new Error('Safe Agent paths cannot traverse symbolic links or junctions.');
|
|
911
|
+
}
|
|
912
|
+
const canonicalCurrent = await fs.realpath(current);
|
|
913
|
+
if (!isPathWithinAgentRoot(canonicalRoot, canonicalCurrent)) {
|
|
914
|
+
throw new Error('Safe Agent path resolves outside the LiveDesk files directory.');
|
|
915
|
+
}
|
|
916
|
+
return;
|
|
917
|
+
} catch (error) {
|
|
918
|
+
if (error?.code !== 'ENOENT') throw error;
|
|
919
|
+
const parent = path.dirname(current);
|
|
920
|
+
if (parent === current) throw new Error('Safe Agent path could not be verified.');
|
|
921
|
+
current = parent;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
async function resolveAgentPath(options, value, permissionMode, rejectSensitive = true) {
|
|
927
|
+
const base = normalizeDirectoryPath(options.filesDir || undefined);
|
|
928
|
+
const text = String(value || '').replace(/\0/g, '').trim();
|
|
929
|
+
if (!text || text.length > 600) throw new Error('path is invalid');
|
|
930
|
+
const resolved = path.resolve(path.isAbsolute(text) ? text : path.join(base, text));
|
|
931
|
+
const relative = path.relative(base, resolved);
|
|
932
|
+
if (permissionMode !== 'full-access' && (relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative))) throw new Error('path is outside the LiveDesk files directory for this permission mode');
|
|
933
|
+
if (permissionMode !== 'full-access') await assertAgentPathDoesNotTraverseLink(base, resolved);
|
|
934
|
+
if (rejectSensitive && isSensitiveAgentPath(resolved)) throw new Error('credential and secret paths are not available');
|
|
935
|
+
return resolved;
|
|
936
|
+
}
|
|
906
937
|
|
|
907
938
|
function runNodeAgentProcess(executable, args, timeoutMs = 15000, cwd = undefined) {
|
|
908
939
|
return new Promise((resolve, reject) => {
|
|
@@ -930,23 +961,111 @@ function redactAgentOutput(value) {
|
|
|
930
961
|
return output.slice(0, MAX_AGENT_OUTPUT_CHARS);
|
|
931
962
|
}
|
|
932
963
|
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
964
|
+
function normalizeNodeProcessKey(value) {
|
|
965
|
+
return path.basename(String(value || '').trim()).toLowerCase().replace(/\.(exe|bin)$/i, '');
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
function parseWindowsCommandLine(commandLine) {
|
|
969
|
+
const text = String(commandLine || '').trim();
|
|
970
|
+
const parsed = [];
|
|
971
|
+
let index = 0;
|
|
972
|
+
while (index < text.length) {
|
|
973
|
+
while (/\s/.test(text[index] || '')) index += 1;
|
|
974
|
+
if (index >= text.length) break;
|
|
975
|
+
let value = '';
|
|
976
|
+
let quoted = false;
|
|
977
|
+
while (index < text.length) {
|
|
978
|
+
const character = text[index];
|
|
979
|
+
if (character === '\\') {
|
|
980
|
+
let slashCount = 0;
|
|
981
|
+
while (text[index + slashCount] === '\\') slashCount += 1;
|
|
982
|
+
const next = text[index + slashCount];
|
|
983
|
+
if (next === '"') {
|
|
984
|
+
value += '\\'.repeat(Math.floor(slashCount / 2));
|
|
985
|
+
index += slashCount;
|
|
986
|
+
if (slashCount % 2 === 1) {
|
|
987
|
+
value += '"';
|
|
988
|
+
index += 1;
|
|
989
|
+
} else {
|
|
990
|
+
quoted = !quoted;
|
|
991
|
+
index += 1;
|
|
992
|
+
}
|
|
993
|
+
} else {
|
|
994
|
+
value += '\\'.repeat(slashCount);
|
|
995
|
+
index += slashCount;
|
|
996
|
+
}
|
|
997
|
+
continue;
|
|
998
|
+
}
|
|
999
|
+
if (character === '"') {
|
|
1000
|
+
quoted = !quoted;
|
|
1001
|
+
index += 1;
|
|
1002
|
+
continue;
|
|
1003
|
+
}
|
|
1004
|
+
if (/\s/.test(character) && !quoted) break;
|
|
1005
|
+
value += character;
|
|
1006
|
+
index += 1;
|
|
1007
|
+
}
|
|
1008
|
+
parsed.push(value);
|
|
1009
|
+
while (/\s/.test(text[index] || '')) index += 1;
|
|
1010
|
+
}
|
|
1011
|
+
return parsed;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
function decodeUtf16Base64(value) {
|
|
1015
|
+
try {
|
|
1016
|
+
return Buffer.from(String(value || ''), 'base64').toString('utf16le');
|
|
1017
|
+
} catch {
|
|
1018
|
+
return '';
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
function decodeNullSeparatedBase64(value) {
|
|
1023
|
+
try {
|
|
1024
|
+
return Buffer.from(String(value || ''), 'base64').toString('utf8');
|
|
1025
|
+
} catch {
|
|
1026
|
+
return '';
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
async function findNodeProcessDetails(processName) {
|
|
1031
|
+
const name = String(processName || '').trim();
|
|
1032
|
+
if (!name) return null;
|
|
1033
|
+
if (process.platform === 'win32') {
|
|
1034
|
+
const result = await runNodeAgentProcess('powershell.exe', [
|
|
1035
|
+
'-NoProfile', '-NonInteractive', '-Command',
|
|
1036
|
+
'$name=$args[0]; $p=Get-CimInstance Win32_Process | Where-Object { $_.Name -ieq $name } | Select-Object -First 1; if($p){ $bytes=[Text.Encoding]::Unicode.GetBytes([string]$p.CommandLine); [Console]::Out.WriteLine([string]$p.ProcessId); [Console]::Out.WriteLine([string]$p.ExecutablePath); [Console]::Out.Write([Convert]::ToBase64String($bytes)) }',
|
|
1037
|
+
name
|
|
1038
|
+
], 10000);
|
|
1039
|
+
if (result.exitCode !== 0) return null;
|
|
1040
|
+
const lines = String(result.output || '').trim().split(/\r?\n/);
|
|
1041
|
+
const executable = String(lines[1] || '').trim();
|
|
1042
|
+
if (!lines[0] || !executable) return null;
|
|
1043
|
+
const commandLine = decodeUtf16Base64(lines[2]);
|
|
1044
|
+
const parsed = parseWindowsCommandLine(commandLine);
|
|
1045
|
+
return { pid: Number(lines[0]) || 0, executable, args: parsed.length > 1 ? parsed.slice(1) : null, workingDirectory: null, metadataSource: 'process-command-line' };
|
|
1046
|
+
}
|
|
1047
|
+
if (process.platform === 'linux') {
|
|
1048
|
+
const result = await runNodeAgentProcess('/bin/sh', ['-lc', 'pid=$(pgrep -xo -- "$1" || true); if [ -n "$pid" ] && [ -e "/proc/$pid/exe" ]; then printf "%s\\n%s\\n%s\\n" "$pid" "$(readlink -f "/proc/$pid/exe")" "$(readlink -f "/proc/$pid/cwd")"; base64 -w0 "/proc/$pid/cmdline"; fi', 'livedesk-process-details', name], 10000);
|
|
1049
|
+
if (result.exitCode !== 0) return null;
|
|
1050
|
+
const lines = String(result.output || '').trim().split(/\r?\n/);
|
|
1051
|
+
const executable = String(lines[1] || '').trim();
|
|
1052
|
+
const workingDirectory = String(lines[2] || '').trim();
|
|
1053
|
+
if (!lines[0] || !executable) return null;
|
|
1054
|
+
const parsed = decodeNullSeparatedBase64(lines[3]).split('\0').filter(Boolean);
|
|
1055
|
+
return { pid: Number(lines[0]) || 0, executable, args: parsed.length > 1 ? parsed.slice(1) : null, workingDirectory: workingDirectory || null, metadataSource: 'proc' };
|
|
1056
|
+
}
|
|
1057
|
+
if (process.platform === 'darwin') {
|
|
1058
|
+
const result = await runNodeAgentProcess('/bin/sh', ['-lc', 'pid=$(pgrep -xo -- "$1" || true); if [ -n "$pid" ]; then exe=$(ps -p "$pid" -o comm= | sed "s/^ *//"); cwd=$(lsof -a -p "$pid" -d cwd -Fn 2>/dev/null | sed -n "s/^n//p" | head -n 1); command=$(ps -p "$pid" -o command=); printf "%s\\n%s\\n%s\\n" "$pid" "$exe" "$cwd"; printf "%s" "$command" | base64 | tr -d "\\n"; fi', 'livedesk-process-details', name], 10000);
|
|
1059
|
+
if (result.exitCode !== 0) return null;
|
|
1060
|
+
const lines = String(result.output || '').trim().split(/\r?\n/);
|
|
1061
|
+
const executable = String(lines[1] || '').trim();
|
|
1062
|
+
const workingDirectory = String(lines[2] || '').trim();
|
|
1063
|
+
if (!lines[0] || !executable) return null;
|
|
1064
|
+
const parsed = parseWindowsCommandLine(Buffer.from(String(lines[3] || ''), 'base64').toString('utf8'));
|
|
1065
|
+
return { pid: Number(lines[0]) || 0, executable, args: parsed.length > 1 ? parsed.slice(1) : null, workingDirectory: workingDirectory || null, metadataSource: 'ps-lsof' };
|
|
1066
|
+
}
|
|
1067
|
+
return null;
|
|
1068
|
+
}
|
|
950
1069
|
|
|
951
1070
|
async function persistNodeEnvironmentVariable(name, value) {
|
|
952
1071
|
const variableName = String(name || '').trim();
|
|
@@ -972,31 +1091,34 @@ async function persistNodeEnvironmentVariable(name, value) {
|
|
|
972
1091
|
|
|
973
1092
|
async function executeNodeAgentOperation(options, operation, payload = {}) {
|
|
974
1093
|
const permissionMode = String(payload.permissionMode || 'ask');
|
|
975
|
-
const args = payload.toolArguments && typeof payload.toolArguments === 'object' ? payload.toolArguments : payload;
|
|
976
|
-
if (operation === 'file.read') {
|
|
977
|
-
const filePath = resolveAgentPath(options, args.path, permissionMode);
|
|
1094
|
+
const args = payload.toolArguments && typeof payload.toolArguments === 'object' ? payload.toolArguments : payload;
|
|
1095
|
+
if (operation === 'file.read') {
|
|
1096
|
+
const filePath = await resolveAgentPath(options, args.path, permissionMode);
|
|
978
1097
|
const info = await fs.stat(filePath);
|
|
979
1098
|
const maxBytes = Math.max(1, Math.min(65536, Number(args.maxBytes) || 65536));
|
|
980
1099
|
const content = (await fs.readFile(filePath)).subarray(0, maxBytes).toString('utf8');
|
|
981
1100
|
return { summary: `Read ${Buffer.byteLength(content)} bytes from ${path.basename(filePath)}.`, data: { path: filePath, sizeBytes: info.size, returnedBytes: Buffer.byteLength(content), truncated: info.size > Buffer.byteLength(content), content } };
|
|
982
|
-
}
|
|
983
|
-
if (operation === 'file.write') {
|
|
984
|
-
|
|
985
|
-
const content = String(args.content || '');
|
|
986
|
-
if (Buffer.byteLength(content) > 1048576) throw new Error('file content exceeds the 1 MiB limit');
|
|
987
|
-
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
988
|
-
|
|
1101
|
+
}
|
|
1102
|
+
if (operation === 'file.write') {
|
|
1103
|
+
let filePath = await resolveAgentPath(options, args.path, permissionMode);
|
|
1104
|
+
const content = String(args.content || '');
|
|
1105
|
+
if (Buffer.byteLength(content) > 1048576) throw new Error('file content exceeds the 1 MiB limit');
|
|
1106
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
1107
|
+
// Re-check after creating missing parents so a newly introduced link
|
|
1108
|
+
// cannot turn the write into an outside-root operation.
|
|
1109
|
+
filePath = await resolveAgentPath(options, args.path, permissionMode);
|
|
1110
|
+
if (args.append === true) await fs.appendFile(filePath, content, 'utf8');
|
|
989
1111
|
else await fs.writeFile(filePath, content, 'utf8');
|
|
990
1112
|
return { summary: `Wrote ${Buffer.byteLength(content)} bytes to ${path.basename(filePath)}.`, data: { path: filePath, sizeBytes: (await fs.stat(filePath)).size, append: args.append === true } };
|
|
991
1113
|
}
|
|
992
|
-
if (operation === 'file.delete') {
|
|
993
|
-
const filePath = resolveAgentPath(options, args.path, permissionMode);
|
|
1114
|
+
if (operation === 'file.delete') {
|
|
1115
|
+
const filePath = await resolveAgentPath(options, args.path, permissionMode);
|
|
994
1116
|
if (args.recursive === true) await fs.rm(filePath, { recursive: true, force: false });
|
|
995
1117
|
else await fs.unlink(filePath);
|
|
996
1118
|
return { summary: `Deleted ${path.basename(filePath)}.`, data: { path: filePath, recursive: args.recursive === true } };
|
|
997
1119
|
}
|
|
998
|
-
if (operation === 'file.list') {
|
|
999
|
-
const directory = resolveAgentPath(options, args.path, permissionMode);
|
|
1120
|
+
if (operation === 'file.list') {
|
|
1121
|
+
const directory = await resolveAgentPath(options, args.path, permissionMode);
|
|
1000
1122
|
const entries = await fs.readdir(directory, { withFileTypes: true });
|
|
1001
1123
|
const maxEntries = Math.max(1, Math.min(500, Number(args.maxEntries) || 200));
|
|
1002
1124
|
const data = [];
|
|
@@ -1006,26 +1128,36 @@ async function executeNodeAgentOperation(options, operation, payload = {}) {
|
|
|
1006
1128
|
data.push({ name: entry.name, path: entryPath, type: entry.isDirectory() ? 'directory' : 'file', sizeBytes: entry.isDirectory() ? 0 : (await fs.stat(entryPath)).size });
|
|
1007
1129
|
}
|
|
1008
1130
|
return { summary: `Listed ${data.length} entries.`, data: { path: directory, entries: data, truncated: entries.length > maxEntries } };
|
|
1009
|
-
}
|
|
1010
|
-
if (operation === 'application.launch') {
|
|
1011
|
-
const executable = String(args.executable || '').trim();
|
|
1012
|
-
if (!executable || executable.length > 400 || /[\0\r\n]/.test(executable)) throw new Error('executable is invalid');
|
|
1013
|
-
const
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1131
|
+
}
|
|
1132
|
+
if (operation === 'application.launch') {
|
|
1133
|
+
const executable = String(args.executable || '').trim();
|
|
1134
|
+
if (!executable || executable.length > 400 || /[\0\r\n]/.test(executable)) throw new Error('executable is invalid');
|
|
1135
|
+
const launchArgs = Array.isArray(args.args) ? args.args.slice(0, 32).map(String) : [];
|
|
1136
|
+
const workingDirectory = args.workingDirectory ? await resolveAgentPath(options, args.workingDirectory, permissionMode, false) : process.cwd();
|
|
1137
|
+
const child = spawn(executable, launchArgs, { cwd: workingDirectory, detached: true, windowsHide: true, stdio: 'ignore' });
|
|
1138
|
+
child.unref();
|
|
1139
|
+
launchedProcessRegistry.set(normalizeNodeProcessKey(executable), { executable, args: launchArgs, workingDirectory, metadataSource: 'launch_application' });
|
|
1140
|
+
return { summary: `Started ${path.basename(executable)}.`, data: { executable, args: launchArgs, workingDirectory, pid: child.pid } };
|
|
1141
|
+
}
|
|
1142
|
+
if (operation === 'process.control') {
|
|
1143
|
+
const action = String(args.action || 'stop');
|
|
1144
|
+
const processName = String(args.processName || '').trim();
|
|
1145
|
+
const processDetails = await findNodeProcessDetails(processName);
|
|
1146
|
+
if (!processDetails) {
|
|
1147
|
+
if (action === 'restart') throw new Error(`process-not-found: ${processName}`);
|
|
1148
|
+
return { summary: `${processName} is already stopped.`, data: { action, processName, status: 'already-stopped', ok: true } };
|
|
1149
|
+
}
|
|
1150
|
+
if (action === 'restart') {
|
|
1151
|
+
const restartMetadata = launchedProcessRegistry.get(normalizeNodeProcessKey(processName)) || processDetails;
|
|
1152
|
+
if (!restartMetadata.executable || !Array.isArray(restartMetadata.args) || !restartMetadata.workingDirectory) {
|
|
1153
|
+
throw new Error(`process-restart-metadata-unavailable: ${processName}`);
|
|
1154
|
+
}
|
|
1155
|
+
const stop = await runNodeAgentProcess(process.platform === 'win32' ? 'taskkill' : 'pkill', process.platform === 'win32' ? ['/IM', processName, '/T', '/F'] : ['-TERM', processName]);
|
|
1156
|
+
if (stop.exitCode !== 0 || stop.timedOut) throw new Error(`Process stop failed before restart (exit ${stop.exitCode}).`);
|
|
1157
|
+
const child = spawn(restartMetadata.executable, restartMetadata.args, { cwd: restartMetadata.workingDirectory, detached: true, windowsHide: true, stdio: 'ignore' });
|
|
1158
|
+
child.unref();
|
|
1159
|
+
return { summary: `Restarted ${processName}.`, data: { action, processName, stop, restarted: true, pid: child.pid, executable: restartMetadata.executable, args: restartMetadata.args, workingDirectory: restartMetadata.workingDirectory, metadataSource: restartMetadata.metadataSource } };
|
|
1160
|
+
}
|
|
1029
1161
|
const result = await runNodeAgentProcess(process.platform === 'win32' ? 'taskkill' : 'pkill', process.platform === 'win32' ? ['/IM', processName, '/T'] : ['-TERM', processName]);
|
|
1030
1162
|
return { summary: `${action} requested for ${processName}.`, data: { action, processName, ...result } };
|
|
1031
1163
|
}
|
|
@@ -1054,11 +1186,11 @@ async function executeNodeAgentOperation(options, operation, payload = {}) {
|
|
|
1054
1186
|
const command = String(args.command || '');
|
|
1055
1187
|
const executable = process.platform === 'win32' ? 'cmd.exe' : '/bin/sh';
|
|
1056
1188
|
const commandArgs = process.platform === 'win32' ? ['/d', '/s', '/c', command] : ['-lc', command];
|
|
1057
|
-
const result = await runNodeAgentProcess(executable, commandArgs, args.timeoutMs, args.workingDirectory ? resolveAgentPath(options, args.workingDirectory, permissionMode, false) : undefined);
|
|
1189
|
+
const result = await runNodeAgentProcess(executable, commandArgs, args.timeoutMs, args.workingDirectory ? await resolveAgentPath(options, args.workingDirectory, permissionMode, false) : undefined);
|
|
1058
1190
|
return { summary: result.timedOut ? 'Command timed out.' : `Command exited with code ${result.exitCode}.`, data: { ...result, output: redactAgentOutput(result.output) } };
|
|
1059
1191
|
}
|
|
1060
1192
|
if (operation === 'script.run') {
|
|
1061
|
-
const scriptPath = resolveAgentPath(options, args.path, permissionMode);
|
|
1193
|
+
const scriptPath = await resolveAgentPath(options, args.path, permissionMode);
|
|
1062
1194
|
const executable = process.platform === 'win32' ? 'powershell.exe' : '/bin/sh';
|
|
1063
1195
|
const scriptArgs = process.platform === 'win32' ? ['-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-File', scriptPath, ...(Array.isArray(args.args) ? args.args.slice(0, 32).map(String) : [])] : [scriptPath, ...(Array.isArray(args.args) ? args.args.slice(0, 32).map(String) : [])];
|
|
1064
1196
|
const result = await runNodeAgentProcess(executable, scriptArgs, args.timeoutMs);
|