@vltpkg/cli-sdk 1.4.0 → 1.6.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.
Files changed (74) hide show
  1. package/dist/allow-skills.d.ts +36 -0
  2. package/dist/allow-skills.js +49 -0
  3. package/dist/commands/build.d.ts +15 -4
  4. package/dist/commands/build.js +50 -12
  5. package/dist/commands/ci.d.ts +2 -2
  6. package/dist/commands/ci.js +10 -2
  7. package/dist/commands/create.d.ts +2 -1
  8. package/dist/commands/create.js +2 -3
  9. package/dist/commands/exec.d.ts +2 -1
  10. package/dist/commands/exec.js +2 -3
  11. package/dist/commands/init.js +4 -3
  12. package/dist/commands/install/reporter.d.ts +1 -1
  13. package/dist/commands/install/reporter.js +91 -5
  14. package/dist/commands/install.d.ts +50 -4
  15. package/dist/commands/install.js +107 -25
  16. package/dist/commands/list.js +8 -2
  17. package/dist/commands/publish.d.ts +0 -1
  18. package/dist/commands/publish.js +27 -16
  19. package/dist/commands/query.js +8 -2
  20. package/dist/commands/setup.d.ts +28 -2
  21. package/dist/commands/setup.js +185 -3
  22. package/dist/commands/skills.d.ts +56 -0
  23. package/dist/commands/skills.js +267 -0
  24. package/dist/commands/token.js +1 -1
  25. package/dist/commands/uninstall.d.ts +15 -4
  26. package/dist/commands/uninstall.js +32 -4
  27. package/dist/commands/unpublish.d.ts +0 -1
  28. package/dist/commands/unpublish.js +17 -4
  29. package/dist/commands/update.d.ts +13 -1
  30. package/dist/commands/update.js +18 -1
  31. package/dist/config/definition.d.ts +52 -0
  32. package/dist/config/definition.js +109 -1
  33. package/dist/config/index.d.ts +26 -3
  34. package/dist/config/index.js +149 -7
  35. package/dist/custom-help.js +4 -0
  36. package/dist/global-bin-dir.d.ts +37 -0
  37. package/dist/global-bin-dir.js +138 -0
  38. package/dist/global-project.d.ts +18 -0
  39. package/dist/global-project.js +67 -0
  40. package/dist/global-state.d.ts +24 -0
  41. package/dist/global-state.js +94 -0
  42. package/dist/global.d.ts +78 -0
  43. package/dist/global.js +409 -0
  44. package/dist/index.js +14 -3
  45. package/dist/install-receipt.d.ts +40 -0
  46. package/dist/install-receipt.js +69 -0
  47. package/dist/load-command.d.ts +2 -0
  48. package/dist/migrate-workspaces.d.ts +16 -0
  49. package/dist/migrate-workspaces.js +44 -0
  50. package/dist/output.js +13 -0
  51. package/dist/parse-add-remove-args.js +2 -14
  52. package/dist/print-err.js +4 -1
  53. package/dist/publish-config.d.ts +9 -0
  54. package/dist/publish-config.js +8 -0
  55. package/dist/query-auth.d.ts +3 -2
  56. package/dist/query-auth.js +6 -4
  57. package/dist/reload-config.js +2 -1
  58. package/dist/require-registry.d.ts +7 -0
  59. package/dist/require-registry.js +13 -1
  60. package/dist/self-update.d.ts +74 -0
  61. package/dist/self-update.js +401 -0
  62. package/dist/shell-setup/env.d.ts +9 -0
  63. package/dist/shell-setup/env.js +25 -0
  64. package/dist/shell-setup/index.d.ts +69 -0
  65. package/dist/shell-setup/index.js +213 -0
  66. package/dist/shell-setup/posix.d.ts +36 -0
  67. package/dist/shell-setup/posix.js +158 -0
  68. package/dist/shell-setup/windows.d.ts +39 -0
  69. package/dist/shell-setup/windows.js +151 -0
  70. package/dist/shell.d.ts +18 -0
  71. package/dist/shell.js +110 -0
  72. package/dist/skills-prompt.d.ts +28 -0
  73. package/dist/skills-prompt.js +78 -0
  74. package/package.json +30 -28
@@ -0,0 +1,401 @@
1
+ import { findCmdShimIfExists } from '@vltpkg/cmd-shim';
2
+ import { isDepID } from '@vltpkg/dep-id';
3
+ import { error } from '@vltpkg/error-cause';
4
+ import { lt, valid } from '@vltpkg/semver';
5
+ import { Spec } from '@vltpkg/spec';
6
+ import { which } from '@vltpkg/which';
7
+ import { spawn } from 'node:child_process';
8
+ import { createHash } from 'node:crypto';
9
+ import { constants, existsSync } from 'node:fs';
10
+ import { access, chmod, lstat, readFile, realpath, rename, rm, stat, } from 'node:fs/promises';
11
+ import { basename, dirname, extname, join, relative, resolve, sep, } from 'node:path';
12
+ import { loadPackageJson } from 'package-json-from-dist';
13
+ import { findSelf } from "./global-bin-dir.js";
14
+ import { globalSpec } from "./global.js";
15
+ import { globalWorkspacePath, isInside, samePath, } from "./global-project.js";
16
+ import { readGlobalState, updateGlobalState } from "./global-state.js";
17
+ import { writeInstallReceipt } from "./install-receipt.js";
18
+ import { parseSpecArg } from "./require-registry.js";
19
+ import { prettyPath } from "./shell.js";
20
+ const { version: running } = loadPackageJson(import.meta.filename, process.env.__VLT_INTERNAL_CLI_PACKAGE_JSON);
21
+ const installerLine = 'Re-run the installer to update vlt:\n curl -fsSL https://install.vlt.sh | bash';
22
+ const writable = (dir) => access(dir, constants.W_OK).then(() => true, () => false);
23
+ // exit 1 without usage: the usage was fine
24
+ const refuse = (self, message) => {
25
+ process.exitCode = 1;
26
+ return { status: 'refused', from: running, dir: self.dir, message };
27
+ };
28
+ const isFile = (f) => stat(f).then(s => s.isFile(), () => false);
29
+ const cellars = () => [
30
+ process.env.HOMEBREW_CELLAR,
31
+ '/opt/homebrew/Cellar',
32
+ '/usr/local/Cellar',
33
+ '/home/linuxbrew/.linuxbrew/Cellar',
34
+ ].filter((c) => !!c);
35
+ const whichNpm = async () => {
36
+ try {
37
+ const found = await which('npm', { nothrow: true });
38
+ if (!found)
39
+ return;
40
+ const real = await realpath((await findCmdShimIfExists(found))?.[1] ?? found);
41
+ return basename(real) === 'npm-cli.js' ? real : undefined;
42
+ }
43
+ catch { }
44
+ };
45
+ // npm's -g layout: <prefix>/lib/node_modules, win32 <prefix>/node_modules
46
+ const findNpm = async (self) => {
47
+ const i = self.target.lastIndexOf(`${sep}node_modules${sep}vlt${sep}`);
48
+ if (i === -1)
49
+ return;
50
+ const nm = self.target.slice(0, i) + sep + 'node_modules';
51
+ const win32 = process.platform === 'win32';
52
+ const up = dirname(nm);
53
+ const prefix = win32 ?
54
+ // vlt.cmd is in the prefix
55
+ samePath(up, self.dir) && up
56
+ : basename(up) === 'lib' && dirname(up);
57
+ if (!prefix)
58
+ return;
59
+ const node = dirname(process.execPath);
60
+ const candidates = [
61
+ join(nm, 'npm/bin/npm-cli.js'),
62
+ win32 ?
63
+ join(node, 'node_modules/npm/bin/npm-cli.js')
64
+ : join(dirname(node), 'lib/node_modules/npm/bin/npm-cli.js'),
65
+ ];
66
+ for (const c of candidates) {
67
+ if (await isFile(c))
68
+ return { npmCli: c, prefix };
69
+ }
70
+ const npmCli = await whichNpm();
71
+ return npmCli && { npmCli, prefix };
72
+ };
73
+ const classify = async (self, root) => {
74
+ // before the receipt: it can outlive the vlt it was written for
75
+ const g = await realpath(root).catch(() => resolve(root));
76
+ if (isInside(g, self.target))
77
+ return { kind: 'global-project' };
78
+ const { receipt } = self;
79
+ if (receipt?.data.method === 'standalone') {
80
+ if (self.standalone)
81
+ return { kind: 'standalone-receipt', receipt };
82
+ }
83
+ else if (receipt) {
84
+ const npm = receipt.data.method === 'npm' && (await findNpm(self));
85
+ return npm ?
86
+ { kind: 'npm', ...npm, receipt }
87
+ : { kind: 'installer' };
88
+ }
89
+ // before npm: a node formula has npm's layout
90
+ if (cellars().some(c => isInside(c, self.target))) {
91
+ return { kind: 'homebrew' };
92
+ }
93
+ if (self.standalone)
94
+ return { kind: 'standalone' };
95
+ const npm = await findNpm(self);
96
+ return npm ? { kind: 'npm', ...npm } : { kind: 'unknown' };
97
+ };
98
+ const sha512 = async (file) => `sha512-${createHash('sha512')
99
+ .update(await readFile(file))
100
+ .digest('base64')}`;
101
+ const safeBin = (b) => /^[a-z0-9][\w.-]*$/i.test(b);
102
+ /** a refusal message, or undefined once replaced */
103
+ const updateStandalone = async (self, receipt, to, fetchRelease) => {
104
+ const { target, channel, binaries = [] } = receipt.data;
105
+ if (!fetchRelease || !target)
106
+ return installerLine;
107
+ const win32 = process.platform === 'win32';
108
+ const at = prettyPath(self.dir);
109
+ // stat().uid is 0 on win32
110
+ if (!win32 &&
111
+ (await stat(self.found)).uid === 0 &&
112
+ process.getuid?.() !== 0) {
113
+ return `vlt at ${at} is owned by root. Update it the way you installed it, or run this as root.`;
114
+ }
115
+ if (!(await writable(self.dir))) {
116
+ return `vlt at ${at} is not writable. Update it the way you installed it.`;
117
+ }
118
+ const ext = extname(self.found).toLowerCase() === '.exe' ? '.exe' : '';
119
+ const entries = [];
120
+ for (const bin of new Set(binaries)) {
121
+ if (bin === 'vlt' || !safeBin(bin))
122
+ continue;
123
+ const file = join(self.dir, bin + ext);
124
+ const st = await lstat(file).catch(() => undefined);
125
+ // links follow vlt
126
+ if (st && !st.isSymbolicLink())
127
+ entries.push({ bin, file });
128
+ }
129
+ // last, so a failure part-way leaves a working vlt
130
+ entries.push({
131
+ bin: 'vlt',
132
+ file: join(self.dir, basename(self.found)),
133
+ });
134
+ const tmps = [];
135
+ const cleanup = () => Promise.all(tmps.map(f => rm(f, { force: true })));
136
+ const ready = [];
137
+ try {
138
+ for (const { bin, file } of entries) {
139
+ // a running vlt.exe.old: the rename below says so
140
+ if (win32)
141
+ await rm(`${file}.old`, { force: true }).catch(() => { });
142
+ // same dir: rename is atomic
143
+ const dest = join(self.dir, `.${bin}-${to}.tmp`);
144
+ tmps.push(dest);
145
+ const { checksum } = await fetchRelease({
146
+ version: to,
147
+ target,
148
+ channel,
149
+ bin,
150
+ dest,
151
+ });
152
+ const found = await sha512(dest);
153
+ if (found !== checksum) {
154
+ throw error(`Checksum mismatch for ${bin} ${to}`, {
155
+ code: 'EINTEGRITY',
156
+ wanted: checksum,
157
+ found,
158
+ });
159
+ }
160
+ await chmod(dest, (await stat(file)).mode & 0o777);
161
+ ready.push({ file, dest });
162
+ }
163
+ }
164
+ catch (er) {
165
+ await cleanup();
166
+ throw er;
167
+ }
168
+ // never write into a running file: rename only
169
+ for (const { file, dest } of ready) {
170
+ try {
171
+ if (win32) {
172
+ // a running .exe can be renamed, not replaced
173
+ await rename(file, `${file}.old`);
174
+ await rename(dest, file).catch(async (er) => {
175
+ await rename(`${file}.old`, file).catch(() => { });
176
+ throw er;
177
+ });
178
+ }
179
+ else {
180
+ await rename(dest, file);
181
+ }
182
+ }
183
+ catch (cause) {
184
+ await cleanup();
185
+ throw error(`Could not replace ${file}. Close other vlt processes and editors, and check permissions.`, { path: file, cause });
186
+ }
187
+ }
188
+ };
189
+ const runNpm = (npmCli, prefix, arg) => new Promise((res, rej) => {
190
+ // stdout to stderr: keeps --view=json parseable
191
+ const child = spawn(process.execPath, [npmCli, 'install', '--global', '--prefix', prefix, arg], { stdio: ['inherit', 2, 2] });
192
+ child.on('error', rej);
193
+ child.on('close', (code) => res(code ?? 1));
194
+ });
195
+ const rewriteReceipt = (receipt, to) => receipt &&
196
+ writeInstallReceipt(receipt.file, { version: to }).catch(() => { });
197
+ // vlt, vlt@..., a vlt tarball
198
+ const vltArg = /^vlt(@|$)|(^|[/\\:])vlt-\d[^/\\]*\.tgz$/;
199
+ /** `vlt install -g vlt...`, for the human view */
200
+ export const isSelfUpdateArgs = (conf) => conf.command === 'install' &&
201
+ !!conf.globalRoot &&
202
+ conf.positionals.some(p => vltArg.test(p));
203
+ /**
204
+ * `vlt install -g vlt`: update the vlt on the PATH the way it was
205
+ * installed. Undefined when vlt is not a positional.
206
+ */
207
+ export const selfUpdate = async (conf, { fetchRelease } = {}) => {
208
+ const { globalRoot, positionals } = conf;
209
+ if (!globalRoot || !positionals.length)
210
+ return;
211
+ const specs = await Promise.all(positionals.map(p => globalSpec(p, conf)));
212
+ const [spec] = specs;
213
+ if (!spec || !specs.some(s => s.name === 'vlt'))
214
+ return;
215
+ if (specs.length > 1) {
216
+ throw error('Update vlt on its own, without other packages', {
217
+ code: 'EUSAGE',
218
+ found: positionals.join(' '),
219
+ });
220
+ }
221
+ const self = await findSelf();
222
+ if (!self) {
223
+ throw error(`Can't tell which vlt to update: run the vlt on your PATH, not ${process.argv[1] ?? process.execPath}`, { code: 'EUSAGE' });
224
+ }
225
+ const owner = await classify(self, globalRoot);
226
+ const at = prettyPath(self.dir);
227
+ const foreign = `vlt at ${at} is not managed by vlt or npm. Update it the way you installed it.`;
228
+ if (owner.kind === 'installer') {
229
+ return { done: refuse(self, installerLine) };
230
+ }
231
+ if (owner.kind === 'homebrew') {
232
+ return {
233
+ done: refuse(self, `vlt at ${at} was installed by Homebrew. Run \`brew upgrade vlt\`.`),
234
+ };
235
+ }
236
+ if (owner.kind === 'standalone') {
237
+ return { done: refuse(self, foreign) };
238
+ }
239
+ // npm's node_modules not writable: npm's EACCES says so
240
+ const bootstrap = (owner.kind === 'npm' || owner.kind === 'unknown') &&
241
+ !(await writable(self.dir));
242
+ if (owner.kind === 'unknown' && !bootstrap) {
243
+ return { done: refuse(self, foreign) };
244
+ }
245
+ const raw = String(positionals[0]);
246
+ const implicit = !parseSpecArg(raw, conf.options).bareSpec;
247
+ const receipt = 'receipt' in owner ? owner.receipt : undefined;
248
+ const channel = receipt?.data.channel;
249
+ const tag = channel ?? conf.options.tag;
250
+ const { name, version: to } = await conf.options.packageInfo.manifest(implicit && channel ?
251
+ Spec.parse('vlt', tag, conf.options)
252
+ : spec);
253
+ if (name !== 'vlt' || !to) {
254
+ throw error(`${raw} is not a version of vlt`, {
255
+ code: 'EUSAGE',
256
+ found: name,
257
+ });
258
+ }
259
+ const kind = bootstrap ? 'bootstrap'
260
+ : owner.kind === 'standalone-receipt' ? 'standalone'
261
+ : owner.kind === 'npm' ? 'npm'
262
+ : 'global-project';
263
+ const base = { case: kind, from: running, to, dir: self.dir };
264
+ if (to === running)
265
+ return { done: { ...base, status: 'up-to-date' } };
266
+ // `latest` may lag a new major
267
+ if (implicit && lt(to, running)) {
268
+ return { done: { ...base, status: 'newer-running', tag } };
269
+ }
270
+ const registry = spec.final.type === 'registry';
271
+ if (owner.kind === 'standalone-receipt') {
272
+ // releases are registry versions
273
+ if (!registry || !valid(to)) {
274
+ throw error(`${raw} is not a vlt release`, {
275
+ code: 'EUSAGE',
276
+ found: raw,
277
+ });
278
+ }
279
+ const refused = await updateStandalone(self, owner.receipt, to, fetchRelease);
280
+ if (refused)
281
+ return { done: refuse(self, refused) };
282
+ await rewriteReceipt(owner.receipt, to);
283
+ return { done: { ...base, status: 'updated' } };
284
+ }
285
+ if (owner.kind === 'npm' && !bootstrap) {
286
+ const code = await runNpm(owner.npmCli, owner.prefix, registry ? `vlt@${to}` : `vlt@${spec.bareSpec}`);
287
+ // npm already said why
288
+ if (code !== 0) {
289
+ process.exitCode = code;
290
+ return { done: { ...base, status: 'failed' } };
291
+ }
292
+ await rewriteReceipt(receipt, to);
293
+ return { done: { ...base, status: 'updated' } };
294
+ }
295
+ // the ws pins what was resolved
296
+ if (registry)
297
+ conf.positionals = [`vlt@${to}`];
298
+ return {
299
+ selfUnwritable: bootstrap,
300
+ finish: async (global) => {
301
+ const u = {
302
+ ...base,
303
+ status: 'updated',
304
+ dir: global?.binDir ?? self.dir,
305
+ ...(bootstrap ? { notWritable: self.dir } : {}),
306
+ };
307
+ if (bootstrap &&
308
+ global?.inPath &&
309
+ global.bins.includes('vlt')) {
310
+ const now = await which('vlt', { nothrow: true }).catch(() => null);
311
+ const first = now && dirname(now);
312
+ if (first &&
313
+ !samePath(await realpath(first).catch(() => first), global.binDir)) {
314
+ u.shadowedBy = first;
315
+ }
316
+ }
317
+ return u;
318
+ },
319
+ };
320
+ };
321
+ /** `vlt uninstall -g vlt` of a vlt that is not a global package */
322
+ export const refuseSelfUninstall = async (conf) => {
323
+ const { globalRoot, positionals } = conf;
324
+ if (!globalRoot || !positionals.includes('vlt'))
325
+ return;
326
+ const ws = resolve(globalRoot, globalWorkspacePath('vlt'));
327
+ if (existsSync(resolve(ws, 'package.json')))
328
+ return;
329
+ const self = await findSelf();
330
+ if (!self)
331
+ return;
332
+ const { kind } = await classify(self, globalRoot);
333
+ return refuse(self, kind === 'npm' ?
334
+ 'vlt was installed by npm. Run `npm uninstall -g vlt` to remove it.'
335
+ : kind === 'homebrew' ?
336
+ 'vlt was installed by Homebrew. Run `brew uninstall vlt` to remove it.'
337
+ : `vlt at ${prettyPath(self.dir)} is not managed by vlt. Remove it the way you installed it.`);
338
+ };
339
+ /** store id of the running vlt, when it runs from the global project */
340
+ export const runningStoreDep = async (root) => {
341
+ const script = process.argv[1];
342
+ if (!script)
343
+ return;
344
+ try {
345
+ const [real, store] = await Promise.all([
346
+ realpath(script),
347
+ realpath(resolve(root, 'node_modules/.vlt')),
348
+ ]);
349
+ const [id] = relative(store, real).split(sep);
350
+ return isDepID(id) ? id : undefined;
351
+ }
352
+ catch { }
353
+ };
354
+ /**
355
+ * Record the running vlt's store dir for removal by a later -g
356
+ * command when the graph no longer has it, and forget listed dirs
357
+ * the graph has again.
358
+ */
359
+ export const deferSelfRemove = async (root, graph, keep) => {
360
+ const store = resolve(await realpath(root), 'node_modules/.vlt');
361
+ const add = keep && !graph.nodes.has(keep) ? [resolve(store, keep)] : [];
362
+ const { pendingRemove = [] } = await readGlobalState(root);
363
+ const kept = pendingRemove.filter(p => {
364
+ const id = basename(p);
365
+ return !(isDepID(id) && graph.nodes.has(id));
366
+ });
367
+ if (!add.length && kept.length === pendingRemove.length)
368
+ return;
369
+ await updateGlobalState(root, s => ({
370
+ ...s,
371
+ pendingRemove: [...new Set([...kept, ...add])],
372
+ }));
373
+ };
374
+ /** human lines for a self-update */
375
+ export const selfUpdateLines = (s) => {
376
+ if (s.status === 'refused')
377
+ return [s.message];
378
+ if (s.status === 'up-to-date') {
379
+ return [`✅ vlt ${s.to} is already up to date`];
380
+ }
381
+ if (s.status === 'newer-running') {
382
+ return [
383
+ `ℹ️ vlt ${s.from} is running but "${s.tag}" is ${s.to}; run \`vlt i -g vlt@${s.tag}\` to downgrade`,
384
+ ];
385
+ }
386
+ if (s.status === 'failed')
387
+ return [];
388
+ if (s.case === 'bootstrap') {
389
+ return [
390
+ `ℹ️ ${prettyPath(s.notWritable ?? s.dir)} is not writable, so vlt ${s.to} was installed as a global package.`,
391
+ ...(s.shadowedBy ?
392
+ [
393
+ `⚠️ ${prettyPath(s.shadowedBy)} is earlier in your PATH, so \`vlt\` still runs vlt ${s.from}.`,
394
+ ]
395
+ : []),
396
+ ];
397
+ }
398
+ return [
399
+ `⬆️ Updated vlt ${s.from} → ${s.to} in ${prettyPath(s.dir)}${s.case === 'npm' ? ' (via npm)' : ''}`,
400
+ ];
401
+ };
@@ -0,0 +1,9 @@
1
+ import type { ShellOptions } from '../shell.ts';
2
+ /** `<global-dir>/env`, sourced by sh-family rc files */
3
+ export declare const envFile: (globalDir: string) => string;
4
+ /** `<global-dir>/env.fish`, sourced by fish */
5
+ export declare const envFishFile: (globalDir: string) => string;
6
+ /** sh script adding `dir` to the `PATH` once */
7
+ export declare const renderEnv: (dir: string, o?: ShellOptions) => string;
8
+ /** fish script adding `dir` to the `PATH` of the session */
9
+ export declare const renderEnvFish: (dir: string, o?: ShellOptions) => string;
@@ -0,0 +1,25 @@
1
+ import { resolve } from 'node:path';
2
+ import { fishPath, posixPath, shellPathCommand } from "../shell.js";
3
+ /** `<global-dir>/env`, sourced by sh-family rc files */
4
+ export const envFile = (globalDir) => resolve(globalDir, 'env');
5
+ /** `<global-dir>/env.fish`, sourced by fish */
6
+ export const envFishFile = (globalDir) => resolve(globalDir, 'env.fish');
7
+ /** sh script adding `dir` to the `PATH` once */
8
+ export const renderEnv = (dir, o = {}) => [
9
+ '# vlt global bin dir; sourced from the shell rc file. Edit with `vlt setup --path`.',
10
+ 'case ":$PATH:" in',
11
+ ` *:${posixPath(dir, o)}:*) ;;`,
12
+ ` *) ${shellPathCommand('sh', dir, o)} ;;`,
13
+ 'esac',
14
+ '',
15
+ ].join('\n');
16
+ /** fish script adding `dir` to the `PATH` of the session */
17
+ export const renderEnvFish = (dir, o = {}) => {
18
+ const d = fishPath(dir, o);
19
+ return [
20
+ '# vlt global bin dir; sourced from fish config. Edit with `vlt setup --path`.',
21
+ // session only, and fish_add_path needs fish 3.2
22
+ `contains -- ${d} $PATH; or set -gx PATH ${d} $PATH`,
23
+ '',
24
+ ].join('\n');
25
+ };
@@ -0,0 +1,69 @@
1
+ import type { GlobalBins } from '../global.ts';
2
+ import type { Shell, ShellOptions } from '../shell.ts';
3
+ import type { FileAction, FileChange } from './posix.ts';
4
+ import type { WindowsPathChange } from './windows.ts';
5
+ export type { FileAction } from './posix.ts';
6
+ /** whether `vlt setup --path` can edit config for `shell` */
7
+ export declare const canSetupPath: (shell: Shell, platform?: NodeJS.Platform) => boolean;
8
+ export type PathSetupOptions = ShellOptions & {
9
+ /** holds the env files and backups */
10
+ globalDir: string;
11
+ /** dir to add to the `PATH` */
12
+ dir: string;
13
+ shell: Shell;
14
+ };
15
+ export type PathSetupPlan = {
16
+ globalDir: string;
17
+ dir: string;
18
+ shell: Shell;
19
+ changes: FileChange[];
20
+ /** win32: user Path change, instead of files */
21
+ registry?: WindowsPathChange;
22
+ /** win32: env the user Path was read with */
23
+ env?: NodeJS.ProcessEnv;
24
+ };
25
+ export type PathSetupFile = {
26
+ file: string;
27
+ kind: 'env' | 'rc' | 'registry';
28
+ action: FileAction | 'prepend';
29
+ };
30
+ export type PathSetupResult = {
31
+ dir: string;
32
+ shell: Shell;
33
+ files: PathSetupFile[];
34
+ backups: string[];
35
+ };
36
+ /** what adding `dir` to the `PATH` of new shells would change */
37
+ export declare const planPathSetup: (o: PathSetupOptions) => Promise<PathSetupPlan>;
38
+ export declare const pathSetupChanged: (plan: PathSetupPlan) => boolean;
39
+ export declare const pathSetupFiles: (plan: PathSetupPlan) => PathSetupFile[];
40
+ /** rc files or the user Path, for display */
41
+ export declare const rcList: (files: PathSetupFile[], home?: string) => string;
42
+ /** write the plan: env files, rc files, user Path, backed up */
43
+ export declare const applyPathSetup: (plan: PathSetupPlan) => Promise<PathSetupResult>;
44
+ /** loads the env file into the current shell (win32: adds `dir`) */
45
+ export declare const sourceCommand: (shell: Shell, globalDir: string, dir: string, o?: ShellOptions) => string;
46
+ export declare const pathSetupLines: (r: PathSetupResult, source: string, home?: string) => string[];
47
+ /** one trimmed answer */
48
+ export declare const ask: (question: string, { input, output, }?: {
49
+ input?: NodeJS.ReadableStream;
50
+ output?: NodeJS.WritableStream;
51
+ }) => Promise<string>;
52
+ export type OfferOptions = ShellOptions & {
53
+ globalDir: string;
54
+ yes?: boolean;
55
+ noModifyPath?: boolean;
56
+ input?: NodeJS.ReadableStream & {
57
+ isTTY?: boolean;
58
+ };
59
+ output?: NodeJS.WritableStream & {
60
+ isTTY?: boolean;
61
+ };
62
+ /** once, before the first prompt or line */
63
+ beforeOutput?: () => void;
64
+ };
65
+ /**
66
+ * After `install -g` linked into a dir not in the `PATH`: offer, once,
67
+ * in a terminal, to add it to the PATH. Never throws.
68
+ */
69
+ export declare const offerPathSetup: (g: GlobalBins, o: OfferOptions) => Promise<void>;