@vantaloom/cli 0.1.2 → 0.1.5

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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/src/cli.mjs +236 -121
package/README.md CHANGED
@@ -9,4 +9,4 @@ vantaloom status
9
9
  vantaloom update
10
10
  ```
11
11
 
12
- The CLI downloads platform-specific runtime packages produced by the Vantaloom GitHub CI pipeline.
12
+ The CLI downloads the current platform runtime from public npm packages such as `@vantaloom/runtime-win32-x64`, `@vantaloom/runtime-linux-x64`, and `@vantaloom/runtime-darwin-arm64`. No GitHub token is required for install or update.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vantaloom/cli",
3
- "version": "0.1.2",
3
+ "version": "0.1.5",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Vantaloom local runtime manager.",
package/src/cli.mjs CHANGED
@@ -2,12 +2,10 @@ import { execFileSync, spawnSync } from "node:child_process"
2
2
  import {
3
3
  chmodSync,
4
4
  existsSync,
5
- lstatSync,
6
5
  mkdirSync,
7
6
  mkdtempSync,
8
7
  readdirSync,
9
8
  readFileSync,
10
- readlinkSync,
11
9
  rmSync,
12
10
  writeFileSync,
13
11
  } from "node:fs"
@@ -21,19 +19,7 @@ const repoCandidate = path.resolve(cliRoot, "..", "..")
21
19
  const installedConfigPath = path.join(cliRoot, "config.json")
22
20
  const defaultReleaseTag = "runtime-latest"
23
21
  const defaultRepo = "Timefiles404/Vantaloom-next"
24
-
25
- const runtimePackages = [
26
- "@next/env",
27
- "@swc/helpers",
28
- "baseline-browser-mapping",
29
- "caniuse-lite",
30
- "client-only",
31
- "postcss",
32
- "react",
33
- "react-dom",
34
- "scheduler",
35
- "styled-jsx",
36
- ]
22
+ const defaultNpmRegistry = "https://registry.npmjs.org"
37
23
 
38
24
  export async function main(argv) {
39
25
  const command = argv[0] ?? "help"
@@ -43,19 +29,23 @@ export async function main(argv) {
43
29
  case "install":
44
30
  if (options.package) {
45
31
  await installFromPackage({ ...options, update: false })
46
- } else if (shouldUseDistSync(options)) {
32
+ } else if (shouldUseSourceInstall(options)) {
33
+ await installFromSource(options)
34
+ } else if (shouldUseReleaseSync(options)) {
47
35
  await syncFromRelease(options, "install")
48
36
  } else {
49
- await installFromSource(options)
37
+ await syncFromNpmRegistry(options, "install")
50
38
  }
51
39
  return
52
40
  case "update":
53
41
  if (options.package) {
54
42
  await installFromPackage({ ...options, update: true })
55
- } else if (shouldUseDistSync(options)) {
43
+ } else if (shouldUseSourceInstall(options)) {
44
+ await installFromSource({ ...options, update: true })
45
+ } else if (shouldUseReleaseSync(options)) {
56
46
  await syncFromRelease(options, "update")
57
47
  } else {
58
- await installFromSource({ ...options, update: true })
48
+ await syncFromNpmRegistry(options, "update")
59
49
  }
60
50
  return
61
51
  case "package":
@@ -126,6 +116,10 @@ async function packageRuntime(options) {
126
116
  buildWeb: options.buildWeb,
127
117
  })
128
118
 
119
+ if (options.npmPackage) {
120
+ writeRuntimePackageMetadata(packageRoot, sourceRoot, builtPlatform)
121
+ }
122
+
129
123
  if (options.archive) {
130
124
  const archivePath = `${packageRoot}.tar.gz`
131
125
  removeKnownPath(archivePath, path.dirname(archivePath))
@@ -161,7 +155,7 @@ async function buildRuntimePackage(sourceRoot, packageRoot, options) {
161
155
  runPnpm(["--filter", "vantaloom-app", "build"], { cwd: sourceRoot })
162
156
  }
163
157
 
164
- await copyStandaloneWeb(sourceRoot, buildWeb)
158
+ await copyStaticWeb(sourceRoot, buildWeb)
165
159
  await copyCliDirectory(path.join(packageRoot, "cli"), sourceRoot, runtimeConfigFromSource(sourceRoot))
166
160
  writeBuildManifest(packageRoot, version, platform)
167
161
 
@@ -219,6 +213,46 @@ async function applyPackage(packageRoot, prefix, options) {
219
213
  return version
220
214
  }
221
215
 
216
+ async function syncFromNpmRegistry(options, action) {
217
+ const prefix = safeDirectory(options.prefix ?? defaultPrefix())
218
+ const installedConfig = readInstalledConfig(prefix)
219
+ const runtimePackage = options.runtimePackage || installedConfig.runtimePackage || runtimePackageName(platformId())
220
+ const runtimeVersion = options.runtimeVersion || installedConfig.runtimeVersion || "latest"
221
+ const registry = normalizeRegistry(options.npmRegistry || installedConfig.npmRegistry || defaultNpmRegistry)
222
+ const tempRoot = mkdtempSync(path.join(os.tmpdir(), "vantaloom-npm-"))
223
+
224
+ try {
225
+ const extractRoot = path.join(tempRoot, "extract")
226
+ const archive = path.join(tempRoot, `${packageBasename(runtimePackage)}-${runtimeVersion}.tgz`)
227
+ mkdirSync(extractRoot, { recursive: true })
228
+
229
+ const resolved = await resolveNpmPackage({ registry, name: runtimePackage, version: runtimeVersion })
230
+ await downloadNpmTarball({
231
+ tarballUrl: resolved.tarball,
232
+ target: archive,
233
+ packageName: runtimePackage,
234
+ version: resolved.version,
235
+ })
236
+ run("tar", ["-xzf", archive, "-C", extractRoot])
237
+
238
+ const packageRoot = findExtractedNpmPackage(extractRoot)
239
+ const version = await applyPackage(packageRoot, prefix, {
240
+ noStart: options.noStart,
241
+ runtimePackage,
242
+ runtimeVersion: options.runtimeVersion ? resolved.version : "latest",
243
+ npmRegistry: registry,
244
+ update: action === "update",
245
+ })
246
+
247
+ console.log(`${action === "update" ? "updated" : "installed"} Vantaloom: ${prefix}`)
248
+ console.log(`version: ${version}`)
249
+ console.log(`source: ${runtimePackage}@${resolved.version}`)
250
+ console.log(`run: ${displayCommand(prefix)} status`)
251
+ } finally {
252
+ removeKnownPath(tempRoot, os.tmpdir())
253
+ }
254
+ }
255
+
222
256
  async function syncFromRelease(options, action) {
223
257
  const prefix = safeDirectory(options.prefix ?? defaultPrefix())
224
258
  const installedConfig = readInstalledConfig(prefix)
@@ -261,7 +295,7 @@ async function syncFromRelease(options, action) {
261
295
  }
262
296
 
263
297
  async function downloadReleaseAsset({ repo, releaseTag, assetName, target, token }) {
264
- const url = `https://github.com/${repo}/releases/download/${releaseTag}/${assetName}`
298
+ const releaseUrl = `https://api.github.com/repos/${repo}/releases/tags/${releaseTag}`
265
299
  const headers = {
266
300
  "User-Agent": "vantaloom-cli",
267
301
  }
@@ -270,7 +304,28 @@ async function downloadReleaseAsset({ repo, releaseTag, assetName, target, token
270
304
  headers.Authorization = `Bearer ${githubToken}`
271
305
  }
272
306
 
273
- const response = await fetch(url, { headers })
307
+ const releaseResponse = await fetch(releaseUrl, { headers })
308
+ if (!releaseResponse.ok) {
309
+ const detail = await releaseResponse.text().catch(() => "")
310
+ const authHint = releaseResponse.status === 404 || releaseResponse.status === 403
311
+ ? " If the repository is private, set VANTALOOM_GITHUB_TOKEN to a GitHub token that can read releases."
312
+ : ""
313
+ throw new Error(`failed to inspect ${repo}@${releaseTag}: HTTP ${releaseResponse.status}.${authHint}${detail ? ` ${detail.slice(0, 200)}` : ""}`)
314
+ }
315
+
316
+ const release = await releaseResponse.json()
317
+ const asset = release.assets?.find((asset) => asset.name === assetName)
318
+ if (!asset) {
319
+ const names = release.assets?.map((asset) => asset.name).join(", ") || "none"
320
+ throw new Error(`missing release asset ${assetName} in ${repo}@${releaseTag}; available assets: ${names}`)
321
+ }
322
+
323
+ const response = await fetch(asset.url, {
324
+ headers: {
325
+ ...headers,
326
+ Accept: "application/octet-stream",
327
+ },
328
+ })
274
329
  if (!response.ok) {
275
330
  const detail = await response.text().catch(() => "")
276
331
  const authHint = response.status === 404 || response.status === 403
@@ -283,8 +338,53 @@ async function downloadReleaseAsset({ repo, releaseTag, assetName, target, token
283
338
  await writeFile(target, buffer)
284
339
  }
285
340
 
286
- function shouldUseDistSync(options) {
287
- return !options.local && !options.source && !options.buildWeb
341
+ async function resolveNpmPackage({ registry, name, version }) {
342
+ const metadataUrl = `${registry}/${encodeURIComponent(name).replace("%2F", "%2f")}`
343
+ const response = await fetch(metadataUrl, {
344
+ headers: {
345
+ Accept: "application/vnd.npm.install-v1+json",
346
+ "User-Agent": "vantaloom-cli",
347
+ },
348
+ })
349
+ if (!response.ok) {
350
+ const detail = await response.text().catch(() => "")
351
+ throw new Error(`failed to inspect npm package ${name}: HTTP ${response.status}${detail ? ` ${detail.slice(0, 200)}` : ""}`)
352
+ }
353
+
354
+ const metadata = await response.json()
355
+ const selectedVersion = metadata["dist-tags"]?.[version] ?? version
356
+ const packageVersion = metadata.versions?.[selectedVersion]
357
+ if (!packageVersion?.dist?.tarball) {
358
+ const available = Object.keys(metadata.versions ?? {}).slice(-8).join(", ") || "none"
359
+ throw new Error(`missing npm package ${name}@${version}; available versions: ${available}`)
360
+ }
361
+ return {
362
+ version: selectedVersion,
363
+ tarball: packageVersion.dist.tarball,
364
+ }
365
+ }
366
+
367
+ async function downloadNpmTarball({ tarballUrl, target, packageName, version }) {
368
+ const response = await fetch(tarballUrl, {
369
+ headers: {
370
+ "User-Agent": "vantaloom-cli",
371
+ },
372
+ })
373
+ if (!response.ok) {
374
+ const detail = await response.text().catch(() => "")
375
+ throw new Error(`failed to download ${packageName}@${version}: HTTP ${response.status}${detail ? ` ${detail.slice(0, 200)}` : ""}`)
376
+ }
377
+
378
+ const buffer = Buffer.from(await response.arrayBuffer())
379
+ await writeFile(target, buffer)
380
+ }
381
+
382
+ function shouldUseSourceInstall(options) {
383
+ return Boolean(options.local || options.source || options.buildWeb)
384
+ }
385
+
386
+ function shouldUseReleaseSync(options) {
387
+ return Boolean(options.repo || options.remote || options.releaseTag || options.githubToken)
288
388
  }
289
389
 
290
390
  function assertRuntimePackage(packageRoot) {
@@ -317,7 +417,7 @@ function readJSONIfExists(filePath) {
317
417
 
318
418
  function mergeRuntimeConfig(packageConfig, existingConfig, overrides) {
319
419
  const merged = { ...packageConfig }
320
- for (const key of ["sourceRoot", "remote", "repo", "releaseTag"]) {
420
+ for (const key of ["sourceRoot", "remote", "repo", "releaseTag", "runtimePackage", "runtimeVersion", "npmRegistry"]) {
321
421
  if (!merged[key] && existingConfig[key]) {
322
422
  merged[key] = existingConfig[key]
323
423
  }
@@ -325,12 +425,30 @@ function mergeRuntimeConfig(packageConfig, existingConfig, overrides) {
325
425
  if (overrides.sourceRoot) {
326
426
  merged.sourceRoot = overrides.sourceRoot
327
427
  }
428
+ if (overrides.runtimePackage) {
429
+ merged.runtimePackage = overrides.runtimePackage
430
+ }
431
+ if (overrides.runtimeVersion) {
432
+ merged.runtimeVersion = overrides.runtimeVersion
433
+ }
434
+ if (overrides.npmRegistry) {
435
+ merged.npmRegistry = overrides.npmRegistry
436
+ }
328
437
  if (!merged.repo) {
329
438
  merged.repo = defaultRepo
330
439
  }
331
440
  if (!merged.releaseTag) {
332
441
  merged.releaseTag = defaultReleaseTag
333
442
  }
443
+ if (!merged.runtimePackage) {
444
+ merged.runtimePackage = runtimePackageName(platformId())
445
+ }
446
+ if (!merged.runtimeVersion) {
447
+ merged.runtimeVersion = "latest"
448
+ }
449
+ if (!merged.npmRegistry) {
450
+ merged.npmRegistry = defaultNpmRegistry
451
+ }
334
452
  return merged
335
453
  }
336
454
 
@@ -342,6 +460,9 @@ function runtimeConfigFromSource(sourceRoot) {
342
460
  ...(remote ? { remote } : {}),
343
461
  repo,
344
462
  releaseTag: defaultReleaseTag,
463
+ runtimePackage: runtimePackageName(platformId()),
464
+ runtimeVersion: "latest",
465
+ npmRegistry: defaultNpmRegistry,
345
466
  }
346
467
  }
347
468
 
@@ -361,6 +482,22 @@ function findExtractedPackage(extractRoot, platform) {
361
482
  throw new Error(`could not find extracted Vantaloom package in ${extractRoot}`)
362
483
  }
363
484
 
485
+ function findExtractedNpmPackage(extractRoot) {
486
+ const expected = path.join(extractRoot, "package")
487
+ if (existsSync(expected)) {
488
+ return expected
489
+ }
490
+
491
+ const directories = readdirSync(extractRoot, { withFileTypes: true })
492
+ .filter((entry) => entry.isDirectory())
493
+ .map((entry) => path.join(extractRoot, entry.name))
494
+ if (directories.length === 1) {
495
+ return directories[0]
496
+ }
497
+
498
+ throw new Error(`could not find extracted npm package in ${extractRoot}`)
499
+ }
500
+
364
501
  function tryFindSourceRoot() {
365
502
  try {
366
503
  return findSourceRoot()
@@ -401,29 +538,16 @@ function inferGitHubRepo(remote) {
401
538
  return sshMatch?.[1] ?? ""
402
539
  }
403
540
 
404
- async function copyStandaloneWeb(sourceRoot, buildWeb) {
405
- const standalone = path.join(sourceRoot, "apps", "vantaloom", ".next", "standalone")
406
- const staticSource = path.join(sourceRoot, "apps", "vantaloom", ".next", "static")
407
- const publicSource = path.join(sourceRoot, "apps", "vantaloom", "public")
408
- if (!existsSync(standalone)) {
541
+ async function copyStaticWeb(sourceRoot, buildWeb) {
542
+ const exportRoot = path.join(sourceRoot, "apps", "vantaloom", "out")
543
+ if (!existsSync(exportRoot)) {
409
544
  throw new Error(
410
- "missing Next standalone output; let GitHub CI run production build, or pass --build-web for a local one-off build"
545
+ "missing Next static export output; let GitHub CI run production build, or pass --build-web for a local one-off build"
411
546
  )
412
547
  }
413
548
 
414
549
  removeKnownPath(buildWeb, path.dirname(buildWeb))
415
- const preserveStandaloneLinks = process.platform !== "win32"
416
- await copyDir(standalone, buildWeb, { dereference: !preserveStandaloneLinks })
417
- if (preserveStandaloneLinks) {
418
- await copyStandaloneHoistedTargets(sourceRoot, buildWeb)
419
- }
420
- await copyDir(staticSource, path.join(buildWeb, "apps", "vantaloom", ".next", "static"))
421
- await copyDir(publicSource, path.join(buildWeb, "apps", "vantaloom", "public"))
422
-
423
- const appNodeModules = path.join(buildWeb, "apps", "vantaloom", "node_modules")
424
- for (const packageName of runtimePackages) {
425
- await copyPnpmRuntimePackage(sourceRoot, packageName, appNodeModules)
426
- }
550
+ await copyDir(exportRoot, buildWeb)
427
551
  }
428
552
 
429
553
  async function copyCliDirectory(target, sourceRoot, config) {
@@ -483,81 +607,6 @@ function buildGo(sourceRoot, buildBin, name) {
483
607
  ], { cwd: sourceRoot })
484
608
  }
485
609
 
486
- async function copyPnpmRuntimePackage(sourceRoot, packageName, destinationNodeModules) {
487
- const pnpmRoot = path.join(sourceRoot, "node_modules", ".pnpm")
488
- const storeName = packageName.replace("/", "+")
489
- const packageRoot = readdirSync(pnpmRoot, { withFileTypes: true })
490
- .filter((entry) => entry.isDirectory() && entry.name.startsWith(`${storeName}@`))
491
- .map((entry) => path.join(pnpmRoot, entry.name))
492
- .sort()
493
- .reverse()[0]
494
- if (!packageRoot) {
495
- throw new Error(`missing pnpm runtime package: ${packageName}`)
496
- }
497
-
498
- const source = path.join(packageRoot, "node_modules", ...packageName.split("/"))
499
- if (!existsSync(source)) {
500
- throw new Error(`missing pnpm runtime package source: ${source}`)
501
- }
502
-
503
- await copyDir(source, path.join(destinationNodeModules, ...packageName.split("/")))
504
- }
505
-
506
- async function copyStandaloneHoistedTargets(sourceRoot, buildWeb) {
507
- const sourceHoisted = path.join(sourceRoot, "node_modules", ".pnpm", "node_modules")
508
- const buildHoisted = path.join(buildWeb, "node_modules", ".pnpm", "node_modules")
509
- const packageNames = findHoistedSymlinkPackages(path.join(buildWeb, "node_modules"))
510
-
511
- for (const packageName of packageNames) {
512
- const source = path.join(sourceHoisted, ...packageName.split("/"))
513
- if (existsSync(source)) {
514
- await copyDir(source, path.join(buildHoisted, ...packageName.split("/")))
515
- }
516
- }
517
- }
518
-
519
- function findHoistedSymlinkPackages(nodeModules) {
520
- const packages = new Set()
521
- if (!existsSync(nodeModules)) {
522
- return packages
523
- }
524
-
525
- for (const entry of readdirSync(nodeModules, { withFileTypes: true })) {
526
- if (entry.name === ".pnpm" || entry.name.startsWith(".")) {
527
- continue
528
- }
529
-
530
- const entryPath = path.join(nodeModules, entry.name)
531
- if (entry.name.startsWith("@") && entry.isDirectory()) {
532
- for (const scopedEntry of readdirSync(entryPath, { withFileTypes: true })) {
533
- addHoistedSymlinkPackage(packages, path.join(entryPath, scopedEntry.name), `${entry.name}/${scopedEntry.name}`)
534
- }
535
- continue
536
- }
537
-
538
- addHoistedSymlinkPackage(packages, entryPath, entry.name)
539
- }
540
-
541
- return packages
542
- }
543
-
544
- function addHoistedSymlinkPackage(packages, packagePath, packageName) {
545
- let stat
546
- try {
547
- stat = lstatSync(packagePath)
548
- } catch {
549
- return
550
- }
551
- if (!stat.isSymbolicLink()) {
552
- return
553
- }
554
-
555
- const target = readlinkSync(packagePath).replaceAll("\\", "/")
556
- if (target.includes(".pnpm/node_modules/")) {
557
- packages.add(packageName)
558
- }
559
- }
560
-
561
610
  async function copyDir(source, destination, options = {}) {
562
611
  if (!existsSync(source)) {
563
612
  throw new Error(`missing source directory: ${source}`)
@@ -589,6 +638,39 @@ function writeBuildManifest(buildRoot, version, platform) {
589
638
  )
590
639
  }
591
640
 
641
+ function writeRuntimePackageMetadata(packageRoot, sourceRoot, platform) {
642
+ const version = npmPackageVersion(sourceRoot)
643
+ const { os: runtimeOS, cpu } = parsePlatformId(platform)
644
+ const name = runtimePackageName(platform)
645
+ writeFileSync(
646
+ path.join(packageRoot, "package.json"),
647
+ `${JSON.stringify(
648
+ {
649
+ name,
650
+ version,
651
+ private: false,
652
+ description: `Vantaloom local runtime for ${platform}.`,
653
+ type: "module",
654
+ os: [runtimeOS],
655
+ cpu: [cpu],
656
+ files: ["bin", "web", "cli", "manifest.json", "VERSION", "README.md"],
657
+ publishConfig: {
658
+ access: "public",
659
+ },
660
+ engines: {
661
+ node: ">=20",
662
+ },
663
+ },
664
+ null,
665
+ 2
666
+ )}\n`
667
+ )
668
+ writeFileSync(
669
+ path.join(packageRoot, "README.md"),
670
+ `# ${name}\n\nPlatform runtime package for Vantaloom ${platform}. Install @vantaloom/cli instead of this package directly.\n`
671
+ )
672
+ }
673
+
592
674
  function findSourceRoot(sourceOption) {
593
675
  if (sourceOption) {
594
676
  return assertSourceRoot(path.resolve(sourceOption))
@@ -605,6 +687,11 @@ function findSourceRoot(sourceOption) {
605
687
  return assertSourceRoot(repoCandidate)
606
688
  }
607
689
 
690
+ function npmPackageVersion(sourceRoot) {
691
+ const packageJSON = readJSONIfExists(path.join(sourceRoot, "packages", "cli", "package.json"))
692
+ return packageJSON.version ?? "0.0.0"
693
+ }
694
+
608
695
  function assertSourceRoot(sourceRoot) {
609
696
  if (!existsSync(path.join(sourceRoot, "apps", "api", "go.mod"))) {
610
697
  throw new Error(`not a Vantaloom source root: ${sourceRoot}`)
@@ -641,6 +728,9 @@ function parseOptions(args) {
641
728
  case "remote":
642
729
  case "release-tag":
643
730
  case "github-token":
731
+ case "runtime-package":
732
+ case "runtime-version":
733
+ case "npm-registry":
644
734
  options[toCamel(key)] = inlineValue ?? args[++index]
645
735
  if (!options[toCamel(key)]) {
646
736
  throw new Error(`missing value for --${key}`)
@@ -655,6 +745,9 @@ function parseOptions(args) {
655
745
  case "archive":
656
746
  options.archive = true
657
747
  break
748
+ case "npm-package":
749
+ options.npmPackage = true
750
+ break
658
751
  case "local":
659
752
  options.local = true
660
753
  break
@@ -714,6 +807,28 @@ function platformId() {
714
807
  return `${process.platform}-${process.arch}`
715
808
  }
716
809
 
810
+ function runtimePackageName(platform) {
811
+ return `@vantaloom/runtime-${platform}`
812
+ }
813
+
814
+ function parsePlatformId(platform) {
815
+ const parts = platform.split("-")
816
+ const cpu = parts.pop()
817
+ const runtimeOS = parts.join("-")
818
+ if (!runtimeOS || !cpu) {
819
+ throw new Error(`invalid platform id: ${platform}`)
820
+ }
821
+ return { os: runtimeOS, cpu }
822
+ }
823
+
824
+ function packageBasename(name) {
825
+ return name.split("/").pop() ?? name
826
+ }
827
+
828
+ function normalizeRegistry(value) {
829
+ return value.replace(/\/+$/, "")
830
+ }
831
+
717
832
  function defaultPrefix() {
718
833
  if (process.env.VANTALOOM_HOME) {
719
834
  return process.env.VANTALOOM_HOME
@@ -747,11 +862,11 @@ function printHelp() {
747
862
  console.log(`Vantaloom CLI
748
863
 
749
864
  Usage:
750
- vantaloom install [--prefix <dir>] [--repo <owner/name>] [--release-tag <tag>] [--github-token <token>] [--package <dir>] [--no-start]
865
+ vantaloom install [--prefix <dir>] [--runtime-version <version>] [--npm-registry <url>] [--package <dir>] [--no-start]
751
866
  vantaloom install --local [--prefix <dir>] [--source <repo>] [--build-web] [--no-start]
752
- vantaloom update [--prefix <dir>] [--repo <owner/name>] [--release-tag <tag>] [--github-token <token>] [--no-start]
867
+ vantaloom update [--prefix <dir>] [--runtime-version <version>] [--npm-registry <url>] [--no-start]
753
868
  vantaloom update --local [--prefix <dir>] [--source <repo>] [--build-web] [--no-start]
754
- vantaloom package [--source <repo>] [--output <dir>] [--build-web] [--archive]
869
+ vantaloom package [--source <repo>] [--output <dir>] [--build-web] [--archive] [--npm-package]
755
870
  vantaloom start [--prefix <dir>] [--component all|api|agent|web]
756
871
  vantaloom stop [--prefix <dir>] [--component all|api|agent|web]
757
872
  vantaloom restart [--prefix <dir>] [--component all|api|agent|web]