@sparkelf/dsh-plus 0.2.2-alpha.2.30 → 0.2.2-alpha.2.32
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/LICENSE +21 -0
- 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 +15 -16
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DeepSeek
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/lib/apply.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as parseOfficialWorkspacePackages, r as runApply, t as materializeOfficialPackageScope } from "./apply-
|
|
1
|
+
import { n as parseOfficialWorkspacePackages, r as runApply, t as materializeOfficialPackageScope } from "./apply-08huHfLG.js";
|
|
2
2
|
export { materializeOfficialPackageScope, parseOfficialWorkspacePackages, runApply };
|
package/lib/bin.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
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";
|
|
6
|
-
import { dirname,
|
|
6
|
+
import { dirname, join, posix, resolve, win32 } from "node:path";
|
|
7
7
|
import { homedir } from "node:os";
|
|
8
|
-
import semver
|
|
8
|
+
import semver from "semver";
|
|
9
9
|
import { parseDocument } from "yaml";
|
|
10
10
|
import { fileURLToPath } from "node:url";
|
|
11
11
|
import { createServer } from "node:net";
|
|
@@ -790,125 +790,6 @@ async function waitForAuthenticatedUrl(logPath, timeoutMilliseconds) {
|
|
|
790
790
|
}
|
|
791
791
|
}
|
|
792
792
|
//#endregion
|
|
793
|
-
//#region lib/types/patch-set.js
|
|
794
|
-
/**
|
|
795
|
-
* Read the Plus distribution's embedded patch set.
|
|
796
|
-
*
|
|
797
|
-
* The distribution owns one patch set for official DSH and, separately, the patches it
|
|
798
|
-
* carries for third-party packages. Both live inside the distribution package: the
|
|
799
|
-
* manifest declares entries, and each entry's payload is a file under `patches/`. A
|
|
800
|
-
* consumer resolves no independently published patch package.
|
|
801
|
-
*
|
|
802
|
-
* The two lists are governed differently. A Plus entry must target an official package
|
|
803
|
-
* that the profile republishes and overrides; a third-party entry must name its upstream
|
|
804
|
-
* and a retirement condition, and never becomes part of the official patch set.
|
|
805
|
-
*/
|
|
806
|
-
function object(value, label) {
|
|
807
|
-
if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error(label + " must be an object");
|
|
808
|
-
return value;
|
|
809
|
-
}
|
|
810
|
-
function string(value, label) {
|
|
811
|
-
if (typeof value !== "string" || value === "") throw new Error(label + " must be a non-empty string");
|
|
812
|
-
return value;
|
|
813
|
-
}
|
|
814
|
-
function range(value, label) {
|
|
815
|
-
const text = string(value, label);
|
|
816
|
-
if (validRange(text) === null) throw new Error(label + " is not a semantic-version range: " + text);
|
|
817
|
-
return text;
|
|
818
|
-
}
|
|
819
|
-
/** A payload stays inside the distribution package it is declared by. */
|
|
820
|
-
function patchFile(distributionDirectory, declared, label) {
|
|
821
|
-
const absolute = resolve(distributionDirectory, declared);
|
|
822
|
-
const local = relative(distributionDirectory, absolute);
|
|
823
|
-
if (local === "" || isAbsolute(local) || local === ".." || local.startsWith("../")) throw new Error(label + " must stay inside the distribution package: " + declared);
|
|
824
|
-
if (!existsSync(absolute)) throw new Error(label + " does not exist: " + absolute);
|
|
825
|
-
return local.replaceAll("\\", "/");
|
|
826
|
-
}
|
|
827
|
-
function sourceTarget(value, sourceBaseRevision, label) {
|
|
828
|
-
const target = object(value, label);
|
|
829
|
-
if (target.kind !== "dsh-source") throw new Error(label + ".kind must be dsh-source");
|
|
830
|
-
if (!Array.isArray(target.paths) || target.paths.length === 0) throw new Error(label + ".paths must be a non-empty array");
|
|
831
|
-
const paths = target.paths.map((entry, index) => {
|
|
832
|
-
const path = string(entry, label + ".paths[" + String(index) + "]");
|
|
833
|
-
if (!path.endsWith("/")) throw new Error(label + ".paths entries must be repository directory prefixes");
|
|
834
|
-
return path;
|
|
835
|
-
});
|
|
836
|
-
if (!Array.isArray(target.packages) || target.packages.length === 0) throw new Error(label + ".packages must be a non-empty array");
|
|
837
|
-
return {
|
|
838
|
-
kind: "dsh-source",
|
|
839
|
-
baseRevision: sourceBaseRevision,
|
|
840
|
-
packages: target.packages.map((entry, index) => {
|
|
841
|
-
const name = string(entry, label + ".packages[" + String(index) + "]");
|
|
842
|
-
if (!name.startsWith("@deepseek-ai/")) throw new Error(label + ".packages entries must be official package names");
|
|
843
|
-
return name;
|
|
844
|
-
}),
|
|
845
|
-
paths
|
|
846
|
-
};
|
|
847
|
-
}
|
|
848
|
-
function npmTarget(value, label) {
|
|
849
|
-
const target = object(value, label);
|
|
850
|
-
if (target.kind !== "npm") throw new Error(label + ".kind must be npm");
|
|
851
|
-
return {
|
|
852
|
-
kind: "npm",
|
|
853
|
-
name: string(target.name, label + ".name"),
|
|
854
|
-
range: range(target.range, label + ".range")
|
|
855
|
-
};
|
|
856
|
-
}
|
|
857
|
-
function entry(value, scope, sourceBaseRevision, distributionDirectory, label) {
|
|
858
|
-
const record = object(value, label);
|
|
859
|
-
const id = string(record.id, label + ".id");
|
|
860
|
-
const dsh = range(record.dsh, label + ".dsh");
|
|
861
|
-
const file = patchFile(distributionDirectory, string(record.file, label + ".file"), label + ".file");
|
|
862
|
-
const retireWhen = string(record.retireWhen, label + ".retireWhen");
|
|
863
|
-
const targetLabel = label + ".target";
|
|
864
|
-
const target = scope === "plus" ? object(record.target, targetLabel).kind === "dsh-source" ? sourceTarget(record.target, sourceBaseRevision, targetLabel) : npmTarget(record.target, targetLabel) : npmTarget(record.target, targetLabel);
|
|
865
|
-
if (scope === "third-party") return {
|
|
866
|
-
id,
|
|
867
|
-
scope,
|
|
868
|
-
dsh,
|
|
869
|
-
file,
|
|
870
|
-
retireWhen,
|
|
871
|
-
upstreamUrl: string(record.upstreamUrl, label + ".upstreamUrl"),
|
|
872
|
-
target
|
|
873
|
-
};
|
|
874
|
-
return {
|
|
875
|
-
id,
|
|
876
|
-
scope,
|
|
877
|
-
dsh,
|
|
878
|
-
file,
|
|
879
|
-
retireWhen,
|
|
880
|
-
target
|
|
881
|
-
};
|
|
882
|
-
}
|
|
883
|
-
/**
|
|
884
|
-
* Read and validate the embedded patch set from an installed distribution.
|
|
885
|
-
* @param distributionDirectory - installed `@sparkelf/dsh-plus` directory.
|
|
886
|
-
* @param manifest - its parsed package manifest.
|
|
887
|
-
* @returns the ordered Plus entries, third-party entries, and the exact source base.
|
|
888
|
-
*/
|
|
889
|
-
function readPatchSet(distributionDirectory, manifest) {
|
|
890
|
-
const plus = object(manifest.dshPlus, "dshPlus");
|
|
891
|
-
const sourceBaseRevision = string(object(plus.sourceBase, "dshPlus.sourceBase").revision, "dshPlus.sourceBase.revision");
|
|
892
|
-
const declaration = object(plus.patchSet, "dshPlus.patchSet");
|
|
893
|
-
if (declaration.formatVersion !== 1) throw new Error("dshPlus.patchSet.formatVersion must be 1");
|
|
894
|
-
if (!Array.isArray(declaration.entries) || declaration.entries.length === 0) throw new Error("dshPlus.patchSet.entries must be a non-empty array");
|
|
895
|
-
const entries = declaration.entries.map((value, index) => entry(value, "plus", sourceBaseRevision, distributionDirectory, "dshPlus.patchSet.entries[" + String(index) + "]"));
|
|
896
|
-
const thirdPartyRaw = plus.thirdPartyPatches;
|
|
897
|
-
const thirdParty = thirdPartyRaw === void 0 ? [] : Array.isArray(thirdPartyRaw) ? thirdPartyRaw.map((value, index) => entry(value, "third-party", sourceBaseRevision, distributionDirectory, "dshPlus.thirdPartyPatches[" + String(index) + "]")) : (() => {
|
|
898
|
-
throw new Error("dshPlus.thirdPartyPatches must be an array");
|
|
899
|
-
})();
|
|
900
|
-
const ids = /* @__PURE__ */ new Set();
|
|
901
|
-
for (const item of [...entries, ...thirdParty]) {
|
|
902
|
-
if (ids.has(item.id)) throw new Error("duplicate patch entry id: " + item.id);
|
|
903
|
-
ids.add(item.id);
|
|
904
|
-
}
|
|
905
|
-
return {
|
|
906
|
-
entries,
|
|
907
|
-
thirdPartyPatches: thirdParty,
|
|
908
|
-
sourceBaseRevision
|
|
909
|
-
};
|
|
910
|
-
}
|
|
911
|
-
//#endregion
|
|
912
793
|
//#region lib/types/standalone-profile.js
|
|
913
794
|
/**
|
|
914
795
|
* Runtime paths and profile composition for a standalone Plus installation.
|
|
@@ -977,6 +858,11 @@ function requireStringArray(value, label) {
|
|
|
977
858
|
if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) throw new Error(label + " must be a string array");
|
|
978
859
|
return value;
|
|
979
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
|
+
}
|
|
980
866
|
/** Resolve the DSH home, honouring the environment override the launcher itself reads. */
|
|
981
867
|
function resolveHome(env = process.env) {
|
|
982
868
|
const configured = env.DSH_HOME;
|
|
@@ -1014,11 +900,12 @@ function isWithin(candidate, parent, platform = process.platform) {
|
|
|
1014
900
|
* @returns absolute path to the installed distribution.
|
|
1015
901
|
*/
|
|
1016
902
|
function resolveDistributionDirectory(anchor) {
|
|
903
|
+
const ownDirectory = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
1017
904
|
let resolved;
|
|
1018
905
|
try {
|
|
1019
906
|
resolved = dirname(createRequire(anchor).resolve("@sparkelf/dsh-plus/package.json"));
|
|
1020
907
|
} catch {
|
|
1021
|
-
|
|
908
|
+
return ownDirectory;
|
|
1022
909
|
}
|
|
1023
910
|
let current = resolve(dirname(anchor));
|
|
1024
911
|
for (;;) {
|
|
@@ -1027,20 +914,14 @@ function resolveDistributionDirectory(anchor) {
|
|
|
1027
914
|
if (parent === current) break;
|
|
1028
915
|
current = parent;
|
|
1029
916
|
}
|
|
1030
|
-
|
|
917
|
+
return ownDirectory;
|
|
1031
918
|
}
|
|
1032
|
-
/** The reviewed bundle order and pins the installed distribution declares. */
|
|
1033
919
|
function readDistributionProfile(distributionDirectory) {
|
|
1034
920
|
const manifest = requireRecord(JSON.parse(readFileSync(join(distributionDirectory, "package.json"), "utf8")), "Plus distribution manifest");
|
|
1035
921
|
const plus = requireRecord(manifest.dshPlus, "dshPlus");
|
|
1036
922
|
const profile = requireRecord(plus.profile, "dshPlus.profile");
|
|
1037
|
-
const
|
|
923
|
+
const dependencies = requireDependencyMap(requireRecord(profile.dependencies, "dshPlus.profile.dependencies"), "dshPlus.profile.dependencies");
|
|
1038
924
|
const rawAllowBuilds = requireRecord(profile.allowBuilds, "dshPlus.profile.allowBuilds");
|
|
1039
|
-
const dependencies = {};
|
|
1040
|
-
for (const [name, spec] of Object.entries(rawDependencies)) {
|
|
1041
|
-
if (typeof spec !== "string" || spec === "") throw new Error("dshPlus.profile.dependencies." + name + " must be a non-empty string");
|
|
1042
|
-
dependencies[name] = spec;
|
|
1043
|
-
}
|
|
1044
925
|
const allowBuilds = {};
|
|
1045
926
|
for (const [name, allowed] of Object.entries(rawAllowBuilds)) {
|
|
1046
927
|
if (typeof allowed !== "boolean") throw new Error("dshPlus.profile.allowBuilds." + name + " must be a boolean");
|
|
@@ -1052,6 +933,16 @@ function readDistributionProfile(distributionDirectory) {
|
|
|
1052
933
|
if (typeof spec !== "string" || spec === "") throw new Error("dshPlus.profile.overrides." + name + " must be a non-empty string");
|
|
1053
934
|
overrides[name] = spec;
|
|
1054
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
|
+
}
|
|
1055
946
|
const compatibility = requireRecord(plus.compatibility, "dshPlus.compatibility");
|
|
1056
947
|
return {
|
|
1057
948
|
name: String(manifest.name),
|
|
@@ -1059,10 +950,20 @@ function readDistributionProfile(distributionDirectory) {
|
|
|
1059
950
|
dependencies,
|
|
1060
951
|
allowBuilds,
|
|
1061
952
|
overrides,
|
|
953
|
+
editions,
|
|
1062
954
|
dshRange: String(compatibility.dsh),
|
|
1063
955
|
version: String(manifest.version)
|
|
1064
956
|
};
|
|
1065
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
|
+
}
|
|
1066
967
|
/**
|
|
1067
968
|
* Give the profile its own installed tree, built from the distribution's declarations.
|
|
1068
969
|
*
|
|
@@ -1082,7 +983,11 @@ function readDistributionProfile(distributionDirectory) {
|
|
|
1082
983
|
* @param consumerDirectory - directory whose `node_modules` holds the installation.
|
|
1083
984
|
*/
|
|
1084
985
|
function installProfilePackages(paths, consumerDirectory) {
|
|
1085
|
-
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
|
+
}
|
|
1086
991
|
const profileModules = join(paths.profileDirectory, "node_modules");
|
|
1087
992
|
if (existsSync(profileModules)) {
|
|
1088
993
|
linkNestedBundles(paths, profileModules);
|
|
@@ -1104,6 +1009,7 @@ function installProfilePackages(paths, consumerDirectory) {
|
|
|
1104
1009
|
function installWithRegistryFallback(paths) {
|
|
1105
1010
|
const registries = registryOrder();
|
|
1106
1011
|
for (const [index, registry] of registries.entries()) {
|
|
1012
|
+
if (index > 0) rmSync(join(paths.profileDirectory, "pnpm-lock.yaml"), { force: true });
|
|
1107
1013
|
const result = spawnSync("pnpm", [
|
|
1108
1014
|
"install",
|
|
1109
1015
|
"--no-frozen-lockfile",
|
|
@@ -1112,7 +1018,8 @@ function installWithRegistryFallback(paths) {
|
|
|
1112
1018
|
], {
|
|
1113
1019
|
cwd: paths.profileDirectory,
|
|
1114
1020
|
stdio: "inherit",
|
|
1115
|
-
shell: process.platform === "win32"
|
|
1021
|
+
shell: process.platform === "win32",
|
|
1022
|
+
timeout: 5 * 6e4
|
|
1116
1023
|
});
|
|
1117
1024
|
if (result.error !== void 0) throw result.error;
|
|
1118
1025
|
if (result.status === 0) return;
|
|
@@ -1171,7 +1078,7 @@ const MAINLAND_REGISTRY = "https://registry.npmmirror.com";
|
|
|
1171
1078
|
*/
|
|
1172
1079
|
function registryOrder() {
|
|
1173
1080
|
const configured = process.env.DSH_PLUS_INSTALL_REGISTRY;
|
|
1174
|
-
if (configured !== void 0 && configured !== "") return [configured, MAINLAND_REGISTRY];
|
|
1081
|
+
if (configured !== void 0 && configured !== "") return [configured, configured === MAINLAND_REGISTRY ? OFFICIAL_REGISTRY : MAINLAND_REGISTRY];
|
|
1175
1082
|
const locale = [
|
|
1176
1083
|
process.env.LANG,
|
|
1177
1084
|
process.env.LC_ALL,
|
|
@@ -1272,12 +1179,85 @@ function resolvePaths(anchor, env = process.env) {
|
|
|
1272
1179
|
*
|
|
1273
1180
|
* @param paths - resolved standalone paths.
|
|
1274
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.
|
|
1275
1183
|
* @returns whether this call created the manifest.
|
|
1276
1184
|
*/
|
|
1277
|
-
function ensureProfile(paths, consumerDirectory) {
|
|
1185
|
+
function ensureProfile(paths, consumerDirectory, edition) {
|
|
1278
1186
|
const manifestPath = join(paths.profileDirectory, "package.json");
|
|
1279
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];
|
|
1280
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
|
+
}
|
|
1281
1261
|
writeProfileOverrides(paths.profileDirectory, distribution.overrides, distribution.allowBuilds, paths.omittedPackages);
|
|
1282
1262
|
installProfilePackages(paths, consumerDirectory);
|
|
1283
1263
|
return false;
|
|
@@ -1287,14 +1267,11 @@ function ensureProfile(paths, consumerDirectory) {
|
|
|
1287
1267
|
name: "dsh-profile-plus",
|
|
1288
1268
|
private: true,
|
|
1289
1269
|
type: "module",
|
|
1290
|
-
dependencies:
|
|
1291
|
-
"@sparkelf/dsh-plus": distribution.version,
|
|
1292
|
-
"@deepseek-ai/dsh": distribution.dshRange,
|
|
1293
|
-
...distribution.dependencies
|
|
1294
|
-
},
|
|
1270
|
+
dependencies: compositionPackages,
|
|
1295
1271
|
dsh: { profile: {
|
|
1296
|
-
bundles:
|
|
1297
|
-
patchReload: "live"
|
|
1272
|
+
bundles: [...compositionBundles],
|
|
1273
|
+
patchReload: "live",
|
|
1274
|
+
...edition === void 0 ? {} : { plusEdition: edition }
|
|
1298
1275
|
} }
|
|
1299
1276
|
};
|
|
1300
1277
|
writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
|
|
@@ -1322,7 +1299,7 @@ function writeProfileOverrides(profileDirectory, overrides, allowBuilds, omitted
|
|
|
1322
1299
|
for (const [name, spec] of Object.entries(omittedPackages)) document.setIn(["overrides", name], spec);
|
|
1323
1300
|
for (const [name, allowed] of Object.entries(allowBuilds)) document.setIn(["allowBuilds", name], allowed);
|
|
1324
1301
|
if (document.get("nodeLinker") === void 0) document.set("nodeLinker", "hoisted");
|
|
1325
|
-
if (document.get("autoInstallPeers") === void 0) document.set("autoInstallPeers",
|
|
1302
|
+
if (document.get("autoInstallPeers") === void 0) document.set("autoInstallPeers", true);
|
|
1326
1303
|
writeFileSync(workspacePath, String(document));
|
|
1327
1304
|
}
|
|
1328
1305
|
/** Run git in one directory, returning undefined instead of throwing when asked to. */
|
|
@@ -1378,7 +1355,18 @@ function resolveInstalledPackage(from, packageName) {
|
|
|
1378
1355
|
try {
|
|
1379
1356
|
manifestPath = requireFrom.resolve(packageName + "/package.json");
|
|
1380
1357
|
} catch {
|
|
1381
|
-
|
|
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");
|
|
1382
1370
|
}
|
|
1383
1371
|
const manifest = requireRecord(JSON.parse(readFileSync(manifestPath, "utf8")), packageName + " manifest");
|
|
1384
1372
|
return {
|
|
@@ -1408,6 +1396,7 @@ function parseStartOptions(argv) {
|
|
|
1408
1396
|
let host = "127.0.0.1";
|
|
1409
1397
|
let open = true;
|
|
1410
1398
|
let foreground = false;
|
|
1399
|
+
let edition;
|
|
1411
1400
|
let capabilities;
|
|
1412
1401
|
for (let index = 0; index < argv.length; index += 1) {
|
|
1413
1402
|
const token = argv[index];
|
|
@@ -1433,6 +1422,13 @@ function parseStartOptions(argv) {
|
|
|
1433
1422
|
foreground = true;
|
|
1434
1423
|
continue;
|
|
1435
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
|
+
}
|
|
1436
1432
|
if (token === "--capabilities") {
|
|
1437
1433
|
const value = argv[index + 1];
|
|
1438
1434
|
if (value === void 0) throw new Error("--capabilities requires a comma-separated list, or an empty string for none");
|
|
@@ -1450,6 +1446,7 @@ function parseStartOptions(argv) {
|
|
|
1450
1446
|
host,
|
|
1451
1447
|
open,
|
|
1452
1448
|
foreground,
|
|
1449
|
+
edition,
|
|
1453
1450
|
capabilities
|
|
1454
1451
|
};
|
|
1455
1452
|
}
|
|
@@ -1535,6 +1532,56 @@ function runForeground(entry, profileName, port, host, open) {
|
|
|
1535
1532
|
if (!open) args.push("--no-open");
|
|
1536
1533
|
return spawnSync(process.execPath, args, { stdio: "inherit" }).status ?? 1;
|
|
1537
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
|
+
}
|
|
1538
1585
|
async function start(argv) {
|
|
1539
1586
|
const options = parseStartOptions(argv);
|
|
1540
1587
|
const anchor = installationAnchor();
|
|
@@ -1568,8 +1615,9 @@ async function start(argv) {
|
|
|
1568
1615
|
}
|
|
1569
1616
|
console.log("pnpm installed.");
|
|
1570
1617
|
}
|
|
1571
|
-
const created = ensureProfile(paths, installationRoot());
|
|
1618
|
+
const created = ensureProfile(paths, installationRoot(), options.edition);
|
|
1572
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);
|
|
1573
1621
|
for (const label of applyProfileNpmPatches(paths.distributionDirectory, paths.profileDirectory)) console.log("Applied the reviewed patch " + label);
|
|
1574
1622
|
const answers = created || !existsSync(join(paths.home, "capabilities.json")) ? options.capabilities === void 0 ? await interviewCapabilities(true) : selectCapabilities(options.capabilities) : void 0;
|
|
1575
1623
|
if (answers !== void 0) {
|
|
@@ -1912,6 +1960,23 @@ async function doctor() {
|
|
|
1912
1960
|
const record = readCapabilityRecord(paths.home);
|
|
1913
1961
|
const drifted = record === void 0 ? [] : CAPABILITIES.filter((capability) => record.enabled.includes(capability.id) !== actual.mounted.includes(capability.id));
|
|
1914
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
|
+
}
|
|
1915
1980
|
console.log(failures === 0 ? "No problems found." : String(failures) + " problem(s) found.");
|
|
1916
1981
|
return failures === 0 ? 0 : 1;
|
|
1917
1982
|
}
|
|
@@ -1919,6 +1984,7 @@ const USAGE = [
|
|
|
1919
1984
|
"Usage: dsh-plus <command> [options]",
|
|
1920
1985
|
"",
|
|
1921
1986
|
"Commands:",
|
|
1987
|
+
" install install an edition package manifest into the profile",
|
|
1922
1988
|
" start start the server (first run creates the profile)",
|
|
1923
1989
|
" stop stop the server",
|
|
1924
1990
|
" status report whether the server is running",
|
|
@@ -1931,6 +1997,11 @@ const USAGE = [
|
|
|
1931
1997
|
" --host <h> interface to bind (default 127.0.0.1)",
|
|
1932
1998
|
" --no-open do not open a browser",
|
|
1933
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)",
|
|
1934
2005
|
"",
|
|
1935
2006
|
"capabilities options:",
|
|
1936
2007
|
" --enable <ids> enable the comma-separated capability ids",
|
|
@@ -1953,6 +2024,7 @@ async function runStandaloneCli(argv) {
|
|
|
1953
2024
|
console.log(USAGE);
|
|
1954
2025
|
return 0;
|
|
1955
2026
|
}
|
|
2027
|
+
if (command === "install") return install(rest);
|
|
1956
2028
|
if (command === "start") return await start(rest);
|
|
1957
2029
|
if (command === "stop") return stop();
|
|
1958
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;
|