@sparkelf/dsh-plus 0.2.1-rc.2.4 → 0.2.2-alpha.2.10
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/README.md +7 -5
- package/README.zh.md +7 -5
- package/lib/apply-08huHfLG.js +665 -0
- package/lib/apply-DmICvIGh.js +653 -0
- package/lib/apply.js +1 -1
- package/lib/bin.js +229 -47
- package/lib/types/apply.d.ts +1 -1
- package/lib/types/apply.js +56 -117
- package/lib/types/patch-set.d.ts +59 -0
- package/lib/types/patch-set.js +132 -0
- package/lib/types/standalone-cli.js +93 -2
- package/lib/types/standalone-profile.d.ts +8 -1
- package/lib/types/standalone-profile.js +191 -53
- package/package.json +603 -175
- package/patches/approval-allow-policy.patch +108 -0
- package/patches/atomic-write-zombie-lock-holder.patch +53 -0
- package/patches/bootstrap-exempt-names.patch +32 -0
- package/patches/browser-auth-mode.patch +127 -0
- package/patches/composer-popover-boundaries.patch +337 -0
- package/patches/diagram-preview.patch +562 -0
- package/patches/image-offload-hoist-replay.patch +533 -0
- package/patches/legacy-code-preset.patch +148 -0
- package/patches/llm-pi-ai-transport-truncation.patch +33 -0
- package/patches/mobile-journal-generation.patch +76 -0
- package/patches/office-preview-stable-load.patch +34 -0
- package/patches/officecli-deliverables.patch +42 -0
- package/patches/ptc-mcp-schema-types.patch +156 -0
- package/patches/responses-reasoning-status.patch +289 -0
- package/patches/session-envelope-ignorable.patch +63 -0
- package/patches/session-export-chinese.patch +85 -0
- package/patches/session-format-legacy-restart.patch +35 -0
- package/patches/session-log-trajectory-toolbar.patch +352 -0
- package/patches/state-dot-brand-blue.patch +185 -0
- package/patches/ui-settings-compact-phone.patch +76 -0
- package/patches/web-runtime-compat.patch +83 -0
- package/patches/workspace-storage-restore.patch +186 -0
- package/patches/wsl-native-open.patch +265 -0
package/lib/bin.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { r as runApply } from "./apply-
|
|
2
|
+
import { i as readPatchSet, r as runApply } from "./apply-08huHfLG.js";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { execFileSync, spawn, spawnSync } from "node:child_process";
|
|
5
5
|
import { createWriteStream, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
|
|
@@ -858,6 +858,11 @@ function requireStringArray(value, label) {
|
|
|
858
858
|
if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) throw new Error(label + " must be a string array");
|
|
859
859
|
return value;
|
|
860
860
|
}
|
|
861
|
+
/** Read one non-empty string field. */
|
|
862
|
+
function requireString(value, label) {
|
|
863
|
+
if (typeof value !== "string" || value.trim() === "") throw new Error(label + " must be a non-empty string");
|
|
864
|
+
return value;
|
|
865
|
+
}
|
|
861
866
|
/** Resolve the DSH home, honouring the environment override the launcher itself reads. */
|
|
862
867
|
function resolveHome(env = process.env) {
|
|
863
868
|
const configured = env.DSH_HOME;
|
|
@@ -895,11 +900,12 @@ function isWithin(candidate, parent, platform = process.platform) {
|
|
|
895
900
|
* @returns absolute path to the installed distribution.
|
|
896
901
|
*/
|
|
897
902
|
function resolveDistributionDirectory(anchor) {
|
|
903
|
+
const ownDirectory = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
898
904
|
let resolved;
|
|
899
905
|
try {
|
|
900
906
|
resolved = dirname(createRequire(anchor).resolve("@sparkelf/dsh-plus/package.json"));
|
|
901
907
|
} catch {
|
|
902
|
-
|
|
908
|
+
return ownDirectory;
|
|
903
909
|
}
|
|
904
910
|
let current = resolve(dirname(anchor));
|
|
905
911
|
for (;;) {
|
|
@@ -908,20 +914,14 @@ function resolveDistributionDirectory(anchor) {
|
|
|
908
914
|
if (parent === current) break;
|
|
909
915
|
current = parent;
|
|
910
916
|
}
|
|
911
|
-
|
|
917
|
+
return ownDirectory;
|
|
912
918
|
}
|
|
913
|
-
/** The reviewed bundle order and pins the installed distribution declares. */
|
|
914
919
|
function readDistributionProfile(distributionDirectory) {
|
|
915
920
|
const manifest = requireRecord(JSON.parse(readFileSync(join(distributionDirectory, "package.json"), "utf8")), "Plus distribution manifest");
|
|
916
921
|
const plus = requireRecord(manifest.dshPlus, "dshPlus");
|
|
917
922
|
const profile = requireRecord(plus.profile, "dshPlus.profile");
|
|
918
|
-
const
|
|
923
|
+
const dependencies = requireDependencyMap(requireRecord(profile.dependencies, "dshPlus.profile.dependencies"), "dshPlus.profile.dependencies");
|
|
919
924
|
const rawAllowBuilds = requireRecord(profile.allowBuilds, "dshPlus.profile.allowBuilds");
|
|
920
|
-
const dependencies = {};
|
|
921
|
-
for (const [name, spec] of Object.entries(rawDependencies)) {
|
|
922
|
-
if (typeof spec !== "string" || spec === "") throw new Error("dshPlus.profile.dependencies." + name + " must be a non-empty string");
|
|
923
|
-
dependencies[name] = spec;
|
|
924
|
-
}
|
|
925
925
|
const allowBuilds = {};
|
|
926
926
|
for (const [name, allowed] of Object.entries(rawAllowBuilds)) {
|
|
927
927
|
if (typeof allowed !== "boolean") throw new Error("dshPlus.profile.allowBuilds." + name + " must be a boolean");
|
|
@@ -933,6 +933,16 @@ function readDistributionProfile(distributionDirectory) {
|
|
|
933
933
|
if (typeof spec !== "string" || spec === "") throw new Error("dshPlus.profile.overrides." + name + " must be a non-empty string");
|
|
934
934
|
overrides[name] = spec;
|
|
935
935
|
}
|
|
936
|
+
const editions = {};
|
|
937
|
+
const rawEditions = plus.editions === void 0 ? {} : requireRecord(plus.editions, "dshPlus.editions");
|
|
938
|
+
for (const [id, value] of Object.entries(rawEditions)) {
|
|
939
|
+
const edition = requireRecord(value, "dshPlus.editions." + id);
|
|
940
|
+
editions[id] = {
|
|
941
|
+
label: requireString(edition.label, "dshPlus.editions." + id + ".label"),
|
|
942
|
+
bundles: requireStringArray(edition.bundles, "dshPlus.editions." + id + ".bundles"),
|
|
943
|
+
packages: requireDependencyMap(requireRecord(edition.packages, "dshPlus.editions." + id + ".packages"), "dshPlus.editions." + id + ".packages")
|
|
944
|
+
};
|
|
945
|
+
}
|
|
936
946
|
const compatibility = requireRecord(plus.compatibility, "dshPlus.compatibility");
|
|
937
947
|
return {
|
|
938
948
|
name: String(manifest.name),
|
|
@@ -940,10 +950,20 @@ function readDistributionProfile(distributionDirectory) {
|
|
|
940
950
|
dependencies,
|
|
941
951
|
allowBuilds,
|
|
942
952
|
overrides,
|
|
953
|
+
editions,
|
|
943
954
|
dshRange: String(compatibility.dsh),
|
|
944
955
|
version: String(manifest.version)
|
|
945
956
|
};
|
|
946
957
|
}
|
|
958
|
+
/** Read one package-name-to-spec map, rejecting empty entries. */
|
|
959
|
+
function requireDependencyMap(value, label) {
|
|
960
|
+
const dependencies = {};
|
|
961
|
+
for (const [name, spec] of Object.entries(value)) {
|
|
962
|
+
if (typeof spec !== "string" || spec === "") throw new Error(label + "." + name + " must be a non-empty string");
|
|
963
|
+
dependencies[name] = spec;
|
|
964
|
+
}
|
|
965
|
+
return dependencies;
|
|
966
|
+
}
|
|
947
967
|
/**
|
|
948
968
|
* Give the profile its own installed tree, built from the distribution's declarations.
|
|
949
969
|
*
|
|
@@ -963,7 +983,11 @@ function readDistributionProfile(distributionDirectory) {
|
|
|
963
983
|
* @param consumerDirectory - directory whose `node_modules` holds the installation.
|
|
964
984
|
*/
|
|
965
985
|
function installProfilePackages(paths, consumerDirectory) {
|
|
966
|
-
if (!existsSync(join(consumerDirectory, "node_modules")))
|
|
986
|
+
if (!existsSync(join(consumerDirectory, "node_modules"))) {
|
|
987
|
+
installWithRegistryFallback(paths);
|
|
988
|
+
alignReplacedPackageNames(join(paths.profileDirectory, "node_modules"));
|
|
989
|
+
return;
|
|
990
|
+
}
|
|
967
991
|
const profileModules = join(paths.profileDirectory, "node_modules");
|
|
968
992
|
if (existsSync(profileModules)) {
|
|
969
993
|
linkNestedBundles(paths, profileModules);
|
|
@@ -985,6 +1009,7 @@ function installProfilePackages(paths, consumerDirectory) {
|
|
|
985
1009
|
function installWithRegistryFallback(paths) {
|
|
986
1010
|
const registries = registryOrder();
|
|
987
1011
|
for (const [index, registry] of registries.entries()) {
|
|
1012
|
+
if (index > 0) rmSync(join(paths.profileDirectory, "pnpm-lock.yaml"), { force: true });
|
|
988
1013
|
const result = spawnSync("pnpm", [
|
|
989
1014
|
"install",
|
|
990
1015
|
"--no-frozen-lockfile",
|
|
@@ -993,7 +1018,8 @@ function installWithRegistryFallback(paths) {
|
|
|
993
1018
|
], {
|
|
994
1019
|
cwd: paths.profileDirectory,
|
|
995
1020
|
stdio: "inherit",
|
|
996
|
-
shell: process.platform === "win32"
|
|
1021
|
+
shell: process.platform === "win32",
|
|
1022
|
+
timeout: 5 * 6e4
|
|
997
1023
|
});
|
|
998
1024
|
if (result.error !== void 0) throw result.error;
|
|
999
1025
|
if (result.status === 0) return;
|
|
@@ -1052,7 +1078,7 @@ const MAINLAND_REGISTRY = "https://registry.npmmirror.com";
|
|
|
1052
1078
|
*/
|
|
1053
1079
|
function registryOrder() {
|
|
1054
1080
|
const configured = process.env.DSH_PLUS_INSTALL_REGISTRY;
|
|
1055
|
-
if (configured !== void 0 && configured !== "") return [configured, MAINLAND_REGISTRY];
|
|
1081
|
+
if (configured !== void 0 && configured !== "") return [configured, configured === MAINLAND_REGISTRY ? OFFICIAL_REGISTRY : MAINLAND_REGISTRY];
|
|
1056
1082
|
const locale = [
|
|
1057
1083
|
process.env.LANG,
|
|
1058
1084
|
process.env.LC_ALL,
|
|
@@ -1153,12 +1179,85 @@ function resolvePaths(anchor, env = process.env) {
|
|
|
1153
1179
|
*
|
|
1154
1180
|
* @param paths - resolved standalone paths.
|
|
1155
1181
|
* @param consumerDirectory - directory whose `node_modules` holds the installed packages.
|
|
1182
|
+
* @param edition - edition id whose package list to install, or undefined for the default.
|
|
1156
1183
|
* @returns whether this call created the manifest.
|
|
1157
1184
|
*/
|
|
1158
|
-
function ensureProfile(paths, consumerDirectory) {
|
|
1185
|
+
function ensureProfile(paths, consumerDirectory, edition) {
|
|
1159
1186
|
const manifestPath = join(paths.profileDirectory, "package.json");
|
|
1160
1187
|
const distribution = readDistributionProfile(paths.distributionDirectory);
|
|
1188
|
+
const composition = edition === void 0 ? void 0 : distribution.editions[edition];
|
|
1189
|
+
if (edition !== void 0 && composition === void 0) {
|
|
1190
|
+
const offered = Object.keys(distribution.editions);
|
|
1191
|
+
throw new Error("unknown edition \"" + edition + "\"; this release offers " + (offered.length === 0 ? "(none)" : offered.join(", ")));
|
|
1192
|
+
}
|
|
1193
|
+
for (const name of Object.keys(composition?.packages ?? {})) if (name.startsWith("@deepseek-ai/")) throw new Error("edition \"" + String(edition) + "\" lists the official package " + name + "; editions contain only third-party or self-developed plugins");
|
|
1194
|
+
const runtime = distribution.dshRange.replace(/^>=?/u, "");
|
|
1195
|
+
const baseBundles = composition === void 0 ? distribution.bundles : distribution.bundles.filter((bundle) => bundle.startsWith("@deepseek-ai/") || bundle === "@sparkelf/dsh-plus");
|
|
1196
|
+
const basePackages = composition === void 0 ? distribution.dependencies : {
|
|
1197
|
+
"@deepseek-ai/dsh": distribution.dshRange,
|
|
1198
|
+
"@sparkelf/dsh-plus": distribution.version,
|
|
1199
|
+
"@deepseek-ai/cordis": "^4.0.6-alpha.1",
|
|
1200
|
+
"@deepseek-ai/cordis-plugin-group": "^1.0.6-alpha.1",
|
|
1201
|
+
"@deepseek-ai/cordis-plugin-include": "^1.0.11-alpha.1",
|
|
1202
|
+
"@deepseek-ai/cordis-plugin-loader": "^1.0.7-alpha.1",
|
|
1203
|
+
"@deepseek-ai/dsh-home-paths": runtime,
|
|
1204
|
+
"@deepseek-ai/dsh-launch-environment": runtime,
|
|
1205
|
+
"@deepseek-ai/dsh-agent": runtime,
|
|
1206
|
+
"@deepseek-ai/dsh-llm": runtime,
|
|
1207
|
+
"@deepseek-ai/dsh-scope": runtime,
|
|
1208
|
+
"@deepseek-ai/dsh-session": runtime,
|
|
1209
|
+
"@deepseek-ai/dsh-system-prompt": runtime,
|
|
1210
|
+
"@deepseek-ai/dsh-user-approval": runtime,
|
|
1211
|
+
"@deepseek-ai/dsh-attachment": runtime,
|
|
1212
|
+
"@deepseek-ai/dsh-compaction": runtime,
|
|
1213
|
+
"@deepseek-ai/dsh-fs": runtime,
|
|
1214
|
+
"@deepseek-ai/dsh-shell": runtime,
|
|
1215
|
+
"@deepseek-ai/dsh-spill": runtime,
|
|
1216
|
+
"@deepseek-ai/dsh-sandbox": runtime,
|
|
1217
|
+
"@deepseek-ai/dsh-ptc-runtime": runtime,
|
|
1218
|
+
"@deepseek-ai/dsh-llm-deepseek": runtime,
|
|
1219
|
+
"@deepseek-ai/dsh-deepseek-account": runtime,
|
|
1220
|
+
"@deepseek-ai/dsh-anonymous-user-id": runtime,
|
|
1221
|
+
"@deepseek-ai/dsh-bash-local": runtime,
|
|
1222
|
+
"@deepseek-ai/dsh-client-store": runtime,
|
|
1223
|
+
"@deepseek-ai/dsh-jobs": runtime,
|
|
1224
|
+
"@deepseek-ai/dsh-sdk-protocol": runtime,
|
|
1225
|
+
"@deepseek-ai/dsh-session-persistence": runtime,
|
|
1226
|
+
"@deepseek-ai/dsh-session-telemetry": runtime,
|
|
1227
|
+
"@deepseek-ai/dsh-session-title-llm": runtime,
|
|
1228
|
+
"@deepseek-ai/dsh-util-workspace-path": runtime,
|
|
1229
|
+
"@deepseek-ai/dsh-workflow": runtime,
|
|
1230
|
+
...Object.fromEntries(baseBundles.filter((bundle) => bundle.startsWith("@deepseek-ai/dsh-")).map((bundle) => [bundle, runtime]))
|
|
1231
|
+
};
|
|
1232
|
+
const compositionPackages = composition === void 0 ? basePackages : {
|
|
1233
|
+
...basePackages,
|
|
1234
|
+
...composition.packages
|
|
1235
|
+
};
|
|
1236
|
+
for (const [alias, target] of Object.entries({
|
|
1237
|
+
"dsh-better-sidebar": "@sparkelf/dsh-better-sidebar",
|
|
1238
|
+
"dsh-sql-workbench": "@sparkelf/dsh-sql-workbench"
|
|
1239
|
+
})) {
|
|
1240
|
+
const spec = compositionPackages[target];
|
|
1241
|
+
if (spec !== void 0 && compositionPackages[alias] === void 0) compositionPackages[alias] = "npm:" + target + "@" + spec;
|
|
1242
|
+
}
|
|
1243
|
+
const compositionBundles = composition === void 0 ? baseBundles : [...baseBundles, ...composition.bundles];
|
|
1161
1244
|
if (existsSync(manifestPath)) {
|
|
1245
|
+
if (composition !== void 0) {
|
|
1246
|
+
const manifest = requireRecord(JSON.parse(readFileSync(manifestPath, "utf8")), "Plus profile manifest");
|
|
1247
|
+
manifest.dependencies = {
|
|
1248
|
+
...manifest.dependencies,
|
|
1249
|
+
...compositionPackages
|
|
1250
|
+
};
|
|
1251
|
+
manifest.dsh = {
|
|
1252
|
+
...manifest.dsh,
|
|
1253
|
+
profile: {
|
|
1254
|
+
...manifest.dsh?.profile,
|
|
1255
|
+
bundles: [...compositionBundles],
|
|
1256
|
+
...edition === void 0 ? {} : { plusEdition: edition }
|
|
1257
|
+
}
|
|
1258
|
+
};
|
|
1259
|
+
writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
|
|
1260
|
+
}
|
|
1162
1261
|
writeProfileOverrides(paths.profileDirectory, distribution.overrides, distribution.allowBuilds, paths.omittedPackages);
|
|
1163
1262
|
installProfilePackages(paths, consumerDirectory);
|
|
1164
1263
|
return false;
|
|
@@ -1168,14 +1267,11 @@ function ensureProfile(paths, consumerDirectory) {
|
|
|
1168
1267
|
name: "dsh-profile-plus",
|
|
1169
1268
|
private: true,
|
|
1170
1269
|
type: "module",
|
|
1171
|
-
dependencies:
|
|
1172
|
-
"@sparkelf/dsh-plus": distribution.version,
|
|
1173
|
-
"@deepseek-ai/dsh": distribution.dshRange,
|
|
1174
|
-
...distribution.dependencies
|
|
1175
|
-
},
|
|
1270
|
+
dependencies: compositionPackages,
|
|
1176
1271
|
dsh: { profile: {
|
|
1177
|
-
bundles:
|
|
1178
|
-
patchReload: "live"
|
|
1272
|
+
bundles: [...compositionBundles],
|
|
1273
|
+
patchReload: "live",
|
|
1274
|
+
...edition === void 0 ? {} : { plusEdition: edition }
|
|
1179
1275
|
} }
|
|
1180
1276
|
};
|
|
1181
1277
|
writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
|
|
@@ -1203,7 +1299,7 @@ function writeProfileOverrides(profileDirectory, overrides, allowBuilds, omitted
|
|
|
1203
1299
|
for (const [name, spec] of Object.entries(omittedPackages)) document.setIn(["overrides", name], spec);
|
|
1204
1300
|
for (const [name, allowed] of Object.entries(allowBuilds)) document.setIn(["allowBuilds", name], allowed);
|
|
1205
1301
|
if (document.get("nodeLinker") === void 0) document.set("nodeLinker", "hoisted");
|
|
1206
|
-
if (document.get("autoInstallPeers") === void 0) document.set("autoInstallPeers",
|
|
1302
|
+
if (document.get("autoInstallPeers") === void 0) document.set("autoInstallPeers", true);
|
|
1207
1303
|
writeFileSync(workspacePath, String(document));
|
|
1208
1304
|
}
|
|
1209
1305
|
/** Run git in one directory, returning undefined instead of throwing when asked to. */
|
|
@@ -1234,30 +1330,21 @@ function git(root, args, acceptFailure = false) {
|
|
|
1234
1330
|
* @returns the labels of the patches that were applied.
|
|
1235
1331
|
*/
|
|
1236
1332
|
function applyProfileNpmPatches(distributionDirectory, profileDirectory) {
|
|
1237
|
-
const
|
|
1238
|
-
if (!Array.isArray(names)) throw new Error("dshPlus.patchPackages must be an array");
|
|
1333
|
+
const patchSet = readPatchSet(distributionDirectory, requireRecord(JSON.parse(readFileSync(join(distributionDirectory, "package.json"), "utf8")), "Plus distribution manifest"));
|
|
1239
1334
|
const applied = [];
|
|
1240
|
-
for (const
|
|
1241
|
-
if (
|
|
1242
|
-
const
|
|
1243
|
-
const
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
"apply",
|
|
1254
|
-
"--reverse",
|
|
1255
|
-
"--check",
|
|
1256
|
-
file
|
|
1257
|
-
], true) !== void 0) continue;
|
|
1258
|
-
git(patched.directory, ["apply", file]);
|
|
1259
|
-
applied.push(value + " -> " + targetName);
|
|
1260
|
-
}
|
|
1335
|
+
for (const entry of [...patchSet.entries, ...patchSet.thirdPartyPatches]) {
|
|
1336
|
+
if (entry.target.kind !== "npm") continue;
|
|
1337
|
+
const targetName = entry.target.name;
|
|
1338
|
+
const patched = resolveInstalledPackage(profileDirectory, targetName);
|
|
1339
|
+
const file = resolve(distributionDirectory, entry.file);
|
|
1340
|
+
if (git(patched.directory, [
|
|
1341
|
+
"apply",
|
|
1342
|
+
"--reverse",
|
|
1343
|
+
"--check",
|
|
1344
|
+
file
|
|
1345
|
+
], true) !== void 0) continue;
|
|
1346
|
+
git(patched.directory, ["apply", file]);
|
|
1347
|
+
applied.push(entry.id + " -> " + targetName);
|
|
1261
1348
|
}
|
|
1262
1349
|
return applied;
|
|
1263
1350
|
}
|
|
@@ -1268,7 +1355,18 @@ function resolveInstalledPackage(from, packageName) {
|
|
|
1268
1355
|
try {
|
|
1269
1356
|
manifestPath = requireFrom.resolve(packageName + "/package.json");
|
|
1270
1357
|
} catch {
|
|
1271
|
-
|
|
1358
|
+
let directory;
|
|
1359
|
+
try {
|
|
1360
|
+
directory = dirname(requireFrom.resolve(packageName));
|
|
1361
|
+
} catch {
|
|
1362
|
+
throw new Error(packageName + " is not installed under " + from);
|
|
1363
|
+
}
|
|
1364
|
+
while (!existsSync(resolve(directory, "package.json"))) {
|
|
1365
|
+
const parent = dirname(directory);
|
|
1366
|
+
if (parent === directory) throw new Error(packageName + " has no resolvable package manifest under " + from);
|
|
1367
|
+
directory = parent;
|
|
1368
|
+
}
|
|
1369
|
+
manifestPath = resolve(directory, "package.json");
|
|
1272
1370
|
}
|
|
1273
1371
|
const manifest = requireRecord(JSON.parse(readFileSync(manifestPath, "utf8")), packageName + " manifest");
|
|
1274
1372
|
return {
|
|
@@ -1298,6 +1396,7 @@ function parseStartOptions(argv) {
|
|
|
1298
1396
|
let host = "127.0.0.1";
|
|
1299
1397
|
let open = true;
|
|
1300
1398
|
let foreground = false;
|
|
1399
|
+
let edition;
|
|
1301
1400
|
let capabilities;
|
|
1302
1401
|
for (let index = 0; index < argv.length; index += 1) {
|
|
1303
1402
|
const token = argv[index];
|
|
@@ -1323,6 +1422,13 @@ function parseStartOptions(argv) {
|
|
|
1323
1422
|
foreground = true;
|
|
1324
1423
|
continue;
|
|
1325
1424
|
}
|
|
1425
|
+
if (token === "--edition") {
|
|
1426
|
+
const value = argv[index + 1];
|
|
1427
|
+
if (value === void 0 || value === "") throw new Error("--edition requires a value");
|
|
1428
|
+
edition = value;
|
|
1429
|
+
index += 1;
|
|
1430
|
+
continue;
|
|
1431
|
+
}
|
|
1326
1432
|
if (token === "--capabilities") {
|
|
1327
1433
|
const value = argv[index + 1];
|
|
1328
1434
|
if (value === void 0) throw new Error("--capabilities requires a comma-separated list, or an empty string for none");
|
|
@@ -1340,6 +1446,7 @@ function parseStartOptions(argv) {
|
|
|
1340
1446
|
host,
|
|
1341
1447
|
open,
|
|
1342
1448
|
foreground,
|
|
1449
|
+
edition,
|
|
1343
1450
|
capabilities
|
|
1344
1451
|
};
|
|
1345
1452
|
}
|
|
@@ -1425,6 +1532,56 @@ function runForeground(entry, profileName, port, host, open) {
|
|
|
1425
1532
|
if (!open) args.push("--no-open");
|
|
1426
1533
|
return spawnSync(process.execPath, args, { stdio: "inherit" }).status ?? 1;
|
|
1427
1534
|
}
|
|
1535
|
+
/** Parse the install command's edition selection. */
|
|
1536
|
+
function parseInstallOptions(argv) {
|
|
1537
|
+
let edition;
|
|
1538
|
+
let profile;
|
|
1539
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
1540
|
+
const token = argv[index];
|
|
1541
|
+
if (token === "--edition") {
|
|
1542
|
+
const value = argv[index + 1];
|
|
1543
|
+
if (value === void 0 || value === "") throw new Error("--edition requires a value");
|
|
1544
|
+
edition = value;
|
|
1545
|
+
index += 1;
|
|
1546
|
+
continue;
|
|
1547
|
+
}
|
|
1548
|
+
if (token === "--profile") {
|
|
1549
|
+
const value = argv[index + 1];
|
|
1550
|
+
if (value === void 0 || value === "") throw new Error("--profile requires a value");
|
|
1551
|
+
profile = value;
|
|
1552
|
+
index += 1;
|
|
1553
|
+
continue;
|
|
1554
|
+
}
|
|
1555
|
+
throw new Error("unknown option: " + String(token));
|
|
1556
|
+
}
|
|
1557
|
+
if (edition === void 0) throw new Error("install requires --edition personal or --edition team");
|
|
1558
|
+
return {
|
|
1559
|
+
edition,
|
|
1560
|
+
profile
|
|
1561
|
+
};
|
|
1562
|
+
}
|
|
1563
|
+
/**
|
|
1564
|
+
* Install one edition's package manifest into the profile.
|
|
1565
|
+
*
|
|
1566
|
+
* The profile's `package.json` is the install artifact; there is no separate standalone
|
|
1567
|
+
* package. A later `start` uses the same manifest, so changing the edition is a new
|
|
1568
|
+
* install rather than a second product.
|
|
1569
|
+
*
|
|
1570
|
+
* @param argv - arguments after `install`.
|
|
1571
|
+
* @returns the process exit code.
|
|
1572
|
+
*/
|
|
1573
|
+
function install(argv) {
|
|
1574
|
+
const { edition, profile } = parseInstallOptions(argv);
|
|
1575
|
+
const base = resolvePaths(declarationAnchor());
|
|
1576
|
+
const paths = profile === void 0 ? base : {
|
|
1577
|
+
...base,
|
|
1578
|
+
profileName: profile,
|
|
1579
|
+
profileDirectory: join(base.home, "profiles", profile)
|
|
1580
|
+
};
|
|
1581
|
+
ensureProfile(paths, installationRoot(), edition);
|
|
1582
|
+
console.log("Installed the " + edition + " edition into " + paths.profileDirectory);
|
|
1583
|
+
return 0;
|
|
1584
|
+
}
|
|
1428
1585
|
async function start(argv) {
|
|
1429
1586
|
const options = parseStartOptions(argv);
|
|
1430
1587
|
const anchor = installationAnchor();
|
|
@@ -1458,8 +1615,9 @@ async function start(argv) {
|
|
|
1458
1615
|
}
|
|
1459
1616
|
console.log("pnpm installed.");
|
|
1460
1617
|
}
|
|
1461
|
-
const created = ensureProfile(paths, installationRoot());
|
|
1618
|
+
const created = ensureProfile(paths, installationRoot(), options.edition);
|
|
1462
1619
|
console.log(created ? "Created the " + paths.profileName + " profile at " + paths.profileDirectory : "Using the existing " + paths.profileName + " profile");
|
|
1620
|
+
if (options.edition !== void 0) console.log("Edition: " + options.edition);
|
|
1463
1621
|
for (const label of applyProfileNpmPatches(paths.distributionDirectory, paths.profileDirectory)) console.log("Applied the reviewed patch " + label);
|
|
1464
1622
|
const answers = created || !existsSync(join(paths.home, "capabilities.json")) ? options.capabilities === void 0 ? await interviewCapabilities(true) : selectCapabilities(options.capabilities) : void 0;
|
|
1465
1623
|
if (answers !== void 0) {
|
|
@@ -1802,6 +1960,23 @@ async function doctor() {
|
|
|
1802
1960
|
const record = readCapabilityRecord(paths.home);
|
|
1803
1961
|
const drifted = record === void 0 ? [] : CAPABILITIES.filter((capability) => record.enabled.includes(capability.id) !== actual.mounted.includes(capability.id));
|
|
1804
1962
|
check(drifted.length === 0, drifted.length === 0 ? "capabilities: " + (actual.mounted.length === 0 ? "(none enabled)" : actual.mounted.join(", ")) : "capabilities disagree with capabilities.json: " + drifted.map((capability) => capability.id).join(", ") + " (run dsh-plus capabilities)");
|
|
1963
|
+
const profileManifestPath = join(paths.profileDirectory, "package.json");
|
|
1964
|
+
if (existsSync(profileManifestPath)) {
|
|
1965
|
+
const profileManifest = JSON.parse(readFileSync(profileManifestPath, "utf8"));
|
|
1966
|
+
const editionId = profileManifest.dsh?.profile?.plusEdition;
|
|
1967
|
+
if (editionId !== void 0) {
|
|
1968
|
+
const edition = readDistributionProfile(paths.distributionDirectory).editions[editionId];
|
|
1969
|
+
if (edition === void 0) check(false, "edition \"" + editionId + "\" is not declared by this distribution");
|
|
1970
|
+
else {
|
|
1971
|
+
const bundles = new Set(profileManifest.dsh?.profile?.bundles ?? []);
|
|
1972
|
+
const missingBundles = edition.bundles.filter((bundle) => !bundles.has(bundle));
|
|
1973
|
+
const packageNames = Object.keys(edition.packages);
|
|
1974
|
+
const missingPackages = packageNames.filter((name) => !existsSync(join(paths.profileDirectory, "node_modules", ...name.split("/"), "package.json")));
|
|
1975
|
+
check(missingBundles.length === 0, "edition " + editionId + ": " + String(edition.bundles.length - missingBundles.length) + "/" + String(edition.bundles.length) + " bundles mounted" + (missingBundles.length === 0 ? "" : " (missing " + missingBundles.join(", ") + ")"));
|
|
1976
|
+
check(missingPackages.length === 0, "edition " + editionId + ": " + String(packageNames.length - missingPackages.length) + "/" + String(packageNames.length) + " packages installed" + (missingPackages.length === 0 ? "" : " (missing " + missingPackages.join(", ") + ")"));
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1805
1980
|
console.log(failures === 0 ? "No problems found." : String(failures) + " problem(s) found.");
|
|
1806
1981
|
return failures === 0 ? 0 : 1;
|
|
1807
1982
|
}
|
|
@@ -1809,6 +1984,7 @@ const USAGE = [
|
|
|
1809
1984
|
"Usage: dsh-plus <command> [options]",
|
|
1810
1985
|
"",
|
|
1811
1986
|
"Commands:",
|
|
1987
|
+
" install install an edition package manifest into the profile",
|
|
1812
1988
|
" start start the server (first run creates the profile)",
|
|
1813
1989
|
" stop stop the server",
|
|
1814
1990
|
" status report whether the server is running",
|
|
@@ -1821,6 +1997,11 @@ const USAGE = [
|
|
|
1821
1997
|
" --host <h> interface to bind (default 127.0.0.1)",
|
|
1822
1998
|
" --no-open do not open a browser",
|
|
1823
1999
|
" --foreground run in this terminal instead of in the background",
|
|
2000
|
+
" --edition <id> install the named edition manifest (personal or team)",
|
|
2001
|
+
"",
|
|
2002
|
+
"install options:",
|
|
2003
|
+
" --edition <id> package manifest to install (personal or team)",
|
|
2004
|
+
" --profile <n> profile name to install into (default: this installation)",
|
|
1824
2005
|
"",
|
|
1825
2006
|
"capabilities options:",
|
|
1826
2007
|
" --enable <ids> enable the comma-separated capability ids",
|
|
@@ -1843,6 +2024,7 @@ async function runStandaloneCli(argv) {
|
|
|
1843
2024
|
console.log(USAGE);
|
|
1844
2025
|
return 0;
|
|
1845
2026
|
}
|
|
2027
|
+
if (command === "install") return install(rest);
|
|
1846
2028
|
if (command === "start") return await start(rest);
|
|
1847
2029
|
if (command === "stop") return stop();
|
|
1848
2030
|
if (command === "status") return status();
|
package/lib/types/apply.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Materialize the Plus distribution's
|
|
1
|
+
/** Materialize the Plus distribution's embedded patch set without Desktop. */
|
|
2
2
|
/** One official workspace package available as a profile peer dependency. */
|
|
3
3
|
export interface OfficialWorkspacePackage {
|
|
4
4
|
name: string;
|