@chikhamx/voidx 3.6.0 → 3.7.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/bin/postinstall.js +35 -60
- package/bin/runtime-install.js +261 -0
- package/bin/voidx.js +34 -40
- package/package.json +2 -2
package/bin/postinstall.js
CHANGED
|
@@ -4,14 +4,19 @@
|
|
|
4
4
|
// Post-install: download a standalone Python, create venv, pip install voidx.
|
|
5
5
|
// Uses only the bundled Python — never falls back to the system Python.
|
|
6
6
|
|
|
7
|
-
const { createWriteStream, existsSync, mkdirSync, readFileSync,
|
|
7
|
+
const { createWriteStream, existsSync, mkdirSync, readFileSync, unlinkSync, rmSync } = require("fs");
|
|
8
8
|
const { spawnSync } = require("child_process");
|
|
9
|
-
const { join
|
|
9
|
+
const { join } = require("path");
|
|
10
10
|
const os = require("os");
|
|
11
|
-
const fs = require("fs");
|
|
12
11
|
const path = require("path");
|
|
13
12
|
|
|
14
13
|
const pkg = require("../package.json");
|
|
14
|
+
const {
|
|
15
|
+
installVerifyAndRepair,
|
|
16
|
+
resolveBundledCliWheel,
|
|
17
|
+
verifyPair,
|
|
18
|
+
writeMarkerAtomic,
|
|
19
|
+
} = require("./runtime-install");
|
|
15
20
|
|
|
16
21
|
// ── Python build metadata ──────────────────────────────────────────────────
|
|
17
22
|
// Pin to a specific python-build-standalone release tag and CPython version.
|
|
@@ -248,13 +253,8 @@ function readMarker(markerPath) {
|
|
|
248
253
|
try { return readFileSync(markerPath, "utf8"); } catch { return ""; }
|
|
249
254
|
}
|
|
250
255
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
writeFileSync(markerPath, content);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// ── pip install ────────────────────────────────────────────────────────────
|
|
257
|
-
function pipInstall(venvPython, packageSpec, env) {
|
|
256
|
+
// ── pip setup ──────────────────────────────────────────────────────────────
|
|
257
|
+
function upgradePip(venvPython, env) {
|
|
258
258
|
// Upgrade pip first to avoid resolver bugs in old versions
|
|
259
259
|
const pipUpgradeEnv = Object.assign({}, env, {
|
|
260
260
|
PIP_NO_INPUT: "1",
|
|
@@ -269,39 +269,6 @@ function pipInstall(venvPython, packageSpec, env) {
|
|
|
269
269
|
if (pipUpgradeResult.error || pipUpgradeResult.status !== 0) {
|
|
270
270
|
console.error(" ⚠️ Failed to upgrade pip, continuing with current version…");
|
|
271
271
|
}
|
|
272
|
-
|
|
273
|
-
const pipEnv = Object.assign({}, env, {
|
|
274
|
-
PIP_NO_INPUT: "1",
|
|
275
|
-
PIP_DISABLE_PIP_VERSION_CHECK: "1",
|
|
276
|
-
PYTHON_KEYRING_BACKEND: "keyring.backends.null.Keyring",
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
const pipArgs = ["-m", "pip", "install", "--upgrade", "--no-cache-dir", "--progress-bar", "on"];
|
|
280
|
-
|
|
281
|
-
// Support custom PyPI index for users behind firewalls or in regions with slow PyPI access
|
|
282
|
-
const pipIndex = env.VOIDX_NPM_PIP_INDEX;
|
|
283
|
-
if (pipIndex) {
|
|
284
|
-
pipArgs.push("-i", pipIndex);
|
|
285
|
-
// Extract host for --trusted-host when using a custom index
|
|
286
|
-
try {
|
|
287
|
-
const indexUrl = new URL(pipIndex);
|
|
288
|
-
pipArgs.push("--trusted-host", indexUrl.hostname);
|
|
289
|
-
} catch {}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
pipArgs.push(packageSpec);
|
|
293
|
-
|
|
294
|
-
const result = spawnSync(
|
|
295
|
-
venvPython,
|
|
296
|
-
pipArgs,
|
|
297
|
-
{ encoding: "utf8", stdio: "inherit", windowsHide: true, env: pipEnv }
|
|
298
|
-
);
|
|
299
|
-
if (result.error) {
|
|
300
|
-
throw new Error(`pip install failed: ${result.error.message}`);
|
|
301
|
-
}
|
|
302
|
-
if (result.status !== 0) {
|
|
303
|
-
throw new Error("pip install failed. See errors above.");
|
|
304
|
-
}
|
|
305
272
|
}
|
|
306
273
|
|
|
307
274
|
// ── Main ───────────────────────────────────────────────────────────────────
|
|
@@ -322,8 +289,17 @@ async function main() {
|
|
|
322
289
|
|
|
323
290
|
// Already set up and up-to-date?
|
|
324
291
|
if (existsSync(executable) && readMarker(markerPath) === marker) {
|
|
325
|
-
|
|
326
|
-
|
|
292
|
+
const verification = verifyPair({
|
|
293
|
+
venvPython,
|
|
294
|
+
executable,
|
|
295
|
+
expectedVersion: pkg.version,
|
|
296
|
+
env,
|
|
297
|
+
});
|
|
298
|
+
if (verification.ok) {
|
|
299
|
+
console.error(`\n✅ voidx ${pkg.version} ready (cached)\n`);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
console.error(` ⚠️ Cached environment is invalid: ${verification.message}`);
|
|
327
303
|
}
|
|
328
304
|
|
|
329
305
|
// Step 1: Download bundled Python (required — no system Python fallback)
|
|
@@ -359,7 +335,7 @@ async function main() {
|
|
|
359
335
|
console.error(" Extraction complete.");
|
|
360
336
|
|
|
361
337
|
// Clean up archive to save disk
|
|
362
|
-
try {
|
|
338
|
+
try { unlinkSync(archivePath); } catch {}
|
|
363
339
|
} catch (err) {
|
|
364
340
|
// Clean up partial archive on failure
|
|
365
341
|
try { unlinkSync(archivePath); } catch {}
|
|
@@ -403,23 +379,22 @@ async function main() {
|
|
|
403
379
|
}
|
|
404
380
|
}
|
|
405
381
|
|
|
406
|
-
// Step 3:
|
|
407
|
-
console.error(" [3/
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
// Step 4: pip install bundled voidx_cli wheel (terminal frontend)
|
|
411
|
-
console.error(" [4/4] Installing voidx_cli frontend…");
|
|
382
|
+
// Step 3: install and verify the exact core/CLI pair
|
|
383
|
+
console.error(" [3/3] Installing and verifying voidx…");
|
|
384
|
+
upgradePip(venvPython, env);
|
|
412
385
|
const npmDir = path.resolve(__dirname, "..");
|
|
413
|
-
const
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
386
|
+
const wheelPath = resolveBundledCliWheel(npmDir, pkg.version);
|
|
387
|
+
installVerifyAndRepair({
|
|
388
|
+
venvPython,
|
|
389
|
+
executable,
|
|
390
|
+
coreSpec: packageSpec,
|
|
391
|
+
cliSpec: wheelPath,
|
|
392
|
+
expectedVersion: pkg.version,
|
|
393
|
+
env,
|
|
394
|
+
});
|
|
420
395
|
|
|
421
396
|
// Done
|
|
422
|
-
|
|
397
|
+
writeMarkerAtomic(markerPath, marker);
|
|
423
398
|
console.error(`\n✅ voidx ${pkg.version} installed! Run: voidx\n`);
|
|
424
399
|
}
|
|
425
400
|
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const { spawnSync } = require("child_process");
|
|
7
|
+
|
|
8
|
+
const VERIFY_PROBE = String.raw`
|
|
9
|
+
import importlib
|
|
10
|
+
import json
|
|
11
|
+
import os
|
|
12
|
+
import re
|
|
13
|
+
import subprocess
|
|
14
|
+
import sys
|
|
15
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
16
|
+
|
|
17
|
+
current_directory = os.path.normcase(os.path.realpath(os.getcwd()))
|
|
18
|
+
sys.path = [
|
|
19
|
+
entry
|
|
20
|
+
for entry in sys.path
|
|
21
|
+
if entry and os.path.normcase(os.path.realpath(entry)) != current_directory
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
def installed_version(name):
|
|
25
|
+
try:
|
|
26
|
+
return version(name)
|
|
27
|
+
except PackageNotFoundError:
|
|
28
|
+
return None
|
|
29
|
+
except Exception:
|
|
30
|
+
return None
|
|
31
|
+
|
|
32
|
+
payload = {
|
|
33
|
+
"core_version": installed_version("voidx"),
|
|
34
|
+
"cli_version": installed_version("voidx-cli"),
|
|
35
|
+
"core_import": False,
|
|
36
|
+
"cli_import": False,
|
|
37
|
+
"entrypoint_ok": False,
|
|
38
|
+
"entrypoint_version": None,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
importlib.import_module("voidx")
|
|
43
|
+
payload["core_import"] = True
|
|
44
|
+
except Exception as exc:
|
|
45
|
+
payload["core_error"] = str(exc)
|
|
46
|
+
|
|
47
|
+
try:
|
|
48
|
+
importlib.import_module("voidx_cli")
|
|
49
|
+
payload["cli_import"] = True
|
|
50
|
+
except Exception as exc:
|
|
51
|
+
payload["cli_error"] = str(exc)
|
|
52
|
+
|
|
53
|
+
try:
|
|
54
|
+
completed = subprocess.run(
|
|
55
|
+
[sys.argv[1], "--version"],
|
|
56
|
+
capture_output=True,
|
|
57
|
+
text=True,
|
|
58
|
+
timeout=30,
|
|
59
|
+
)
|
|
60
|
+
output = (completed.stdout or completed.stderr or "").strip()
|
|
61
|
+
payload["entrypoint_ok"] = completed.returncode == 0
|
|
62
|
+
match = re.search(r"\d+\.\d+\.\d+(?:[A-Za-z0-9.+-]*)?", output)
|
|
63
|
+
payload["entrypoint_version"] = match.group(0) if match else None
|
|
64
|
+
except Exception as exc:
|
|
65
|
+
payload["entrypoint_error"] = str(exc)
|
|
66
|
+
|
|
67
|
+
print(json.dumps(payload))
|
|
68
|
+
`;
|
|
69
|
+
|
|
70
|
+
function resolveBundledCliWheel(npmDir, version) {
|
|
71
|
+
const filename = `voidx_cli-${version}-py3-none-any.whl`;
|
|
72
|
+
const wheelPath = path.join(npmDir, filename);
|
|
73
|
+
if (!fs.existsSync(wheelPath)) {
|
|
74
|
+
throw new Error(`Bundled ${filename} not found.`);
|
|
75
|
+
}
|
|
76
|
+
return wheelPath;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function pipEnvironment(env) {
|
|
80
|
+
return {
|
|
81
|
+
...env,
|
|
82
|
+
PIP_NO_INPUT: "1",
|
|
83
|
+
PIP_DISABLE_PIP_VERSION_CHECK: "1",
|
|
84
|
+
PYTHON_KEYRING_BACKEND: "keyring.backends.null.Keyring",
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function buildPipArgs({ coreSpec, cliSpec, forceReinstall, env }) {
|
|
89
|
+
const args = [
|
|
90
|
+
"-m",
|
|
91
|
+
"pip",
|
|
92
|
+
"install",
|
|
93
|
+
"--upgrade",
|
|
94
|
+
"--no-cache-dir",
|
|
95
|
+
"--progress-bar",
|
|
96
|
+
"on",
|
|
97
|
+
];
|
|
98
|
+
if (forceReinstall) {
|
|
99
|
+
args.push("--force-reinstall");
|
|
100
|
+
}
|
|
101
|
+
const pipIndex = env.VOIDX_NPM_PIP_INDEX;
|
|
102
|
+
if (pipIndex) {
|
|
103
|
+
args.push("-i", pipIndex);
|
|
104
|
+
try {
|
|
105
|
+
args.push("--trusted-host", new URL(pipIndex).hostname);
|
|
106
|
+
} catch {}
|
|
107
|
+
}
|
|
108
|
+
args.push(coreSpec, cliSpec);
|
|
109
|
+
return args;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function installPair({
|
|
113
|
+
venvPython,
|
|
114
|
+
coreSpec,
|
|
115
|
+
cliSpec,
|
|
116
|
+
env,
|
|
117
|
+
forceReinstall = false,
|
|
118
|
+
runner = spawnSync,
|
|
119
|
+
}) {
|
|
120
|
+
const result = runner(
|
|
121
|
+
venvPython,
|
|
122
|
+
buildPipArgs({ coreSpec, cliSpec, forceReinstall, env }),
|
|
123
|
+
{
|
|
124
|
+
encoding: "utf8",
|
|
125
|
+
stdio: "inherit",
|
|
126
|
+
windowsHide: true,
|
|
127
|
+
env: pipEnvironment(env),
|
|
128
|
+
}
|
|
129
|
+
);
|
|
130
|
+
if (result.error) {
|
|
131
|
+
throw new Error(`pip install failed: ${result.error.message}`);
|
|
132
|
+
}
|
|
133
|
+
if (result.status !== 0) {
|
|
134
|
+
throw new Error("pip install failed. See errors above.");
|
|
135
|
+
}
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function verifyPair({
|
|
140
|
+
venvPython,
|
|
141
|
+
executable,
|
|
142
|
+
expectedVersion,
|
|
143
|
+
env,
|
|
144
|
+
runner = spawnSync,
|
|
145
|
+
}) {
|
|
146
|
+
const result = runner(
|
|
147
|
+
venvPython,
|
|
148
|
+
["-c", VERIFY_PROBE, executable],
|
|
149
|
+
{
|
|
150
|
+
encoding: "utf8",
|
|
151
|
+
windowsHide: true,
|
|
152
|
+
env,
|
|
153
|
+
}
|
|
154
|
+
);
|
|
155
|
+
if (result.error || result.status !== 0) {
|
|
156
|
+
const detail = result.error
|
|
157
|
+
? result.error.message
|
|
158
|
+
: (result.stderr || result.stdout || `verification exited ${result.status}`).trim();
|
|
159
|
+
return {
|
|
160
|
+
ok: false,
|
|
161
|
+
coreVersion: null,
|
|
162
|
+
cliVersion: null,
|
|
163
|
+
message: `Installation verification failed: ${detail}`,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
let payload;
|
|
168
|
+
try {
|
|
169
|
+
payload = JSON.parse((result.stdout || "").trim());
|
|
170
|
+
} catch (error) {
|
|
171
|
+
return {
|
|
172
|
+
ok: false,
|
|
173
|
+
coreVersion: null,
|
|
174
|
+
cliVersion: null,
|
|
175
|
+
message: `Installation verification returned invalid data: ${error.message}`,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const coreVersion = payload.core_version || null;
|
|
180
|
+
const cliVersion = payload.cli_version || null;
|
|
181
|
+
const failures = [];
|
|
182
|
+
if (!coreVersion) failures.push("voidx is not installed");
|
|
183
|
+
if (!cliVersion) failures.push("voidx-cli is not installed");
|
|
184
|
+
if (!payload.core_import) failures.push("voidx is not importable");
|
|
185
|
+
if (!payload.cli_import) failures.push("voidx-cli is not importable");
|
|
186
|
+
if (!payload.entrypoint_ok) failures.push("voidx entry point failed");
|
|
187
|
+
if (coreVersion && cliVersion && coreVersion !== cliVersion) {
|
|
188
|
+
failures.push(`package versions differ (${coreVersion} != ${cliVersion})`);
|
|
189
|
+
}
|
|
190
|
+
if (coreVersion && payload.entrypoint_version !== coreVersion) {
|
|
191
|
+
failures.push(
|
|
192
|
+
`entry point version differs (${payload.entrypoint_version || "missing"} != ${coreVersion})`
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
if (coreVersion !== expectedVersion) {
|
|
196
|
+
failures.push(`voidx version is ${coreVersion || "missing"}, expected ${expectedVersion}`);
|
|
197
|
+
}
|
|
198
|
+
if (cliVersion !== expectedVersion) {
|
|
199
|
+
failures.push(`voidx-cli version is ${cliVersion || "missing"}, expected ${expectedVersion}`);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return {
|
|
203
|
+
ok: failures.length === 0,
|
|
204
|
+
coreVersion,
|
|
205
|
+
cliVersion,
|
|
206
|
+
message: failures.length === 0
|
|
207
|
+
? `Verified voidx and voidx-cli ${expectedVersion}`
|
|
208
|
+
: failures.join("; "),
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function installVerifyAndRepair(options) {
|
|
213
|
+
const installFn = options.installFn || installPair;
|
|
214
|
+
const verifyFn = options.verifyFn || verifyPair;
|
|
215
|
+
let initialInstallError = null;
|
|
216
|
+
try {
|
|
217
|
+
installFn({ ...options, forceReinstall: false });
|
|
218
|
+
} catch (error) {
|
|
219
|
+
initialInstallError = error;
|
|
220
|
+
}
|
|
221
|
+
let verification = verifyFn(options);
|
|
222
|
+
if (verification.ok) {
|
|
223
|
+
return verification;
|
|
224
|
+
}
|
|
225
|
+
let repairInstallError = null;
|
|
226
|
+
try {
|
|
227
|
+
installFn({ ...options, forceReinstall: true });
|
|
228
|
+
} catch (error) {
|
|
229
|
+
repairInstallError = error;
|
|
230
|
+
}
|
|
231
|
+
verification = verifyFn(options);
|
|
232
|
+
if (!verification.ok) {
|
|
233
|
+
const installError = repairInstallError || initialInstallError;
|
|
234
|
+
const detail = installError
|
|
235
|
+
? `${verification.message}; ${installError.message}`
|
|
236
|
+
: verification.message;
|
|
237
|
+
throw new Error(detail);
|
|
238
|
+
}
|
|
239
|
+
return verification;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function writeMarkerAtomic(markerPath, marker) {
|
|
243
|
+
fs.mkdirSync(path.dirname(markerPath), { recursive: true });
|
|
244
|
+
const temporaryPath = `${markerPath}.${process.pid}.tmp`;
|
|
245
|
+
try {
|
|
246
|
+
fs.writeFileSync(temporaryPath, marker);
|
|
247
|
+
fs.renameSync(temporaryPath, markerPath);
|
|
248
|
+
} finally {
|
|
249
|
+
try {
|
|
250
|
+
fs.unlinkSync(temporaryPath);
|
|
251
|
+
} catch {}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
module.exports = {
|
|
256
|
+
installPair,
|
|
257
|
+
installVerifyAndRepair,
|
|
258
|
+
resolveBundledCliWheel,
|
|
259
|
+
verifyPair,
|
|
260
|
+
writeMarkerAtomic,
|
|
261
|
+
};
|
package/bin/voidx.js
CHANGED
|
@@ -7,6 +7,12 @@ const os = require("os");
|
|
|
7
7
|
const path = require("path");
|
|
8
8
|
|
|
9
9
|
const pkg = require("../package.json");
|
|
10
|
+
const {
|
|
11
|
+
installVerifyAndRepair,
|
|
12
|
+
resolveBundledCliWheel,
|
|
13
|
+
verifyPair,
|
|
14
|
+
writeMarkerAtomic,
|
|
15
|
+
} = require("./runtime-install");
|
|
10
16
|
|
|
11
17
|
// ── Configuration ──────────────────────────────────────────────────────────
|
|
12
18
|
|
|
@@ -190,6 +196,7 @@ function resolveVoidxExecutable(venvDir) {
|
|
|
190
196
|
|
|
191
197
|
function ensureVenv(python, venvDir, env) {
|
|
192
198
|
const executable = resolveVoidxExecutable(venvDir);
|
|
199
|
+
const venvPython = resolveVenvPython(venvDir);
|
|
193
200
|
if (env.VOIDX_NPM_SKIP_BOOTSTRAP === "1") {
|
|
194
201
|
if (!fs.existsSync(executable)) {
|
|
195
202
|
throw new Error(`voidx executable not found in ${venvDir}.`);
|
|
@@ -199,16 +206,26 @@ function ensureVenv(python, venvDir, env) {
|
|
|
199
206
|
|
|
200
207
|
const markerPath = path.join(venvDir, ".voidx-install-version");
|
|
201
208
|
const marker = `${pkg.version}\n${PBS_TAG}\n${PBS_CPYTHON}\n`;
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
209
|
+
let needsInstall = !fs.existsSync(executable) || readMarker(markerPath) !== marker;
|
|
210
|
+
if (fs.existsSync(executable) && readMarker(markerPath) === marker) {
|
|
211
|
+
const verification = verifyPair({
|
|
212
|
+
venvPython,
|
|
213
|
+
executable,
|
|
214
|
+
expectedVersion: pkg.version,
|
|
215
|
+
env,
|
|
216
|
+
});
|
|
217
|
+
if (verification.ok) {
|
|
218
|
+
debug(env, `Using cached environment at ${venvDir}`);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
console.error(` Cached environment is invalid: ${verification.message}`);
|
|
222
|
+
needsInstall = true;
|
|
205
223
|
}
|
|
206
224
|
|
|
207
225
|
// v2 → v3 migration: clean up legacy data before first v3 run
|
|
208
226
|
runV2CleanupIfNeeded(venvDir, env);
|
|
209
227
|
|
|
210
228
|
fs.mkdirSync(path.dirname(venvDir), { recursive: true });
|
|
211
|
-
const venvPython = resolveVenvPython(venvDir);
|
|
212
229
|
|
|
213
230
|
// If venv exists but is corrupted (python binary missing), nuke and rebuild
|
|
214
231
|
if (fs.existsSync(venvDir) && !fs.existsSync(venvPython)) {
|
|
@@ -242,7 +259,7 @@ function ensureVenv(python, venvDir, env) {
|
|
|
242
259
|
}
|
|
243
260
|
}
|
|
244
261
|
|
|
245
|
-
if (
|
|
262
|
+
if (needsInstall) {
|
|
246
263
|
const packageSpec = env.VOIDX_NPM_PACKAGE_SPEC || `voidx==${pkg.version}`;
|
|
247
264
|
console.error(
|
|
248
265
|
`\n📦 Downloading ${packageSpec} and dependencies… ` +
|
|
@@ -264,49 +281,26 @@ function ensureVenv(python, venvDir, env) {
|
|
|
264
281
|
console.error(" ⚠️ Failed to upgrade pip, continuing with current version…");
|
|
265
282
|
}
|
|
266
283
|
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
PYTHON_KEYRING_BACKEND: "keyring.backends.null.Keyring",
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
const pipArgs = ["-m", "pip", "install", "--upgrade", "--no-cache-dir", "--progress-bar", "on"];
|
|
274
|
-
|
|
275
|
-
// Support custom PyPI index
|
|
276
|
-
const pipIndex = env.VOIDX_NPM_PIP_INDEX;
|
|
277
|
-
if (pipIndex) {
|
|
278
|
-
pipArgs.push("-i", pipIndex);
|
|
279
|
-
try {
|
|
280
|
-
const indexUrl = new URL(pipIndex);
|
|
281
|
-
pipArgs.push("--trusted-host", indexUrl.hostname);
|
|
282
|
-
} catch {}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
pipArgs.push(packageSpec);
|
|
286
|
-
|
|
287
|
-
const result = spawnSync(
|
|
284
|
+
const npmDir = path.resolve(__dirname, "..");
|
|
285
|
+
const wheelPath = resolveBundledCliWheel(npmDir, pkg.version);
|
|
286
|
+
installVerifyAndRepair({
|
|
288
287
|
venvPython,
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
);
|
|
296
|
-
}
|
|
297
|
-
if (result.status !== 0) {
|
|
298
|
-
throw new Error(`Failed to install ${packageSpec}. See errors above.`);
|
|
299
|
-
}
|
|
288
|
+
executable,
|
|
289
|
+
coreSpec: packageSpec,
|
|
290
|
+
cliSpec: wheelPath,
|
|
291
|
+
expectedVersion: pkg.version,
|
|
292
|
+
env,
|
|
293
|
+
});
|
|
300
294
|
}
|
|
301
295
|
|
|
302
|
-
|
|
296
|
+
writeMarkerAtomic(markerPath, marker);
|
|
303
297
|
}
|
|
304
298
|
|
|
305
299
|
// ── v2 → v3 migration ─────────────────────────────────────────────────────
|
|
306
300
|
|
|
307
301
|
function runV2CleanupIfNeeded(venvDir, env) {
|
|
308
302
|
const markerPath = path.join(venvDir, ".voidx-install-version");
|
|
309
|
-
const oldMarker =
|
|
303
|
+
const oldMarker = readMarker(markerPath).trim();
|
|
310
304
|
if (!oldMarker) return; // fresh install, nothing to migrate
|
|
311
305
|
|
|
312
306
|
const oldVersion = parseVersion(oldMarker.split("\n")[0]);
|
|
@@ -360,7 +354,7 @@ function runV2CleanupIfNeeded(venvDir, env) {
|
|
|
360
354
|
|
|
361
355
|
// ── Helpers ────────────────────────────────────────────────────────────────
|
|
362
356
|
|
|
363
|
-
function
|
|
357
|
+
function readMarker(filePath) {
|
|
364
358
|
try {
|
|
365
359
|
return fs.readFileSync(filePath, "utf8");
|
|
366
360
|
} catch {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chikhamx/voidx",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.7.0",
|
|
4
4
|
"description": "npm launcher for voidx, a terminal AI coding agent.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
@@ -31,6 +31,6 @@
|
|
|
31
31
|
],
|
|
32
32
|
"scripts": {
|
|
33
33
|
"postinstall": "node bin/postinstall.js",
|
|
34
|
-
"check": "node --check bin/voidx.js && node --check bin/postinstall.js"
|
|
34
|
+
"check": "node --check bin/voidx.js && node --check bin/postinstall.js && node --check bin/runtime-install.js"
|
|
35
35
|
}
|
|
36
36
|
}
|