@sparkelf/dsh-plus 0.2.2-alpha.2.30 → 0.2.2-alpha.2.31
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/lib/apply.js +1 -1
- package/lib/bin.js +217 -145
- package/lib/types/apply.d.ts +1 -1
- package/lib/types/apply.js +56 -117
- package/lib/types/standalone-cli.js +93 -2
- package/lib/types/standalone-profile.d.ts +8 -1
- package/lib/types/standalone-profile.js +179 -26
- package/package.json +4 -5
package/lib/types/apply.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
/** Materialize the Plus distribution's
|
|
1
|
+
/** Materialize the Plus distribution's embedded patch set without Desktop. */
|
|
2
2
|
import { spawnSync } from 'node:child_process';
|
|
3
3
|
import { chmodSync, copyFileSync, existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, symlinkSync, writeFileSync, } from 'node:fs';
|
|
4
4
|
import { createRequire } from 'node:module';
|
|
5
|
-
import { dirname, isAbsolute, relative, resolve } from 'node:path';
|
|
5
|
+
import { basename, dirname, isAbsolute, relative, resolve } from 'node:path';
|
|
6
6
|
import { tmpdir } from 'node:os';
|
|
7
7
|
import { satisfies, valid, validRange } from 'semver';
|
|
8
8
|
import { parseDocument } from 'yaml';
|
|
9
|
+
import { readPatchSet } from "./patch-set.js";
|
|
9
10
|
const FORMAT_VERSION = 1;
|
|
10
11
|
function isSelectedNpmPatch(patch) {
|
|
11
12
|
return patch.target.kind === 'npm';
|
|
@@ -50,7 +51,22 @@ function requireStringArray(value, label) {
|
|
|
50
51
|
}
|
|
51
52
|
function resolveInstalledPackage(distributionDirectory, packageName) {
|
|
52
53
|
const requireFromDistribution = createRequire(resolve(distributionDirectory, 'package.json'));
|
|
53
|
-
|
|
54
|
+
let manifestPath;
|
|
55
|
+
try {
|
|
56
|
+
manifestPath = requireFromDistribution.resolve(packageName + '/package.json');
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// Some packages do not export `./package.json`; resolve the entry module instead and walk
|
|
60
|
+
// up to the directory that holds the manifest.
|
|
61
|
+
let directory = dirname(requireFromDistribution.resolve(packageName));
|
|
62
|
+
while (!existsSync(resolve(directory, 'package.json'))) {
|
|
63
|
+
const parent = dirname(directory);
|
|
64
|
+
if (parent === directory)
|
|
65
|
+
throw new Error(packageName + ' has no resolvable package manifest');
|
|
66
|
+
directory = parent;
|
|
67
|
+
}
|
|
68
|
+
manifestPath = resolve(directory, 'package.json');
|
|
69
|
+
}
|
|
54
70
|
const manifest = readJsonObject(manifestPath, packageName + ' manifest');
|
|
55
71
|
return {
|
|
56
72
|
name: packageName,
|
|
@@ -59,48 +75,6 @@ function resolveInstalledPackage(distributionDirectory, packageName) {
|
|
|
59
75
|
manifest,
|
|
60
76
|
};
|
|
61
77
|
}
|
|
62
|
-
function resolvePatchFile(packageDirectory, declared) {
|
|
63
|
-
const absoluteFile = resolve(packageDirectory, declared);
|
|
64
|
-
const local = relative(packageDirectory, absoluteFile);
|
|
65
|
-
if (isAbsolute(local) || local === '..' || local.startsWith('../')) {
|
|
66
|
-
throw new Error('patch file must stay inside its patch package: ' + declared);
|
|
67
|
-
}
|
|
68
|
-
if (!existsSync(absoluteFile))
|
|
69
|
-
throw new Error('patch file does not exist: ' + absoluteFile);
|
|
70
|
-
return { relativeFile: local.replaceAll('\\', '/'), absoluteFile };
|
|
71
|
-
}
|
|
72
|
-
function parseVariant(value, index, patchPackage) {
|
|
73
|
-
const label = patchPackage.name + ' dshPatch.variants[' + String(index) + ']';
|
|
74
|
-
const variant = requireObject(value, label);
|
|
75
|
-
const target = requireObject(variant.target, label + '.target');
|
|
76
|
-
const kind = requireString(target.kind, label + '.target.kind');
|
|
77
|
-
const common = {
|
|
78
|
-
id: requireString(variant.id, label + '.id'),
|
|
79
|
-
dsh: requireRange(variant.dsh, label + '.dsh'),
|
|
80
|
-
file: requireString(variant.file, label + '.file'),
|
|
81
|
-
patchPackage,
|
|
82
|
-
};
|
|
83
|
-
if (kind === 'npm') {
|
|
84
|
-
return {
|
|
85
|
-
...common,
|
|
86
|
-
target: {
|
|
87
|
-
kind,
|
|
88
|
-
name: requireString(target.name, label + '.target.name'),
|
|
89
|
-
range: requireRange(target.range, label + '.target.range'),
|
|
90
|
-
},
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
if (kind === 'dsh-source') {
|
|
94
|
-
return {
|
|
95
|
-
...common,
|
|
96
|
-
target: {
|
|
97
|
-
kind,
|
|
98
|
-
baseRevision: requireString(target.baseRevision, label + '.target.baseRevision'),
|
|
99
|
-
},
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
throw new Error('unsupported patch target kind: ' + kind);
|
|
103
|
-
}
|
|
104
78
|
function git(root, args, acceptFailure = false) {
|
|
105
79
|
const result = spawnSync('git', args, { cwd: root, encoding: 'utf8' });
|
|
106
80
|
if (result.status === 0)
|
|
@@ -148,23 +122,6 @@ function requireSourceBase(root, baseRevision) {
|
|
|
148
122
|
}
|
|
149
123
|
return checkoutRevision;
|
|
150
124
|
}
|
|
151
|
-
function patchPackageVariants(distributionDirectory, names) {
|
|
152
|
-
const variants = [];
|
|
153
|
-
for (const name of names) {
|
|
154
|
-
const patchPackage = resolveInstalledPackage(distributionDirectory, name);
|
|
155
|
-
const declaration = requireObject(patchPackage.manifest.dshPatch, name + ' dshPatch');
|
|
156
|
-
if (declaration.formatVersion !== FORMAT_VERSION) {
|
|
157
|
-
throw new Error('unsupported dshPatch formatVersion in ' + name + ': ' + String(declaration.formatVersion));
|
|
158
|
-
}
|
|
159
|
-
if (!Array.isArray(declaration.variants) || declaration.variants.length === 0) {
|
|
160
|
-
throw new Error(name + ' dshPatch.variants must be a non-empty array');
|
|
161
|
-
}
|
|
162
|
-
for (const [index, value] of declaration.variants.entries()) {
|
|
163
|
-
variants.push(parseVariant(value, index, patchPackage));
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
return variants;
|
|
167
|
-
}
|
|
168
125
|
// 先验证official source,再物化Plus声明的profile依赖,避免source不匹配时改动用户profile。
|
|
169
126
|
function prepareSelection(distributionDirectory, profileDirectory, dshRoot) {
|
|
170
127
|
const distributionManifest = readJsonObject(resolve(distributionDirectory, 'package.json'), 'Plus distribution manifest');
|
|
@@ -192,31 +149,24 @@ function prepareSelection(distributionDirectory, profileDirectory, dshRoot) {
|
|
|
192
149
|
throw new Error('dshPlus.profile.allowBuilds.' + name + ' must be a boolean');
|
|
193
150
|
allowBuilds[name] = allowed;
|
|
194
151
|
}
|
|
195
|
-
const
|
|
152
|
+
const patchSet = readPatchSet(distributionDirectory, distributionManifest);
|
|
196
153
|
const dependencies = requireObject(distributionManifest.dependencies, 'Plus distribution dependencies');
|
|
197
154
|
const dshManifest = readJsonObject(resolve(dshRoot, 'package.json'), 'DSH source manifest');
|
|
198
155
|
const dshVersion = requireVersion(dshManifest.version, 'DSH source version');
|
|
199
156
|
if (!satisfies(dshVersion, dshRange, { includePrerelease: true })) {
|
|
200
157
|
throw new Error(distributionName + '@' + distributionVersion + ' requires DSH ' + dshRange + ', found ' + dshVersion);
|
|
201
158
|
}
|
|
202
|
-
const checkoutRevision = requireSourceBase(dshRoot,
|
|
203
|
-
const
|
|
204
|
-
for (const variant of patchPackageVariants(distributionDirectory, patchPackageNames)) {
|
|
205
|
-
const entries = groups.get(variant.id) ?? [];
|
|
206
|
-
entries.push(variant);
|
|
207
|
-
groups.set(variant.id, entries);
|
|
208
|
-
}
|
|
159
|
+
const checkoutRevision = requireSourceBase(dshRoot, patchSet.sourceBaseRevision);
|
|
160
|
+
const patchEntries = [...patchSet.entries, ...patchSet.thirdPartyPatches];
|
|
209
161
|
const sourceStates = new Map();
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
if (variant.target.kind !== 'dsh-source'
|
|
214
|
-
|| variant.target.baseRevision !== baseRevision
|
|
215
|
-
|| !satisfies(dshVersion, variant.dsh, { includePrerelease: true }))
|
|
216
|
-
continue;
|
|
217
|
-
const file = resolvePatchFile(variant.patchPackage.directory, variant.file);
|
|
218
|
-
sourceStates.set(file.absoluteFile, sourcePatchState(dshRoot, file.absoluteFile));
|
|
162
|
+
for (const item of patchEntries) {
|
|
163
|
+
if (!satisfies(dshVersion, item.dsh, { includePrerelease: true })) {
|
|
164
|
+
throw new Error('patch ' + item.id + ' declares DSH ' + item.dsh + ', found ' + dshVersion);
|
|
219
165
|
}
|
|
166
|
+
if (item.target.kind !== 'dsh-source')
|
|
167
|
+
continue;
|
|
168
|
+
const absoluteFile = resolve(distributionDirectory, item.file);
|
|
169
|
+
sourceStates.set(absoluteFile, sourcePatchState(dshRoot, absoluteFile));
|
|
220
170
|
}
|
|
221
171
|
const pendingSourceFiles = [...sourceStates].flatMap(([file, state]) => state === 'pending' ? [file] : []);
|
|
222
172
|
preflightSourcePatches(dshRoot, pendingSourceFiles);
|
|
@@ -227,49 +177,38 @@ function prepareSelection(distributionDirectory, profileDirectory, dshRoot) {
|
|
|
227
177
|
return { name, version: installed.version };
|
|
228
178
|
});
|
|
229
179
|
const runtimePackages = [
|
|
230
|
-
...Object.keys(dependencies).
|
|
180
|
+
...Object.keys(dependencies).sort().map((name) => {
|
|
231
181
|
const installed = resolveInstalledPackage(distributionDirectory, name);
|
|
232
182
|
return { name, version: installed.version };
|
|
233
183
|
}),
|
|
234
184
|
...profileDependencies,
|
|
235
185
|
].sort((left, right) => left.name.localeCompare(right.name));
|
|
236
186
|
const selected = [];
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
patchPackage: { name: variant.patchPackage.name, version: variant.patchPackage.version },
|
|
262
|
-
file: file.relativeFile,
|
|
263
|
-
absoluteFile: file.absoluteFile,
|
|
264
|
-
target: { kind: 'npm', name: variant.target.name, version: targetVersion },
|
|
265
|
-
}];
|
|
187
|
+
for (const item of patchEntries) {
|
|
188
|
+
const absoluteFile = resolve(distributionDirectory, item.file);
|
|
189
|
+
if (item.target.kind === 'dsh-source') {
|
|
190
|
+
selected.push({
|
|
191
|
+
id: item.id,
|
|
192
|
+
scope: item.scope,
|
|
193
|
+
file: item.file,
|
|
194
|
+
absoluteFile,
|
|
195
|
+
target: { kind: 'dsh-source', baseRevision: patchSet.sourceBaseRevision },
|
|
196
|
+
alreadyApplied: sourceStates.get(absoluteFile) === 'applied',
|
|
197
|
+
});
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
const targetDirectory = item.target.name in profileDependencySpecs ? profileDirectory : distributionDirectory;
|
|
201
|
+
const targetVersion = resolveInstalledPackage(targetDirectory, item.target.name).version;
|
|
202
|
+
if (!satisfies(targetVersion, item.target.range, { includePrerelease: true })) {
|
|
203
|
+
throw new Error('patch ' + item.id + ' targets ' + item.target.name + ' ' + item.target.range + ', found ' + targetVersion);
|
|
204
|
+
}
|
|
205
|
+
selected.push({
|
|
206
|
+
id: item.id,
|
|
207
|
+
scope: item.scope,
|
|
208
|
+
file: item.file,
|
|
209
|
+
absoluteFile,
|
|
210
|
+
target: { kind: 'npm', name: item.target.name, version: targetVersion },
|
|
266
211
|
});
|
|
267
|
-
const [candidate] = candidates;
|
|
268
|
-
if (candidate === undefined)
|
|
269
|
-
throw new Error('no compatible patch variant for ' + id + ' on DSH ' + dshVersion);
|
|
270
|
-
if (candidates.length > 1)
|
|
271
|
-
throw new Error('multiple compatible patch variants for ' + id + ' on DSH ' + dshVersion);
|
|
272
|
-
selected.push(candidate);
|
|
273
212
|
}
|
|
274
213
|
const lockPatches = selected.map((patch) => {
|
|
275
214
|
if ('alreadyApplied' in patch) {
|
|
@@ -299,7 +238,7 @@ function materializePatchFiles(profileDirectory, patches) {
|
|
|
299
238
|
const root = resolve(profileDirectory, '.dsh-plus', 'patches');
|
|
300
239
|
rmSync(root, { recursive: true, force: true });
|
|
301
240
|
const stablePatches = patches.map((patch) => {
|
|
302
|
-
const destination = resolve(root, patch.
|
|
241
|
+
const destination = resolve(root, patch.scope, patch.id, basename(patch.file));
|
|
303
242
|
mkdirSync(dirname(destination), { recursive: true });
|
|
304
243
|
copyFileSync(patch.absoluteFile, destination);
|
|
305
244
|
return { ...patch, absoluteFile: destination };
|
|
@@ -323,7 +262,7 @@ function materializePatchFiles(profileDirectory, patches) {
|
|
|
323
262
|
continue;
|
|
324
263
|
}
|
|
325
264
|
// 成员或版本变化必须改变workspace路径,使pnpm重新应用新的组合payload。
|
|
326
|
-
const members = group.map(patch => encodeURIComponent(patch.id
|
|
265
|
+
const members = group.map(patch => encodeURIComponent(patch.id)).join('+');
|
|
327
266
|
const destination = resolve(root, 'combined', encodeURIComponent(key), members + '.patch');
|
|
328
267
|
mkdirSync(dirname(destination), { recursive: true });
|
|
329
268
|
const contents = group.map((patch) => {
|
|
@@ -25,6 +25,7 @@ function parseStartOptions(argv) {
|
|
|
25
25
|
let host = '127.0.0.1';
|
|
26
26
|
let open = true;
|
|
27
27
|
let foreground = false;
|
|
28
|
+
let edition;
|
|
28
29
|
let capabilities;
|
|
29
30
|
for (let index = 0; index < argv.length; index += 1) {
|
|
30
31
|
const token = argv[index];
|
|
@@ -52,6 +53,14 @@ function parseStartOptions(argv) {
|
|
|
52
53
|
foreground = true;
|
|
53
54
|
continue;
|
|
54
55
|
}
|
|
56
|
+
if (token === '--edition') {
|
|
57
|
+
const value = argv[index + 1];
|
|
58
|
+
if (value === undefined || value === '')
|
|
59
|
+
throw new Error('--edition requires a value');
|
|
60
|
+
edition = value;
|
|
61
|
+
index += 1;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
55
64
|
if (token === '--capabilities') {
|
|
56
65
|
const value = argv[index + 1];
|
|
57
66
|
if (value === undefined)
|
|
@@ -73,7 +82,7 @@ function parseStartOptions(argv) {
|
|
|
73
82
|
}
|
|
74
83
|
throw new Error('unknown option: ' + String(token));
|
|
75
84
|
}
|
|
76
|
-
return { port, host, open, foreground, capabilities };
|
|
85
|
+
return { port, host, open, foreground, edition, capabilities };
|
|
77
86
|
}
|
|
78
87
|
/**
|
|
79
88
|
* Resolve a stated capability selection.
|
|
@@ -157,6 +166,54 @@ function runForeground(entry, profileName, port, host, open) {
|
|
|
157
166
|
const result = spawnSync(process.execPath, args, { stdio: 'inherit' });
|
|
158
167
|
return result.status ?? 1;
|
|
159
168
|
}
|
|
169
|
+
/** Parse the install command's edition selection. */
|
|
170
|
+
function parseInstallOptions(argv) {
|
|
171
|
+
let edition;
|
|
172
|
+
let profile;
|
|
173
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
174
|
+
const token = argv[index];
|
|
175
|
+
if (token === '--edition') {
|
|
176
|
+
const value = argv[index + 1];
|
|
177
|
+
if (value === undefined || value === '')
|
|
178
|
+
throw new Error('--edition requires a value');
|
|
179
|
+
edition = value;
|
|
180
|
+
index += 1;
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
if (token === '--profile') {
|
|
184
|
+
const value = argv[index + 1];
|
|
185
|
+
if (value === undefined || value === '')
|
|
186
|
+
throw new Error('--profile requires a value');
|
|
187
|
+
profile = value;
|
|
188
|
+
index += 1;
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
throw new Error('unknown option: ' + String(token));
|
|
192
|
+
}
|
|
193
|
+
if (edition === undefined)
|
|
194
|
+
throw new Error('install requires --edition personal or --edition team');
|
|
195
|
+
return { edition, profile };
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Install one edition's package manifest into the profile.
|
|
199
|
+
*
|
|
200
|
+
* The profile's `package.json` is the install artifact; there is no separate standalone
|
|
201
|
+
* package. A later `start` uses the same manifest, so changing the edition is a new
|
|
202
|
+
* install rather than a second product.
|
|
203
|
+
*
|
|
204
|
+
* @param argv - arguments after `install`.
|
|
205
|
+
* @returns the process exit code.
|
|
206
|
+
*/
|
|
207
|
+
function install(argv) {
|
|
208
|
+
const { edition, profile } = parseInstallOptions(argv);
|
|
209
|
+
const base = resolvePaths(declarationAnchor());
|
|
210
|
+
const paths = profile === undefined
|
|
211
|
+
? base
|
|
212
|
+
: { ...base, profileName: profile, profileDirectory: join(base.home, 'profiles', profile) };
|
|
213
|
+
ensureProfile(paths, installationRoot(), edition);
|
|
214
|
+
console.log('Installed the ' + edition + ' edition into ' + paths.profileDirectory);
|
|
215
|
+
return 0;
|
|
216
|
+
}
|
|
160
217
|
async function start(argv) {
|
|
161
218
|
const options = parseStartOptions(argv);
|
|
162
219
|
const anchor = installationAnchor();
|
|
@@ -202,10 +259,12 @@ async function start(argv) {
|
|
|
202
259
|
}
|
|
203
260
|
console.log('pnpm installed.');
|
|
204
261
|
}
|
|
205
|
-
const created = ensureProfile(paths, installationRoot());
|
|
262
|
+
const created = ensureProfile(paths, installationRoot(), options.edition);
|
|
206
263
|
console.log(created
|
|
207
264
|
? 'Created the ' + paths.profileName + ' profile at ' + paths.profileDirectory
|
|
208
265
|
: 'Using the existing ' + paths.profileName + ' profile');
|
|
266
|
+
if (options.edition !== undefined)
|
|
267
|
+
console.log('Edition: ' + options.edition);
|
|
209
268
|
// The profile symlinks the consumer's packages, so a patch lands on the installed
|
|
210
269
|
// copy the launcher loads. A reinstall restores the published bytes, which is why
|
|
211
270
|
// this runs on every start rather than only when the profile was created.
|
|
@@ -581,6 +640,30 @@ async function doctor() {
|
|
|
581
640
|
? 'capabilities: ' + (actual.mounted.length === 0 ? '(none enabled)' : actual.mounted.join(', '))
|
|
582
641
|
: 'capabilities disagree with ' + CAPABILITY_RECORD + ': ' + drifted.map(capability => capability.id).join(', ')
|
|
583
642
|
+ ' (run dsh-plus capabilities)');
|
|
643
|
+
const profileManifestPath = join(paths.profileDirectory, 'package.json');
|
|
644
|
+
if (existsSync(profileManifestPath)) {
|
|
645
|
+
const profileManifest = JSON.parse(readFileSync(profileManifestPath, 'utf8'));
|
|
646
|
+
const editionId = profileManifest.dsh?.profile?.plusEdition;
|
|
647
|
+
if (editionId !== undefined) {
|
|
648
|
+
const distribution = readDistributionProfile(paths.distributionDirectory);
|
|
649
|
+
const edition = distribution.editions[editionId];
|
|
650
|
+
if (edition === undefined) {
|
|
651
|
+
check(false, 'edition "' + editionId + '" is not declared by this distribution');
|
|
652
|
+
}
|
|
653
|
+
else {
|
|
654
|
+
const bundles = new Set(profileManifest.dsh?.profile?.bundles ?? []);
|
|
655
|
+
const missingBundles = edition.bundles.filter(bundle => !bundles.has(bundle));
|
|
656
|
+
const packageNames = Object.keys(edition.packages);
|
|
657
|
+
const missingPackages = packageNames.filter(name => !existsSync(join(paths.profileDirectory, 'node_modules', ...name.split('/'), 'package.json')));
|
|
658
|
+
check(missingBundles.length === 0, 'edition ' + editionId + ': ' + String(edition.bundles.length - missingBundles.length) + '/'
|
|
659
|
+
+ String(edition.bundles.length) + ' bundles mounted'
|
|
660
|
+
+ (missingBundles.length === 0 ? '' : ' (missing ' + missingBundles.join(', ') + ')'));
|
|
661
|
+
check(missingPackages.length === 0, 'edition ' + editionId + ': ' + String(packageNames.length - missingPackages.length) + '/'
|
|
662
|
+
+ String(packageNames.length) + ' packages installed'
|
|
663
|
+
+ (missingPackages.length === 0 ? '' : ' (missing ' + missingPackages.join(', ') + ')'));
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
}
|
|
584
667
|
console.log(failures === 0 ? 'No problems found.' : String(failures) + ' problem(s) found.');
|
|
585
668
|
return failures === 0 ? 0 : 1;
|
|
586
669
|
}
|
|
@@ -588,6 +671,7 @@ const USAGE = [
|
|
|
588
671
|
'Usage: dsh-plus <command> [options]',
|
|
589
672
|
'',
|
|
590
673
|
'Commands:',
|
|
674
|
+
' install install an edition package manifest into the profile',
|
|
591
675
|
' start start the server (first run creates the profile)',
|
|
592
676
|
' stop stop the server',
|
|
593
677
|
' status report whether the server is running',
|
|
@@ -600,6 +684,11 @@ const USAGE = [
|
|
|
600
684
|
' --host <h> interface to bind (default 127.0.0.1)',
|
|
601
685
|
' --no-open do not open a browser',
|
|
602
686
|
' --foreground run in this terminal instead of in the background',
|
|
687
|
+
' --edition <id> install the named edition manifest (personal or team)',
|
|
688
|
+
'',
|
|
689
|
+
'install options:',
|
|
690
|
+
' --edition <id> package manifest to install (personal or team)',
|
|
691
|
+
' --profile <n> profile name to install into (default: this installation)',
|
|
603
692
|
'',
|
|
604
693
|
'capabilities options:',
|
|
605
694
|
' --enable <ids> enable the comma-separated capability ids',
|
|
@@ -622,6 +711,8 @@ export async function runStandaloneCli(argv) {
|
|
|
622
711
|
console.log(USAGE);
|
|
623
712
|
return 0;
|
|
624
713
|
}
|
|
714
|
+
if (command === 'install')
|
|
715
|
+
return install(rest);
|
|
625
716
|
if (command === 'start')
|
|
626
717
|
return await start(rest);
|
|
627
718
|
if (command === 'stop')
|
|
@@ -93,12 +93,18 @@ export declare function isWithin(candidate: string, parent: string, platform?: N
|
|
|
93
93
|
*/
|
|
94
94
|
export declare function resolveDistributionDirectory(anchor: string): string;
|
|
95
95
|
/** The reviewed bundle order and pins the installed distribution declares. */
|
|
96
|
+
export interface EditionComposition {
|
|
97
|
+
readonly label: string;
|
|
98
|
+
readonly bundles: readonly string[];
|
|
99
|
+
readonly packages: Readonly<Record<string, string>>;
|
|
100
|
+
}
|
|
96
101
|
export declare function readDistributionProfile(distributionDirectory: string): {
|
|
97
102
|
readonly name: string;
|
|
98
103
|
readonly bundles: readonly string[];
|
|
99
104
|
readonly dependencies: Readonly<Record<string, string>>;
|
|
100
105
|
readonly allowBuilds: Readonly<Record<string, boolean>>;
|
|
101
106
|
readonly overrides: Readonly<Record<string, string>>;
|
|
107
|
+
readonly editions: Readonly<Record<string, EditionComposition>>;
|
|
102
108
|
readonly dshRange: string;
|
|
103
109
|
readonly version: string;
|
|
104
110
|
};
|
|
@@ -191,9 +197,10 @@ export declare function resolvePaths(anchor: string, env?: NodeJS.ProcessEnv): S
|
|
|
191
197
|
*
|
|
192
198
|
* @param paths - resolved standalone paths.
|
|
193
199
|
* @param consumerDirectory - directory whose `node_modules` holds the installed packages.
|
|
200
|
+
* @param edition - edition id whose package list to install, or undefined for the default.
|
|
194
201
|
* @returns whether this call created the manifest.
|
|
195
202
|
*/
|
|
196
|
-
export declare function ensureProfile(paths: StandalonePaths, consumerDirectory: string): boolean;
|
|
203
|
+
export declare function ensureProfile(paths: StandalonePaths, consumerDirectory: string, edition?: string): boolean;
|
|
197
204
|
/**
|
|
198
205
|
* Apply the reviewed npm-target patches to the profile's installed packages.
|
|
199
206
|
*
|