@vltpkg/cli-sdk 1.3.8 → 1.5.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 +7 -1
- package/dist/commands/build.js +19 -9
- package/dist/commands/cache.d.ts +2 -2
- package/dist/commands/cache.js +22 -7
- package/dist/commands/ci.d.ts +1 -1
- package/dist/commands/ci.js +10 -2
- package/dist/commands/init.js +7 -8
- package/dist/commands/install/reporter.js +46 -0
- package/dist/commands/install.d.ts +29 -1
- package/dist/commands/install.js +35 -1
- package/dist/commands/list.js +3 -1
- package/dist/commands/pack.js +2 -1
- package/dist/commands/pkg.js +4 -1
- package/dist/commands/publish.d.ts +0 -1
- package/dist/commands/publish.js +31 -17
- package/dist/commands/query.js +3 -1
- package/dist/commands/skills.d.ts +56 -0
- package/dist/commands/skills.js +268 -0
- package/dist/commands/uninstall.d.ts +5 -1
- package/dist/commands/uninstall.js +4 -2
- package/dist/commands/unpublish.d.ts +0 -1
- package/dist/commands/unpublish.js +17 -4
- package/dist/commands/update.d.ts +12 -0
- package/dist/commands/update.js +18 -1
- package/dist/commands/version.js +4 -1
- package/dist/config/definition.d.ts +26 -2
- package/dist/config/definition.js +75 -11
- package/dist/config/index.d.ts +4 -0
- package/dist/config/index.js +22 -6
- package/dist/config/spec-aliases.d.ts +22 -0
- package/dist/config/spec-aliases.js +47 -0
- package/dist/custom-help.js +4 -0
- package/dist/exec-command.js +12 -6
- package/dist/index.js +18 -8
- 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 +2 -1
- package/dist/print-err.js +4 -1
- package/dist/publish-config.d.ts +9 -0
- package/dist/publish-config.js +8 -0
- package/dist/save-types.d.ts +20 -0
- package/dist/save-types.js +105 -0
- package/dist/skills-prompt.d.ts +28 -0
- package/dist/skills-prompt.js +78 -0
- package/dist/sort-scope-locations.d.ts +11 -0
- package/dist/sort-scope-locations.js +57 -0
- package/package.json +28 -28
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { UnmatchedPattern, UnscannedSkills } from '@vltpkg/graph';
|
|
2
|
+
import type { WhichConfig } from '@vltpkg/vlt-json';
|
|
3
|
+
import type { LoadedConfig } from './config/index.ts';
|
|
4
|
+
/** An `allow-skills` query stored in a config file. */
|
|
5
|
+
export type StoredAllowSkills = {
|
|
6
|
+
query: string;
|
|
7
|
+
which: WhichConfig;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Outcome of saving `--allow-skills` after install/update. `stored`
|
|
11
|
+
* set: another query is stored and was kept.
|
|
12
|
+
*/
|
|
13
|
+
export type AllowSkillsSave = {
|
|
14
|
+
query: string;
|
|
15
|
+
stored?: StoredAllowSkills;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* The top-level `allow-skills` of the project vlt.json, else the user
|
|
19
|
+
* one. A project `null` or `''` drops the user's.
|
|
20
|
+
*/
|
|
21
|
+
export declare const storedAllowSkills: (conf: Pick<LoadedConfig, "layers">) => StoredAllowSkills | undefined;
|
|
22
|
+
/** The file's name in messages. */
|
|
23
|
+
export declare const configLabel: (which: WhichConfig) => string;
|
|
24
|
+
/**
|
|
25
|
+
* After a successful install/update: save an explicit `--allow-skills`
|
|
26
|
+
* to the project vlt.json, unless another query is stored.
|
|
27
|
+
*/
|
|
28
|
+
export declare const saveAllowSkills: (conf: LoadedConfig) => Promise<AllowSkillsSave | undefined>;
|
|
29
|
+
/** Warnings for `:skill()` patterns that matched nothing. */
|
|
30
|
+
export declare const unmatchedLines: (unmatched?: UnmatchedPattern[]) => string[];
|
|
31
|
+
/** Skills left out: their packages have no security data. */
|
|
32
|
+
export declare const unscannedLines: ({ unscanned, unscannedReason, }: UnscannedSkills) => string[];
|
|
33
|
+
/** `allow-skills` saved to a config file. */
|
|
34
|
+
export declare const savedLine: (query: string, which: WhichConfig) => string;
|
|
35
|
+
/** `--allow-skills` not saved: another query is stored. */
|
|
36
|
+
export declare const keptLine: (s: StoredAllowSkills) => string;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The top-level `allow-skills` of the project vlt.json, else the user
|
|
3
|
+
* one. A project `null` or `''` drops the user's.
|
|
4
|
+
*/
|
|
5
|
+
export const storedAllowSkills = (conf) => {
|
|
6
|
+
const { project, user } = conf.layers;
|
|
7
|
+
const p = project?.['allow-skills'];
|
|
8
|
+
if (p)
|
|
9
|
+
return { query: p, which: 'project' };
|
|
10
|
+
if (project && 'allow-skills' in project)
|
|
11
|
+
return undefined;
|
|
12
|
+
const u = user?.['allow-skills'];
|
|
13
|
+
return u ? { query: u, which: 'user' } : undefined;
|
|
14
|
+
};
|
|
15
|
+
/** The file's name in messages. */
|
|
16
|
+
export const configLabel = (which) => which === 'user' ? 'user vlt.json' : 'vlt.json';
|
|
17
|
+
/**
|
|
18
|
+
* After a successful install/update: save an explicit `--allow-skills`
|
|
19
|
+
* to the project vlt.json, unless another query is stored.
|
|
20
|
+
*/
|
|
21
|
+
export const saveAllowSkills = async (conf) => {
|
|
22
|
+
const query = conf.explicit['allow-skills'];
|
|
23
|
+
if (!query || query === ':not(*)')
|
|
24
|
+
return undefined;
|
|
25
|
+
const stored = storedAllowSkills(conf);
|
|
26
|
+
if (stored?.query === query)
|
|
27
|
+
return undefined;
|
|
28
|
+
if (stored)
|
|
29
|
+
return { query, stored };
|
|
30
|
+
await conf.addConfigToFile('project', { 'allow-skills': query });
|
|
31
|
+
return { query };
|
|
32
|
+
};
|
|
33
|
+
/** Warnings for `:skill()` patterns that matched nothing. */
|
|
34
|
+
export const unmatchedLines = (unmatched = []) => unmatched.map(({ pattern, skills }) => `⚠️ No skill matches "${pattern}"; ${!skills ? 'no installed package matches its selector'
|
|
35
|
+
: skills.length ?
|
|
36
|
+
`the selected packages ship: ${skills.join(', ')}`
|
|
37
|
+
: 'the selected packages ship no skills'}`);
|
|
38
|
+
/** Skills left out: their packages have no security data. */
|
|
39
|
+
export const unscannedLines = ({ unscanned = [], unscannedReason, }) => unscanned.length ?
|
|
40
|
+
[
|
|
41
|
+
`⏳ ${unscanned.length} skill${unscanned.length === 1 ? '' : 's'} left out, ${unscannedReason === 'timeout' ?
|
|
42
|
+
'security data timed out'
|
|
43
|
+
: 'Socket has not scanned their packages yet'}: ${unscanned.join(', ')}. Try again later.`,
|
|
44
|
+
]
|
|
45
|
+
: [];
|
|
46
|
+
/** `allow-skills` saved to a config file. */
|
|
47
|
+
export const savedLine = (query, which) => `Saved allow-skills="${query}" to ${configLabel(which)}`;
|
|
48
|
+
/** `--allow-skills` not saved: another query is stored. */
|
|
49
|
+
export const keptLine = (s) => `allow-skills is already set (${configLabel(s.which)}): "${s.query}"; not replaced. Run vlt skills link to change it, or edit ${configLabel(s.which)}`;
|
package/dist/commands/build.d.ts
CHANGED
|
@@ -3,6 +3,13 @@ import type { CommandFn, CommandUsage } from '../index.ts';
|
|
|
3
3
|
export declare const views: {
|
|
4
4
|
readonly human: (result: BuildResult) => string;
|
|
5
5
|
readonly json: (result: BuildResult) => {
|
|
6
|
+
message: string;
|
|
7
|
+
skipped?: {
|
|
8
|
+
id: import("@vltpkg/dep-id").DepID;
|
|
9
|
+
name: string;
|
|
10
|
+
version: string | undefined;
|
|
11
|
+
}[] | undefined;
|
|
12
|
+
skippedReason?: "timeout" | "unscanned" | undefined;
|
|
6
13
|
success: {
|
|
7
14
|
id: import("@vltpkg/dep-id").DepID;
|
|
8
15
|
name: string;
|
|
@@ -13,7 +20,6 @@ export declare const views: {
|
|
|
13
20
|
name: string;
|
|
14
21
|
version: string | undefined;
|
|
15
22
|
}[];
|
|
16
|
-
message: string;
|
|
17
23
|
};
|
|
18
24
|
};
|
|
19
25
|
export declare const needsRegistry = true;
|
package/dist/commands/build.js
CHANGED
|
@@ -2,39 +2,49 @@ import { build } from '@vltpkg/graph';
|
|
|
2
2
|
import { error } from '@vltpkg/error-cause';
|
|
3
3
|
import { commandUsage } from "../config/usage.js";
|
|
4
4
|
import { isErrorWithCause } from '@vltpkg/types';
|
|
5
|
+
const skippedMessage = (count, reason) => `${count} package${count === 1 ? '' : 's'} not built, ${reason === 'unscanned' ?
|
|
6
|
+
'Socket has not scanned them yet'
|
|
7
|
+
: 'security data timed out'}. Run "vlt build" again later.`;
|
|
5
8
|
export const views = {
|
|
6
9
|
human: (result) => {
|
|
7
10
|
const successCount = result.success.length;
|
|
8
11
|
const failureCount = result.failure.length;
|
|
12
|
+
const skippedCount = result.skipped?.length ?? 0;
|
|
9
13
|
const messages = [];
|
|
10
14
|
if (successCount > 0) {
|
|
11
15
|
messages.push(`🔨 Built ${successCount} package${successCount === 1 ? '' : 's'} successfully.`);
|
|
12
16
|
}
|
|
13
|
-
else {
|
|
17
|
+
else if (!skippedCount) {
|
|
14
18
|
messages.push('📦 All packages are already built.');
|
|
15
19
|
}
|
|
16
20
|
if (failureCount > 0) {
|
|
17
21
|
messages.push(`🔎 ${failureCount} optional package${ /* c8 ignore next */failureCount === 1 ? '' : 's'} failed to build.`);
|
|
18
22
|
}
|
|
23
|
+
if (skippedCount > 0) {
|
|
24
|
+
messages.push(`⏳ ${skippedMessage(skippedCount, result.skippedReason)}`);
|
|
25
|
+
}
|
|
19
26
|
return messages.join('\n');
|
|
20
27
|
},
|
|
21
28
|
json: (result) => {
|
|
22
|
-
const
|
|
29
|
+
const toJSON = (node) => ({
|
|
23
30
|
id: node.id,
|
|
24
31
|
name: node.name,
|
|
25
32
|
version: node.version,
|
|
26
|
-
})
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
version: node.version,
|
|
31
|
-
}));
|
|
33
|
+
});
|
|
34
|
+
const successList = result.success.map(toJSON);
|
|
35
|
+
const failureList = result.failure.map(toJSON);
|
|
36
|
+
const skippedList = result.skipped?.map(toJSON) ?? [];
|
|
32
37
|
return {
|
|
33
38
|
success: successList,
|
|
34
39
|
failure: failureList,
|
|
40
|
+
...(skippedList.length ?
|
|
41
|
+
{ skipped: skippedList, skippedReason: result.skippedReason }
|
|
42
|
+
: {}),
|
|
35
43
|
message: successList.length > 0 ?
|
|
36
44
|
`Built ${successList.length} package${successList.length === 1 ? '' : 's'}.`
|
|
37
|
-
:
|
|
45
|
+
: skippedList.length ?
|
|
46
|
+
skippedMessage(skippedList.length, result.skippedReason)
|
|
47
|
+
: 'No packages needed building.',
|
|
38
48
|
};
|
|
39
49
|
},
|
|
40
50
|
};
|
package/dist/commands/cache.d.ts
CHANGED
|
@@ -56,8 +56,8 @@ declare const usageDef: {
|
|
|
56
56
|
readonly description: "Check global store entries against their cached\n tarballs (file list, contents, exec bits) and remove\n any that differ or have no cached tarball, e.g. after\n a file in `node_modules` was edited in place.";
|
|
57
57
|
};
|
|
58
58
|
readonly 'prune-store': {
|
|
59
|
-
readonly usage: "";
|
|
60
|
-
readonly description: "Remove global store entries that no `node_modules`\n folder links to.
|
|
59
|
+
readonly usage: "[<date>]";
|
|
60
|
+
readonly description: "Remove global store entries that no `node_modules`\n folder links to. Copies do not show use: an entry\n copied or cloned from (install scripts,\n `store-linker=copy`, macOS, a cache on another\n drive) stays if that last happened after\n `<date>`, or in the last 30 days\n without one.";
|
|
61
61
|
};
|
|
62
62
|
};
|
|
63
63
|
readonly examples: {
|
package/dist/commands/cache.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { error } from '@vltpkg/error-cause';
|
|
2
2
|
import { CacheEntry, assertOk } from '@vltpkg/registry-client';
|
|
3
3
|
import { Spec } from '@vltpkg/spec';
|
|
4
|
-
import { removeStoreEntry, storeEntryCopied, storeEntryLinked, storeEntryNames, storeEntryTime, verifyStoreEntry, } from '@vltpkg/tar/store-entry';
|
|
4
|
+
import { removeStoreEntry, storeEntryCopied, storeEntryLastCopied, storeEntryLinked, storeEntryNames, storeEntryTime, verifyStoreEntry, } from '@vltpkg/tar/store-entry';
|
|
5
5
|
import { readStoreIndex } from '@vltpkg/tar/store-index';
|
|
6
6
|
import { integrityHex } from '@vltpkg/types';
|
|
7
7
|
import { readFileSync } from 'node:fs';
|
|
@@ -24,6 +24,8 @@ export class CacheView extends ViewClass {
|
|
|
24
24
|
export const views = {
|
|
25
25
|
human: CacheView,
|
|
26
26
|
};
|
|
27
|
+
/** `prune-store`: days a copied entry stays, by default */
|
|
28
|
+
const pruneDays = 30;
|
|
27
29
|
const usageDef = {
|
|
28
30
|
command: 'cache',
|
|
29
31
|
usage: '<command> [flags]',
|
|
@@ -76,11 +78,14 @@ const usageDef = {
|
|
|
76
78
|
a file in \`node_modules\` was edited in place.`,
|
|
77
79
|
},
|
|
78
80
|
'prune-store': {
|
|
79
|
-
usage: '',
|
|
81
|
+
usage: '[<date>]',
|
|
80
82
|
description: `Remove global store entries that no \`node_modules\`
|
|
81
|
-
folder links to.
|
|
82
|
-
|
|
83
|
-
|
|
83
|
+
folder links to. Copies do not show use: an entry
|
|
84
|
+
copied or cloned from (install scripts,
|
|
85
|
+
\`store-linker=copy\`, macOS, a cache on another
|
|
86
|
+
drive) stays if that last happened after
|
|
87
|
+
\`<date>\`, or in the last ${pruneDays} days
|
|
88
|
+
without one.`,
|
|
84
89
|
},
|
|
85
90
|
},
|
|
86
91
|
examples: {
|
|
@@ -335,14 +340,24 @@ const verify = async (conf, specs, view) => {
|
|
|
335
340
|
...(!all && { missing }),
|
|
336
341
|
};
|
|
337
342
|
};
|
|
338
|
-
const pruneStore = async (conf,
|
|
343
|
+
const pruneStore = async (conf, args, view) => {
|
|
344
|
+
const since = args.length ?
|
|
345
|
+
new Date(args.join(' ')).getTime()
|
|
346
|
+
: Date.now() - pruneDays * 24 * 60 * 60 * 1000;
|
|
347
|
+
if (Number.isNaN(since)) {
|
|
348
|
+
throw error('Invalid date', {
|
|
349
|
+
code: 'EUSAGE',
|
|
350
|
+
found: args.join(' '),
|
|
351
|
+
});
|
|
352
|
+
}
|
|
339
353
|
const { storeRoot } = conf.options;
|
|
340
354
|
const names = storeEntryNames(storeRoot);
|
|
341
355
|
const removed = {};
|
|
342
356
|
for (const hex of names) {
|
|
343
357
|
const entry = resolve(storeRoot, hex);
|
|
344
358
|
const index = readStoreIndex(entry);
|
|
345
|
-
if (storeEntryCopied(entry, index)
|
|
359
|
+
if ((storeEntryCopied(entry, index) &&
|
|
360
|
+
storeEntryLastCopied(entry) >= since) ||
|
|
346
361
|
storeEntryLinked(entry, index)) {
|
|
347
362
|
continue;
|
|
348
363
|
}
|
package/dist/commands/ci.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CommandFn, CommandUsage } from '../index.ts';
|
|
2
2
|
import type { InstallResult } from './install.ts';
|
|
3
|
-
export type CIResult = Pick<InstallResult, 'buildQueue' | 'graph'>;
|
|
3
|
+
export type CIResult = Pick<InstallResult, 'buildQueue' | 'graph' | 'skills'>;
|
|
4
4
|
export declare const needsRegistry = true;
|
|
5
5
|
export declare const needsNpmRegistry = true;
|
|
6
6
|
export declare const usage: CommandUsage;
|
package/dist/commands/ci.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { install } from '@vltpkg/graph';
|
|
2
2
|
import { commandUsage } from "../config/usage.js";
|
|
3
|
+
import { warnIgnoredWorkspaces } from "../migrate-workspaces.js";
|
|
3
4
|
import { lazyView } from "../view.js";
|
|
4
5
|
export const needsRegistry = true;
|
|
5
6
|
export const needsNpmRegistry = true;
|
|
@@ -22,6 +23,10 @@ export const usage = () => commandUsage({
|
|
|
22
23
|
value: '<query>',
|
|
23
24
|
description: 'Filter which packages are allowed to run lifecycle scripts using DSS query syntax.',
|
|
24
25
|
},
|
|
26
|
+
'allow-skills': {
|
|
27
|
+
value: '<query>',
|
|
28
|
+
description: "Link agent skills of packages matching this DSS query into the project's agent skill dirs.",
|
|
29
|
+
},
|
|
25
30
|
'lockfile-only': {
|
|
26
31
|
description: 'Only update lockfile and package.json files; skip node_modules operations.',
|
|
27
32
|
},
|
|
@@ -32,15 +37,18 @@ export const views = {
|
|
|
32
37
|
human: lazyView(async () => (await import('./install/reporter.ts')).InstallReporter),
|
|
33
38
|
};
|
|
34
39
|
export const command = async (conf) => {
|
|
40
|
+
warnIgnoredWorkspaces(conf);
|
|
35
41
|
const ciOptions = {
|
|
36
42
|
...conf.options,
|
|
37
43
|
// same default as install: no scripts
|
|
38
44
|
allowScripts: conf.get('allow-scripts') ?? ':not(*)',
|
|
45
|
+
allowSkills: conf.get('allow-skills'),
|
|
46
|
+
skillsDirs: conf.get('skills-dir'),
|
|
39
47
|
expectLockfile: true,
|
|
40
48
|
frozenLockfile: true,
|
|
41
49
|
cleanInstall: true,
|
|
42
50
|
lockfileOnly: conf.options['lockfile-only'],
|
|
43
51
|
};
|
|
44
|
-
const { buildQueue, graph } = await install(ciOptions);
|
|
45
|
-
return { buildQueue, graph };
|
|
52
|
+
const { buildQueue, graph, skills } = await install(ciOptions);
|
|
53
|
+
return { buildQueue, graph, ...(skills ? { skills } : null) };
|
|
46
54
|
};
|
package/dist/commands/init.js
CHANGED
|
@@ -4,7 +4,7 @@ import { minimatch } from 'minimatch';
|
|
|
4
4
|
import { init } from '@vltpkg/init';
|
|
5
5
|
import { install } from '@vltpkg/graph';
|
|
6
6
|
import { load, save } from '@vltpkg/vlt-json';
|
|
7
|
-
import { assertWSConfig, resolveWSConfig, splitNegatedPatterns, } from '@vltpkg/workspaces';
|
|
7
|
+
import { assertWSConfig, migratableWSConfig, resolveWSConfig, splitNegatedPatterns, } from '@vltpkg/workspaces';
|
|
8
8
|
import { commandUsage } from "../config/usage.js";
|
|
9
9
|
export const usage = () => commandUsage({
|
|
10
10
|
command: 'init',
|
|
@@ -57,16 +57,15 @@ export const command = async (conf) => {
|
|
|
57
57
|
if (conf.values.workspace?.length) {
|
|
58
58
|
// the *effective* config, which may come from the root package.json
|
|
59
59
|
// rather than vlt.json
|
|
60
|
-
const
|
|
60
|
+
const resolved = resolveWSConfig(conf.options.projectRoot, conf.options.packageJson);
|
|
61
|
+
const parsedWSConfig = resolved.config;
|
|
61
62
|
// what gets written back to vlt.json. The raw vlt.json value is
|
|
62
63
|
// reused as-is so its existing shape is preserved. When the
|
|
63
|
-
// definitions live in package.json
|
|
64
|
-
// first -- otherwise adding a `workspaces`
|
|
65
|
-
// every workspace
|
|
64
|
+
// definitions live in package.json or pnpm-workspace.yaml instead,
|
|
65
|
+
// seed vlt.json with them first -- otherwise adding a `workspaces`
|
|
66
|
+
// field here would shadow every workspace already declared there.
|
|
66
67
|
const workspacesConfig = load('workspaces', assertWSConfig) ??
|
|
67
|
-
(
|
|
68
|
-
Object.values(parsedWSConfig).flat()
|
|
69
|
-
: undefined);
|
|
68
|
+
migratableWSConfig(resolved);
|
|
70
69
|
const results = [];
|
|
71
70
|
const addToConfig = [];
|
|
72
71
|
// create a new package.json file for every workspace
|
|
@@ -5,6 +5,7 @@ import { createElement as $, Fragment, useEffect, useState, } from 'react';
|
|
|
5
5
|
import { ViewClass } from "../../view.js";
|
|
6
6
|
import { asError } from '@vltpkg/types';
|
|
7
7
|
import { persistedEntries } from "../../persist-spec-config.js";
|
|
8
|
+
import { keptLine, savedLine, unmatchedLines, unscannedLines, } from "../../allow-skills.js";
|
|
8
9
|
const labels = {
|
|
9
10
|
build: 'resolving dependencies',
|
|
10
11
|
actual: '',
|
|
@@ -75,6 +76,17 @@ const App = ({ trailer }) => {
|
|
|
75
76
|
export class InstallReporter extends ViewClass {
|
|
76
77
|
#instance = null;
|
|
77
78
|
start() {
|
|
79
|
+
// Ink measures the terminal on every render, and when stdout has no
|
|
80
|
+
// width (a pipe, a CI log) it does so by spawning `tput cols` and
|
|
81
|
+
// `tput lines`: thousands of processes over one install. Give a
|
|
82
|
+
// non-TTY stdout the width Ink would fall back to anyway, so the
|
|
83
|
+
// output is the same and nothing is spawned.
|
|
84
|
+
if (!process.stdout.isTTY) {
|
|
85
|
+
// only a sane COLUMNS counts; -1 or Infinity would be truthy
|
|
86
|
+
const cols = Number(process.env.COLUMNS);
|
|
87
|
+
process.stdout.columns ||=
|
|
88
|
+
Number.isInteger(cols) && cols > 0 ? cols : 80;
|
|
89
|
+
}
|
|
78
90
|
this.#instance = render($(App));
|
|
79
91
|
}
|
|
80
92
|
async done(_result, { time }) {
|
|
@@ -87,12 +99,46 @@ export class InstallReporter extends ViewClass {
|
|
|
87
99
|
out +=
|
|
88
100
|
'🔨 Run `vlt build` to run all required scripts to build installed packages.\n';
|
|
89
101
|
}
|
|
102
|
+
const { linked = [], removed = [], conflicts = [], skipped = [], gitignore = [], unmatched = [], } = _result.skills ?? {};
|
|
103
|
+
const s = (n) => (n === 1 ? '' : 's');
|
|
104
|
+
const skills = [];
|
|
105
|
+
if (linked.length) {
|
|
106
|
+
// one per skill, linked in any number of dirs
|
|
107
|
+
const n = new Set(linked.map(r => `${r.id}\0${r.skill}`)).size;
|
|
108
|
+
const dirs = [...new Set(linked.map(r => r.dir))].join(', ');
|
|
109
|
+
skills.push(`🔗 Linked ${n} agent skill${s(n)} into ${dirs}`);
|
|
110
|
+
}
|
|
111
|
+
if (removed.length) {
|
|
112
|
+
skills.push(`🧹 Removed ${removed.length} stale skill link${s(removed.length)}: ${removed.join(', ')}`);
|
|
113
|
+
}
|
|
114
|
+
if (conflicts.length) {
|
|
115
|
+
skills.push(`⚠️ ${conflicts.length} skill link${s(conflicts.length)} skipped, path in use or taken by another package: ${conflicts.join(', ')}`);
|
|
116
|
+
}
|
|
117
|
+
skills.push(...unmatchedLines(unmatched));
|
|
118
|
+
if (skipped.length) {
|
|
119
|
+
skills.push(`⚠️ Skipped ${skipped.join(', ')}`);
|
|
120
|
+
}
|
|
121
|
+
if (gitignore.length) {
|
|
122
|
+
skills.push(`⚠️ Could not update ${gitignore.join(', ')}`);
|
|
123
|
+
}
|
|
124
|
+
skills.push(...unscannedLines(_result.skills ?? {}));
|
|
125
|
+
if (skills.length)
|
|
126
|
+
out += `\n${skills.join('\n')}\n`;
|
|
90
127
|
const saved = _result.persistedConfig;
|
|
91
128
|
if (saved) {
|
|
92
129
|
for (const e of persistedEntries(saved.values)) {
|
|
93
130
|
out += `\nSaved ${e} to ${saved.which} vlt.json`;
|
|
94
131
|
}
|
|
95
132
|
}
|
|
133
|
+
const migrated = _result.migratedWorkspaces;
|
|
134
|
+
if (migrated) {
|
|
135
|
+
out += `\nSaved workspaces from ${migrated.source} to vlt.json`;
|
|
136
|
+
}
|
|
137
|
+
const a = _result.allowSkills;
|
|
138
|
+
if (a?.stored)
|
|
139
|
+
out += `\n${keptLine(a.stored)}`;
|
|
140
|
+
else if (a)
|
|
141
|
+
out += `\n${savedLine(a.query, 'project')}`;
|
|
96
142
|
this.#instance?.rerender($(App, { trailer: out }));
|
|
97
143
|
return undefined;
|
|
98
144
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import type { AllowSkillsSave } from '../allow-skills.ts';
|
|
2
|
+
import type { MigratedWorkspaces } from '../migrate-workspaces.ts';
|
|
1
3
|
import type { SpecConfigPersistPlan } from '../persist-spec-config.ts';
|
|
2
4
|
import type { DepID } from '@vltpkg/dep-id';
|
|
3
|
-
import type { Diff, Graph } from '@vltpkg/graph';
|
|
5
|
+
import type { Diff, Graph, LinkSkillsResult } from '@vltpkg/graph';
|
|
4
6
|
import type { CommandFn, CommandUsage } from '../index.ts';
|
|
5
7
|
/**
|
|
6
8
|
* The resulting object of an install operation. To be used by the view impl.
|
|
@@ -22,12 +24,38 @@ export type InstallResult = {
|
|
|
22
24
|
* Spec config from the cli / env that was saved to a config file.
|
|
23
25
|
*/
|
|
24
26
|
persistedConfig?: SpecConfigPersistPlan;
|
|
27
|
+
/**
|
|
28
|
+
* Workspaces saved to vlt.json from package.json or pnpm-workspace.yaml.
|
|
29
|
+
*/
|
|
30
|
+
migratedWorkspaces?: MigratedWorkspaces;
|
|
31
|
+
/**
|
|
32
|
+
* Agent skill links added or removed.
|
|
33
|
+
*/
|
|
34
|
+
skills?: LinkSkillsResult;
|
|
35
|
+
/**
|
|
36
|
+
* `--allow-skills` saved to vlt.json, or kept because another query
|
|
37
|
+
* is stored.
|
|
38
|
+
*/
|
|
39
|
+
allowSkills?: AllowSkillsSave;
|
|
25
40
|
};
|
|
26
41
|
export declare const needsRegistry = true;
|
|
27
42
|
export declare const needsNpmRegistry = true;
|
|
28
43
|
export declare const usage: CommandUsage;
|
|
29
44
|
export declare const views: {
|
|
30
45
|
readonly json: (i: InstallResult) => {
|
|
46
|
+
allowSkills?: AllowSkillsSave | undefined;
|
|
47
|
+
skills?: {
|
|
48
|
+
unscanned?: string[];
|
|
49
|
+
unscannedReason?: "timeout" | "unscanned";
|
|
50
|
+
removed: string[];
|
|
51
|
+
conflicts: string[];
|
|
52
|
+
dirs: string[];
|
|
53
|
+
skipped?: string[];
|
|
54
|
+
gitignore?: string[];
|
|
55
|
+
unmatched?: import("@vltpkg/graph").UnmatchedPattern[];
|
|
56
|
+
linked: string[];
|
|
57
|
+
} | undefined;
|
|
58
|
+
migratedWorkspaces?: MigratedWorkspaces | undefined;
|
|
31
59
|
persistedConfig?: SpecConfigPersistPlan | undefined;
|
|
32
60
|
buildQueue?: DepID[] | undefined;
|
|
33
61
|
message?: string | undefined;
|
package/dist/commands/install.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
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";
|
|
4
5
|
import { planSpecConfigPersist } from "../persist-spec-config.js";
|
|
5
6
|
import { asUnknownSpecPrefix } from "../require-registry.js";
|
|
7
|
+
import { addTypesDeps } from "../save-types.js";
|
|
8
|
+
import { migrateWorkspaces } from "../migrate-workspaces.js";
|
|
6
9
|
import { trackInstall } from "../telemetry.js";
|
|
7
10
|
import { lazyView } from "../view.js";
|
|
8
11
|
export const needsRegistry = true;
|
|
@@ -32,9 +35,15 @@ export const usage = () => commandUsage({
|
|
|
32
35
|
'save-prod': {
|
|
33
36
|
description: 'Save installed packages to package.json as dependencies.',
|
|
34
37
|
},
|
|
38
|
+
'save-types': {
|
|
39
|
+
description: 'Also save matching @types/* packages to devDependencies for added packages that ship no types.',
|
|
40
|
+
},
|
|
35
41
|
'save-config': {
|
|
36
42
|
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.',
|
|
37
43
|
},
|
|
44
|
+
'no-migrate-workspaces': {
|
|
45
|
+
description: "Don't save workspaces read from package.json or pnpm-workspace.yaml to vlt.json.",
|
|
46
|
+
},
|
|
38
47
|
workspace: {
|
|
39
48
|
value: '<path|glob>',
|
|
40
49
|
description: 'Limit installation targets to matching workspaces.',
|
|
@@ -56,8 +65,17 @@ export const usage = () => commandUsage({
|
|
|
56
65
|
value: '<query>',
|
|
57
66
|
description: 'Filter which packages are allowed to run lifecycle scripts using DSS query syntax.',
|
|
58
67
|
},
|
|
68
|
+
'allow-skills': {
|
|
69
|
+
value: '<query>',
|
|
70
|
+
description: "Link agent skills of packages matching this DSS query into the project's agent skill dirs. Saved to vlt.json.",
|
|
71
|
+
},
|
|
59
72
|
},
|
|
60
73
|
});
|
|
74
|
+
// link mounts; `unchanged` left out
|
|
75
|
+
const skillsJson = ({ linked, unchanged: _, ...rest }) => ({
|
|
76
|
+
linked: linked.map(s => s.mount),
|
|
77
|
+
...rest,
|
|
78
|
+
});
|
|
61
79
|
export const views = {
|
|
62
80
|
json: i => {
|
|
63
81
|
const added = i.diff?.nodes.add ?? new Set();
|
|
@@ -119,6 +137,11 @@ export const views = {
|
|
|
119
137
|
...(i.persistedConfig ?
|
|
120
138
|
{ persistedConfig: i.persistedConfig }
|
|
121
139
|
: null),
|
|
140
|
+
...(i.migratedWorkspaces ?
|
|
141
|
+
{ migratedWorkspaces: i.migratedWorkspaces }
|
|
142
|
+
: null),
|
|
143
|
+
...(i.skills ? { skills: skillsJson(i.skills) } : null),
|
|
144
|
+
...(i.allowSkills ? { allowSkills: i.allowSkills } : null),
|
|
122
145
|
};
|
|
123
146
|
},
|
|
124
147
|
human: lazyView(async () => (await import('./install/reporter.ts')).InstallReporter),
|
|
@@ -130,6 +153,8 @@ export const command = async (conf) => {
|
|
|
130
153
|
const scurry = conf.options.scurry;
|
|
131
154
|
const { add } = parseAddArgs(conf, scurry, monorepo);
|
|
132
155
|
const persist = planSpecConfigPersist(conf);
|
|
156
|
+
if (conf.values['save-types'])
|
|
157
|
+
await addTypesDeps(conf, add);
|
|
133
158
|
const frozenLockfile = conf.options['frozen-lockfile'];
|
|
134
159
|
const expectLockfile = conf.options['expect-lockfile'];
|
|
135
160
|
const lockfileOnly = conf.options['lockfile-only'];
|
|
@@ -140,20 +165,26 @@ export const command = async (conf) => {
|
|
|
140
165
|
String(conf.get('allow-scripts'))
|
|
141
166
|
: ':not(*)';
|
|
142
167
|
/* c8 ignore stop */
|
|
168
|
+
const allowSkills = conf.get('allow-skills');
|
|
143
169
|
const installStart = Date.now();
|
|
144
|
-
const { buildQueue, graph, diff } = await install({
|
|
170
|
+
const { buildQueue, graph, diff, skills } = await install({
|
|
145
171
|
...conf.options,
|
|
146
172
|
frozenLockfile,
|
|
147
173
|
expectLockfile,
|
|
148
174
|
allowScripts,
|
|
175
|
+
allowSkills,
|
|
176
|
+
skillsDirs: conf.get('skills-dir'),
|
|
149
177
|
lockfileOnly,
|
|
150
178
|
saveExact,
|
|
151
179
|
savePrefix,
|
|
152
180
|
}, add).catch((er) => {
|
|
153
181
|
throw asUnknownSpecPrefix(er);
|
|
154
182
|
});
|
|
183
|
+
const migrated = frozenLockfile || expectLockfile ? undefined : (migrateWorkspaces(conf));
|
|
155
184
|
if (persist)
|
|
156
185
|
await conf.addConfigToFile(persist.which, persist.values);
|
|
186
|
+
// nothing linked on --lockfile-only
|
|
187
|
+
const allowSkillsSave = lockfileOnly ? undefined : await saveAllowSkills(conf);
|
|
157
188
|
/* c8 ignore next 9 - telemetry is best-effort */
|
|
158
189
|
try {
|
|
159
190
|
trackInstall({
|
|
@@ -167,5 +198,8 @@ export const command = async (conf) => {
|
|
|
167
198
|
graph,
|
|
168
199
|
diff,
|
|
169
200
|
...(persist ? { persistedConfig: persist } : null),
|
|
201
|
+
...(migrated ? { migratedWorkspaces: migrated } : null),
|
|
202
|
+
...(skills ? { skills } : null),
|
|
203
|
+
...(allowSkillsSave ? { allowSkills: allowSkillsSave } : null),
|
|
170
204
|
};
|
|
171
205
|
};
|
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';
|
|
@@ -138,6 +138,7 @@ export const command = async (conf) => {
|
|
|
138
138
|
securityArchive,
|
|
139
139
|
hostContexts,
|
|
140
140
|
getAuthHeader,
|
|
141
|
+
hasSkills,
|
|
141
142
|
});
|
|
142
143
|
const { nodes: resultNodes } = await scopeQuery.search(scopeQueryString, {
|
|
143
144
|
signal: new AbortController().signal,
|
|
@@ -190,6 +191,7 @@ export const command = async (conf) => {
|
|
|
190
191
|
securityArchive,
|
|
191
192
|
hostContexts,
|
|
192
193
|
getAuthHeader,
|
|
194
|
+
hasSkills,
|
|
193
195
|
});
|
|
194
196
|
const query = queryString ||
|
|
195
197
|
/* c8 ignore next */
|
package/dist/commands/pack.js
CHANGED
|
@@ -9,6 +9,7 @@ import { actual } from '@vltpkg/graph';
|
|
|
9
9
|
import { Query } from '@vltpkg/query';
|
|
10
10
|
import { error } from '@vltpkg/error-cause';
|
|
11
11
|
import { createHostContextsMap } from "../query-host-contexts.js";
|
|
12
|
+
import { sortScopeLocations } from "../sort-scope-locations.js";
|
|
12
13
|
import { minimatch } from 'minimatch';
|
|
13
14
|
export const needsRegistry = true;
|
|
14
15
|
export const usage = () => commandUsage({
|
|
@@ -97,7 +98,7 @@ const scopeLocations = async (queryString, conf) => {
|
|
|
97
98
|
}));
|
|
98
99
|
locations.push(resolve(projectRoot, location));
|
|
99
100
|
}
|
|
100
|
-
return locations;
|
|
101
|
+
return sortScopeLocations(locations, options.monorepo);
|
|
101
102
|
};
|
|
102
103
|
export const command = async (conf) => {
|
|
103
104
|
const { options, projectRoot } = conf;
|
package/dist/commands/pkg.js
CHANGED
|
@@ -9,6 +9,7 @@ import { SecurityArchive } from '@vltpkg/security-archive';
|
|
|
9
9
|
import { views as initViews } from "./init.js";
|
|
10
10
|
import { commandUsage } from "../config/usage.js";
|
|
11
11
|
import { createHostContextsMap } from "../query-host-contexts.js";
|
|
12
|
+
import { sortScopeLocations } from "../sort-scope-locations.js";
|
|
12
13
|
import { minimatch } from 'minimatch';
|
|
13
14
|
export const views = {
|
|
14
15
|
human: (results, _, config) => {
|
|
@@ -129,15 +130,17 @@ export const command = async (conf) => {
|
|
|
129
130
|
const { nodes: resultNodes } = await query.search(queryString, {
|
|
130
131
|
signal: new AbortController().signal,
|
|
131
132
|
});
|
|
133
|
+
const found = [];
|
|
132
134
|
for (const node of resultNodes) {
|
|
133
135
|
const location = node.location;
|
|
134
136
|
assert(location, error(`node ${node.id} has no location`, {
|
|
135
137
|
found: node,
|
|
136
138
|
}));
|
|
137
139
|
if (node.id !== VIRTUAL_ROOT_ID) {
|
|
138
|
-
|
|
140
|
+
found.push(resolve(node.projectRoot, location));
|
|
139
141
|
}
|
|
140
142
|
}
|
|
143
|
+
locations.push(...sortScopeLocations(found, options.monorepo));
|
|
141
144
|
}
|
|
142
145
|
else if (paths?.length || groups?.length || recursive) {
|
|
143
146
|
for (const workspace of options.monorepo ?? []) {
|