@vltpkg/cli-sdk 1.0.0-rc.32 → 1.0.0-rc.33

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 (68) hide show
  1. package/dist/commands/access.d.ts +1 -0
  2. package/dist/commands/access.js +11 -6
  3. package/dist/commands/build.d.ts +1 -0
  4. package/dist/commands/build.js +1 -0
  5. package/dist/commands/cache.d.ts +1 -0
  6. package/dist/commands/cache.js +1 -0
  7. package/dist/commands/ci.d.ts +1 -0
  8. package/dist/commands/ci.js +1 -0
  9. package/dist/commands/create.d.ts +1 -0
  10. package/dist/commands/create.js +1 -0
  11. package/dist/commands/deprecate.d.ts +1 -0
  12. package/dist/commands/deprecate.js +4 -1
  13. package/dist/commands/dist-tag.d.ts +1 -0
  14. package/dist/commands/dist-tag.js +3 -1
  15. package/dist/commands/exec-cache.d.ts +1 -0
  16. package/dist/commands/exec-cache.js +1 -0
  17. package/dist/commands/exec.d.ts +1 -0
  18. package/dist/commands/exec.js +1 -0
  19. package/dist/commands/install.d.ts +1 -0
  20. package/dist/commands/install.js +12 -0
  21. package/dist/commands/list.d.ts +1 -0
  22. package/dist/commands/list.js +1 -0
  23. package/dist/commands/login.js +16 -3
  24. package/dist/commands/logout.d.ts +1 -0
  25. package/dist/commands/logout.js +7 -2
  26. package/dist/commands/pack.d.ts +1 -0
  27. package/dist/commands/pack.js +1 -0
  28. package/dist/commands/ping.d.ts +1 -0
  29. package/dist/commands/ping.js +5 -2
  30. package/dist/commands/profile.d.ts +1 -0
  31. package/dist/commands/profile.js +4 -2
  32. package/dist/commands/publish.d.ts +1 -0
  33. package/dist/commands/publish.js +3 -1
  34. package/dist/commands/query.d.ts +1 -0
  35. package/dist/commands/query.js +1 -0
  36. package/dist/commands/registry.d.ts +26 -0
  37. package/dist/commands/registry.js +99 -0
  38. package/dist/commands/run-exec.d.ts +1 -0
  39. package/dist/commands/run-exec.js +1 -0
  40. package/dist/commands/setup.d.ts +25 -0
  41. package/dist/commands/setup.js +142 -0
  42. package/dist/commands/token.d.ts +1 -0
  43. package/dist/commands/token.js +8 -3
  44. package/dist/commands/uninstall.d.ts +1 -0
  45. package/dist/commands/uninstall.js +1 -0
  46. package/dist/commands/unpublish.d.ts +1 -0
  47. package/dist/commands/unpublish.js +4 -1
  48. package/dist/commands/update.d.ts +1 -0
  49. package/dist/commands/update.js +1 -0
  50. package/dist/commands/view.d.ts +1 -0
  51. package/dist/commands/view.js +3 -2
  52. package/dist/commands/whoami.d.ts +1 -0
  53. package/dist/commands/whoami.js +7 -2
  54. package/dist/config/definition.d.ts +38 -0
  55. package/dist/config/definition.js +88 -11
  56. package/dist/config/index.js +6 -0
  57. package/dist/custom-help.js +17 -1
  58. package/dist/index.js +4 -0
  59. package/dist/load-command.d.ts +6 -0
  60. package/dist/output.js +15 -1
  61. package/dist/print-err.js +10 -1
  62. package/dist/require-registry.d.ts +48 -0
  63. package/dist/require-registry.js +122 -0
  64. package/dist/select-registry.d.ts +23 -0
  65. package/dist/select-registry.js +40 -0
  66. package/dist/verbose-log.d.ts +31 -0
  67. package/dist/verbose-log.js +62 -0
  68. package/package.json +33 -26
@@ -0,0 +1,25 @@
1
+ import type { CommandFn, CommandUsage } from '../index.ts';
2
+ /** Where users sign up for / log into a vlt.io account. */
3
+ export declare const VLT_SIGNUP_URL = "https://www.vlt.io";
4
+ /** Base URL that per-account registries live under. */
5
+ export declare const VLT_REGISTRY_BASE = "https://registry.vlt.io";
6
+ /**
7
+ * The registry aliases that every vlt.io account is provisioned with.
8
+ * `npm` is the {@link https://docs.vlt.sh | default bare-spec alias}.
9
+ */
10
+ export declare const accountRegistries: readonly ["npm", "main"];
11
+ /** Build the per-account registry URL for a given registry name. */
12
+ export declare const accountRegistryURL: (account: string, name: string) => string;
13
+ export type SetupResult = {
14
+ /** the account slug the registries were built for */
15
+ account: string;
16
+ /** which config file the registries were written to */
17
+ which: 'user' | 'project';
18
+ /** the alias -> url map that was staged into config */
19
+ registries: Record<string, string>;
20
+ };
21
+ export declare const views: {
22
+ readonly human: (result: SetupResult) => string;
23
+ };
24
+ export declare const usage: CommandUsage;
25
+ export declare const command: CommandFn<SetupResult>;
@@ -0,0 +1,142 @@
1
+ import { error } from '@vltpkg/error-cause';
2
+ import { RegistryClient } from '@vltpkg/registry-client';
3
+ import { defaultRegistries } from '@vltpkg/spec';
4
+ import { createInterface } from 'node:readline/promises';
5
+ import { commandUsage } from "../config/usage.js";
6
+ import { stdout } from "../output.js";
7
+ /** Where users sign up for / log into a vlt.io account. */
8
+ export const VLT_SIGNUP_URL = 'https://www.vlt.io';
9
+ /** Base URL that per-account registries live under. */
10
+ export const VLT_REGISTRY_BASE = 'https://registry.vlt.io';
11
+ /**
12
+ * The registry aliases that every vlt.io account is provisioned with.
13
+ * `npm` is the {@link https://docs.vlt.sh | default bare-spec alias}.
14
+ */
15
+ export const accountRegistries = ['npm', 'main'];
16
+ /** Build the per-account registry URL for a given registry name. */
17
+ export const accountRegistryURL = (account, name) => `${VLT_REGISTRY_BASE}/${encodeURIComponent(account)}/${name}/`;
18
+ /** Ensure a registry URL ends with a single trailing slash. */
19
+ const normalizeRegistryURL = (url) => url.endsWith('/') ? url : `${url}/`;
20
+ export const views = {
21
+ human: (result) => {
22
+ const lines = [
23
+ `Configured ${Object.keys(result.registries).length} registry ${Object.keys(result.registries).length === 1 ?
24
+ 'alias'
25
+ : 'aliases'} for "${result.account}" in ${result.which} config:`,
26
+ ];
27
+ for (const [name, url] of Object.entries(result.registries)) {
28
+ lines.push(` ${name} -> ${url}`);
29
+ }
30
+ lines.push('', 'You can now install packages, e.g.:', ' vlt install <pkg>');
31
+ return lines.join('\n');
32
+ },
33
+ };
34
+ export const usage = () => commandUsage({
35
+ command: 'setup',
36
+ usage: '[<account>]',
37
+ description: `Configure the registry aliases for your vlt.io account so
38
+ that \`vlt install\` and \`vlx\` work out of the box.
39
+
40
+ Sign up or log in at ${VLT_SIGNUP_URL} first. The wizard
41
+ authenticates against your account and writes the
42
+ \`npm\` and \`main\` registry aliases (and any additional
43
+ aliases you add) to your user \`vlt.json\`.`,
44
+ options: {
45
+ config: {
46
+ value: '<user | project>',
47
+ description: 'Which config file to write to. Defaults to `user`; pass ' +
48
+ '`--config=project` to write to the project `vlt.json`.',
49
+ },
50
+ registries: {
51
+ value: '<name=url>',
52
+ description: 'Additional registry aliases to stage non-interactively. ' +
53
+ 'Combine with `--yes` to run setup unattended.',
54
+ },
55
+ yes: {
56
+ description: 'Skip interactive prompts (requires <account> and does not ' +
57
+ 'open a browser for authentication).',
58
+ },
59
+ },
60
+ });
61
+ export const command = async (conf) => {
62
+ const yes = !!conf.get('yes');
63
+ const which = conf.get('config') === 'project' ? 'project' : 'user';
64
+ let rl;
65
+ const ask = async (question) => {
66
+ rl ??= createInterface(process.stdin, process.stdout);
67
+ return (await rl.question(question)).trim();
68
+ };
69
+ try {
70
+ stdout(`Sign up or log in at ${VLT_SIGNUP_URL} before continuing.`);
71
+ // 1. resolve the account slug
72
+ let account = conf.positionals[0]?.trim();
73
+ if (!account) {
74
+ if (yes) {
75
+ throw error('An account slug is required in non-interactive mode. ' +
76
+ 'Pass it as an argument: `vlt setup <account> --yes`.', { code: 'ECONFIG' });
77
+ }
78
+ account = await ask('vlt.io account or organization slug: ');
79
+ if (!account) {
80
+ throw error('No account slug provided.', { code: 'ECONFIG' });
81
+ }
82
+ }
83
+ // 2. stage the two known account registries
84
+ const registries = {};
85
+ for (const name of accountRegistries) {
86
+ registries[name] = accountRegistryURL(account, name);
87
+ }
88
+ // 3. merge any user-supplied registry aliases (skip built-in defaults)
89
+ const builtinRegistries = defaultRegistries;
90
+ for (const [name, url] of Object.entries(conf.options.registries)) {
91
+ if (builtinRegistries[name] === url)
92
+ continue;
93
+ registries[name] = normalizeRegistryURL(url);
94
+ }
95
+ const rc = new RegistryClient(conf.options);
96
+ // 4. authenticate against the account registries (interactive only)
97
+ if (!yes) {
98
+ const doAuth = await ask('Authenticate with your vlt.io account now? (Y/n) ');
99
+ if (!/^n/i.test(doAuth)) {
100
+ for (const name of accountRegistries) {
101
+ stdout(`Authenticating against the "${name}" registry...`);
102
+ await rc.login(accountRegistryURL(account, name));
103
+ }
104
+ }
105
+ // 5. offer to add further custom aliases
106
+ for (;;) {
107
+ const more = await ask('Add another registry alias? (y/N) ');
108
+ if (!/^y/i.test(more))
109
+ break;
110
+ const name = await ask(' alias name: ');
111
+ if (!name) {
112
+ stdout(' alias name is required, skipping.');
113
+ continue;
114
+ }
115
+ if (name in registries) {
116
+ stdout(` alias "${name}" is already staged, skipping.`);
117
+ continue;
118
+ }
119
+ const url = await ask(' registry url: ');
120
+ if (!url) {
121
+ stdout(' registry url is required, skipping.');
122
+ continue;
123
+ }
124
+ const normalized = normalizeRegistryURL(url);
125
+ registries[name] = normalized;
126
+ const auth = await ask(` authenticate against "${name}" now? (y/N) `);
127
+ if (/^y/i.test(auth)) {
128
+ await rc.login(normalized);
129
+ }
130
+ }
131
+ }
132
+ // 6. persist the staged registries (merged, not clobbered)
133
+ await conf.addConfigToFile(which, { registries });
134
+ return { account, which, registries };
135
+ }
136
+ finally {
137
+ if (rl) {
138
+ rl.close();
139
+ process.stdin.pause();
140
+ }
141
+ }
142
+ };
@@ -23,6 +23,7 @@ export type TokenListResult = {
23
23
  identity: string;
24
24
  registries: RegistryTokens[];
25
25
  };
26
+ export declare const needsRegistry = true;
26
27
  export declare const usage: CommandUsage;
27
28
  export declare const views: {
28
29
  readonly human: (r: TokenListResult | void) => string | undefined;
@@ -2,10 +2,15 @@ import { error } from '@vltpkg/error-cause';
2
2
  import { deleteToken, getKC, getToken, normalizeRegistryKey, registryBase, RegistryClient, setToken, } from '@vltpkg/registry-client';
3
3
  import { commandUsage } from "../config/usage.js";
4
4
  import { readPassword } from "../read-password.js";
5
+ import { requireRegistry } from "../require-registry.js";
6
+ export const needsRegistry = true;
5
7
  export const usage = () => commandUsage({
6
8
  command: 'token',
7
9
  usage: ['list', 'add', 'rm'],
8
- description: `Manage registry authentication tokens in the vlt keychain.`,
10
+ description: `Manage registry authentication tokens in the vlt keychain.
11
+
12
+ Target a specific configured registry by alias with
13
+ \`vlt registry <alias> token <subcommand>\`.`,
9
14
  subcommands: {
10
15
  list: {
11
16
  usage: '',
@@ -131,7 +136,7 @@ const listTokens = async (rc, registry, identity, alias) => {
131
136
  }
132
137
  };
133
138
  export const command = async (conf) => {
134
- const reg = normalizeRegistryKey(conf.options.registry);
139
+ const reg = normalizeRegistryKey(requireRegistry(conf));
135
140
  switch (conf.positionals[0]) {
136
141
  case 'ls':
137
142
  case 'list': {
@@ -140,7 +145,7 @@ export const command = async (conf) => {
140
145
  const registries = [];
141
146
  const seen = new Set();
142
147
  // Always query the default registry first
143
- const defaultReg = conf.options.registry;
148
+ const defaultReg = requireRegistry(conf);
144
149
  seen.add(normalizeRegistryKey(defaultReg));
145
150
  registries.push(await listTokens(rc, defaultReg, identity, 'default'));
146
151
  // Then query all configured registry aliases
@@ -7,6 +7,7 @@ export type UninstallResult = {
7
7
  */
8
8
  graph: Graph;
9
9
  };
10
+ export declare const needsRegistry = true;
10
11
  export declare const usage: CommandUsage;
11
12
  export declare const views: {
12
13
  readonly json: (i: UninstallResult) => import("@vltpkg/graph").LockfileData;
@@ -2,6 +2,7 @@ import { uninstall } from '@vltpkg/graph';
2
2
  import { commandUsage } from "../config/usage.js";
3
3
  import { parseRemoveArgs } from "../parse-add-remove-args.js";
4
4
  import { InstallReporter } from "./install/reporter.js";
5
+ export const needsRegistry = true;
5
6
  export const usage = () => commandUsage({
6
7
  command: 'uninstall',
7
8
  usage: '[package ...]',
@@ -1,4 +1,5 @@
1
1
  import type { CommandFn, CommandUsage } from '../index.ts';
2
+ export declare const needsRegistry = true;
2
3
  export declare const usage: CommandUsage;
3
4
  export type CommandResult = {
4
5
  /** The package name */
@@ -3,6 +3,8 @@ import { RegistryClient } from '@vltpkg/registry-client';
3
3
  import { Spec } from '@vltpkg/spec';
4
4
  import { asError } from '@vltpkg/types';
5
5
  import { commandUsage } from "../config/usage.js";
6
+ import { resolveRegistry } from "../require-registry.js";
7
+ export const needsRegistry = true;
6
8
  export const usage = () => commandUsage({
7
9
  command: 'unpublish',
8
10
  usage: ['<package>@<version>', '<package> --force'],
@@ -49,7 +51,8 @@ export const command = async (conf) => {
49
51
  if (!specArg) {
50
52
  throw error('unpublish requires a package spec argument (e.g. pkg@version)', { code: 'EUSAGE' });
51
53
  }
52
- const { registry, otp, force } = conf.options;
54
+ const { otp, force } = conf.options;
55
+ const registry = await resolveRegistry(conf);
53
56
  const registryUrl = new URL(registry);
54
57
  const spec = Spec.parseArgs(specArg, conf.options);
55
58
  const name = spec.name;
@@ -1,6 +1,7 @@
1
1
  import type { CommandFn, CommandUsage } from '../index.ts';
2
2
  import { InstallReporter } from './install/reporter.ts';
3
3
  import type { InstallResult } from './install.ts';
4
+ export declare const needsRegistry = true;
4
5
  export declare const usage: CommandUsage;
5
6
  export declare const views: {
6
7
  readonly json: (i: InstallResult) => {
@@ -2,6 +2,7 @@ import { update } from '@vltpkg/graph';
2
2
  import { error } from '@vltpkg/error-cause';
3
3
  import { commandUsage } from "../config/usage.js";
4
4
  import { InstallReporter } from "./install/reporter.js";
5
+ export const needsRegistry = true;
5
6
  export const usage = () => commandUsage({
6
7
  command: 'update',
7
8
  usage: '',
@@ -2,6 +2,7 @@ import type { Manifest, Packument } from '@vltpkg/types';
2
2
  import type { PackageReportData } from '@vltpkg/security-archive';
3
3
  import type { CommandFn, CommandUsage } from '../index.ts';
4
4
  import type { ViewOptions } from '../view.ts';
5
+ export declare const needsRegistry = true;
5
6
  export declare const usage: CommandUsage;
6
7
  export type ViewResult = {
7
8
  /** The full packument data from the registry */
@@ -5,6 +5,7 @@ import { SecurityArchive } from '@vltpkg/security-archive';
5
5
  import { Spec } from '@vltpkg/spec';
6
6
  import { joinDepIDTuple } from '@vltpkg/dep-id';
7
7
  import { commandUsage } from "../config/usage.js";
8
+ export const needsRegistry = true;
8
9
  export const usage = () => commandUsage({
9
10
  command: 'view',
10
11
  usage: [
@@ -298,9 +299,9 @@ export const command = async (conf) => {
298
299
  const fieldPath = conf.positionals[1];
299
300
  const spec = Spec.parseArgs(specArg, conf.options);
300
301
  const pic = new PackageInfoClient(conf.options);
301
- // Fetch the packument and resolved manifest
302
+ // Fetch the full packument (needs time, maintainers) and resolved manifest
302
303
  const [packument, resolvedManifest] = await Promise.all([
303
- pic.packument(spec),
304
+ pic.packument(spec, { fullPackument: true }),
304
305
  pic.manifest(spec),
305
306
  ]);
306
307
  const manifest = resolvedManifest;
@@ -1,5 +1,6 @@
1
1
  import type { JSONField } from '@vltpkg/types';
2
2
  import type { CommandFn, CommandUsage } from '../index.ts';
3
+ export declare const needsRegistry = true;
3
4
  export declare const usage: CommandUsage;
4
5
  type CommandResult = {
5
6
  username?: JSONField;
@@ -1,10 +1,15 @@
1
1
  import { RegistryClient } from '@vltpkg/registry-client';
2
2
  import { commandUsage } from "../config/usage.js";
3
+ import { resolveRegistry } from "../require-registry.js";
4
+ export const needsRegistry = true;
3
5
  export const usage = () => commandUsage({
4
6
  command: 'whoami',
5
7
  usage: [''],
6
8
  description: `Look up the username for the currently active token,
7
- when logged into a registry.`,
9
+ when logged into a registry.
10
+
11
+ Target a specific configured registry by alias with
12
+ \`vlt registry <alias> whoami\`.`,
8
13
  options: {
9
14
  registry: {
10
15
  value: '<url>',
@@ -22,7 +27,7 @@ export const views = {
22
27
  };
23
28
  export const command = async (conf) => {
24
29
  const rc = new RegistryClient(conf.options);
25
- const response = await rc.request(new URL('-/whoami', conf.options.registry), { useCache: false });
30
+ const response = await rc.request(new URL('-/whoami', await resolveRegistry(conf)), { useCache: false });
26
31
  const { username } = response.json();
27
32
  return { username };
28
33
  };
@@ -21,9 +21,11 @@ export declare const commands: {
21
21
  readonly '?': "help";
22
22
  readonly info: "view";
23
23
  readonly ls: "list";
24
+ readonly out: "outdated";
24
25
  readonly show: "view";
25
26
  readonly xc: "exec-cache";
26
27
  readonly access: "access";
28
+ readonly audit: "audit";
27
29
  readonly bugs: "bugs";
28
30
  readonly build: "build";
29
31
  readonly cache: "cache";
@@ -35,21 +37,25 @@ export declare const commands: {
35
37
  readonly docs: "docs";
36
38
  readonly exec: "exec";
37
39
  readonly 'exec-local': "exec-local";
40
+ readonly fund: "fund";
38
41
  readonly help: "help";
39
42
  readonly init: "init";
40
43
  readonly install: "install";
41
44
  readonly login: "login";
42
45
  readonly logout: "logout";
43
46
  readonly list: "list";
47
+ readonly outdated: "outdated";
44
48
  readonly pack: "pack";
45
49
  readonly ping: "ping";
46
50
  readonly pkg: "pkg";
47
51
  readonly profile: "profile";
48
52
  readonly publish: "publish";
49
53
  readonly query: "query";
54
+ readonly registry: "registry";
50
55
  readonly repo: "repo";
51
56
  readonly 'run-exec': "run-exec";
52
57
  readonly run: "run";
58
+ readonly setup: "setup";
53
59
  readonly token: "token";
54
60
  readonly uninstall: "uninstall";
55
61
  readonly unpublish: "unpublish";
@@ -85,12 +91,17 @@ export declare const definition: import("jackspeak").Jack<{
85
91
  'no-color': import("jackspeak").ConfigOption<"boolean", false, undefined>;
86
92
  } & {
87
93
  registry: {
94
+ hint: string;
95
+ description: string;
96
+ };
97
+ 'default-registry-alias': {
88
98
  hint: string;
89
99
  default: string;
90
100
  description: string;
91
101
  };
92
102
  } & {
93
103
  registry: import("jackspeak").ConfigOption<"string", false, readonly string[] | undefined>;
104
+ 'default-registry-alias': import("jackspeak").ConfigOption<"string", false, readonly string[] | undefined>;
94
105
  } & {
95
106
  registries: {
96
107
  hint: string;
@@ -306,6 +317,21 @@ export declare const definition: import("jackspeak").Jack<{
306
317
  };
307
318
  } & {
308
319
  view: import("jackspeak").ConfigOption<"string", false, readonly string[] | undefined>;
320
+ } & {
321
+ loglevel: {
322
+ hint: string;
323
+ default: string;
324
+ description: string;
325
+ validOptions: readonly ["silent", "error", "warn", "info", "verbose", "debug"];
326
+ };
327
+ } & {
328
+ loglevel: import("jackspeak").ConfigOption<"string", false, readonly string[] | undefined>;
329
+ } & {
330
+ verbose: {
331
+ description: string;
332
+ };
333
+ } & {
334
+ verbose: import("jackspeak").ConfigOption<"boolean", false, undefined>;
309
335
  } & {
310
336
  'dashboard-root': {
311
337
  hint: string;
@@ -318,6 +344,10 @@ export declare const definition: import("jackspeak").Jack<{
318
344
  short: string;
319
345
  description: string;
320
346
  };
347
+ 'save-exact': {
348
+ short: string;
349
+ description: string;
350
+ };
321
351
  'save-optional': {
322
352
  short: string;
323
353
  description: string;
@@ -331,9 +361,17 @@ export declare const definition: import("jackspeak").Jack<{
331
361
  };
332
362
  } & {
333
363
  'save-dev': import("jackspeak").ConfigOption<"boolean", false, undefined>;
364
+ 'save-exact': import("jackspeak").ConfigOption<"boolean", false, undefined>;
334
365
  'save-optional': import("jackspeak").ConfigOption<"boolean", false, undefined>;
335
366
  'save-peer': import("jackspeak").ConfigOption<"boolean", false, undefined>;
336
367
  'save-prod': import("jackspeak").ConfigOption<"boolean", false, undefined>;
368
+ } & {
369
+ 'save-prefix': {
370
+ description: string;
371
+ default: string;
372
+ };
373
+ } & {
374
+ 'save-prefix': import("jackspeak").ConfigOption<"string", false, readonly string[] | undefined>;
337
375
  } & {
338
376
  'expect-results': {
339
377
  hint: string;
@@ -16,6 +16,7 @@ export const defaultEditor = () => process.env.EDITOR ||
16
16
  : 'vi');
17
17
  const canonicalCommands = {
18
18
  access: 'access',
19
+ audit: 'audit',
19
20
  bugs: 'bugs',
20
21
  build: 'build',
21
22
  cache: 'cache',
@@ -27,6 +28,7 @@ const canonicalCommands = {
27
28
  docs: 'docs',
28
29
  exec: 'exec',
29
30
  'exec-local': 'exec-local',
31
+ fund: 'fund',
30
32
  help: 'help',
31
33
  init: 'init',
32
34
  install: 'install',
@@ -34,15 +36,18 @@ const canonicalCommands = {
34
36
  logout: 'logout',
35
37
  list: 'list',
36
38
  ls: 'ls',
39
+ outdated: 'outdated',
37
40
  pack: 'pack',
38
41
  ping: 'ping',
39
42
  pkg: 'pkg',
40
43
  profile: 'profile',
41
44
  publish: 'publish',
42
45
  query: 'query',
46
+ registry: 'registry',
43
47
  repo: 'repo',
44
48
  'run-exec': 'run-exec',
45
49
  run: 'run',
50
+ setup: 'setup',
46
51
  token: 'token',
47
52
  uninstall: 'uninstall',
48
53
  unpublish: 'unpublish',
@@ -70,6 +75,7 @@ const aliases = {
70
75
  '?': 'help',
71
76
  info: 'view',
72
77
  ls: 'list',
78
+ out: 'outdated',
73
79
  show: 'view',
74
80
  xc: 'exec-cache',
75
81
  };
@@ -155,26 +161,46 @@ export const definition = j
155
161
  .opt({
156
162
  registry: {
157
163
  hint: 'url',
158
- default: 'https://registry.npmjs.org/',
159
164
  description: `Sets the registry for fetching packages, when no registry
160
165
  is explicitly set on a specifier.
161
166
 
162
167
  For example, \`express@latest\` will be resolved by looking
163
168
  up the metadata from this registry.
164
169
 
165
- Note that alias specifiers starting with \`npm:\` will
166
- still map to \`https://registry.npmjs.org/\` if this is
167
- changed, unless the a new mapping is created via the
168
- \`--registries\` option.
170
+ There is **no default**. When unset, bare specifiers fall
171
+ back to the registry alias named by
172
+ \`--default-registry-alias\` (\`npm\` by default). If that
173
+ alias is also unconfigured, commands that need a registry
174
+ fail with a config error. Run \`vlt setup\` (or
175
+ \`vlt login\`) to configure one.
176
+
177
+ See https://docs.vlt.sh/cli
178
+ `,
179
+ },
180
+ 'default-registry-alias': {
181
+ hint: 'name',
182
+ default: 'npm',
183
+ description: `The name of the registry alias (a key in
184
+ \`--registries\`) that bare specifiers (e.g.
185
+ \`express@latest\`) and transitive dependencies without an
186
+ explicit registry protocol resolve through, when neither
187
+ \`--registry\` nor a matching \`--scoped-registries\` entry
188
+ applies.
189
+
190
+ Defaults to \`npm\`. Note that the \`npm\` alias has **no**
191
+ built-in URL -- it must be configured (for example via
192
+ \`vlt setup\`, which points it at your vlt.io registry),
193
+ otherwise bare specifiers will have no registry to resolve
194
+ against.
169
195
  `,
170
196
  },
171
197
  })
172
198
  .optList({
173
199
  registries: {
174
200
  hint: 'name=url',
175
- description: `Specify named registry hosts by their prefix. To set the
176
- default registry used for non-namespaced specifiers,
177
- use the \`--registry\` option.
201
+ description: `Specify named registry hosts by their prefix. To choose
202
+ which alias is used for non-namespaced specifiers, use the
203
+ \`--default-registry-alias\` option.
178
204
 
179
205
  Prefixes can be used as a package alias. For example:
180
206
 
@@ -182,9 +208,10 @@ export const definition = j
182
208
  vlt --registries loc=http://reg.local install foo@loc:foo@1.x
183
209
  \`\`\`
184
210
 
185
- By default, the public npm registry is registered to the
186
- \`npm:\` prefix. It is not recommended to change this
187
- mapping in most cases.
211
+ There is **no** built-in \`npm\` registry URL; the \`npm\`
212
+ alias must be configured (e.g. via \`vlt setup\`) before it
213
+ can be used. The \`gh\` and \`jsr\` aliases have built-in
214
+ defaults that can be overridden here.
188
215
  `,
189
216
  },
190
217
  'scoped-registries': {
@@ -554,6 +581,41 @@ export const definition = j
554
581
  'silent',
555
582
  ],
556
583
  },
584
+ })
585
+ .opt({
586
+ loglevel: {
587
+ hint: 'level',
588
+ default: 'info',
589
+ description: `Sets the verbosity of diagnostic logging written to
590
+ stderr (registry requests, warnings, etc). This is
591
+ independent of \`--view\`, which controls a command's
592
+ result output on stdout.
593
+
594
+ - silent: No diagnostic logging.
595
+ - error: Only errors.
596
+ - warn: Errors and warnings.
597
+ - info: Default. High-level progress.
598
+ - verbose: Adds per-request logging (each registry URL
599
+ with its cache/stale/fetch outcome and status code).
600
+ - debug: Everything, including low-level detail.
601
+
602
+ \`--verbose\` is shorthand for \`--loglevel=verbose\`.`,
603
+ validOptions: [
604
+ 'silent',
605
+ 'error',
606
+ 'warn',
607
+ 'info',
608
+ 'verbose',
609
+ 'debug',
610
+ ],
611
+ },
612
+ })
613
+ .flag({
614
+ verbose: {
615
+ description: `Shorthand for \`--loglevel=verbose\`. Streams each
616
+ registry request to stderr with its cache/fetch outcome
617
+ and status code, useful for debugging request behavior.`,
618
+ },
557
619
  })
558
620
  .optList({
559
621
  'dashboard-root': {
@@ -568,6 +630,12 @@ export const definition = j
568
630
  description: `Save installed packages to a package.json file as
569
631
  devDependencies`,
570
632
  },
633
+ 'save-exact': {
634
+ short: 'E',
635
+ description: `Save installed packages to package.json with an exact
636
+ version rather than using the default semver range
637
+ operator (e.g. \`1.2.3\` instead of \`^1.2.3\`).`,
638
+ },
571
639
  'save-optional': {
572
640
  short: 'O',
573
641
  description: `Save installed packages to a package.json file as
@@ -584,6 +652,15 @@ export const definition = j
584
652
  devDependencies or optionalDependencies, but you want to
585
653
  move it to be a non-optional production dependency.`,
586
654
  },
655
+ })
656
+ .opt({
657
+ 'save-prefix': {
658
+ description: `The version prefix to use when saving dependencies to
659
+ package.json (e.g. \`^\`, \`~\`, \`>=\`, or empty string
660
+ for exact versions). Defaults to \`^\`.
661
+ Ignored when \`--save-exact\` is set.`,
662
+ default: '^',
663
+ },
587
664
  })
588
665
  .opt({
589
666
  'expect-results': {
@@ -212,6 +212,12 @@ export class Config {
212
212
  else
213
213
  this.command = getCommand(p.values['fallback-command']);
214
214
  Object.assign(this, p);
215
+ // `--verbose` is shorthand for `--loglevel=verbose`. Only apply it
216
+ // when loglevel is still at its default so an explicit `--loglevel`
217
+ // always wins.
218
+ if (p.values.verbose && p.values.loglevel === 'info') {
219
+ p.values.loglevel = 'verbose';
220
+ }
215
221
  /* c8 ignore start - unpossible */
216
222
  if (!isParsed(this))
217
223
  throw error('failed to parse config');