memtrace 0.8.0 → 0.8.2
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/install.js +48 -0
- package/installer/package.json +1 -1
- package/lib/cuda-ep.js +355 -0
- package/package.json +7 -7
package/install.js
CHANGED
|
@@ -239,6 +239,50 @@ function selfHealPlatformPackage() {
|
|
|
239
239
|
return true;
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
+
// ── CUDA execution provider (win32 NVIDIA hosts) ─────────────────────────────
|
|
243
|
+
//
|
|
244
|
+
// v0.8.0 dropped `onnxruntime_providers_cuda.dll` from @memtrace/win32-x64
|
|
245
|
+
// (400.9 MB tripped npm's E413 size ceiling); it ships as a GitHub release
|
|
246
|
+
// asset instead. Without it, Windows NVIDIA users silently degrade to
|
|
247
|
+
// DirectML. This step detects an NVIDIA GPU and fetches + sha256-verifies
|
|
248
|
+
// the DLL into the platform package's bin dir. Package-internal
|
|
249
|
+
// provisioning (never touches user config), so it runs pre-consent
|
|
250
|
+
// alongside the optional-dep self-heal. Every failure mode is a warn +
|
|
251
|
+
// continue; `memtrace gpu install-cuda` is the manual retry path.
|
|
252
|
+
// Opt out with MEMTRACE_SKIP_CUDA_EP=1.
|
|
253
|
+
async function maybeInstallCudaEp() {
|
|
254
|
+
const cudaEp = require("./lib/cuda-ep");
|
|
255
|
+
const pkg = platformPackageName(getPlatformKey());
|
|
256
|
+
const gate = cudaEp.shouldFetchCudaEp({ packageName: pkg, env: process.env });
|
|
257
|
+
if (!gate.fetch) return;
|
|
258
|
+
|
|
259
|
+
let binaryPath;
|
|
260
|
+
try {
|
|
261
|
+
binaryPath = getBinaryPath();
|
|
262
|
+
} catch (_) {
|
|
263
|
+
return; // no binary — self-heal already warned, nowhere to put the DLL
|
|
264
|
+
}
|
|
265
|
+
const version = getPinnedPlatformVersion(require("./package.json"), pkg);
|
|
266
|
+
try {
|
|
267
|
+
const result = await cudaEp.installCudaEp({ binaryPath, version, log: console.log });
|
|
268
|
+
if (result.status === "installed") {
|
|
269
|
+
console.log(`memtrace: CUDA execution provider installed at ${result.dllPath}`);
|
|
270
|
+
} else if (result.status === "skipped") {
|
|
271
|
+
console.log(
|
|
272
|
+
`memtrace: CUDA execution provider not installed (${result.reason}). ` +
|
|
273
|
+
`Run 'memtrace gpu install-cuda' to fetch it manually.`
|
|
274
|
+
);
|
|
275
|
+
} else if (result.status === "error") {
|
|
276
|
+
console.warn(
|
|
277
|
+
`memtrace: CUDA execution provider install failed: ${result.reason}. ` +
|
|
278
|
+
`GPU embedding falls back to DirectML; retry with 'memtrace gpu install-cuda'.`
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
} catch (e) {
|
|
282
|
+
console.warn(`memtrace: CUDA execution provider install skipped: ${e.message}`);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
242
286
|
// ── Integration phases (post-consent) ───────────────────────────────────────
|
|
243
287
|
//
|
|
244
288
|
// Everything below this line mutates user configuration and therefore only
|
|
@@ -402,6 +446,9 @@ async function main() {
|
|
|
402
446
|
} catch (e) {
|
|
403
447
|
console.warn(`memtrace: ${e.message}`);
|
|
404
448
|
}
|
|
449
|
+
// Still package-internal: drop the CUDA EP next to the binary on
|
|
450
|
+
// NVIDIA hosts (no-op everywhere else, idempotent on re-runs).
|
|
451
|
+
await maybeInstallCudaEp();
|
|
405
452
|
}
|
|
406
453
|
|
|
407
454
|
// Step 2 — consent gate (memtrace-public #25). Print the full mutation
|
|
@@ -459,6 +506,7 @@ module.exports = {
|
|
|
459
506
|
getBinaryPath,
|
|
460
507
|
ensureExecutableBits,
|
|
461
508
|
runIntegrationPhases,
|
|
509
|
+
maybeInstallCudaEp,
|
|
462
510
|
selfHealPlatformPackage,
|
|
463
511
|
buildSelfHealEnv,
|
|
464
512
|
buildSelfHealInstallArgs,
|
package/installer/package.json
CHANGED
package/lib/cuda-ep.js
ADDED
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// On-demand CUDA execution provider fetch (Windows NVIDIA hosts).
|
|
4
|
+
//
|
|
5
|
+
// As of v0.8.0 the @memtrace/win32-x64 package no longer bundles
|
|
6
|
+
// `onnxruntime_providers_cuda.dll` — at 400.9 MB it pushed the tarball
|
|
7
|
+
// over npm's payload ceiling (E413, broke the v0.8.0 publish). The DLL
|
|
8
|
+
// ships as a GitHub release asset instead (`memtrace-windows-x86_64-
|
|
9
|
+
// cuda-ep.zip`, sha256 recorded in the release's `checksums.txt`), and
|
|
10
|
+
// this module fetches it at install time for hosts that can actually
|
|
11
|
+
// use it. The engine probes CUDA -> DirectML -> CPU at startup, so a
|
|
12
|
+
// missing DLL is never fatal — NVIDIA users just silently land on
|
|
13
|
+
// DirectML, which is what this fetch exists to avoid.
|
|
14
|
+
//
|
|
15
|
+
// Placement contract: the engine's dylib discovery looks next to the
|
|
16
|
+
// running binary (`bridge_ort_dylib_env` in the Rust CLI), so the DLL
|
|
17
|
+
// must land in the platform package's bin/ dir, beside memtrace.exe.
|
|
18
|
+
// That directory is owned by the platform package: an npm upgrade
|
|
19
|
+
// replaces it wholesale, which conveniently re-triggers this fetch on
|
|
20
|
+
// the next postinstall. Everything here is package-internal
|
|
21
|
+
// provisioning — it never touches user config, so install.js runs it
|
|
22
|
+
// BEFORE the consent gate, same as the optional-dep self-heal.
|
|
23
|
+
//
|
|
24
|
+
// Failure policy: best-effort, always. Offline, missing release asset,
|
|
25
|
+
// checksum mismatch, PowerShell missing — every failure path returns a
|
|
26
|
+
// {status, reason} result instead of throwing, and the caller logs a
|
|
27
|
+
// pointer to the manual escape hatch (`memtrace gpu install-cuda`).
|
|
28
|
+
// A postinstall must never fail the package install over an optional
|
|
29
|
+
// accelerator.
|
|
30
|
+
//
|
|
31
|
+
// All IO is dependency-injected (fetch, spawn, fs paths) so tests can
|
|
32
|
+
// drive offline / mismatch / no-GPU modes deterministically — same
|
|
33
|
+
// pattern as lib/update-check.js.
|
|
34
|
+
|
|
35
|
+
const os = require("os");
|
|
36
|
+
const path = require("path");
|
|
37
|
+
const fs = require("fs");
|
|
38
|
+
const crypto = require("crypto");
|
|
39
|
+
const { spawnSync } = require("child_process");
|
|
40
|
+
|
|
41
|
+
const CUDA_EP_ASSET = "memtrace-windows-x86_64-cuda-ep.zip";
|
|
42
|
+
const CUDA_EP_DLL = "onnxruntime_providers_cuda.dll";
|
|
43
|
+
const RELEASE_BASE_URL = "https://github.com/syncable-dev/memtrace/releases/download";
|
|
44
|
+
// Only the default AVX2 package. The noavx2 variant bundles a
|
|
45
|
+
// from-source onnxruntime.dll; pairing it with Microsoft's prebuilt
|
|
46
|
+
// CUDA EP is an untested ABI mix (and pre-Haswell CPU + modern NVIDIA
|
|
47
|
+
// GPU is not a combination worth chasing).
|
|
48
|
+
const CUDA_PACKAGE = "@memtrace/win32-x64";
|
|
49
|
+
|
|
50
|
+
// Abort the zip download if the socket goes silent this long. The asset
|
|
51
|
+
// is ~400 MB so there is deliberately NO total-time cap — slow links
|
|
52
|
+
// are fine, dead links are not.
|
|
53
|
+
const INACTIVITY_TIMEOUT_MS = 60_000;
|
|
54
|
+
const CHECKSUMS_TIMEOUT_MS = 15_000;
|
|
55
|
+
|
|
56
|
+
// ── Pure helpers ─────────────────────────────────────────────────────────────
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Release asset URLs for a memtrace version. Accepts "0.8.0" or
|
|
60
|
+
* "v0.8.0"; release tags are always v-prefixed.
|
|
61
|
+
*/
|
|
62
|
+
function releaseAssetUrls(version, baseUrl) {
|
|
63
|
+
const base = (baseUrl || RELEASE_BASE_URL).replace(/\/+$/, "");
|
|
64
|
+
const tag = version.startsWith("v") ? version : `v${version}`;
|
|
65
|
+
return {
|
|
66
|
+
zipUrl: `${base}/${tag}/${CUDA_EP_ASSET}`,
|
|
67
|
+
checksumsUrl: `${base}/${tag}/checksums.txt`,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Extract the sha256 for `assetName` from `sha256sum`-format text
|
|
73
|
+
* (`<64 hex> <name>`, optional `*` binary marker). Returns lowercase
|
|
74
|
+
* hex or null when the asset has no line.
|
|
75
|
+
*/
|
|
76
|
+
function parseChecksums(text, assetName) {
|
|
77
|
+
if (typeof text !== "string") return null;
|
|
78
|
+
for (const line of text.split(/\r?\n/)) {
|
|
79
|
+
const m = /^([0-9a-fA-F]{64})\s+\*?(.+)$/.exec(line.trim());
|
|
80
|
+
if (m && m[2].trim() === assetName) {
|
|
81
|
+
return m[1].toLowerCase();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Gate: is fetching the CUDA EP even applicable on this install?
|
|
89
|
+
* Returns {fetch, reason}. Pure — platform/package/env all injected.
|
|
90
|
+
*/
|
|
91
|
+
function shouldFetchCudaEp({ platform = os.platform(), packageName, env = process.env } = {}) {
|
|
92
|
+
if (env.MEMTRACE_SKIP_CUDA_EP === "1") {
|
|
93
|
+
return { fetch: false, reason: "MEMTRACE_SKIP_CUDA_EP=1" };
|
|
94
|
+
}
|
|
95
|
+
if (platform !== "win32") {
|
|
96
|
+
return { fetch: false, reason: `platform ${platform} (win32 only)` };
|
|
97
|
+
}
|
|
98
|
+
if (packageName !== CUDA_PACKAGE) {
|
|
99
|
+
return { fetch: false, reason: `platform package ${packageName} (only ${CUDA_PACKAGE})` };
|
|
100
|
+
}
|
|
101
|
+
return { fetch: true, reason: "win32 AVX2 package" };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** True when `spawnSync`-shaped result output looks like an NVIDIA GPU list. */
|
|
105
|
+
function nvidiaSmiSaysYes(result) {
|
|
106
|
+
return Boolean(result && result.status === 0 && /\bGPU \d+/.test(result.stdout || ""));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** True when a Win32_VideoController name dump mentions an NVIDIA adapter. */
|
|
110
|
+
function videoControllerSaysYes(result) {
|
|
111
|
+
return Boolean(result && result.status === 0 && /nvidia/i.test(result.stdout || ""));
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// ── Host probes ──────────────────────────────────────────────────────────────
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Best-effort NVIDIA detection on win32. `nvidia-smi -L` first (present
|
|
118
|
+
* whenever the NVIDIA driver is installed — exactly the hosts where the
|
|
119
|
+
* CUDA EP can load), then a CIM adapter-name query for driver installs
|
|
120
|
+
* that didn't put nvidia-smi on PATH. Ambiguity/errors → false: the
|
|
121
|
+
* download is 400 MB, so we only fetch on a positive signal, and
|
|
122
|
+
* `memtrace gpu install-cuda --force` exists for detection misses.
|
|
123
|
+
*/
|
|
124
|
+
function detectNvidiaGpu({ spawn = spawnSync } = {}) {
|
|
125
|
+
try {
|
|
126
|
+
const smi = spawn("nvidia-smi", ["-L"], { encoding: "utf8", timeout: 5000, windowsHide: true });
|
|
127
|
+
if (nvidiaSmiSaysYes(smi)) return true;
|
|
128
|
+
} catch (_) {
|
|
129
|
+
/* not on PATH — fall through to CIM */
|
|
130
|
+
}
|
|
131
|
+
try {
|
|
132
|
+
const ps = spawn(
|
|
133
|
+
"powershell",
|
|
134
|
+
[
|
|
135
|
+
"-NoProfile",
|
|
136
|
+
"-NonInteractive",
|
|
137
|
+
"-Command",
|
|
138
|
+
"(Get-CimInstance Win32_VideoController).Name",
|
|
139
|
+
],
|
|
140
|
+
{ encoding: "utf8", timeout: 10000, windowsHide: true }
|
|
141
|
+
);
|
|
142
|
+
return videoControllerSaysYes(ps);
|
|
143
|
+
} catch (_) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// ── Network ──────────────────────────────────────────────────────────────────
|
|
149
|
+
|
|
150
|
+
function requireFetch(fetchImpl) {
|
|
151
|
+
const f = fetchImpl || globalThis.fetch;
|
|
152
|
+
if (typeof f !== "function") {
|
|
153
|
+
throw new Error("global fetch unavailable (Node >= 18 required)");
|
|
154
|
+
}
|
|
155
|
+
return f;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
async function fetchText(url, { fetchImpl, timeoutMs = CHECKSUMS_TIMEOUT_MS } = {}) {
|
|
159
|
+
const f = requireFetch(fetchImpl);
|
|
160
|
+
const res = await f(url, {
|
|
161
|
+
redirect: "follow",
|
|
162
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
163
|
+
headers: { "user-agent": "memtrace-install" },
|
|
164
|
+
});
|
|
165
|
+
if (!res.ok) throw new Error(`HTTP ${res.status} for ${url}`);
|
|
166
|
+
return res.text();
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Stream `url` to `destPath`, returning the sha256 hex of the bytes
|
|
171
|
+
* written. Aborts when the connection stalls for `inactivityTimeoutMs`
|
|
172
|
+
* (no total cap — see header comment).
|
|
173
|
+
*/
|
|
174
|
+
async function downloadToFile(url, destPath, { fetchImpl, inactivityTimeoutMs = INACTIVITY_TIMEOUT_MS } = {}) {
|
|
175
|
+
const f = requireFetch(fetchImpl);
|
|
176
|
+
const controller = new AbortController();
|
|
177
|
+
let watchdog = null;
|
|
178
|
+
const armWatchdog = () => {
|
|
179
|
+
clearTimeout(watchdog);
|
|
180
|
+
watchdog = setTimeout(
|
|
181
|
+
() => controller.abort(new Error(`download stalled for ${inactivityTimeoutMs}ms`)),
|
|
182
|
+
inactivityTimeoutMs
|
|
183
|
+
);
|
|
184
|
+
if (watchdog.unref) watchdog.unref();
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
armWatchdog();
|
|
188
|
+
try {
|
|
189
|
+
const res = await f(url, {
|
|
190
|
+
redirect: "follow",
|
|
191
|
+
signal: controller.signal,
|
|
192
|
+
headers: { "user-agent": "memtrace-install" },
|
|
193
|
+
});
|
|
194
|
+
if (!res.ok) throw new Error(`HTTP ${res.status} for ${url}`);
|
|
195
|
+
if (!res.body) throw new Error(`empty response body for ${url}`);
|
|
196
|
+
|
|
197
|
+
const hash = crypto.createHash("sha256");
|
|
198
|
+
const out = fs.createWriteStream(destPath);
|
|
199
|
+
try {
|
|
200
|
+
const reader = res.body.getReader();
|
|
201
|
+
for (;;) {
|
|
202
|
+
const { done, value } = await reader.read();
|
|
203
|
+
if (done) break;
|
|
204
|
+
armWatchdog();
|
|
205
|
+
hash.update(value);
|
|
206
|
+
if (!out.write(value)) {
|
|
207
|
+
await new Promise((resolve, reject) => {
|
|
208
|
+
out.once("drain", resolve);
|
|
209
|
+
out.once("error", reject);
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
await new Promise((resolve, reject) => out.end((err) => (err ? reject(err) : resolve())));
|
|
214
|
+
} catch (e) {
|
|
215
|
+
out.destroy();
|
|
216
|
+
throw e;
|
|
217
|
+
}
|
|
218
|
+
return hash.digest("hex");
|
|
219
|
+
} finally {
|
|
220
|
+
clearTimeout(watchdog);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// ── Extraction ───────────────────────────────────────────────────────────────
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Expand the single-DLL zip into `destDir` with PowerShell's
|
|
228
|
+
* Expand-Archive (built into every supported Windows; Node has no zip
|
|
229
|
+
* reader and this module takes no deps). Returns the extracted DLL
|
|
230
|
+
* path. Throws with stderr context on failure.
|
|
231
|
+
*/
|
|
232
|
+
function extractDll(zipPath, destDir, { spawn = spawnSync } = {}) {
|
|
233
|
+
const result = spawn(
|
|
234
|
+
"powershell",
|
|
235
|
+
[
|
|
236
|
+
"-NoProfile",
|
|
237
|
+
"-NonInteractive",
|
|
238
|
+
"-Command",
|
|
239
|
+
// -LiteralPath: both paths come from mkdtemp and can contain
|
|
240
|
+
// characters PowerShell would otherwise glob.
|
|
241
|
+
`Expand-Archive -LiteralPath '${zipPath}' -DestinationPath '${destDir}' -Force`,
|
|
242
|
+
],
|
|
243
|
+
{ encoding: "utf8", timeout: 120_000, windowsHide: true }
|
|
244
|
+
);
|
|
245
|
+
if (result.status !== 0) {
|
|
246
|
+
const detail = (result.stderr || result.error?.message || "").trim().slice(0, 300);
|
|
247
|
+
throw new Error(`Expand-Archive failed (exit ${result.status})${detail ? `: ${detail}` : ""}`);
|
|
248
|
+
}
|
|
249
|
+
const dllPath = path.join(destDir, CUDA_EP_DLL);
|
|
250
|
+
if (!fs.existsSync(dllPath)) {
|
|
251
|
+
throw new Error(`${CUDA_EP_DLL} not found in archive`);
|
|
252
|
+
}
|
|
253
|
+
return dllPath;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// ── Orchestrator ─────────────────────────────────────────────────────────────
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Fetch + verify + place the CUDA EP DLL next to `binaryPath`.
|
|
260
|
+
* Idempotent: an existing DLL short-circuits unless `force`.
|
|
261
|
+
*
|
|
262
|
+
* Never throws for expected conditions — resolves to:
|
|
263
|
+
* {status: "installed", dllPath}
|
|
264
|
+
* {status: "already-installed", dllPath}
|
|
265
|
+
* {status: "skipped", reason} (no GPU / offline / asset absent)
|
|
266
|
+
* {status: "error", reason} (checksum mismatch, extract/place failure)
|
|
267
|
+
*/
|
|
268
|
+
async function installCudaEp({
|
|
269
|
+
binaryPath,
|
|
270
|
+
version,
|
|
271
|
+
env = process.env,
|
|
272
|
+
fetchImpl,
|
|
273
|
+
spawn = spawnSync,
|
|
274
|
+
detect, // injectable NVIDIA probe for tests
|
|
275
|
+
force = false,
|
|
276
|
+
log = () => {},
|
|
277
|
+
} = {}) {
|
|
278
|
+
const binDir = path.dirname(binaryPath);
|
|
279
|
+
const dllPath = path.join(binDir, CUDA_EP_DLL);
|
|
280
|
+
if (!force && fs.existsSync(dllPath)) {
|
|
281
|
+
return { status: "already-installed", dllPath };
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const hasNvidia = detect ? detect() : detectNvidiaGpu({ spawn });
|
|
285
|
+
if (!hasNvidia && !force) {
|
|
286
|
+
return { status: "skipped", reason: "no NVIDIA GPU detected" };
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const urls = releaseAssetUrls(version, env.MEMTRACE_CUDA_EP_BASE_URL);
|
|
290
|
+
|
|
291
|
+
// checksums.txt first: a ~1 KB fetch that doubles as the offline
|
|
292
|
+
// probe, so we never start a 400 MB transfer we can't verify.
|
|
293
|
+
let checksumsText;
|
|
294
|
+
try {
|
|
295
|
+
checksumsText = await fetchText(urls.checksumsUrl, { fetchImpl });
|
|
296
|
+
} catch (e) {
|
|
297
|
+
return { status: "skipped", reason: `release checksums unreachable (${e.message})` };
|
|
298
|
+
}
|
|
299
|
+
const expected = parseChecksums(checksumsText, CUDA_EP_ASSET);
|
|
300
|
+
if (!expected) {
|
|
301
|
+
return { status: "skipped", reason: `release v${version} has no ${CUDA_EP_ASSET}` };
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const workDir = fs.mkdtempSync(path.join(os.tmpdir(), "memtrace-cuda-ep-"));
|
|
305
|
+
try {
|
|
306
|
+
const zipPath = path.join(workDir, CUDA_EP_ASSET);
|
|
307
|
+
log(`memtrace: NVIDIA GPU detected — downloading CUDA execution provider (~400 MB, one-time)…`);
|
|
308
|
+
let actual;
|
|
309
|
+
try {
|
|
310
|
+
actual = await downloadToFile(urls.zipUrl, zipPath, { fetchImpl });
|
|
311
|
+
} catch (e) {
|
|
312
|
+
return { status: "skipped", reason: `download failed (${e.message})` };
|
|
313
|
+
}
|
|
314
|
+
if (actual !== expected) {
|
|
315
|
+
return { status: "error", reason: `sha256 mismatch for ${CUDA_EP_ASSET}: expected ${expected}, got ${actual}` };
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
let extracted;
|
|
319
|
+
try {
|
|
320
|
+
extracted = extractDll(zipPath, workDir, { spawn });
|
|
321
|
+
} catch (e) {
|
|
322
|
+
return { status: "error", reason: e.message };
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Copy into place via a temp name + rename so a crash mid-copy
|
|
326
|
+
// never leaves a truncated DLL where the engine's probe finds it.
|
|
327
|
+
const staging = path.join(binDir, `.${CUDA_EP_DLL}.download`);
|
|
328
|
+
try {
|
|
329
|
+
fs.copyFileSync(extracted, staging);
|
|
330
|
+
fs.renameSync(staging, dllPath);
|
|
331
|
+
} catch (e) {
|
|
332
|
+
try { fs.rmSync(staging, { force: true }); } catch (_) { /* best-effort */ }
|
|
333
|
+
return { status: "error", reason: `could not place DLL in ${binDir} (${e.message})` };
|
|
334
|
+
}
|
|
335
|
+
return { status: "installed", dllPath };
|
|
336
|
+
} finally {
|
|
337
|
+
try { fs.rmSync(workDir, { recursive: true, force: true }); } catch (_) { /* best-effort */ }
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
module.exports = {
|
|
342
|
+
CUDA_EP_ASSET,
|
|
343
|
+
CUDA_EP_DLL,
|
|
344
|
+
CUDA_PACKAGE,
|
|
345
|
+
RELEASE_BASE_URL,
|
|
346
|
+
releaseAssetUrls,
|
|
347
|
+
parseChecksums,
|
|
348
|
+
shouldFetchCudaEp,
|
|
349
|
+
nvidiaSmiSaysYes,
|
|
350
|
+
videoControllerSaysYes,
|
|
351
|
+
detectNvidiaGpu,
|
|
352
|
+
downloadToFile,
|
|
353
|
+
extractDll,
|
|
354
|
+
installCudaEp,
|
|
355
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "memtrace",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.2",
|
|
4
4
|
"description": "Code intelligence graph — MCP server + AI agent skills + visualization UI",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|
|
@@ -39,12 +39,12 @@
|
|
|
39
39
|
"fs-extra": "^11.0.0"
|
|
40
40
|
},
|
|
41
41
|
"optionalDependencies": {
|
|
42
|
-
"@memtrace/darwin-arm64": "0.8.
|
|
43
|
-
"@memtrace/linux-x64": "0.8.
|
|
44
|
-
"@memtrace/linux-arm64": "0.8.
|
|
45
|
-
"@memtrace/win32-x64": "0.8.
|
|
46
|
-
"@memtrace/linux-x64-noavx2": "0.8.
|
|
47
|
-
"@memtrace/win32-x64-noavx2": "0.8.
|
|
42
|
+
"@memtrace/darwin-arm64": "0.8.2",
|
|
43
|
+
"@memtrace/linux-x64": "0.8.2",
|
|
44
|
+
"@memtrace/linux-arm64": "0.8.2",
|
|
45
|
+
"@memtrace/win32-x64": "0.8.2",
|
|
46
|
+
"@memtrace/linux-x64-noavx2": "0.8.2",
|
|
47
|
+
"@memtrace/win32-x64-noavx2": "0.8.2"
|
|
48
48
|
},
|
|
49
49
|
"engines": {
|
|
50
50
|
"node": ">=18"
|