@sparkelf/dsh-plus 0.2.0-rc.17 → 0.2.0-rc.19
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/cordis.patch.yml +3 -11
- package/lib/bin.js +118 -17
- package/lib/types/standalone-capabilities.js +9 -1
- package/lib/types/standalone-cli.js +78 -15
- package/lib/types/standalone-profile.d.ts +45 -1
- package/lib/types/standalone-profile.js +84 -5
- package/package.json +27 -12
package/cordis.patch.yml
CHANGED
|
@@ -28,17 +28,9 @@
|
|
|
28
28
|
- id: plus-backup
|
|
29
29
|
name: '@sparkelf/dsh-plugin-backup'
|
|
30
30
|
|
|
31
|
-
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
config:
|
|
35
|
-
baseUrl: !!js process.env.DSH_DATAOPS_BASE_URL
|
|
36
|
-
serverName: dataops
|
|
37
|
-
credentialRef: dataops_access_token
|
|
38
|
-
targetCredentialRef: dataops_target_ref
|
|
39
|
-
callbackOrigin: !!js process.env.DSH_DATAOPS_CALLBACK_ORIGIN
|
|
40
|
-
toolCallTimeoutMs: 60000
|
|
41
|
-
failOnStartupError: false
|
|
31
|
+
# DataOps tools belong to the DataOps-managed workspace profile only. A
|
|
32
|
+
# standalone profile must not carry DataOps identity or endpoint config, so
|
|
33
|
+
# this layer mounts no DataOps plugin.
|
|
42
34
|
|
|
43
35
|
# A disabled root node carries the package's Web Settings entry into the
|
|
44
36
|
# client inventory; the startup nodes below exclusively own Host schemas.
|
package/lib/bin.js
CHANGED
|
@@ -210,6 +210,7 @@ function capabilityPatchLayer(answers) {
|
|
|
210
210
|
if (enabled.has("computer-use")) rows.push(" - id: computer-use", " name: '@deepseek-ai/dsh-computer-use'", " - id: computer-use-cua-driver-mcp", " name: '@deepseek-ai/dsh-experimental-computer-use-cua-driver-mcp'");
|
|
211
211
|
const lines = ["# Written by dsh-plus start from the capability interview. Enabling or disabling a capability", "# rewrites this file; edits here are replaced."];
|
|
212
212
|
if (rows.length > 0) lines.push("- insert:", ...rows);
|
|
213
|
+
else lines.push("[]");
|
|
213
214
|
if (enabled.has("exa")) lines.push("", "# Route web_search through Exa rather than the built-in provider.", "- id: web", " config:", " searchProvider: exa");
|
|
214
215
|
return lines.join("\n") + "\n";
|
|
215
216
|
}
|
|
@@ -532,8 +533,55 @@ async function waitForAuthenticatedUrl(logPath, timeoutMilliseconds) {
|
|
|
532
533
|
* the launcher mounts exactly the bundles the profile names and nothing expands a
|
|
533
534
|
* bundle's own list.
|
|
534
535
|
*/
|
|
535
|
-
/** Profile name a standalone installation owns. */
|
|
536
|
+
/** Profile name a standalone installation owns when its package declares none. */
|
|
536
537
|
const STANDALONE_PROFILE = "plus";
|
|
538
|
+
/**
|
|
539
|
+
* Read the deployment facts the installing package declares.
|
|
540
|
+
*
|
|
541
|
+
* A standalone package describes the profile it materializes and the capabilities it
|
|
542
|
+
* omits, so a reduced variant owns a differently named profile and a reduced install
|
|
543
|
+
* without the distribution naming either. The declaration travels with the package
|
|
544
|
+
* because npm resolves the tree long before any command of ours runs.
|
|
545
|
+
*
|
|
546
|
+
* @param anchor - path inside the installing package's tree.
|
|
547
|
+
* @param fallback - profile name to use when the declaration is absent.
|
|
548
|
+
* @returns the declared profile name and omitted capabilities.
|
|
549
|
+
*/
|
|
550
|
+
function readStandaloneDeclaration(anchor, fallback = STANDALONE_PROFILE) {
|
|
551
|
+
let current = resolve(anchor);
|
|
552
|
+
for (;;) {
|
|
553
|
+
const declared = readStandaloneFacts(join(current, "package.json"));
|
|
554
|
+
if (declared !== void 0) return declared;
|
|
555
|
+
const parent = dirname(current);
|
|
556
|
+
if (parent === current) return {
|
|
557
|
+
profileName: fallback,
|
|
558
|
+
omittedPackages: {}
|
|
559
|
+
};
|
|
560
|
+
current = parent;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
/** Read one manifest's standalone declaration, or undefined when it carries none. */
|
|
564
|
+
function readStandaloneFacts(manifestPath) {
|
|
565
|
+
if (!existsSync(manifestPath)) return void 0;
|
|
566
|
+
let standalone;
|
|
567
|
+
try {
|
|
568
|
+
standalone = JSON.parse(readFileSync(manifestPath, "utf8")).dshPlusStandalone;
|
|
569
|
+
} catch {
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
const profile = standalone?.profile;
|
|
573
|
+
if (standalone === void 0 || typeof profile !== "string" || profile === "") return void 0;
|
|
574
|
+
const rawOmitted = standalone.omittedPackages;
|
|
575
|
+
const omittedPackages = {};
|
|
576
|
+
if (rawOmitted !== void 0 && typeof rawOmitted === "object" && !Array.isArray(rawOmitted)) for (const [name, spec] of Object.entries(rawOmitted)) {
|
|
577
|
+
if (typeof spec !== "string" || spec === "") throw new Error("dshPlusStandalone.omittedPackages." + name + " must be a non-empty string");
|
|
578
|
+
omittedPackages[name] = spec;
|
|
579
|
+
}
|
|
580
|
+
return {
|
|
581
|
+
profileName: profile,
|
|
582
|
+
omittedPackages
|
|
583
|
+
};
|
|
584
|
+
}
|
|
537
585
|
function requireRecord(value, label) {
|
|
538
586
|
if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error(label + " must be an object");
|
|
539
587
|
return value;
|
|
@@ -814,9 +862,12 @@ function linkBundle(consumerModules, name, source) {
|
|
|
814
862
|
/** Resolve every path a command needs, without creating anything. */
|
|
815
863
|
function resolvePaths(anchor, env = process.env) {
|
|
816
864
|
const home = resolveHome(env);
|
|
865
|
+
const declaration = readStandaloneDeclaration(anchor);
|
|
817
866
|
return {
|
|
818
867
|
home,
|
|
819
|
-
|
|
868
|
+
profileName: declaration.profileName,
|
|
869
|
+
omittedPackages: declaration.omittedPackages,
|
|
870
|
+
profileDirectory: join(home, "profiles", declaration.profileName),
|
|
820
871
|
distributionDirectory: resolveDistributionDirectory(anchor)
|
|
821
872
|
};
|
|
822
873
|
}
|
|
@@ -840,7 +891,7 @@ function ensureProfile(paths, consumerDirectory) {
|
|
|
840
891
|
const manifestPath = join(paths.profileDirectory, "package.json");
|
|
841
892
|
const distribution = readDistributionProfile(paths.distributionDirectory);
|
|
842
893
|
if (existsSync(manifestPath)) {
|
|
843
|
-
writeProfileOverrides(paths.profileDirectory, distribution.overrides, distribution.allowBuilds);
|
|
894
|
+
writeProfileOverrides(paths.profileDirectory, distribution.overrides, distribution.allowBuilds, paths.omittedPackages);
|
|
844
895
|
installProfilePackages(paths, consumerDirectory);
|
|
845
896
|
return false;
|
|
846
897
|
}
|
|
@@ -860,7 +911,7 @@ function ensureProfile(paths, consumerDirectory) {
|
|
|
860
911
|
} }
|
|
861
912
|
};
|
|
862
913
|
writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
|
|
863
|
-
writeProfileOverrides(paths.profileDirectory, distribution.overrides, distribution.allowBuilds);
|
|
914
|
+
writeProfileOverrides(paths.profileDirectory, distribution.overrides, distribution.allowBuilds, paths.omittedPackages);
|
|
864
915
|
installProfilePackages(paths, consumerDirectory);
|
|
865
916
|
return true;
|
|
866
917
|
}
|
|
@@ -874,13 +925,14 @@ function ensureProfile(paths, consumerDirectory) {
|
|
|
874
925
|
* @param profileDirectory - the standalone profile directory.
|
|
875
926
|
* @param overrides - official package name to published replacement spec.
|
|
876
927
|
*/
|
|
877
|
-
function writeProfileOverrides(profileDirectory, overrides, allowBuilds) {
|
|
928
|
+
function writeProfileOverrides(profileDirectory, overrides, allowBuilds, omittedPackages) {
|
|
878
929
|
const workspacePath = join(profileDirectory, "pnpm-workspace.yaml");
|
|
879
930
|
const document = parseDocument(existsSync(workspacePath) ? readFileSync(workspacePath, "utf8") : "");
|
|
880
931
|
const [documentError] = document.errors;
|
|
881
932
|
if (documentError !== void 0) throw new Error("Plus profile workspace is not valid YAML", { cause: documentError });
|
|
882
933
|
if (document.get("packages") === void 0) document.set("packages", ["."]);
|
|
883
934
|
for (const [name, spec] of Object.entries(overrides)) document.setIn(["overrides", name], spec);
|
|
935
|
+
for (const [name, spec] of Object.entries(omittedPackages)) document.setIn(["overrides", name], spec);
|
|
884
936
|
for (const [name, allowed] of Object.entries(allowBuilds)) document.setIn(["allowBuilds", name], allowed);
|
|
885
937
|
if (document.get("nodeLinker") === void 0) document.set("nodeLinker", "hoisted");
|
|
886
938
|
if (document.get("autoInstallPeers") === void 0) document.set("autoInstallPeers", false);
|
|
@@ -978,6 +1030,7 @@ function parseStartOptions(argv) {
|
|
|
978
1030
|
let host = "127.0.0.1";
|
|
979
1031
|
let open = true;
|
|
980
1032
|
let foreground = false;
|
|
1033
|
+
let capabilities;
|
|
981
1034
|
for (let index = 0; index < argv.length; index += 1) {
|
|
982
1035
|
const token = argv[index];
|
|
983
1036
|
if (token === "--port" || token === "-p") {
|
|
@@ -1002,13 +1055,41 @@ function parseStartOptions(argv) {
|
|
|
1002
1055
|
foreground = true;
|
|
1003
1056
|
continue;
|
|
1004
1057
|
}
|
|
1058
|
+
if (token === "--capabilities") {
|
|
1059
|
+
const value = argv[index + 1];
|
|
1060
|
+
if (value === void 0) throw new Error("--capabilities requires a comma-separated list, or an empty string for none");
|
|
1061
|
+
const stated = value === "" ? [] : value.split(",").map((entry) => entry.trim()).filter((entry) => entry !== "");
|
|
1062
|
+
const offered = new Set(CAPABILITIES.map((capability) => capability.id));
|
|
1063
|
+
for (const id of stated) if (!offered.has(id)) throw new Error("unknown capability \"" + id + "\"; this release offers " + [...offered].join(", "));
|
|
1064
|
+
capabilities = stated;
|
|
1065
|
+
index += 1;
|
|
1066
|
+
continue;
|
|
1067
|
+
}
|
|
1005
1068
|
throw new Error("unknown option: " + String(token));
|
|
1006
1069
|
}
|
|
1007
1070
|
return {
|
|
1008
1071
|
port,
|
|
1009
1072
|
host,
|
|
1010
1073
|
open,
|
|
1011
|
-
foreground
|
|
1074
|
+
foreground,
|
|
1075
|
+
capabilities
|
|
1076
|
+
};
|
|
1077
|
+
}
|
|
1078
|
+
/**
|
|
1079
|
+
* Resolve a stated capability selection.
|
|
1080
|
+
*
|
|
1081
|
+
* An unattended install states what it wants instead of answering the interview, so a
|
|
1082
|
+
* name it does not offer has to fail here rather than silently enable nothing: the
|
|
1083
|
+
* deployment would otherwise start with a capability the caller believes it selected.
|
|
1084
|
+
*
|
|
1085
|
+
* @param ids - capability ids the caller selected.
|
|
1086
|
+
* @returns the answers the interview would have returned.
|
|
1087
|
+
*/
|
|
1088
|
+
function selectCapabilities(ids) {
|
|
1089
|
+
const selected = [...new Set(ids)];
|
|
1090
|
+
return {
|
|
1091
|
+
enabled: selected,
|
|
1092
|
+
...selected.includes("mineru") ? { mineruEndpoint: DEFAULT_MINERU_ENDPOINT } : {}
|
|
1012
1093
|
};
|
|
1013
1094
|
}
|
|
1014
1095
|
/**
|
|
@@ -1039,16 +1120,35 @@ function installationRoot() {
|
|
|
1039
1120
|
function installationAnchor() {
|
|
1040
1121
|
return join(installationRoot(), "package.json");
|
|
1041
1122
|
}
|
|
1123
|
+
/**
|
|
1124
|
+
* Path to the installed command's own file, which is where a declaration lookup starts.
|
|
1125
|
+
*
|
|
1126
|
+
* The declaration belongs to the package the user installed, and that package is a
|
|
1127
|
+
* sibling of this module rather than an ancestor: a variant's forwarder imports this
|
|
1128
|
+
* CLI in-process, so `import.meta.url` names `@sparkelf/dsh-plus` while the installed
|
|
1129
|
+
* command is the variant. `process.argv[1]` is the entry that was actually invoked,
|
|
1130
|
+
* which is the package whose declaration applies.
|
|
1131
|
+
*
|
|
1132
|
+
* Walking out from the installation root cannot reach it either: that root is the
|
|
1133
|
+
* project the user ran the command in, so every variant would fall back to the full
|
|
1134
|
+
* profile and keep the capabilities it excluded.
|
|
1135
|
+
*
|
|
1136
|
+
* @returns absolute path to the invoked command, or this module when argv carries none.
|
|
1137
|
+
*/
|
|
1138
|
+
function declarationAnchor() {
|
|
1139
|
+
const invoked = process.argv[1];
|
|
1140
|
+
return invoked === void 0 || invoked === "" ? fileURLToPath(import.meta.url) : resolve(invoked);
|
|
1141
|
+
}
|
|
1042
1142
|
/** The launcher entry this installation must drive. */
|
|
1043
1143
|
function launcherEntry(anchor) {
|
|
1044
1144
|
return createRequire(anchor).resolve("@deepseek-ai/dsh/lib/bin.js");
|
|
1045
1145
|
}
|
|
1046
1146
|
/** Run the server in this process, inheriting stdio. */
|
|
1047
|
-
function runForeground(entry, port, host, open) {
|
|
1147
|
+
function runForeground(entry, profileName, port, host, open) {
|
|
1048
1148
|
const args = [
|
|
1049
1149
|
entry,
|
|
1050
1150
|
"--profile",
|
|
1051
|
-
|
|
1151
|
+
profileName,
|
|
1052
1152
|
"--port",
|
|
1053
1153
|
String(port),
|
|
1054
1154
|
"--host",
|
|
@@ -1060,7 +1160,7 @@ function runForeground(entry, port, host, open) {
|
|
|
1060
1160
|
async function start(argv) {
|
|
1061
1161
|
const options = parseStartOptions(argv);
|
|
1062
1162
|
const anchor = installationAnchor();
|
|
1063
|
-
const paths = resolvePaths(
|
|
1163
|
+
const paths = resolvePaths(declarationAnchor());
|
|
1064
1164
|
if (!pnpmAvailable()) {
|
|
1065
1165
|
const command = pnpmInstallCommand();
|
|
1066
1166
|
console.log("pnpm is required to install the plus profile, and was not found.");
|
|
@@ -1091,9 +1191,9 @@ async function start(argv) {
|
|
|
1091
1191
|
console.log("pnpm installed.");
|
|
1092
1192
|
}
|
|
1093
1193
|
const created = ensureProfile(paths, installationRoot());
|
|
1094
|
-
console.log(created ? "Created the
|
|
1194
|
+
console.log(created ? "Created the " + paths.profileName + " profile at " + paths.profileDirectory : "Using the existing " + paths.profileName + " profile");
|
|
1095
1195
|
for (const label of applyProfileNpmPatches(paths.distributionDirectory, paths.profileDirectory)) console.log("Applied the reviewed patch " + label);
|
|
1096
|
-
const answers = created || !existsSync(join(paths.home, "capabilities.json")) ? await interviewCapabilities(true) : void 0;
|
|
1196
|
+
const answers = created || !existsSync(join(paths.home, "capabilities.json")) ? options.capabilities === void 0 ? await interviewCapabilities(true) : selectCapabilities(options.capabilities) : void 0;
|
|
1097
1197
|
if (answers !== void 0) {
|
|
1098
1198
|
const ready = await installCapabilityServices(answers, paths.home);
|
|
1099
1199
|
writeCapabilityPatch(paths.profileDirectory, answers);
|
|
@@ -1103,16 +1203,17 @@ async function start(argv) {
|
|
|
1103
1203
|
if (answers.enabled.includes("exa") && answers.exaApiKey === void 0) console.log(" Exa: add EXA_API_KEY to " + join(paths.home, CAPABILITY_ENV_FILE) + " when you have a key.");
|
|
1104
1204
|
}
|
|
1105
1205
|
const entry = launcherEntry(anchor);
|
|
1106
|
-
if (options.foreground) return runForeground(entry, options.port, options.host, options.open);
|
|
1206
|
+
if (options.foreground) return runForeground(entry, paths.profileName, options.port, options.host, options.open);
|
|
1107
1207
|
const existing = readState(paths.home);
|
|
1108
1208
|
if (existing !== void 0) {
|
|
1109
1209
|
console.log("Plus is already running at " + existing.url);
|
|
1110
1210
|
console.log("Stop it with: dsh-plus stop");
|
|
1111
1211
|
return 0;
|
|
1112
1212
|
}
|
|
1113
|
-
return startDetached(paths
|
|
1213
|
+
return startDetached(paths, entry, options);
|
|
1114
1214
|
}
|
|
1115
|
-
async function startDetached(
|
|
1215
|
+
async function startDetached(paths, entry, options) {
|
|
1216
|
+
const home = paths.home;
|
|
1116
1217
|
const port = await choosePort(options.port, options.host);
|
|
1117
1218
|
if (port === void 0) {
|
|
1118
1219
|
console.error("No free port in the range " + String(options.port) + "-" + String(options.port + 9) + ".");
|
|
@@ -1120,15 +1221,15 @@ async function startDetached(home, entry, options) {
|
|
|
1120
1221
|
return 1;
|
|
1121
1222
|
}
|
|
1122
1223
|
if (port !== options.port) console.log("Port " + String(options.port) + " is in use; using " + String(port) + ".");
|
|
1123
|
-
const logPath = join(stateDirectory(home), "server.log");
|
|
1224
|
+
const logPath = join(stateDirectory(paths.home), "server.log");
|
|
1124
1225
|
const env = {
|
|
1125
1226
|
...process.env,
|
|
1126
|
-
DSH_HOME: home
|
|
1227
|
+
DSH_HOME: paths.home
|
|
1127
1228
|
};
|
|
1128
1229
|
const args = [
|
|
1129
1230
|
entry,
|
|
1130
1231
|
"--profile",
|
|
1131
|
-
|
|
1232
|
+
paths.profileName,
|
|
1132
1233
|
"--port",
|
|
1133
1234
|
String(port),
|
|
1134
1235
|
"--host",
|
|
@@ -159,8 +159,16 @@ export function capabilityPatchLayer(answers) {
|
|
|
159
159
|
'# ' + CAPABILITY_MARKER + ' Enabling or disabling a capability',
|
|
160
160
|
'# rewrites this file; edits here are replaced.',
|
|
161
161
|
];
|
|
162
|
-
|
|
162
|
+
// The loader requires a top-level YAML array, so a selection that mounts nothing
|
|
163
|
+
// still has to produce one. Comments alone parse as `null`, and the profile then
|
|
164
|
+
// refuses to boot with "must be a top-level YAML array of loader patch entries" —
|
|
165
|
+
// which is the whole deployment, not just the missing capability.
|
|
166
|
+
if (rows.length > 0) {
|
|
163
167
|
lines.push('- insert:', ...rows);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
lines.push('[]');
|
|
171
|
+
}
|
|
164
172
|
if (enabled.has('exa')) {
|
|
165
173
|
lines.push('', '# Route web_search through Exa rather than the built-in provider.', '- id: web', ' config:', ' searchProvider: exa');
|
|
166
174
|
}
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
import { spawnSync } from 'node:child_process';
|
|
11
11
|
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
12
12
|
import { createRequire } from 'node:module';
|
|
13
|
-
import { dirname, join } from 'node:path';
|
|
13
|
+
import { dirname, join, resolve } from 'node:path';
|
|
14
14
|
import { fileURLToPath } from 'node:url';
|
|
15
15
|
import { newerVersion } from "./registry-versions.js";
|
|
16
|
-
import { CAPABILITY_ENV_FILE, CAPABILITY_MARKER, CAPABILITY_RECORD, capabilityEnvironment, capabilityPatchLayer, installCapabilityServices, interviewCapabilities, } from "./standalone-capabilities.js";
|
|
16
|
+
import { CAPABILITIES, CAPABILITY_ENV_FILE, CAPABILITY_MARKER, CAPABILITY_RECORD, DEFAULT_MINERU_ENDPOINT, capabilityEnvironment, capabilityPatchLayer, installCapabilityServices, interviewCapabilities, } from "./standalone-capabilities.js";
|
|
17
17
|
import { DEFAULT_PORT, STOP_GRACE_MILLISECONDS, choosePort, clearState, isRunning, portAvailable, readState, spawnServer, stateDirectory, waitForAuthenticatedUrl, waitForServer, writeState, } from "./standalone-server.js";
|
|
18
18
|
import { STANDALONE_PROFILE, applyProfileNpmPatches, ensureProfile, pnpmAvailable, pnpmInstallCommand, pnpmInstallCommands, registryOrder, readDistributionProfile, resolvePaths, } from "./standalone-profile.js";
|
|
19
19
|
/** Milliseconds a start waits for the server to answer before reporting failure. */
|
|
@@ -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 capabilities;
|
|
28
29
|
for (let index = 0; index < argv.length; index += 1) {
|
|
29
30
|
const token = argv[index];
|
|
30
31
|
if (token === '--port' || token === '-p') {
|
|
@@ -51,9 +52,47 @@ function parseStartOptions(argv) {
|
|
|
51
52
|
foreground = true;
|
|
52
53
|
continue;
|
|
53
54
|
}
|
|
55
|
+
if (token === '--capabilities') {
|
|
56
|
+
const value = argv[index + 1];
|
|
57
|
+
if (value === undefined)
|
|
58
|
+
throw new Error('--capabilities requires a comma-separated list, or an empty string for none');
|
|
59
|
+
const stated = value === '' ? [] : value.split(',').map(entry => entry.trim()).filter(entry => entry !== '');
|
|
60
|
+
// A stated selection is the only way an unattended install chooses capabilities, so
|
|
61
|
+
// a name this release does not offer fails here: the deployment would otherwise
|
|
62
|
+
// start without a capability its caller believes it selected. Validating at parse
|
|
63
|
+
// time also makes the failure independent of what is installed.
|
|
64
|
+
const offered = new Set(CAPABILITIES.map(capability => capability.id));
|
|
65
|
+
for (const id of stated) {
|
|
66
|
+
if (!offered.has(id)) {
|
|
67
|
+
throw new Error('unknown capability "' + id + '"; this release offers ' + [...offered].join(', '));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
capabilities = stated;
|
|
71
|
+
index += 1;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
54
74
|
throw new Error('unknown option: ' + String(token));
|
|
55
75
|
}
|
|
56
|
-
return { port, host, open, foreground };
|
|
76
|
+
return { port, host, open, foreground, capabilities };
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Resolve a stated capability selection.
|
|
80
|
+
*
|
|
81
|
+
* An unattended install states what it wants instead of answering the interview, so a
|
|
82
|
+
* name it does not offer has to fail here rather than silently enable nothing: the
|
|
83
|
+
* deployment would otherwise start with a capability the caller believes it selected.
|
|
84
|
+
*
|
|
85
|
+
* @param ids - capability ids the caller selected.
|
|
86
|
+
* @returns the answers the interview would have returned.
|
|
87
|
+
*/
|
|
88
|
+
function selectCapabilities(ids) {
|
|
89
|
+
const selected = [...new Set(ids)];
|
|
90
|
+
// MinerU is started from an endpoint the interview collects; an unattended install
|
|
91
|
+
// gets the documented default rather than an unset one.
|
|
92
|
+
return {
|
|
93
|
+
enabled: selected,
|
|
94
|
+
...selected.includes('mineru') ? { mineruEndpoint: DEFAULT_MINERU_ENDPOINT } : {},
|
|
95
|
+
};
|
|
57
96
|
}
|
|
58
97
|
/**
|
|
59
98
|
* Where the installation that owns this command keeps its packages.
|
|
@@ -87,13 +126,32 @@ function installationRoot() {
|
|
|
87
126
|
function installationAnchor() {
|
|
88
127
|
return join(installationRoot(), 'package.json');
|
|
89
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Path to the installed command's own file, which is where a declaration lookup starts.
|
|
131
|
+
*
|
|
132
|
+
* The declaration belongs to the package the user installed, and that package is a
|
|
133
|
+
* sibling of this module rather than an ancestor: a variant's forwarder imports this
|
|
134
|
+
* CLI in-process, so `import.meta.url` names `@sparkelf/dsh-plus` while the installed
|
|
135
|
+
* command is the variant. `process.argv[1]` is the entry that was actually invoked,
|
|
136
|
+
* which is the package whose declaration applies.
|
|
137
|
+
*
|
|
138
|
+
* Walking out from the installation root cannot reach it either: that root is the
|
|
139
|
+
* project the user ran the command in, so every variant would fall back to the full
|
|
140
|
+
* profile and keep the capabilities it excluded.
|
|
141
|
+
*
|
|
142
|
+
* @returns absolute path to the invoked command, or this module when argv carries none.
|
|
143
|
+
*/
|
|
144
|
+
function declarationAnchor() {
|
|
145
|
+
const invoked = process.argv[1];
|
|
146
|
+
return invoked === undefined || invoked === '' ? fileURLToPath(import.meta.url) : resolve(invoked);
|
|
147
|
+
}
|
|
90
148
|
/** The launcher entry this installation must drive. */
|
|
91
149
|
function launcherEntry(anchor) {
|
|
92
150
|
return createRequire(anchor).resolve('@deepseek-ai/dsh/lib/bin.js');
|
|
93
151
|
}
|
|
94
152
|
/** Run the server in this process, inheriting stdio. */
|
|
95
|
-
function runForeground(entry, port, host, open) {
|
|
96
|
-
const args = [entry, '--profile',
|
|
153
|
+
function runForeground(entry, profileName, port, host, open) {
|
|
154
|
+
const args = [entry, '--profile', profileName, '--port', String(port), '--host', host];
|
|
97
155
|
if (!open)
|
|
98
156
|
args.push('--no-open');
|
|
99
157
|
const result = spawnSync(process.execPath, args, { stdio: 'inherit' });
|
|
@@ -102,7 +160,9 @@ function runForeground(entry, port, host, open) {
|
|
|
102
160
|
async function start(argv) {
|
|
103
161
|
const options = parseStartOptions(argv);
|
|
104
162
|
const anchor = installationAnchor();
|
|
105
|
-
|
|
163
|
+
// The profile's own name and omissions come from the package that installed this
|
|
164
|
+
// command, which is a different tree position than the dependencies it resolves.
|
|
165
|
+
const paths = resolvePaths(declarationAnchor());
|
|
106
166
|
// The profile installs its own dependency tree, which needs pnpm. Asking here rather
|
|
107
167
|
// than failing inside the install turns a missing prerequisite into a decision the
|
|
108
168
|
// consumer makes, and the install it can run is the one command that provides it.
|
|
@@ -144,8 +204,8 @@ async function start(argv) {
|
|
|
144
204
|
}
|
|
145
205
|
const created = ensureProfile(paths, installationRoot());
|
|
146
206
|
console.log(created
|
|
147
|
-
? 'Created the ' +
|
|
148
|
-
: 'Using the existing ' +
|
|
207
|
+
? 'Created the ' + paths.profileName + ' profile at ' + paths.profileDirectory
|
|
208
|
+
: 'Using the existing ' + paths.profileName + ' profile');
|
|
149
209
|
// The profile symlinks the consumer's packages, so a patch lands on the installed
|
|
150
210
|
// copy the launcher loads. A reinstall restores the published bytes, which is why
|
|
151
211
|
// this runs on every start rather than only when the profile was created.
|
|
@@ -157,7 +217,9 @@ async function start(argv) {
|
|
|
157
217
|
// on every start would make a restart look like a first install.
|
|
158
218
|
const needsInterview = created || !existsSync(join(paths.home, CAPABILITY_RECORD));
|
|
159
219
|
const answers = needsInterview
|
|
160
|
-
?
|
|
220
|
+
? options.capabilities === undefined
|
|
221
|
+
? await interviewCapabilities(true)
|
|
222
|
+
: selectCapabilities(options.capabilities)
|
|
161
223
|
: undefined;
|
|
162
224
|
if (answers !== undefined) {
|
|
163
225
|
const ready = await installCapabilityServices(answers, paths.home);
|
|
@@ -172,16 +234,17 @@ async function start(argv) {
|
|
|
172
234
|
}
|
|
173
235
|
const entry = launcherEntry(anchor);
|
|
174
236
|
if (options.foreground)
|
|
175
|
-
return runForeground(entry, options.port, options.host, options.open);
|
|
237
|
+
return runForeground(entry, paths.profileName, options.port, options.host, options.open);
|
|
176
238
|
const existing = readState(paths.home);
|
|
177
239
|
if (existing !== undefined) {
|
|
178
240
|
console.log('Plus is already running at ' + existing.url);
|
|
179
241
|
console.log('Stop it with: dsh-plus stop');
|
|
180
242
|
return 0;
|
|
181
243
|
}
|
|
182
|
-
return startDetached(paths
|
|
244
|
+
return startDetached(paths, entry, options);
|
|
183
245
|
}
|
|
184
|
-
async function startDetached(
|
|
246
|
+
async function startDetached(paths, entry, options) {
|
|
247
|
+
const home = paths.home;
|
|
185
248
|
const port = await choosePort(options.port, options.host);
|
|
186
249
|
if (port === undefined) {
|
|
187
250
|
console.error('No free port in the range ' + String(options.port) + '-' + String(options.port + 9) + '.');
|
|
@@ -190,9 +253,9 @@ async function startDetached(home, entry, options) {
|
|
|
190
253
|
}
|
|
191
254
|
if (port !== options.port)
|
|
192
255
|
console.log('Port ' + String(options.port) + ' is in use; using ' + String(port) + '.');
|
|
193
|
-
const logPath = join(stateDirectory(home), 'server.log');
|
|
194
|
-
const env = { ...process.env, DSH_HOME: home };
|
|
195
|
-
const args = [entry, '--profile',
|
|
256
|
+
const logPath = join(stateDirectory(paths.home), 'server.log');
|
|
257
|
+
const env = { ...process.env, DSH_HOME: paths.home };
|
|
258
|
+
const args = [entry, '--profile', paths.profileName, '--port', String(port), '--host', options.host, '--no-open'];
|
|
196
259
|
const pid = spawnServer({ command: process.execPath, args, env, logPath });
|
|
197
260
|
const url = 'http://' + options.host + ':' + String(port) + '/';
|
|
198
261
|
const ready = await waitForServer(url, READY_TIMEOUT_MILLISECONDS);
|
|
@@ -8,12 +8,56 @@
|
|
|
8
8
|
* the launcher mounts exactly the bundles the profile names and nothing expands a
|
|
9
9
|
* bundle's own list.
|
|
10
10
|
*/
|
|
11
|
-
/** Profile name a standalone installation owns. */
|
|
11
|
+
/** Profile name a standalone installation owns when its package declares none. */
|
|
12
12
|
export declare const STANDALONE_PROFILE = "plus";
|
|
13
|
+
/**
|
|
14
|
+
* Read the profile name the installing package declares.
|
|
15
|
+
*
|
|
16
|
+
* A standalone package describes the profile it materializes, so a reduced variant can
|
|
17
|
+
* own a differently named profile beside the full one instead of overwriting it. The
|
|
18
|
+
* declaration travels with the package because npm resolves the tree long before any
|
|
19
|
+
* command of ours runs, and the distribution cannot name a profile for a package it
|
|
20
|
+
* does not own.
|
|
21
|
+
*
|
|
22
|
+
* @param anchor - path inside the installing package's tree.
|
|
23
|
+
* @param fallback - profile name to use when the declaration is absent.
|
|
24
|
+
* @returns the declared profile name, or the fallback.
|
|
25
|
+
*/
|
|
26
|
+
export declare function resolveStandaloneProfile(anchor: string, fallback?: string): string;
|
|
27
|
+
/** What the installing package declares about the deployment it owns. */
|
|
28
|
+
export interface StandaloneDeclaration {
|
|
29
|
+
/** Profile name the launcher materializes. */
|
|
30
|
+
readonly profileName: string;
|
|
31
|
+
/**
|
|
32
|
+
* Capabilities the deployment must not install, as package name to override spec.
|
|
33
|
+
*
|
|
34
|
+
* npm substitutes rather than deletes, so each entry names the placeholder the
|
|
35
|
+
* capability is replaced with. The profile workspace applies these as overrides,
|
|
36
|
+
* which is where pnpm reads them.
|
|
37
|
+
*/
|
|
38
|
+
readonly omittedPackages: Readonly<Record<string, string>>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Read the deployment facts the installing package declares.
|
|
42
|
+
*
|
|
43
|
+
* A standalone package describes the profile it materializes and the capabilities it
|
|
44
|
+
* omits, so a reduced variant owns a differently named profile and a reduced install
|
|
45
|
+
* without the distribution naming either. The declaration travels with the package
|
|
46
|
+
* because npm resolves the tree long before any command of ours runs.
|
|
47
|
+
*
|
|
48
|
+
* @param anchor - path inside the installing package's tree.
|
|
49
|
+
* @param fallback - profile name to use when the declaration is absent.
|
|
50
|
+
* @returns the declared profile name and omitted capabilities.
|
|
51
|
+
*/
|
|
52
|
+
export declare function readStandaloneDeclaration(anchor: string, fallback?: string): StandaloneDeclaration;
|
|
13
53
|
/** Resolved locations for one standalone installation. */
|
|
14
54
|
export interface StandalonePaths {
|
|
15
55
|
/** DSH home holding profiles, credentials, and session data. */
|
|
16
56
|
readonly home: string;
|
|
57
|
+
/** Profile name the launcher boots, as the installing package declares it. */
|
|
58
|
+
readonly profileName: string;
|
|
59
|
+
/** Capabilities the deployment omits, as package name to override spec. */
|
|
60
|
+
readonly omittedPackages: Readonly<Record<string, string>>;
|
|
17
61
|
/** Profile directory the launcher boots. */
|
|
18
62
|
readonly profileDirectory: string;
|
|
19
63
|
/** Installed Plus distribution directory. */
|
|
@@ -14,8 +14,79 @@ import { createRequire } from 'node:module';
|
|
|
14
14
|
import { homedir } from 'node:os';
|
|
15
15
|
import { dirname, join, posix, resolve, win32 } from 'node:path';
|
|
16
16
|
import { parseDocument } from 'yaml';
|
|
17
|
-
/** Profile name a standalone installation owns. */
|
|
17
|
+
/** Profile name a standalone installation owns when its package declares none. */
|
|
18
18
|
export const STANDALONE_PROFILE = 'plus';
|
|
19
|
+
/**
|
|
20
|
+
* Read the profile name the installing package declares.
|
|
21
|
+
*
|
|
22
|
+
* A standalone package describes the profile it materializes, so a reduced variant can
|
|
23
|
+
* own a differently named profile beside the full one instead of overwriting it. The
|
|
24
|
+
* declaration travels with the package because npm resolves the tree long before any
|
|
25
|
+
* command of ours runs, and the distribution cannot name a profile for a package it
|
|
26
|
+
* does not own.
|
|
27
|
+
*
|
|
28
|
+
* @param anchor - path inside the installing package's tree.
|
|
29
|
+
* @param fallback - profile name to use when the declaration is absent.
|
|
30
|
+
* @returns the declared profile name, or the fallback.
|
|
31
|
+
*/
|
|
32
|
+
export function resolveStandaloneProfile(anchor, fallback = STANDALONE_PROFILE) {
|
|
33
|
+
return readStandaloneDeclaration(anchor, fallback).profileName;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Read the deployment facts the installing package declares.
|
|
37
|
+
*
|
|
38
|
+
* A standalone package describes the profile it materializes and the capabilities it
|
|
39
|
+
* omits, so a reduced variant owns a differently named profile and a reduced install
|
|
40
|
+
* without the distribution naming either. The declaration travels with the package
|
|
41
|
+
* because npm resolves the tree long before any command of ours runs.
|
|
42
|
+
*
|
|
43
|
+
* @param anchor - path inside the installing package's tree.
|
|
44
|
+
* @param fallback - profile name to use when the declaration is absent.
|
|
45
|
+
* @returns the declared profile name and omitted capabilities.
|
|
46
|
+
*/
|
|
47
|
+
export function readStandaloneDeclaration(anchor, fallback = STANDALONE_PROFILE) {
|
|
48
|
+
// The anchor is the CLI file; walk out to the package that declares the forwarder.
|
|
49
|
+
let current = resolve(anchor);
|
|
50
|
+
for (;;) {
|
|
51
|
+
const manifestPath = join(current, 'package.json');
|
|
52
|
+
const declared = readStandaloneFacts(manifestPath);
|
|
53
|
+
if (declared !== undefined)
|
|
54
|
+
return declared;
|
|
55
|
+
const parent = dirname(current);
|
|
56
|
+
if (parent === current)
|
|
57
|
+
return { profileName: fallback, omittedPackages: {} };
|
|
58
|
+
current = parent;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/** Read one manifest's standalone declaration, or undefined when it carries none. */
|
|
62
|
+
function readStandaloneFacts(manifestPath) {
|
|
63
|
+
if (!existsSync(manifestPath))
|
|
64
|
+
return undefined;
|
|
65
|
+
let standalone;
|
|
66
|
+
try {
|
|
67
|
+
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
68
|
+
standalone = manifest.dshPlusStandalone;
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// A package whose manifest cannot be read declares nothing; the caller keeps walking
|
|
72
|
+
// because the declaring package may sit above it.
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
const profile = standalone?.profile;
|
|
76
|
+
if (standalone === undefined || typeof profile !== 'string' || profile === '')
|
|
77
|
+
return undefined;
|
|
78
|
+
const rawOmitted = standalone.omittedPackages;
|
|
79
|
+
const omittedPackages = {};
|
|
80
|
+
if (rawOmitted !== undefined && typeof rawOmitted === 'object' && !Array.isArray(rawOmitted)) {
|
|
81
|
+
for (const [name, spec] of Object.entries(rawOmitted)) {
|
|
82
|
+
if (typeof spec !== 'string' || spec === '') {
|
|
83
|
+
throw new Error('dshPlusStandalone.omittedPackages.' + name + ' must be a non-empty string');
|
|
84
|
+
}
|
|
85
|
+
omittedPackages[name] = spec;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return { profileName: profile, omittedPackages };
|
|
89
|
+
}
|
|
19
90
|
function requireRecord(value, label) {
|
|
20
91
|
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
21
92
|
throw new Error(label + ' must be an object');
|
|
@@ -336,9 +407,12 @@ function linkBundle(consumerModules, name, source) {
|
|
|
336
407
|
/** Resolve every path a command needs, without creating anything. */
|
|
337
408
|
export function resolvePaths(anchor, env = process.env) {
|
|
338
409
|
const home = resolveHome(env);
|
|
410
|
+
const declaration = readStandaloneDeclaration(anchor);
|
|
339
411
|
return {
|
|
340
412
|
home,
|
|
341
|
-
|
|
413
|
+
profileName: declaration.profileName,
|
|
414
|
+
omittedPackages: declaration.omittedPackages,
|
|
415
|
+
profileDirectory: join(home, 'profiles', declaration.profileName),
|
|
342
416
|
distributionDirectory: resolveDistributionDirectory(anchor),
|
|
343
417
|
};
|
|
344
418
|
}
|
|
@@ -366,7 +440,7 @@ export function ensureProfile(paths, consumerDirectory) {
|
|
|
366
440
|
// script allowlist — and a distribution release changes them. Rewriting on every
|
|
367
441
|
// start is what lets an upgraded installation receive the new values; a profile
|
|
368
442
|
// written once keeps whatever its own release decided and can never be corrected.
|
|
369
|
-
writeProfileOverrides(paths.profileDirectory, distribution.overrides, distribution.allowBuilds);
|
|
443
|
+
writeProfileOverrides(paths.profileDirectory, distribution.overrides, distribution.allowBuilds, paths.omittedPackages);
|
|
370
444
|
installProfilePackages(paths, consumerDirectory);
|
|
371
445
|
return false;
|
|
372
446
|
}
|
|
@@ -392,7 +466,7 @@ export function ensureProfile(paths, consumerDirectory) {
|
|
|
392
466
|
};
|
|
393
467
|
writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + '\n');
|
|
394
468
|
// The overrides must reach the workspace before the install that reads them.
|
|
395
|
-
writeProfileOverrides(paths.profileDirectory, distribution.overrides, distribution.allowBuilds);
|
|
469
|
+
writeProfileOverrides(paths.profileDirectory, distribution.overrides, distribution.allowBuilds, paths.omittedPackages);
|
|
396
470
|
installProfilePackages(paths, consumerDirectory);
|
|
397
471
|
return true;
|
|
398
472
|
}
|
|
@@ -406,7 +480,7 @@ export function ensureProfile(paths, consumerDirectory) {
|
|
|
406
480
|
* @param profileDirectory - the standalone profile directory.
|
|
407
481
|
* @param overrides - official package name to published replacement spec.
|
|
408
482
|
*/
|
|
409
|
-
function writeProfileOverrides(profileDirectory, overrides, allowBuilds) {
|
|
483
|
+
function writeProfileOverrides(profileDirectory, overrides, allowBuilds, omittedPackages) {
|
|
410
484
|
const workspacePath = join(profileDirectory, 'pnpm-workspace.yaml');
|
|
411
485
|
const document = parseDocument(existsSync(workspacePath) ? readFileSync(workspacePath, 'utf8') : '');
|
|
412
486
|
const [documentError] = document.errors;
|
|
@@ -416,6 +490,11 @@ function writeProfileOverrides(profileDirectory, overrides, allowBuilds) {
|
|
|
416
490
|
document.set('packages', ['.']);
|
|
417
491
|
for (const [name, spec] of Object.entries(overrides))
|
|
418
492
|
document.setIn(['overrides', name], spec);
|
|
493
|
+
// A capability the deployment omits is substituted rather than deleted, because npm's
|
|
494
|
+
// override has no removal form. Writing it here keeps the omission in the one place
|
|
495
|
+
// pnpm reads, so an install never receives the capability the variant excluded.
|
|
496
|
+
for (const [name, spec] of Object.entries(omittedPackages))
|
|
497
|
+
document.setIn(['overrides', name], spec);
|
|
419
498
|
// pnpm refuses an install whose packages want to run build scripts until each is
|
|
420
499
|
// decided, so the distribution's reviewed decisions travel with the install rather
|
|
421
500
|
// than waiting for an interactive approval no start can offer.
|
package/package.json
CHANGED
|
@@ -3,12 +3,8 @@
|
|
|
3
3
|
"dsh-plus": "lib/bin.js"
|
|
4
4
|
},
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@deepseek-ai/dsh-computer-use": ">=0.1.6-alpha.1",
|
|
7
|
-
"@deepseek-ai/dsh-experimental-computer-use-cua-driver-mcp": ">=0.1.6-alpha.1",
|
|
8
6
|
"@deepseek-ai/dsh-tool-session-query": ">=0.1.6-alpha.1",
|
|
9
|
-
"@deepseek-ai/dsh-web-search-exa": ">=0.1.6-alpha.1",
|
|
10
7
|
"@sparkelf/dsh-client-ui-skill-center": ">=0.2.0-rc.17",
|
|
11
|
-
"@sparkelf/dsh-mobile-bridge": ">=0.2.11",
|
|
12
8
|
"@sparkelf/dsh-patch-better-sidebar-browser-url-seed": ">=0.2.0-rc.17",
|
|
13
9
|
"@sparkelf/dsh-patch-better-sidebar-html-preview-path": ">=0.2.0-rc.17",
|
|
14
10
|
"@sparkelf/dsh-patch-better-sidebar-main-view-session": ">=0.2.0-rc.17",
|
|
@@ -29,7 +25,6 @@
|
|
|
29
25
|
"@sparkelf/dsh-patch-workspace-storage-restore": ">=0.2.0-rc.17",
|
|
30
26
|
"@sparkelf/dsh-patch-wsl-native-open": ">=0.2.0-rc.17",
|
|
31
27
|
"@sparkelf/dsh-plugin-backup": ">=0.2.0-rc.17",
|
|
32
|
-
"@sparkelf/dsh-plugin-dataops": ">=0.2.0-rc.17",
|
|
33
28
|
"@sparkelf/dsh-plugin-mcp-credentials": ">=0.2.0-rc.17",
|
|
34
29
|
"@sparkelf/dsh-plugin-subagent-settings": ">=0.2.0-rc.17",
|
|
35
30
|
"dshmarket": ">=1.45.1",
|
|
@@ -67,11 +62,11 @@
|
|
|
67
62
|
"@sparkelf/dsh-patch-ptc-mcp-schema-types",
|
|
68
63
|
"@sparkelf/dsh-patch-web-base-path",
|
|
69
64
|
"@sparkelf/dsh-patch-composer-popover-boundaries",
|
|
70
|
-
"@sparkelf/dsh-patch-mobile-journal-generation",
|
|
71
65
|
"@sparkelf/dsh-patch-session-format-legacy-restart",
|
|
72
66
|
"@sparkelf/dsh-patch-wsl-native-open",
|
|
73
67
|
"@sparkelf/dsh-patch-better-sidebar-html-preview-path",
|
|
74
|
-
"@sparkelf/dsh-patch-session-query-unindexable-session"
|
|
68
|
+
"@sparkelf/dsh-patch-session-query-unindexable-session",
|
|
69
|
+
"@sparkelf/dsh-patch-mobile-journal-generation"
|
|
75
70
|
],
|
|
76
71
|
"profile": {
|
|
77
72
|
"allowBuilds": {
|
|
@@ -92,7 +87,6 @@
|
|
|
92
87
|
"@deepseek-ai/dsh-experimental-agent-team-web-profile",
|
|
93
88
|
"@sparkelf/dsh-mineru",
|
|
94
89
|
"@sparkelf/dsh-officecli",
|
|
95
|
-
"@sparkelf/dsh-mobile-bridge",
|
|
96
90
|
"dshmarket",
|
|
97
91
|
"@huanlin/dsh-plugin-better-locale",
|
|
98
92
|
"dsh-better-sidebar",
|
|
@@ -104,7 +98,8 @@
|
|
|
104
98
|
"@sparkelf/dsh-plus",
|
|
105
99
|
"dsh-sql-workbench",
|
|
106
100
|
"@sparkelf/dsh-ssh-manager",
|
|
107
|
-
"@sparkelf/dsh-api-client"
|
|
101
|
+
"@sparkelf/dsh-api-client",
|
|
102
|
+
"dsh-right-bg-anim"
|
|
108
103
|
],
|
|
109
104
|
"dependencies": {
|
|
110
105
|
"@changfenhuang/dsh-genui": "0.11.0",
|
|
@@ -120,13 +115,15 @@
|
|
|
120
115
|
"@sparkelf/dsh-ssh-manager": "0.7.2",
|
|
121
116
|
"@sparkelf/dsh-workbench-vault": "0.1.2",
|
|
122
117
|
"dsh-better-sidebar": "0.19.1",
|
|
118
|
+
"dsh-right-bg-anim": "1.1.0",
|
|
123
119
|
"dsh-sql-workbench": "0.5.1",
|
|
124
120
|
"dsh-video-preview": "0.1.4"
|
|
125
121
|
},
|
|
126
122
|
"overrides": {
|
|
127
|
-
"@deepseek-ai/dsh-agent-presets": "npm:@sparkelf/dsh-agent-presets@0.1.6-alpha.
|
|
123
|
+
"@deepseek-ai/dsh-agent-presets": "npm:@sparkelf/dsh-agent-presets@0.1.6-alpha.3",
|
|
128
124
|
"@deepseek-ai/dsh-api-gateway": "npm:@sparkelf/dsh-api-gateway@0.1.6-alpha.2",
|
|
129
|
-
"@deepseek-ai/dsh-api-session-controller": "npm:@sparkelf/dsh-api-session-controller@0.1.6-alpha.
|
|
125
|
+
"@deepseek-ai/dsh-api-session-controller": "npm:@sparkelf/dsh-api-session-controller@0.1.6-alpha.3",
|
|
126
|
+
"@deepseek-ai/dsh-api-terminal-controller": "npm:@sparkelf/dsh-api-terminal-controller@0.1.6-alpha.3",
|
|
130
127
|
"@deepseek-ai/dsh-client-connection": "npm:@sparkelf/dsh-client-connection@0.1.6-alpha.2",
|
|
131
128
|
"@deepseek-ai/dsh-client-ui-agent-preset": "npm:@sparkelf/dsh-client-ui-agent-preset@0.1.6-alpha.2",
|
|
132
129
|
"@deepseek-ai/dsh-client-ui-deliverables": "npm:@sparkelf/dsh-client-ui-deliverables@0.1.6-alpha.2",
|
|
@@ -143,10 +140,23 @@
|
|
|
143
140
|
"@deepseek-ai/dsh-native-command": "npm:@sparkelf/dsh-native-command@0.1.6-alpha.2",
|
|
144
141
|
"@deepseek-ai/dsh-session-format-v0-to-v1": "npm:@sparkelf/dsh-session-format-v0-to-v1@0.1.6-alpha.2",
|
|
145
142
|
"@deepseek-ai/dsh-session-log-export": "npm:@sparkelf/dsh-session-log-export@0.1.6-alpha.2",
|
|
143
|
+
"@deepseek-ai/dsh-session-query-sqlite": "npm:@sparkelf/dsh-session-query-sqlite@0.1.6-alpha.2",
|
|
146
144
|
"@deepseek-ai/dsh-tools": "npm:@sparkelf/dsh-tools@0.1.6-alpha.2",
|
|
147
145
|
"@deepseek-ai/dsh-web-app": "npm:@sparkelf/dsh-web-app@0.1.6-alpha.2",
|
|
148
146
|
"@deepseek-ai/dsh-web-frontend": "npm:@sparkelf/dsh-web-frontend@0.1.6-alpha.2",
|
|
149
147
|
"@deepseek-ai/dsh-workspace": "npm:@sparkelf/dsh-workspace@0.1.6-alpha.2"
|
|
148
|
+
},
|
|
149
|
+
"standaloneVariants": {
|
|
150
|
+
"dataops": {
|
|
151
|
+
"excludeBundles": [],
|
|
152
|
+
"excludePackages": [
|
|
153
|
+
"@deepseek-ai/dsh-computer-use",
|
|
154
|
+
"@deepseek-ai/dsh-experimental-computer-use-cua-driver-mcp",
|
|
155
|
+
"@deepseek-ai/dsh-web-search-exa"
|
|
156
|
+
],
|
|
157
|
+
"packageName": "@sparkelf/dsh-dataops-standalone",
|
|
158
|
+
"profile": "dataops-web"
|
|
159
|
+
}
|
|
150
160
|
}
|
|
151
161
|
},
|
|
152
162
|
"sourceBase": {
|
|
@@ -176,6 +186,11 @@
|
|
|
176
186
|
"license": "MIT",
|
|
177
187
|
"main": "lib/index.js",
|
|
178
188
|
"name": "@sparkelf/dsh-plus",
|
|
189
|
+
"optionalDependencies": {
|
|
190
|
+
"@deepseek-ai/dsh-computer-use": ">=0.1.6-alpha.1",
|
|
191
|
+
"@deepseek-ai/dsh-experimental-computer-use-cua-driver-mcp": ">=0.1.6-alpha.1",
|
|
192
|
+
"@deepseek-ai/dsh-web-search-exa": ">=0.1.6-alpha.1"
|
|
193
|
+
},
|
|
179
194
|
"peerDependencies": {
|
|
180
195
|
"@deepseek-ai/cordis": ">=4.0.1"
|
|
181
196
|
},
|
|
@@ -189,5 +204,5 @@
|
|
|
189
204
|
},
|
|
190
205
|
"type": "module",
|
|
191
206
|
"types": "lib/types/index.d.ts",
|
|
192
|
-
"version": "0.2.0-rc.
|
|
207
|
+
"version": "0.2.0-rc.19"
|
|
193
208
|
}
|