@vantaloom/cli 0.2.0 → 0.3.1
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/package.json +1 -1
- package/src/cli.mjs +136 -10
package/package.json
CHANGED
package/src/cli.mjs
CHANGED
|
@@ -20,6 +20,9 @@ const installedConfigPath = path.join(cliRoot, "config.json")
|
|
|
20
20
|
const defaultReleaseTag = "runtime-latest"
|
|
21
21
|
const defaultRepo = "Timefiles404/Vantaloom-next"
|
|
22
22
|
const defaultNpmRegistry = "https://registry.npmjs.org"
|
|
23
|
+
const fallbackNpmRegistries = [
|
|
24
|
+
"https://registry.npmmirror.com",
|
|
25
|
+
]
|
|
23
26
|
|
|
24
27
|
export async function main(argv) {
|
|
25
28
|
const command = argv[0] ?? "help"
|
|
@@ -186,6 +189,10 @@ async function applyPackage(packageRoot, prefix, options) {
|
|
|
186
189
|
spawnSync(existingCtl, ["stop", "--prefix", prefix], { stdio: "inherit" })
|
|
187
190
|
}
|
|
188
191
|
|
|
192
|
+
// Kill lingering tray process that may hold locks on bin/ (older versions
|
|
193
|
+
// don't write tray.pid, so vantaloomctl stop won't find them).
|
|
194
|
+
killTrayProcess(prefix)
|
|
195
|
+
|
|
189
196
|
for (const name of ["bin", "web", "cli"]) {
|
|
190
197
|
removeKnownPath(path.join(prefix, name), prefix)
|
|
191
198
|
await cp(path.join(packageRoot, name), path.join(prefix, name), {
|
|
@@ -226,7 +233,8 @@ async function syncFromNpmRegistry(options, action) {
|
|
|
226
233
|
const installedConfig = readInstalledConfig(prefix)
|
|
227
234
|
const runtimePackage = options.runtimePackage || installedConfig.runtimePackage || runtimePackageName(platformId())
|
|
228
235
|
const runtimeVersion = options.runtimeVersion || installedConfig.runtimeVersion || "latest"
|
|
229
|
-
const
|
|
236
|
+
const explicitRegistry = options.npmRegistry || installedConfig.npmRegistry
|
|
237
|
+
const registry = normalizeRegistry(explicitRegistry || detectNpmRegistry() || defaultNpmRegistry)
|
|
230
238
|
const tempRoot = mkdtempSync(path.join(os.tmpdir(), "vantaloom-npm-"))
|
|
231
239
|
|
|
232
240
|
try {
|
|
@@ -234,7 +242,11 @@ async function syncFromNpmRegistry(options, action) {
|
|
|
234
242
|
const archive = path.join(tempRoot, `${packageBasename(runtimePackage)}-${runtimeVersion}.tgz`)
|
|
235
243
|
mkdirSync(extractRoot, { recursive: true })
|
|
236
244
|
|
|
237
|
-
const resolved = await
|
|
245
|
+
const resolved = await resolveNpmPackageWithFallback({
|
|
246
|
+
registries: explicitRegistry ? [registry] : [registry, ...fallbackNpmRegistries.map(normalizeRegistry)],
|
|
247
|
+
name: runtimePackage,
|
|
248
|
+
version: runtimeVersion,
|
|
249
|
+
})
|
|
238
250
|
await downloadNpmTarball({
|
|
239
251
|
tarballUrl: resolved.tarball,
|
|
240
252
|
target: archive,
|
|
@@ -248,13 +260,14 @@ async function syncFromNpmRegistry(options, action) {
|
|
|
248
260
|
noStart: options.noStart,
|
|
249
261
|
runtimePackage,
|
|
250
262
|
runtimeVersion: options.runtimeVersion ? resolved.version : "latest",
|
|
251
|
-
npmRegistry: registry,
|
|
263
|
+
npmRegistry: resolved.registry,
|
|
252
264
|
update: action === "update",
|
|
253
265
|
})
|
|
254
266
|
|
|
255
267
|
console.log(`${action === "update" ? "updated" : "installed"} Vantaloom: ${prefix}`)
|
|
256
268
|
console.log(`version: ${version}`)
|
|
257
269
|
console.log(`source: ${runtimePackage}@${resolved.version}`)
|
|
270
|
+
console.log(`registry: ${resolved.registry}`)
|
|
258
271
|
console.log(`run: ${displayCommand(prefix)} status`)
|
|
259
272
|
} finally {
|
|
260
273
|
removeKnownPath(tempRoot, os.tmpdir())
|
|
@@ -346,14 +359,95 @@ async function downloadReleaseAsset({ repo, releaseTag, assetName, target, token
|
|
|
346
359
|
await writeFile(target, buffer)
|
|
347
360
|
}
|
|
348
361
|
|
|
362
|
+
function detectNpmRegistry() {
|
|
363
|
+
// 1. NPM_CONFIG_REGISTRY env var (highest priority, set by npm/npx when running)
|
|
364
|
+
if (process.env.NPM_CONFIG_REGISTRY) {
|
|
365
|
+
return process.env.npm_config_registry || process.env.NPM_CONFIG_REGISTRY
|
|
366
|
+
}
|
|
367
|
+
// npm also sets the lowercase variant
|
|
368
|
+
if (process.env.npm_config_registry) {
|
|
369
|
+
return process.env.npm_config_registry
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// 2. Read user .npmrc
|
|
373
|
+
try {
|
|
374
|
+
const npmrcPaths = [
|
|
375
|
+
path.join(os.homedir(), ".npmrc"),
|
|
376
|
+
]
|
|
377
|
+
// Also check project-level .npmrc
|
|
378
|
+
const localNpmrc = path.resolve(".npmrc")
|
|
379
|
+
if (localNpmrc !== npmrcPaths[0]) {
|
|
380
|
+
npmrcPaths.unshift(localNpmrc)
|
|
381
|
+
}
|
|
382
|
+
for (const npmrcPath of npmrcPaths) {
|
|
383
|
+
if (existsSync(npmrcPath)) {
|
|
384
|
+
const content = readFileSync(npmrcPath, "utf8")
|
|
385
|
+
const match = content.match(/^\s*registry\s*=\s*(.+)/m)
|
|
386
|
+
if (match) {
|
|
387
|
+
return match[1].trim()
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
} catch {
|
|
392
|
+
// Ignore .npmrc read errors
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
return ""
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
async function resolveNpmPackageWithFallback({ registries, name, version }) {
|
|
399
|
+
const errors = []
|
|
400
|
+
for (const registry of registries) {
|
|
401
|
+
try {
|
|
402
|
+
const result = await resolveNpmPackage({ registry, name, version })
|
|
403
|
+
return { ...result, registry }
|
|
404
|
+
} catch (error) {
|
|
405
|
+
const isNetworkError = error?.cause?.code === "ECONNREFUSED"
|
|
406
|
+
|| error?.cause?.code === "ENOTFOUND"
|
|
407
|
+
|| error?.cause?.code === "ETIMEDOUT"
|
|
408
|
+
|| error?.cause?.code === "ECONNRESET"
|
|
409
|
+
|| error?.cause?.code === "UND_ERR_CONNECT_TIMEOUT"
|
|
410
|
+
|| (error instanceof TypeError && error.message === "fetch failed")
|
|
411
|
+
errors.push({ registry, error, isNetworkError })
|
|
412
|
+
|
|
413
|
+
if (isNetworkError && registries.length > 1) {
|
|
414
|
+
console.error(`vantaloom: ${registry} unreachable, trying next registry...`)
|
|
415
|
+
continue
|
|
416
|
+
}
|
|
417
|
+
// Non-network error (404, parse error, etc.) — don't try fallbacks
|
|
418
|
+
throw error
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// All registries failed with network errors
|
|
423
|
+
const tried = errors.map((e) => e.registry).join(", ")
|
|
424
|
+
throw new Error(
|
|
425
|
+
`all registries unreachable (tried: ${tried}). ` +
|
|
426
|
+
`Check your network or specify --npm-registry <url>`
|
|
427
|
+
)
|
|
428
|
+
}
|
|
429
|
+
|
|
349
430
|
async function resolveNpmPackage({ registry, name, version }) {
|
|
350
431
|
const metadataUrl = `${registry}/${encodeURIComponent(name).replace("%2F", "%2f")}`
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
432
|
+
let response
|
|
433
|
+
try {
|
|
434
|
+
response = await fetch(metadataUrl, {
|
|
435
|
+
headers: {
|
|
436
|
+
Accept: "application/vnd.npm.install-v1+json",
|
|
437
|
+
"User-Agent": "vantaloom-cli",
|
|
438
|
+
},
|
|
439
|
+
signal: AbortSignal.timeout(15000),
|
|
440
|
+
})
|
|
441
|
+
} catch (error) {
|
|
442
|
+
if (error instanceof TypeError && error.message === "fetch failed") {
|
|
443
|
+
const cause = error.cause ? ` (${error.cause.code || error.cause.message || error.cause})` : ""
|
|
444
|
+
throw Object.assign(
|
|
445
|
+
new Error(`cannot reach registry ${registry}${cause}`),
|
|
446
|
+
{ cause: error.cause }
|
|
447
|
+
)
|
|
448
|
+
}
|
|
449
|
+
throw error
|
|
450
|
+
}
|
|
357
451
|
if (!response.ok) {
|
|
358
452
|
const detail = await response.text().catch(() => "")
|
|
359
453
|
throw new Error(`failed to inspect npm package ${name}: HTTP ${response.status}${detail ? ` ${detail.slice(0, 200)}` : ""}`)
|
|
@@ -470,7 +564,7 @@ function runtimeConfigFromSource(sourceRoot) {
|
|
|
470
564
|
releaseTag: defaultReleaseTag,
|
|
471
565
|
runtimePackage: runtimePackageName(platformId()),
|
|
472
566
|
runtimeVersion: "latest",
|
|
473
|
-
npmRegistry: defaultNpmRegistry,
|
|
567
|
+
npmRegistry: detectNpmRegistry() || defaultNpmRegistry,
|
|
474
568
|
}
|
|
475
569
|
}
|
|
476
570
|
|
|
@@ -897,6 +991,38 @@ async function writeText(filePath, content) {
|
|
|
897
991
|
await writeFile(filePath, content)
|
|
898
992
|
}
|
|
899
993
|
|
|
994
|
+
function killTrayProcess(prefix) {
|
|
995
|
+
if (process.platform === "win32") {
|
|
996
|
+
// Try PID file first (new tray versions write runtime/tray.pid).
|
|
997
|
+
const pidFile = path.join(prefix, "runtime", "tray.pid")
|
|
998
|
+
if (existsSync(pidFile)) {
|
|
999
|
+
const pid = readFileSync(pidFile, "utf8").trim()
|
|
1000
|
+
if (pid) {
|
|
1001
|
+
spawnSync("taskkill", ["/PID", pid, "/F"], { stdio: "ignore" })
|
|
1002
|
+
try { rmSync(pidFile, { force: true }) } catch {}
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
// Fallback: kill by image name if the binary is inside our prefix.
|
|
1006
|
+
const result = spawnSync("tasklist", ["/FI", "IMAGENAME eq vantaloom-tray.exe", "/FO", "CSV", "/NH"], {
|
|
1007
|
+
encoding: "utf8",
|
|
1008
|
+
windowsHide: true,
|
|
1009
|
+
})
|
|
1010
|
+
if (result.stdout) {
|
|
1011
|
+
for (const line of result.stdout.split("\n")) {
|
|
1012
|
+
const match = line.match(/"vantaloom-tray\.exe","(\d+)"/)
|
|
1013
|
+
if (match) {
|
|
1014
|
+
spawnSync("taskkill", ["/PID", match[1], "/F"], { stdio: "ignore" })
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
// Brief pause to let file handles release.
|
|
1019
|
+
spawnSync("timeout", ["/t", "1", "/nobreak"], { stdio: "ignore", windowsHide: true })
|
|
1020
|
+
} else {
|
|
1021
|
+
// Unix: pkill by name (best-effort).
|
|
1022
|
+
spawnSync("pkill", ["-f", "vantaloom-tray"], { stdio: "ignore" })
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
|
|
900
1026
|
function printHelp() {
|
|
901
1027
|
console.log(`Vantaloom CLI
|
|
902
1028
|
|