@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.
- package/dist/allow-skills.d.ts +36 -0
- package/dist/allow-skills.js +49 -0
- package/dist/commands/build.d.ts +15 -4
- package/dist/commands/build.js +50 -12
- package/dist/commands/ci.d.ts +2 -2
- package/dist/commands/ci.js +10 -2
- package/dist/commands/create.d.ts +2 -1
- package/dist/commands/create.js +2 -3
- package/dist/commands/exec.d.ts +2 -1
- package/dist/commands/exec.js +2 -3
- package/dist/commands/init.js +4 -3
- package/dist/commands/install/reporter.d.ts +1 -1
- package/dist/commands/install/reporter.js +91 -5
- package/dist/commands/install.d.ts +50 -4
- package/dist/commands/install.js +107 -25
- package/dist/commands/list.js +8 -2
- package/dist/commands/publish.d.ts +0 -1
- package/dist/commands/publish.js +27 -16
- package/dist/commands/query.js +8 -2
- package/dist/commands/setup.d.ts +28 -2
- package/dist/commands/setup.js +185 -3
- package/dist/commands/skills.d.ts +56 -0
- package/dist/commands/skills.js +267 -0
- package/dist/commands/token.js +1 -1
- package/dist/commands/uninstall.d.ts +15 -4
- package/dist/commands/uninstall.js +32 -4
- package/dist/commands/unpublish.d.ts +0 -1
- package/dist/commands/unpublish.js +17 -4
- package/dist/commands/update.d.ts +13 -1
- package/dist/commands/update.js +18 -1
- package/dist/config/definition.d.ts +52 -0
- package/dist/config/definition.js +109 -1
- package/dist/config/index.d.ts +26 -3
- package/dist/config/index.js +149 -7
- package/dist/custom-help.js +4 -0
- package/dist/global-bin-dir.d.ts +37 -0
- package/dist/global-bin-dir.js +138 -0
- package/dist/global-project.d.ts +18 -0
- package/dist/global-project.js +67 -0
- package/dist/global-state.d.ts +24 -0
- package/dist/global-state.js +94 -0
- package/dist/global.d.ts +78 -0
- package/dist/global.js +409 -0
- package/dist/index.js +14 -3
- package/dist/install-receipt.d.ts +40 -0
- package/dist/install-receipt.js +69 -0
- package/dist/load-command.d.ts +2 -0
- package/dist/migrate-workspaces.d.ts +16 -0
- package/dist/migrate-workspaces.js +44 -0
- package/dist/output.js +13 -0
- package/dist/parse-add-remove-args.js +2 -14
- package/dist/print-err.js +4 -1
- package/dist/publish-config.d.ts +9 -0
- package/dist/publish-config.js +8 -0
- package/dist/query-auth.d.ts +3 -2
- package/dist/query-auth.js +6 -4
- package/dist/reload-config.js +2 -1
- package/dist/require-registry.d.ts +7 -0
- package/dist/require-registry.js +13 -1
- package/dist/self-update.d.ts +74 -0
- package/dist/self-update.js +401 -0
- package/dist/shell-setup/env.d.ts +9 -0
- package/dist/shell-setup/env.js +25 -0
- package/dist/shell-setup/index.d.ts +69 -0
- package/dist/shell-setup/index.js +213 -0
- package/dist/shell-setup/posix.d.ts +36 -0
- package/dist/shell-setup/posix.js +158 -0
- package/dist/shell-setup/windows.d.ts +39 -0
- package/dist/shell-setup/windows.js +151 -0
- package/dist/shell.d.ts +18 -0
- package/dist/shell.js +110 -0
- package/dist/skills-prompt.d.ts +28 -0
- package/dist/skills-prompt.js +78 -0
- package/package.json +30 -28
package/dist/commands/install.js
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import { commandUsage } from "../config/usage.js";
|
|
2
2
|
import { install } from '@vltpkg/graph';
|
|
3
|
+
import { saveAllowSkills } from "../allow-skills.js";
|
|
3
4
|
import { parseAddArgs } from "../parse-add-remove-args.js";
|
|
5
|
+
import { assertGlobalOptions, linkGlobalBins, parseGlobalAddArgs, removeGlobalWorkspaces, } from "../global.js";
|
|
6
|
+
import { resolveGlobalBinDir } from "../global-bin-dir.js";
|
|
7
|
+
import { deferSelfRemove, runningStoreDep, selfUpdate, } from "../self-update.js";
|
|
4
8
|
import { planSpecConfigPersist } from "../persist-spec-config.js";
|
|
5
9
|
import { asUnknownSpecPrefix } from "../require-registry.js";
|
|
6
10
|
import { addTypesDeps } from "../save-types.js";
|
|
11
|
+
import { migrateWorkspaces } from "../migrate-workspaces.js";
|
|
7
12
|
import { trackInstall } from "../telemetry.js";
|
|
8
13
|
import { lazyView } from "../view.js";
|
|
9
14
|
export const needsRegistry = true;
|
|
@@ -39,6 +44,9 @@ export const usage = () => commandUsage({
|
|
|
39
44
|
'save-config': {
|
|
40
45
|
description: 'Save registry and git host options given on the command line or via env (e.g. `--registries name=url`) to the project vlt.json, or the user vlt.json with --config=user.',
|
|
41
46
|
},
|
|
47
|
+
'no-migrate-workspaces': {
|
|
48
|
+
description: "Don't save workspaces read from package.json or pnpm-workspace.yaml to vlt.json.",
|
|
49
|
+
},
|
|
42
50
|
workspace: {
|
|
43
51
|
value: '<path|glob>',
|
|
44
52
|
description: 'Limit installation targets to matching workspaces.',
|
|
@@ -60,10 +68,24 @@ export const usage = () => commandUsage({
|
|
|
60
68
|
value: '<query>',
|
|
61
69
|
description: 'Filter which packages are allowed to run lifecycle scripts using DSS query syntax.',
|
|
62
70
|
},
|
|
71
|
+
'allow-skills': {
|
|
72
|
+
value: '<query>',
|
|
73
|
+
description: "Link agent skills of packages matching this DSS query into the project's agent skill dirs. Saved to vlt.json.",
|
|
74
|
+
},
|
|
75
|
+
global: {
|
|
76
|
+
description: 'Install packages globally, each in its own workspace of the global project, linking their bins. `vlt install -g vlt` updates vlt itself.',
|
|
77
|
+
},
|
|
63
78
|
},
|
|
64
79
|
});
|
|
80
|
+
// link mounts; `unchanged` left out
|
|
81
|
+
const skillsJson = ({ linked, unchanged: _, ...rest }) => ({
|
|
82
|
+
linked: linked.map(s => s.mount),
|
|
83
|
+
...rest,
|
|
84
|
+
});
|
|
65
85
|
export const views = {
|
|
66
86
|
json: i => {
|
|
87
|
+
if (!('graph' in i))
|
|
88
|
+
return { self: i.self };
|
|
67
89
|
const added = i.diff?.nodes.add ?? new Set();
|
|
68
90
|
const deleted = i.diff?.nodes.delete ?? new Set();
|
|
69
91
|
// The actual (from) graph represents what was on disk before the install.
|
|
@@ -117,12 +139,19 @@ export const views = {
|
|
|
117
139
|
...(i.buildQueue?.length ?
|
|
118
140
|
{
|
|
119
141
|
buildQueue: i.buildQueue,
|
|
120
|
-
message: `${i.buildQueue.length} packages that will need to be built, run "vlt build" to complete the install.`,
|
|
142
|
+
message: `${i.buildQueue.length} packages that will need to be built, run "vlt build${i.global ? ' -g' : ''}" to complete the install.`,
|
|
121
143
|
}
|
|
122
144
|
: null),
|
|
123
145
|
...(i.persistedConfig ?
|
|
124
146
|
{ persistedConfig: i.persistedConfig }
|
|
125
147
|
: null),
|
|
148
|
+
...(i.migratedWorkspaces ?
|
|
149
|
+
{ migratedWorkspaces: i.migratedWorkspaces }
|
|
150
|
+
: null),
|
|
151
|
+
...(i.skills ? { skills: skillsJson(i.skills) } : null),
|
|
152
|
+
...(i.allowSkills ? { allowSkills: i.allowSkills } : null),
|
|
153
|
+
...(i.global ? { global: i.global } : null),
|
|
154
|
+
...(i.self ? { self: i.self } : null),
|
|
126
155
|
};
|
|
127
156
|
},
|
|
128
157
|
human: lazyView(async () => (await import('./install/reporter.ts')).InstallReporter),
|
|
@@ -130,36 +159,52 @@ export const views = {
|
|
|
130
159
|
export const command = async (conf) => {
|
|
131
160
|
// TODO: we should probably throw an error if the user
|
|
132
161
|
// tries to install using view=mermaid
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
162
|
+
if (conf.globalRoot)
|
|
163
|
+
assertGlobalOptions(conf);
|
|
164
|
+
// throws before any global ws dir is created
|
|
136
165
|
const persist = planSpecConfigPersist(conf);
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
166
|
+
// vlt i -g vlt: before any global ws or bin dir is created
|
|
167
|
+
const selfPlan = await selfUpdate(conf);
|
|
168
|
+
if (selfPlan && 'done' in selfPlan)
|
|
169
|
+
return { self: selfPlan.done };
|
|
170
|
+
const binDir = conf.globalRoot ?
|
|
171
|
+
await resolveGlobalBinDir(conf, {
|
|
172
|
+
selfUnwritable: !!selfPlan?.selfUnwritable,
|
|
173
|
+
})
|
|
174
|
+
: undefined;
|
|
175
|
+
// before reading options, it may reset them
|
|
176
|
+
const globalAdd = conf.globalRoot ? await parseGlobalAddArgs(conf) : undefined;
|
|
177
|
+
// never removed from under itself
|
|
178
|
+
const keep = conf.globalRoot ?
|
|
179
|
+
await runningStoreDep(conf.globalRoot)
|
|
180
|
+
: undefined;
|
|
149
181
|
const installStart = Date.now();
|
|
150
|
-
const { buildQueue, graph, diff } = await
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
expectLockfile,
|
|
154
|
-
allowScripts,
|
|
155
|
-
lockfileOnly,
|
|
156
|
-
saveExact,
|
|
157
|
-
savePrefix,
|
|
158
|
-
}, add).catch((er) => {
|
|
182
|
+
const { buildQueue, graph, diff, skills } = await runInstall(conf, globalAdd?.add, keep).catch(async (er) => {
|
|
183
|
+
if (globalAdd)
|
|
184
|
+
await removeGlobalWorkspaces(globalAdd.created);
|
|
159
185
|
throw asUnknownSpecPrefix(er);
|
|
160
186
|
});
|
|
187
|
+
const migrated = (conf.options['frozen-lockfile'] ||
|
|
188
|
+
conf.options['expect-lockfile']) ?
|
|
189
|
+
undefined
|
|
190
|
+
: migrateWorkspaces(conf);
|
|
191
|
+
if (conf.globalRoot)
|
|
192
|
+
await deferSelfRemove(conf.globalRoot, graph, keep);
|
|
193
|
+
const global = globalAdd &&
|
|
194
|
+
binDir &&
|
|
195
|
+
(await linkGlobalBins(graph, {
|
|
196
|
+
projectRoot: conf.options.projectRoot,
|
|
197
|
+
scurry: conf.options.scurry,
|
|
198
|
+
force: conf.options.force,
|
|
199
|
+
binDir,
|
|
200
|
+
fallback: () => resolveGlobalBinDir(conf, { selfUnwritable: true }),
|
|
201
|
+
}, globalAdd.importers));
|
|
161
202
|
if (persist)
|
|
162
203
|
await conf.addConfigToFile(persist.which, persist.values);
|
|
204
|
+
// nothing linked on --lockfile-only
|
|
205
|
+
const allowSkillsSave = conf.options['lockfile-only'] ?
|
|
206
|
+
undefined
|
|
207
|
+
: await saveAllowSkills(conf);
|
|
163
208
|
/* c8 ignore next 9 - telemetry is best-effort */
|
|
164
209
|
try {
|
|
165
210
|
trackInstall({
|
|
@@ -173,5 +218,42 @@ export const command = async (conf) => {
|
|
|
173
218
|
graph,
|
|
174
219
|
diff,
|
|
175
220
|
...(persist ? { persistedConfig: persist } : null),
|
|
221
|
+
...(migrated ? { migratedWorkspaces: migrated } : null),
|
|
222
|
+
...(skills ? { skills } : null),
|
|
223
|
+
...(allowSkillsSave ? { allowSkills: allowSkillsSave } : null),
|
|
224
|
+
...(global ? { global } : null),
|
|
225
|
+
...(selfPlan ? { self: await selfPlan.finish(global) } : null),
|
|
176
226
|
};
|
|
177
227
|
};
|
|
228
|
+
// async, so any throw rolls back global ws dirs
|
|
229
|
+
const runInstall = async (conf, globalAdd, keep) => {
|
|
230
|
+
const monorepo = conf.options.monorepo;
|
|
231
|
+
const scurry = conf.options.scurry;
|
|
232
|
+
const add = globalAdd ?? parseAddArgs(conf, scurry, monorepo).add;
|
|
233
|
+
// global ws has only the package as dep
|
|
234
|
+
if (conf.values['save-types'] && !globalAdd)
|
|
235
|
+
await addTypesDeps(conf, add);
|
|
236
|
+
const frozenLockfile = conf.options['frozen-lockfile'];
|
|
237
|
+
const expectLockfile = conf.options['expect-lockfile'];
|
|
238
|
+
const lockfileOnly = conf.options['lockfile-only'];
|
|
239
|
+
const saveExact = conf.values['save-exact'];
|
|
240
|
+
const savePrefix = conf.values['save-prefix'];
|
|
241
|
+
/* c8 ignore start */
|
|
242
|
+
const allowScripts = conf.get('allow-scripts') ?
|
|
243
|
+
String(conf.get('allow-scripts'))
|
|
244
|
+
: ':not(*)';
|
|
245
|
+
/* c8 ignore stop */
|
|
246
|
+
const allowSkills = conf.get('allow-skills');
|
|
247
|
+
return install({
|
|
248
|
+
...conf.options,
|
|
249
|
+
frozenLockfile,
|
|
250
|
+
expectLockfile,
|
|
251
|
+
allowScripts,
|
|
252
|
+
allowSkills,
|
|
253
|
+
skillsDirs: conf.get('skills-dir'),
|
|
254
|
+
lockfileOnly,
|
|
255
|
+
saveExact,
|
|
256
|
+
savePrefix,
|
|
257
|
+
...(keep ? { keepNodes: new Set([keep]) } : null),
|
|
258
|
+
}, add);
|
|
259
|
+
};
|
package/dist/commands/list.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { actual, asNode, humanReadableOutput, jsonOutput, mermaidOutput, GraphModifier, } from '@vltpkg/graph';
|
|
1
|
+
import { actual, asNode, hasSkills, humanReadableOutput, jsonOutput, mermaidOutput, GraphModifier, } from '@vltpkg/graph';
|
|
2
2
|
import { Query } from '@vltpkg/query';
|
|
3
3
|
import { SecurityArchive } from '@vltpkg/security-archive';
|
|
4
4
|
import { error } from '@vltpkg/error-cause';
|
|
@@ -63,6 +63,9 @@ export const usage = () => commandUsage({
|
|
|
63
63
|
value: '[human | json | mermaid | svg | png | count]',
|
|
64
64
|
description: 'Output format. Defaults to human-readable or json if no tty. Use svg or png to render the dependency graph as an image and open it. Count outputs the number of dependency relationships in the result.',
|
|
65
65
|
},
|
|
66
|
+
global: {
|
|
67
|
+
description: 'List globally installed packages.',
|
|
68
|
+
},
|
|
66
69
|
},
|
|
67
70
|
});
|
|
68
71
|
export const views = {
|
|
@@ -101,7 +104,8 @@ export const command = async (conf) => {
|
|
|
101
104
|
const usesHostContext = [queryString, scopeQueryString].some(q => q?.includes(':host('));
|
|
102
105
|
// optionally load the cwd graph if we found a package.json file
|
|
103
106
|
if (mainManifest) {
|
|
104
|
-
|
|
107
|
+
// the global project is always vlt managed
|
|
108
|
+
if (!usesHostContext && !conf.globalRoot) {
|
|
105
109
|
assertVltInstalled(conf.options.projectRoot, 'ls');
|
|
106
110
|
}
|
|
107
111
|
graph = actual.load({
|
|
@@ -138,6 +142,7 @@ export const command = async (conf) => {
|
|
|
138
142
|
securityArchive,
|
|
139
143
|
hostContexts,
|
|
140
144
|
getAuthHeader,
|
|
145
|
+
hasSkills,
|
|
141
146
|
});
|
|
142
147
|
const { nodes: resultNodes } = await scopeQuery.search(scopeQueryString, {
|
|
143
148
|
signal: new AbortController().signal,
|
|
@@ -190,6 +195,7 @@ export const command = async (conf) => {
|
|
|
190
195
|
securityArchive,
|
|
191
196
|
hostContexts,
|
|
192
197
|
getAuthHeader,
|
|
198
|
+
hasSkills,
|
|
193
199
|
});
|
|
194
200
|
const query = queryString ||
|
|
195
201
|
/* c8 ignore next */
|
package/dist/commands/publish.js
CHANGED
|
@@ -14,14 +14,17 @@ import { sortScopeLocations } from "../sort-scope-locations.js";
|
|
|
14
14
|
import { minimatch } from 'minimatch';
|
|
15
15
|
import { resolveRegistry } from "../require-registry.js";
|
|
16
16
|
import { stderr } from "../output.js";
|
|
17
|
-
|
|
17
|
+
import { getPublishConfig } from "../publish-config.js";
|
|
18
18
|
export const usage = () => commandUsage({
|
|
19
19
|
command: 'publish',
|
|
20
20
|
usage: '',
|
|
21
21
|
description: `Create a tarball from a package and publish it to the configured registry.
|
|
22
22
|
|
|
23
23
|
This command will pack the package in the current directory or specified folder,
|
|
24
|
-
and then upload it to the configured registry
|
|
24
|
+
and then upload it to the configured registry.
|
|
25
|
+
|
|
26
|
+
The registry is the package's \`publishConfig.registry\` if set (no other
|
|
27
|
+
registry config needed), else \`--registry\`, else a configured alias.`,
|
|
25
28
|
options: {
|
|
26
29
|
tag: {
|
|
27
30
|
description: 'Publish the package with the given tag',
|
|
@@ -143,22 +146,34 @@ export const command = async (conf) => {
|
|
|
143
146
|
single = options.packageJson.find(process.cwd()) ?? projectRoot;
|
|
144
147
|
}
|
|
145
148
|
if (single) {
|
|
146
|
-
|
|
149
|
+
const [target] = await resolveTargets([single], conf);
|
|
150
|
+
assert(target);
|
|
151
|
+
return commandSingle(target, conf);
|
|
147
152
|
}
|
|
148
153
|
assert(locations.length > 0, error('No workspaces or query results found'));
|
|
149
154
|
const results = [];
|
|
150
|
-
for (const
|
|
151
|
-
results.push(await commandSingle(
|
|
155
|
+
for (const target of await resolveTargets(locations, conf)) {
|
|
156
|
+
results.push(await commandSingle(target, conf));
|
|
152
157
|
}
|
|
153
158
|
return results;
|
|
154
159
|
};
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
+
/**
|
|
161
|
+
* Registry of every target, before anything runs or publishes.
|
|
162
|
+
* The configured one is only resolved (or prompted for) once.
|
|
163
|
+
*/
|
|
164
|
+
const resolveTargets = async (locations, conf) => {
|
|
165
|
+
let fallback;
|
|
166
|
+
const targets = [];
|
|
167
|
+
for (const location of locations) {
|
|
168
|
+
const manifestPath = conf.options.packageJson.find(location);
|
|
169
|
+
assert(manifestPath, 'No package.json found');
|
|
170
|
+
const manifestDir = dirname(manifestPath);
|
|
171
|
+
const manifest = conf.options.packageJson.read(manifestDir);
|
|
172
|
+
const registry = getPublishConfig(manifest)?.registry ??
|
|
173
|
+
(await (fallback ??= resolveRegistry(conf)));
|
|
174
|
+
targets.push({ manifestDir, registry });
|
|
160
175
|
}
|
|
161
|
-
return
|
|
176
|
+
return targets;
|
|
162
177
|
};
|
|
163
178
|
/** Of several readmes at the package root, npm prefers the markdown one. */
|
|
164
179
|
const README_MARKDOWN_EXTENSION = /\.(?:md|markdown|mdown|mdwn|mkd|mkdn)$/i;
|
|
@@ -182,17 +197,13 @@ const readPublishReadme = (packDir, files) => {
|
|
|
182
197
|
readmeFilename,
|
|
183
198
|
};
|
|
184
199
|
};
|
|
185
|
-
const commandSingle = async (
|
|
186
|
-
const manifestPath = conf.options.packageJson.find(location);
|
|
187
|
-
assert(manifestPath, 'No package.json found');
|
|
188
|
-
const manifestDir = dirname(manifestPath);
|
|
200
|
+
const commandSingle = async ({ manifestDir, registry }, conf) => {
|
|
189
201
|
const manifest = conf.options.packageJson.read(manifestDir);
|
|
190
202
|
assert(!manifest.private, error('Package has been marked as private'));
|
|
191
203
|
const { 'dry-run': dry = false, otp } = conf.options;
|
|
192
204
|
const publishConfig = getPublishConfig(manifest);
|
|
193
205
|
const tag = publishConfig?.tag ?? conf.options.tag;
|
|
194
206
|
const access = publishConfig?.access ?? conf.options.access;
|
|
195
|
-
const registry = publishConfig?.registry ?? (await resolveRegistry(conf));
|
|
196
207
|
const registryUrl = new URL(registryBase(registry));
|
|
197
208
|
const runOptions = {
|
|
198
209
|
cwd: manifestDir,
|
package/dist/commands/query.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { actual, asNode, humanReadableOutput, jsonOutput, mermaidOutput, GraphModifier, } from '@vltpkg/graph';
|
|
1
|
+
import { actual, asNode, hasSkills, humanReadableOutput, jsonOutput, mermaidOutput, GraphModifier, } from '@vltpkg/graph';
|
|
2
2
|
import { Query } from '@vltpkg/query';
|
|
3
3
|
import { stdout } from "../output.js";
|
|
4
4
|
import { error } from '@vltpkg/error-cause';
|
|
@@ -80,6 +80,9 @@ export const usage = () => commandUsage({
|
|
|
80
80
|
value: '[human | json | mermaid | svg | png | count]',
|
|
81
81
|
description: 'Output format. Defaults to human-readable or json if no tty. Use svg or png to render the dependency graph as an image and open it. Count outputs the number of dependency relationships in the result.',
|
|
82
82
|
},
|
|
83
|
+
global: {
|
|
84
|
+
description: 'Query the global project.',
|
|
85
|
+
},
|
|
83
86
|
},
|
|
84
87
|
});
|
|
85
88
|
const validateExpectedResult = (conf, edges) => {
|
|
@@ -128,7 +131,8 @@ export const command = async (conf) => {
|
|
|
128
131
|
const usesHostContext = [queryString, scopeQueryString].some(q => q?.includes(':host('));
|
|
129
132
|
// optionally load the cwd graph if we found a package.json file
|
|
130
133
|
if (mainManifest) {
|
|
131
|
-
|
|
134
|
+
// the global project is always vlt managed
|
|
135
|
+
if (!usesHostContext && !conf.globalRoot) {
|
|
132
136
|
assertVltInstalled(conf.options.projectRoot, 'query');
|
|
133
137
|
}
|
|
134
138
|
graph = actual.load({
|
|
@@ -166,6 +170,7 @@ export const command = async (conf) => {
|
|
|
166
170
|
hostContexts,
|
|
167
171
|
diffFiles,
|
|
168
172
|
getAuthHeader,
|
|
173
|
+
hasSkills,
|
|
169
174
|
});
|
|
170
175
|
const { nodes: resultNodes } = await scopeQuery.search(scopeQueryString, {
|
|
171
176
|
signal: new AbortController().signal,
|
|
@@ -231,6 +236,7 @@ export const command = async (conf) => {
|
|
|
231
236
|
hostContexts,
|
|
232
237
|
diffFiles,
|
|
233
238
|
getAuthHeader,
|
|
239
|
+
hasSkills,
|
|
234
240
|
});
|
|
235
241
|
const query = queryString ||
|
|
236
242
|
(graph ? defaultProjectQueryString : defaultLocalScopeQueryString);
|
package/dist/commands/setup.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { Shell } from '../shell.ts';
|
|
2
|
+
import type { PathSetupFile } from '../shell-setup/index.ts';
|
|
1
3
|
import type { CommandFn, CommandUsage } from '../index.ts';
|
|
2
4
|
/** Where users sign up for / log into a vlt.io account. */
|
|
3
5
|
export declare const VLT_SIGNUP_URL = "https://www.vlt.io";
|
|
@@ -29,9 +31,33 @@ export type SetupResult = {
|
|
|
29
31
|
* the project's `vlt.json`, so the result won't take effect here.
|
|
30
32
|
*/
|
|
31
33
|
shadowedByProject?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* PATH step outcome; absent when skipped (--yes, no terminal,
|
|
36
|
+
* no-modify-path)
|
|
37
|
+
*/
|
|
38
|
+
path?: SetupPathResult['path'] | SetupPathFailed;
|
|
39
|
+
};
|
|
40
|
+
export type SetupPathFailed = {
|
|
41
|
+
status: 'failed';
|
|
42
|
+
/** why; may hold the manual line */
|
|
43
|
+
message: string;
|
|
44
|
+
};
|
|
45
|
+
export type SetupPathResult = {
|
|
46
|
+
path: {
|
|
47
|
+
status: 'added' | 'unchanged' | 'in-path' | 'disabled' | 'cancelled';
|
|
48
|
+
/** canonical dir added to the PATH */
|
|
49
|
+
dir: string;
|
|
50
|
+
shell: Shell;
|
|
51
|
+
files: PathSetupFile[];
|
|
52
|
+
backups: string[];
|
|
53
|
+
/** manual line for the shell */
|
|
54
|
+
command: string;
|
|
55
|
+
/** loads it in the current shell */
|
|
56
|
+
source: string;
|
|
57
|
+
};
|
|
32
58
|
};
|
|
33
59
|
export declare const views: {
|
|
34
|
-
readonly human: (result: SetupResult) => string;
|
|
60
|
+
readonly human: (result: SetupResult | SetupPathResult) => string;
|
|
35
61
|
};
|
|
36
62
|
export declare const usage: CommandUsage;
|
|
37
|
-
export declare const command: CommandFn<SetupResult>;
|
|
63
|
+
export declare const command: CommandFn<SetupResult | SetupPathResult>;
|
package/dist/commands/setup.js
CHANGED
|
@@ -8,6 +8,10 @@ import { registrySelectionFields } from "../config/merge-layers.js";
|
|
|
8
8
|
import { commandUsage } from "../config/usage.js";
|
|
9
9
|
import { normalizeRegistryURL } from "../require-registry.js";
|
|
10
10
|
import { stdout } from "../output.js";
|
|
11
|
+
import { resolveGlobalBinDir } from "../global-bin-dir.js";
|
|
12
|
+
import { detectShell, prettyPath, shellPathCommand, } from "../shell.js";
|
|
13
|
+
import { applyPathSetup, ask as askLine, pathSetupChanged, pathSetupFiles, pathSetupLines, planPathSetup, rcList, sourceCommand, } from "../shell-setup/index.js";
|
|
14
|
+
import { editPathHint } from "../shell-setup/windows.js";
|
|
11
15
|
/** Where users sign up for / log into a vlt.io account. */
|
|
12
16
|
export const VLT_SIGNUP_URL = 'https://www.vlt.io';
|
|
13
17
|
/** Base URL that per-account registries live under. */
|
|
@@ -58,8 +62,47 @@ const accountAuthError = (account, er) => (isErrorWithCause(er) &&
|
|
|
58
62
|
`organization at ${VLT_SIGNUP_URL}, then run \`vlt setup\` again.`,
|
|
59
63
|
].join('\n'), { code: 'ECONFIG', cause: er })
|
|
60
64
|
: asError(er);
|
|
65
|
+
const pathView = (r, wizard = false) => {
|
|
66
|
+
if (r.status === 'failed') {
|
|
67
|
+
return `⚠️ Could not add the global bin folder to your PATH: ${r.message}`;
|
|
68
|
+
}
|
|
69
|
+
const dir = prettyPath(r.dir);
|
|
70
|
+
const rcs = rcList(r.files);
|
|
71
|
+
// the command lasts one session
|
|
72
|
+
const keep = process.platform === 'win32' ?
|
|
73
|
+
[` To keep it: ${editPathHint}`]
|
|
74
|
+
: [];
|
|
75
|
+
switch (r.status) {
|
|
76
|
+
case 'added':
|
|
77
|
+
return pathSetupLines(r, r.source).join('\n');
|
|
78
|
+
case 'unchanged':
|
|
79
|
+
return [
|
|
80
|
+
`✅ ${dir} is already added to your PATH in ${rcs}`,
|
|
81
|
+
` Open a new terminal, or run: ${r.source}`,
|
|
82
|
+
].join('\n');
|
|
83
|
+
case 'in-path':
|
|
84
|
+
return wizard ? '' : `✅ ${dir} is already on your PATH`;
|
|
85
|
+
case 'disabled':
|
|
86
|
+
return [
|
|
87
|
+
`ℹ️ no-modify-path is set, so nothing was changed. To add ${dir} to your PATH, run:`,
|
|
88
|
+
` ${r.command}`,
|
|
89
|
+
...keep,
|
|
90
|
+
].join('\n');
|
|
91
|
+
case 'cancelled':
|
|
92
|
+
if (wizard) {
|
|
93
|
+
return `ℹ️ Skipped. Run \`vlt setup --path\` later to add ${dir} to your PATH.`;
|
|
94
|
+
}
|
|
95
|
+
return [
|
|
96
|
+
`Nothing changed. To add ${dir} to your PATH, run:`,
|
|
97
|
+
` ${r.command}`,
|
|
98
|
+
...keep,
|
|
99
|
+
].join('\n');
|
|
100
|
+
}
|
|
101
|
+
};
|
|
61
102
|
export const views = {
|
|
62
103
|
human: (result) => {
|
|
104
|
+
if (!('account' in result))
|
|
105
|
+
return pathView(result.path);
|
|
63
106
|
const lines = [
|
|
64
107
|
`Configured ${Object.keys(result.registries).length} registry ${Object.keys(result.registries).length === 1 ?
|
|
65
108
|
'alias'
|
|
@@ -71,13 +114,19 @@ export const views = {
|
|
|
71
114
|
if (result.shadowedByProject) {
|
|
72
115
|
lines.push('', `Note: this project's vlt.json configures its own registries, and`, 'project config takes precedence. Re-run with `--config=project`', 'to configure this project instead.');
|
|
73
116
|
}
|
|
117
|
+
const path = result.path && pathView(result.path, true);
|
|
118
|
+
if (path)
|
|
119
|
+
lines.push('', path);
|
|
74
120
|
lines.push('', 'You can now install packages, e.g.:', ' vlt install <pkg>');
|
|
75
121
|
return lines.join('\n');
|
|
76
122
|
},
|
|
77
123
|
};
|
|
78
124
|
export const usage = () => commandUsage({
|
|
79
125
|
command: 'setup',
|
|
80
|
-
usage:
|
|
126
|
+
usage: [
|
|
127
|
+
'[<account>]',
|
|
128
|
+
'--path [--yes] [--global-bin-dir=<path>]',
|
|
129
|
+
],
|
|
81
130
|
description: `Configure the registry aliases for your vlt.io account so
|
|
82
131
|
that \`vlt install\` and \`vlx\` work out of the box.
|
|
83
132
|
|
|
@@ -85,7 +134,19 @@ export const usage = () => commandUsage({
|
|
|
85
134
|
authenticates against your account, stores the token
|
|
86
135
|
for both the \`npm\` and \`main\` registries, and writes
|
|
87
136
|
those aliases (and any additional aliases you add) to
|
|
88
|
-
your user \`vlt.json
|
|
137
|
+
your user \`vlt.json\`.
|
|
138
|
+
|
|
139
|
+
In a terminal, if the global bin folder isn't on
|
|
140
|
+
your \`PATH\` or set up yet, it ends by asking
|
|
141
|
+
\`Setup PATH for global installs? (Y/n)\`: yes adds
|
|
142
|
+
it (same as \`--path\`), no skips it. Run
|
|
143
|
+
\`vlt setup --path\` later to do just that step.
|
|
144
|
+
|
|
145
|
+
With \`--path\`, add the global bin folder
|
|
146
|
+
(\`--global-bin-dir\`) to your \`PATH\` instead: writes
|
|
147
|
+
\`<global-dir>/env\` and a marked section that loads
|
|
148
|
+
it into your shell config. On Windows it adds it to
|
|
149
|
+
your user \`Path\` (\`HKCU\\Environment\`).`,
|
|
89
150
|
options: {
|
|
90
151
|
config: {
|
|
91
152
|
value: '<user | project>',
|
|
@@ -99,11 +160,129 @@ export const usage = () => commandUsage({
|
|
|
99
160
|
},
|
|
100
161
|
yes: {
|
|
101
162
|
description: 'Skip interactive prompts (requires <account> and does not ' +
|
|
102
|
-
'open a browser for authentication).'
|
|
163
|
+
'open a browser for authentication). With --path: edit ' +
|
|
164
|
+
'without asking. Without --path: skips the PATH prompt.',
|
|
165
|
+
},
|
|
166
|
+
path: {
|
|
167
|
+
description: 'Only add the global bin folder to your PATH via your ' +
|
|
168
|
+
'shell config (user Path on Windows).',
|
|
169
|
+
},
|
|
170
|
+
'global-bin-dir': {
|
|
171
|
+
value: '<path>',
|
|
172
|
+
description: 'The folder to add to your PATH.',
|
|
103
173
|
},
|
|
104
174
|
},
|
|
105
175
|
});
|
|
176
|
+
const runPathSetup = async (o) => {
|
|
177
|
+
const root = o.globalDir;
|
|
178
|
+
const bin = await resolveGlobalBinDir({
|
|
179
|
+
projectRoot: root,
|
|
180
|
+
globalBinDir: o.globalBinDir,
|
|
181
|
+
});
|
|
182
|
+
const shell = detectShell();
|
|
183
|
+
const base = {
|
|
184
|
+
dir: bin.dir,
|
|
185
|
+
shell,
|
|
186
|
+
files: [],
|
|
187
|
+
backups: [],
|
|
188
|
+
command: shellPathCommand(shell, bin.dir),
|
|
189
|
+
source: sourceCommand(shell, root, bin.dir),
|
|
190
|
+
};
|
|
191
|
+
if (bin.inPath) {
|
|
192
|
+
return { ...base, status: 'in-path' };
|
|
193
|
+
}
|
|
194
|
+
// scripted installers must not fail
|
|
195
|
+
if (o.noModifyPath) {
|
|
196
|
+
return { ...base, status: 'disabled' };
|
|
197
|
+
}
|
|
198
|
+
const opts = { globalDir: root, dir: bin.dir, shell };
|
|
199
|
+
let plan = await planPathSetup(opts);
|
|
200
|
+
const files = pathSetupFiles(plan);
|
|
201
|
+
if (!pathSetupChanged(plan)) {
|
|
202
|
+
return { ...base, status: 'unchanged', files };
|
|
203
|
+
}
|
|
204
|
+
if (!o.yes) {
|
|
205
|
+
if (!process.stdin.isTTY) {
|
|
206
|
+
throw error('Not a terminal: pass --yes to add it to your PATH', {
|
|
207
|
+
code: 'EUSAGE',
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
const answer = await (o.ask ?? askLine)(o.question({ dir: prettyPath(bin.dir), rcs: rcList(files) })).catch((er) => {
|
|
211
|
+
// Ctrl-C
|
|
212
|
+
if (asError(er).name !== 'AbortError')
|
|
213
|
+
throw er;
|
|
214
|
+
process.stdout.write('\n');
|
|
215
|
+
return 'n';
|
|
216
|
+
});
|
|
217
|
+
if (/^n/i.test(answer)) {
|
|
218
|
+
return { ...base, status: 'cancelled', files };
|
|
219
|
+
}
|
|
220
|
+
// rc files may have changed while asking
|
|
221
|
+
plan = await planPathSetup(opts);
|
|
222
|
+
}
|
|
223
|
+
const r = await applyPathSetup(plan);
|
|
224
|
+
return {
|
|
225
|
+
...base,
|
|
226
|
+
status: 'added',
|
|
227
|
+
files: r.files,
|
|
228
|
+
backups: r.backups,
|
|
229
|
+
};
|
|
230
|
+
};
|
|
231
|
+
const setupPath = async (conf, root) => {
|
|
232
|
+
if (conf.positionals.length) {
|
|
233
|
+
throw error('`vlt setup --path` takes no arguments', {
|
|
234
|
+
code: 'EUSAGE',
|
|
235
|
+
found: conf.positionals[0],
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
return {
|
|
239
|
+
path: await runPathSetup({
|
|
240
|
+
globalDir: root,
|
|
241
|
+
globalBinDir: conf.globalBinDir,
|
|
242
|
+
yes: !!conf.get('yes'),
|
|
243
|
+
noModifyPath: !!conf.get('no-modify-path'),
|
|
244
|
+
question: ({ dir, rcs }) => `Add ${dir} to your PATH in ${rcs}? (Y/n) `,
|
|
245
|
+
}),
|
|
246
|
+
};
|
|
247
|
+
};
|
|
248
|
+
// end of the wizard, in a terminal only
|
|
249
|
+
const offerPath = async (conf, yes, ask) => {
|
|
250
|
+
if (yes || !process.stdin.isTTY || conf.get('no-modify-path')) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
const g = conf.globalProject();
|
|
254
|
+
if (!g)
|
|
255
|
+
return;
|
|
256
|
+
try {
|
|
257
|
+
return await runPathSetup({
|
|
258
|
+
globalDir: g.root,
|
|
259
|
+
globalBinDir: g.binDir,
|
|
260
|
+
question: () => 'Setup PATH for global installs? (Y/n) ',
|
|
261
|
+
ask,
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
catch (er) {
|
|
265
|
+
// registries are already saved
|
|
266
|
+
const e = asError(er);
|
|
267
|
+
// e.g. the global-bin-dir that could not be created
|
|
268
|
+
const found = (isErrorWithCause(e) &&
|
|
269
|
+
isObject(e.cause) &&
|
|
270
|
+
typeof e.cause.found === 'string') ?
|
|
271
|
+
prettyPath(e.cause.found)
|
|
272
|
+
: undefined;
|
|
273
|
+
return {
|
|
274
|
+
status: 'failed',
|
|
275
|
+
message: found && !e.message.includes(found) ?
|
|
276
|
+
`${e.message}: ${found}`
|
|
277
|
+
: e.message,
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
};
|
|
106
281
|
export const command = async (conf) => {
|
|
282
|
+
// set only by --path, see Config#globalProject
|
|
283
|
+
const root = conf.globalRoot;
|
|
284
|
+
if (root)
|
|
285
|
+
return setupPath(conf, root);
|
|
107
286
|
const yes = !!conf.get('yes');
|
|
108
287
|
const which = configWriteTarget(conf, 'user');
|
|
109
288
|
let rl;
|
|
@@ -198,11 +377,14 @@ export const command = async (conf) => {
|
|
|
198
377
|
// worked.
|
|
199
378
|
const shadowedByProject = which === 'user' &&
|
|
200
379
|
registrySelectionFields.some(f => f in (conf.layers.project ?? {}));
|
|
380
|
+
// 8. offer PATH setup for global installs
|
|
381
|
+
const path = await offerPath(conf, yes, ask);
|
|
201
382
|
return {
|
|
202
383
|
account,
|
|
203
384
|
which,
|
|
204
385
|
registries,
|
|
205
386
|
...(shadowedByProject ? { shadowedByProject } : undefined),
|
|
387
|
+
...(path ? { path } : undefined),
|
|
206
388
|
};
|
|
207
389
|
}
|
|
208
390
|
finally {
|