@sparkelf/dsh-plus 0.1.0-rc.11 → 0.1.0-rc.13

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.i18n.yaml CHANGED
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/bundle/plus/README.md
5
- README.md: a48ce3e778e2cf121f9abfe1cb12fbe1a4ec7c9a
6
- README.zh.md: 0fd4947ad19983bb44fcf69b3c148e3eccb043e4
5
+ README.md: a8ac5367fb3de36c0ee24c27bfc0f7f1cc72c8cc
6
+ README.zh.md: a179074b4bec9ec8f857c6cbe5fa8b9e4bbebde6
package/README.md CHANGED
@@ -9,7 +9,7 @@ English | [中文](README.zh.md)
9
9
 
10
10
  ## Summary
11
11
 
12
- This distribution composes official `@deepseek-ai/dsh-base` and `@deepseek-ai/dsh-web-app` with the selected external sidebar, mobile bridge, plugin market, GenUI package, five complete Plus capability packages, and nine independent patch packages. It owns only ordered composition, minimum compatibility metadata, dependency closure, explicit materialization, and the credential-free deployment lock; capability behavior and patch payloads stay in their owning packages.
12
+ This distribution composes official `@deepseek-ai/dsh-base` and `@deepseek-ai/dsh-web-app` with the selected external sidebar, mobile bridge, plugin market, GenUI package, five in-repository Plus capability packages and one externally owned Supervisor package, and fifteen independent patch packages. It owns only ordered composition, minimum compatibility metadata, dependency closure, explicit materialization, and the credential-free deployment lock; capability behavior and patch payloads stay in their owning packages.
13
13
 
14
14
  ## Table of Contents
15
15
 
@@ -31,9 +31,11 @@ dsh plugin --profile plus exec dsh-plus apply --dsh-root /path/to/official-dsh
31
31
  dsh --profile plus
32
32
  ```
33
33
 
34
- The explicit apply step requires official revision `cd5ef8148158c3a752a658978873241fdf8e2bbc`, materializes every selected runtime package as a profile-direct dependency, applies all pending source payloads together, configures exact npm patches, removes retired Plus-owned entries, and writes `.dsh-plus/patchset.lock.json` with mode `0600`. It installs `dsh-better-sidebar@0.17.1` at the profile root, explicitly allows only its `node-pty` native build, and links the profile's `@deepseek-ai` scope to the exact official dsh CLI dependency tree at `apps/cli/node_modules/@deepseek-ai`. Version conflicts and source mismatches fail before profile installation or source mutation. The package has no install lifecycle script.
34
+ The explicit apply step requires official revision `0a53fb55bea101816fa226bb964ae2bed71c343b`, materializes every selected runtime package as a profile-direct dependency, applies all pending source payloads together, configures exact npm patches, removes retired Plus-owned entries, and writes `.dsh-plus/patchset.lock.json` with mode `0600`. It installs stable `dsh-better-sidebar@0.17.1`, Office preview `0.1.2`, and video preview `0.1.4` at the profile root, applies the exact alpha.2 Settings patch, explicitly allows only the sidebar's `node-pty` native build, and builds the profile's `@deepseek-ai` scope from the exact official dsh CLI dependency tree plus official source workspaces needed by out-of-tree plugin peers. SparkElf-owned external Mobile Bridge `0.2.10` and independently maintained dshmarket `1.38.1` each carry alpha.2 Settings compatibility in their own release, so Plus applies no Mobile Bridge patch. Version conflicts and source mismatches fail before profile installation or source mutation. The package has no install lifecycle script.
35
35
 
36
- Official DSH supplies onboarding, Workspace selection, Session export, Turn folding, and the base image path. The external `@changfenhuang/dsh-genui` bundle owns generated UI, including inline interactive charts emitted by the model as `dsh-ui`. The temporary GenUI streaming EChart patch targets only `0.9.6` and retires after [upstream PR #87](https://github.com/omdsh-dev/dsh-genui/pull/87) ships in npm and the real inline-chart path passes. DataOps and Document Attachments mount only when their endpoint environment variables exist. Agent Teams is excluded because the official packages are private experimental workspaces and shipped profiles disable them.
36
+ Official DSH supplies onboarding, Workspace selection, Session export, Turn folding, and the base image path. Plus builds that source with the official client profile, keeps the attachment chooser directly after the composer command button, adds Better Sidebar previews for Office documents and video, replaces mixed English `Session` wording in the Simplified-Chinese Session export UI, and places the desktop Session-log action immediately before Trajectory search while retaining its Header position on phones. The external `@changfenhuang/dsh-genui` bundle owns generated UI, including inline interactive charts emitted by the model as `dsh-ui`. Two exact `0.9.6` patches keep top-level streaming complete, register the bundled `genui` skill, publish the compact chart signature, and reject invalid chart fields; each retires after its upstream behavior ships and the real DataOps chart path passes without it. The registry-pinned Supervisor from `SparkElf/dsh-plugins-plus` manages an explicitly materialized runtime and restores Sessions interrupted by its own restart; optional Desktop from `SparkElf/dsh-plus-desktop` delegates tray commands to that package. Neither source tree lives in this fork. DataOps and Document Attachments mount only when their endpoint environment variables exist. Agent Teams is excluded because the official packages are private experimental workspaces and shipped profiles disable them.
37
+
38
+ Plus explicitly selects `browserAuthentication: disabled`: its Web URL is clean and opens without a process-token exchange or browser cookie, while Connection still applies the official Host/Origin trust fence. Every process that can reach an accepted authority can therefore use the complete Host API, including Shell, files, and Sessions. The official `web` profile keeps the upstream `required` default; only the Plus composition opts out.
37
39
 
38
40
  -----
39
41
 
package/README.zh.md CHANGED
@@ -9,7 +9,7 @@ kind: "package-bundle"
9
9
 
10
10
  ## 概述
11
11
 
12
- 该distribution把official `@deepseek-ai/dsh-base`及`@deepseek-ai/dsh-web-app`与selected external sidebar、mobile bridge、plugin market、GenUI package、五个完整Plus capability packages及九个independent patch packages组合起来。它只持有ordered composition、minimum compatibility metadata、dependency closure、explicit materialization及credential-free deployment lock;capability behavior和patch payloads仍属于各自package。
12
+ 该distribution把official `@deepseek-ai/dsh-base`及`@deepseek-ai/dsh-web-app`与selected external sidebar、mobile bridge、plugin market、GenUI package、五个in-repository Plus capability packages及一个externally owned Supervisor package及十五个independent patch packages组合起来。它只持有ordered composition、minimum compatibility metadata、dependency closure、explicit materialization及credential-free deployment lock;capability behavior和patch payloads仍属于各自package。
13
13
 
14
14
  ## 目录
15
15
 
@@ -31,9 +31,11 @@ dsh plugin --profile plus exec dsh-plus apply --dsh-root /path/to/official-dsh
31
31
  dsh --profile plus
32
32
  ```
33
33
 
34
- explicit apply步骤要求official revision `cd5ef8148158c3a752a658978873241fdf8e2bbc`,把每个selected runtime package materialize为profile-direct dependency,一次应用全部pending source payloads,配置exact npm patches,删除retired Plus-owned entries,并以`0600` mode写入`.dsh-plus/patchset.lock.json`。它在profile root安装`dsh-better-sidebar@0.17.1`,只显式允许其`node-pty` native build,并把profile的`@deepseek-ai` scope链接到`apps/cli/node_modules/@deepseek-ai`中的exact official dsh CLI dependency tree。version conflict和source mismatch会在profile installation或source mutation前失败。该package没有install lifecycle script。
34
+ explicit apply步骤要求official revision `0a53fb55bea101816fa226bb964ae2bed71c343b`,把每个selected runtime package materialize为profile-direct dependency,一次应用全部pending source payloads,配置exact npm patches,删除retired Plus-owned entries,并以`0600` mode写入`.dsh-plus/patchset.lock.json`。它在profile root安装stable `dsh-better-sidebar@0.17.1`、Office preview `0.1.2`与video preview `0.1.4`,应用exact alpha.2 Settings patch,只显式允许sidebar的`node-pty` native build,并用exact official dsh CLI dependency tree及out-of-tree plugin peers所需的official source workspaces共同构建profile的`@deepseek-ai` scope。SparkElf自有external Mobile Bridge `0.2.10`与独立维护的dshmarket `1.38.1`各自在自身release中包含alpha.2 Settings compatibility,因此Plus不应用Mobile Bridge patch。version conflict和source mismatch会在profile installation或source mutation前失败。该package没有install lifecycle script。
35
35
 
36
- Official DSH提供onboarding、Workspace selection、Session export、Turn folding及base image path。External `@changfenhuang/dsh-genui` bundle拥有generated UI,包括模型以`dsh-ui`输出的inline interactive charts。Temporary GenUI streaming EChart patch只target `0.9.6`;[upstream PR #87](https://github.com/omdsh-dev/dsh-genui/pull/87)进入npm且真实inline-chart path通过后退役。DataOps和Document Attachments仅在对应endpoint environment variables存在时mount。Agent Teams被排除,因为official packages属于private experimental workspaces且shipped profiles会禁用它们。
36
+ Official DSH提供onboarding、Workspace selection、Session export、Turn folding及base image path。Plus使用official client profile构建该source,把附件选择器保持在输入框指令按钮正右侧,增加Better Sidebar的Office document与video preview,把简体中文会话导出界面中混用的英文`Session`替换为中文,并在桌面端把会话日志操作放到Trajectory搜索框紧邻左侧,同时在手机上保留其Header位置。External `@changfenhuang/dsh-genui` bundle拥有generated UI,包括模型以`dsh-ui`输出的inline interactive charts。两个exact `0.9.6` patch分别保持top-level streaming完整,并注册bundled `genui` skill、发布紧凑chart signature及拒绝非法chart fields;各自upstream behavior发布且真实DataOps chart path在不使用对应patch时通过后退役。来自`SparkElf/dsh-plugins-plus`且由registry精确固定的Supervisor管理显式materialize的runtime并恢复被其自身restart中断的Sessions;来自`SparkElf/dsh-plus-desktop`的可选Desktop把tray commands委托给该package。两个source tree都不在本fork中。DataOps和Document Attachments仅在对应endpoint environment variables存在时mount。Agent Teams被排除,因为official packages属于private experimental workspaces且shipped profiles会禁用它们。
37
+
38
+ Plus显式选择`browserAuthentication: disabled`:其Web URL保持clean,无需process-token exchange或browser cookie即可打开,同时Connection仍执行official Host/Origin trust fence。因此所有能访问accepted authority的进程都能使用包含Shell、files与Sessions在内的完整Host API。official `web` profile保留upstream `required` default;只有Plus composition选择关闭。
37
39
 
38
40
  -----
39
41
 
package/cordis.patch.yml CHANGED
@@ -1,6 +1,11 @@
1
1
  - id: subagent-model-selection-settings
2
2
  disabled: true
3
3
 
4
+ - id: connection
5
+ config:
6
+ trustedHosts: !!js ctx.webRuntime.trustedHosts
7
+ browserAuthentication: disabled
8
+
4
9
  - insert:
5
10
  - id: plus-backup
6
11
  name: '@sparkelf/dsh-plugin-backup'
package/lib/apply.js CHANGED
@@ -1,12 +1,16 @@
1
1
  import { createRequire } from "node:module";
2
2
  import { spawnSync } from "node:child_process";
3
- import { chmodSync, copyFileSync, existsSync, mkdirSync, readFileSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
3
+ import { chmodSync, copyFileSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
4
4
  import { dirname, isAbsolute, relative, resolve } from "node:path";
5
+ import { tmpdir } from "node:os";
5
6
  import { satisfies, valid, validRange } from "semver";
6
7
  import { parseDocument } from "yaml";
7
8
  //#region lib/types/apply.js
8
9
  /** Materialize the Plus distribution's independent patch packages without Desktop. */
9
10
  const FORMAT_VERSION = 1;
11
+ function isSelectedNpmPatch(patch) {
12
+ return patch.target.kind === "npm";
13
+ }
10
14
  function readJsonObject(path, label) {
11
15
  const parsed = JSON.parse(readFileSync(path, "utf8"));
12
16
  if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error(label + " must be a JSON object");
@@ -113,6 +117,40 @@ function sourcePatchState(root, file) {
113
117
  ]);
114
118
  throw new Error("unreachable");
115
119
  }
120
+ /** 在隔离index中按真实顺序预演source patches,避免失败后污染official worktree。 */
121
+ function preflightSourcePatches(root, files) {
122
+ if (files.length === 0) return;
123
+ const directory = mkdtempSync(resolve(tmpdir(), "dsh-plus-source-patches-"));
124
+ const index = resolve(directory, "index");
125
+ const env = {
126
+ ...process.env,
127
+ GIT_INDEX_FILE: index
128
+ };
129
+ const run = (args) => {
130
+ const result = spawnSync("git", args, {
131
+ cwd: root,
132
+ encoding: "utf8",
133
+ env
134
+ });
135
+ if (result.status === 0) return;
136
+ const detail = result.stderr.trim();
137
+ throw new Error("git " + args.join(" ") + " failed" + (detail === "" ? "" : ": " + detail));
138
+ };
139
+ try {
140
+ run(["read-tree", "HEAD"]);
141
+ for (const file of files) run([
142
+ "apply",
143
+ "--cached",
144
+ "--3way",
145
+ file
146
+ ]);
147
+ } finally {
148
+ rmSync(directory, {
149
+ recursive: true,
150
+ force: true
151
+ });
152
+ }
153
+ }
116
154
  function requireSourceBase(root, baseRevision) {
117
155
  const checkoutRevision = requireString(git(root, ["rev-parse", "HEAD"]), "DSH checkout revision");
118
156
  if (checkoutRevision !== baseRevision) throw new Error("DSH checkout must be exact official base " + baseRevision + ", found " + checkoutRevision);
@@ -160,18 +198,14 @@ function prepareSelection(distributionDirectory, profileDirectory, dshRoot) {
160
198
  groups.set(variant.id, entries);
161
199
  }
162
200
  const sourceStates = /* @__PURE__ */ new Map();
163
- for (const variant of [...groups.values()].flat()) {
201
+ const orderedGroups = [...groups].sort(([left], [right]) => left.localeCompare(right));
202
+ for (const [, variants] of orderedGroups) for (const variant of variants) {
164
203
  if (variant.target.kind !== "dsh-source" || variant.target.baseRevision !== baseRevision || !satisfies(dshVersion, variant.dsh, { includePrerelease: true })) continue;
165
204
  const file = resolvePatchFile(variant.patchPackage.directory, variant.file);
166
205
  sourceStates.set(file.absoluteFile, sourcePatchState(dshRoot, file.absoluteFile));
167
206
  }
168
- const pendingSourceFiles = [...sourceStates].flatMap(([file, state]) => state === "pending" ? [file] : []);
169
- if (pendingSourceFiles.length > 0) git(dshRoot, [
170
- "apply",
171
- "--check",
172
- ...pendingSourceFiles
173
- ]);
174
- if (writeProfileRequirements(profileDirectory, profileDependencySpecs, allowBuilds)) runPnpm(profileDirectory, ["install"], "pnpm install Plus profile dependencies");
207
+ preflightSourcePatches(dshRoot, [...sourceStates].flatMap(([file, state]) => state === "pending" ? [file] : []));
208
+ if (writeProfileRequirements(profileDirectory, profileDependencySpecs, allowBuilds)) runPnpm(profileDirectory, ["install", "--no-frozen-lockfile"], "pnpm install Plus profile dependencies");
175
209
  const profileDependencies = Object.keys(profileDependencySpecs).sort().map((name) => {
176
210
  return {
177
211
  name,
@@ -185,8 +219,8 @@ function prepareSelection(distributionDirectory, profileDirectory, dshRoot) {
185
219
  };
186
220
  }), ...profileDependencies].sort((left, right) => left.name.localeCompare(right.name));
187
221
  const selected = [];
188
- for (const id of [...groups.keys()].sort()) {
189
- const candidates = (groups.get(id) ?? []).flatMap((variant) => {
222
+ for (const [id, variants] of orderedGroups) {
223
+ const candidates = variants.flatMap((variant) => {
190
224
  if (!satisfies(dshVersion, variant.dsh, { includePrerelease: true })) return [];
191
225
  const file = resolvePatchFile(variant.patchPackage.directory, variant.file);
192
226
  if (variant.target.kind === "dsh-source") {
@@ -258,13 +292,14 @@ function prepareSelection(distributionDirectory, profileDirectory, dshRoot) {
258
292
  }
259
293
  };
260
294
  }
295
+ /** 保留每个独立payload,并为同一npm目标生成pnpm可消费的唯一组合patch。 */
261
296
  function materializePatchFiles(profileDirectory, patches) {
262
297
  const root = resolve(profileDirectory, ".dsh-plus", "patches");
263
298
  rmSync(root, {
264
299
  recursive: true,
265
300
  force: true
266
301
  });
267
- return patches.map((patch) => {
302
+ const stablePatches = patches.map((patch) => {
268
303
  const destination = resolve(root, patch.patchPackage.name, patch.patchPackage.version, patch.file);
269
304
  mkdirSync(dirname(destination), { recursive: true });
270
305
  copyFileSync(patch.absoluteFile, destination);
@@ -273,23 +308,49 @@ function materializePatchFiles(profileDirectory, patches) {
273
308
  absoluteFile: destination
274
309
  };
275
310
  });
311
+ const npmGroups = /* @__PURE__ */ new Map();
312
+ for (const patch of stablePatches) {
313
+ if (!isSelectedNpmPatch(patch)) continue;
314
+ const key = patch.target.name + "@" + patch.target.version;
315
+ const group = npmGroups.get(key);
316
+ if (group === void 0) npmGroups.set(key, [patch]);
317
+ else group.push(patch);
318
+ }
319
+ const npmPatchFiles = /* @__PURE__ */ new Map();
320
+ for (const [key, group] of npmGroups) {
321
+ const first = group[0];
322
+ if (group.length === 1) {
323
+ npmPatchFiles.set(key, first.absoluteFile);
324
+ continue;
325
+ }
326
+ const members = group.map((patch) => encodeURIComponent(patch.id + "@" + patch.patchPackage.version)).join("+");
327
+ const destination = resolve(root, "combined", encodeURIComponent(key), members + ".patch");
328
+ mkdirSync(dirname(destination), { recursive: true });
329
+ writeFileSync(destination, group.map((patch) => {
330
+ const content = readFileSync(patch.absoluteFile, "utf8");
331
+ return content.endsWith("\n") ? content : content + "\n";
332
+ }).join(""));
333
+ npmPatchFiles.set(key, destination);
334
+ }
335
+ return {
336
+ patches: stablePatches,
337
+ npmPatchFiles
338
+ };
276
339
  }
277
- function profilePatchConfiguration(profileDirectory, patches) {
340
+ function profilePatchConfiguration(profileDirectory, npmPatchFiles) {
278
341
  const document = parseDocument(readFileSync(resolve(profileDirectory, "pnpm-workspace.yaml"), "utf8"));
279
342
  const [documentError] = document.errors;
280
343
  if (documentError !== void 0) throw new Error("Plus profile workspace is not valid YAML", { cause: documentError });
281
344
  let changed = false;
282
- const desiredKeys = new Set(patches.flatMap((patch) => patch.target.kind === "npm" ? [patch.target.name + "@" + patch.target.version] : []));
345
+ const desiredKeys = new Set(npmPatchFiles.keys());
283
346
  const workspace = requireObject(document.toJS(), "Plus profile workspace");
284
347
  const configured = workspace.patchedDependencies === void 0 ? {} : requireObject(workspace.patchedDependencies, "Plus profile patchedDependencies");
285
348
  for (const [key, value] of Object.entries(configured)) if (typeof value === "string" && value.startsWith(".dsh-plus/patches/") && !desiredKeys.has(key)) {
286
349
  document.deleteIn(["patchedDependencies", key]);
287
350
  changed = true;
288
351
  }
289
- for (const patch of patches) {
290
- if (patch.target.kind !== "npm") continue;
291
- const key = patch.target.name + "@" + patch.target.version;
292
- const value = relative(profileDirectory, patch.absoluteFile).replaceAll("\\", "/");
352
+ for (const [key, file] of npmPatchFiles) {
353
+ const value = relative(profileDirectory, file).replaceAll("\\", "/");
293
354
  const current = document.getIn(["patchedDependencies", key]);
294
355
  if (current !== void 0 && current !== value && (typeof current !== "string" || !current.startsWith(".dsh-plus/patches/"))) throw new Error("profile patchedDependencies." + key + " is already owned by another payload");
295
356
  if (current === value) continue;
@@ -375,27 +436,92 @@ function pendingSourcePatchFiles(patches) {
375
436
  return patches.flatMap((patch) => "alreadyApplied" in patch && !patch.alreadyApplied ? [patch.absoluteFile] : []);
376
437
  }
377
438
  function applySelectedPatches(profileDirectory, dshRoot, patches, profileChanged) {
378
- const stablePatches = materializePatchFiles(profileDirectory, patches);
439
+ const materialized = materializePatchFiles(profileDirectory, patches);
379
440
  const workspacePath = resolve(profileDirectory, "pnpm-workspace.yaml");
380
- const workspace = profilePatchConfiguration(profileDirectory, stablePatches);
441
+ const workspace = profilePatchConfiguration(profileDirectory, materialized.npmPatchFiles);
381
442
  if (workspace.changed) writeFileSync(workspacePath, workspace.text);
382
- if (profileChanged || workspace.changed) runPnpm(profileDirectory, ["install"], "pnpm install in Plus profile");
383
- const sourceFiles = pendingSourcePatchFiles(stablePatches);
384
- if (sourceFiles.length > 0) git(dshRoot, ["apply", ...sourceFiles]);
385
- if (stablePatches.some((patch) => patch.target.kind === "dsh-source")) runPnpm(dshRoot, ["run", "build"], "official DSH build after source patches");
443
+ if (profileChanged || workspace.changed) runPnpm(profileDirectory, ["install", "--no-frozen-lockfile"], "pnpm install in Plus profile");
444
+ const sourceFiles = pendingSourcePatchFiles(materialized.patches);
445
+ if (sourceFiles.length > 0) git(dshRoot, ["update-index", "--refresh"], true);
446
+ for (const file of sourceFiles) git(dshRoot, [
447
+ "apply",
448
+ "--3way",
449
+ file
450
+ ]);
451
+ if (materialized.patches.some((patch) => patch.target.kind === "dsh-source")) runPnpm(dshRoot, ["run", "build:official"], "official DSH build after source patches");
386
452
  }
387
453
  function officialPackageRoot(dshRoot) {
388
454
  return resolve(dshRoot, "apps", "cli");
389
455
  }
390
- function linkOfficialPackages(profileDirectory, dshRoot) {
391
- const source = resolve(officialPackageRoot(dshRoot), "node_modules", "@deepseek-ai");
392
- if (!existsSync(source)) throw new Error("official DSH dependencies are missing under " + source);
456
+ /**
457
+ * Parse pnpm's workspace roster into exact official package directories.
458
+ * @param dshRoot - exact official DSH checkout root.
459
+ * @param stdout - JSON emitted by `pnpm -r list --json --depth -1`.
460
+ * @returns sorted official package names and directories inside the checkout.
461
+ */
462
+ function parseOfficialWorkspacePackages(dshRoot, stdout) {
463
+ const parsed = JSON.parse(stdout);
464
+ if (!Array.isArray(parsed)) throw new Error("pnpm workspace package list must be an array");
465
+ const packages = /* @__PURE__ */ new Map();
466
+ for (const [index, value] of parsed.entries()) {
467
+ if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error("pnpm workspace package list[" + String(index) + "] must be an object");
468
+ const entry = value;
469
+ if (typeof entry.name !== "string" || !entry.name.startsWith("@deepseek-ai/")) continue;
470
+ const localName = entry.name.slice(13);
471
+ if (localName === "" || localName.includes("/")) throw new Error("unsupported official workspace package name: " + entry.name);
472
+ if (typeof entry.path !== "string" || entry.path === "") throw new Error("pnpm workspace package " + entry.name + " has no path");
473
+ const directory = resolve(dshRoot, entry.path);
474
+ const local = relative(dshRoot, directory);
475
+ if (isAbsolute(local) || local === ".." || local.startsWith("../")) throw new Error("official workspace package escapes DSH root: " + entry.name);
476
+ const previous = packages.get(entry.name);
477
+ if (previous !== void 0 && previous !== directory) throw new Error("duplicate official workspace package: " + entry.name);
478
+ packages.set(entry.name, directory);
479
+ }
480
+ return [...packages].sort(([left], [right]) => left.localeCompare(right)).map(([name, directory]) => ({
481
+ name,
482
+ directory
483
+ }));
484
+ }
485
+ function listOfficialWorkspacePackages(dshRoot) {
486
+ const result = spawnSync("pnpm", [
487
+ "-r",
488
+ "list",
489
+ "--json",
490
+ "--depth",
491
+ "-1"
492
+ ], {
493
+ cwd: dshRoot,
494
+ encoding: "utf8",
495
+ shell: process.platform === "win32"
496
+ });
497
+ if (result.error !== void 0) throw result.error;
498
+ if (result.status !== 0) throw new Error("pnpm list official DSH workspace packages failed with exit code " + String(result.status));
499
+ return parseOfficialWorkspacePackages(dshRoot, result.stdout);
500
+ }
501
+ /**
502
+ * Build the profile's official scope from the CLI closure plus source workspaces.
503
+ * @param profileDirectory - materialized Plus profile root.
504
+ * @param cliScope - official packages already installed under the DSH CLI.
505
+ * @param workspacePackages - additional official source workspaces required by external peers.
506
+ */
507
+ function materializeOfficialPackageScope(profileDirectory, cliScope, workspacePackages) {
508
+ if (!existsSync(cliScope)) throw new Error("official DSH dependencies are missing under " + cliScope);
393
509
  const destination = resolve(profileDirectory, "node_modules", "@deepseek-ai");
394
510
  rmSync(destination, {
395
511
  recursive: true,
396
512
  force: true
397
513
  });
398
- symlinkSync(source, destination, process.platform === "win32" ? "junction" : "dir");
514
+ mkdirSync(destination, { recursive: true });
515
+ const linkType = process.platform === "win32" ? "junction" : "dir";
516
+ for (const name of readdirSync(cliScope).sort()) symlinkSync(resolve(cliScope, name), resolve(destination, name), linkType);
517
+ for (const entry of workspacePackages) {
518
+ const target = resolve(destination, entry.name.slice(13));
519
+ if (existsSync(target)) continue;
520
+ symlinkSync(entry.directory, target, linkType);
521
+ }
522
+ }
523
+ function linkOfficialPackages(profileDirectory, dshRoot) {
524
+ materializeOfficialPackageScope(profileDirectory, resolve(officialPackageRoot(dshRoot), "node_modules", "@deepseek-ai"), listOfficialWorkspacePackages(dshRoot));
399
525
  }
400
526
  function writeLock(profileDirectory, lock) {
401
527
  const directory = resolve(profileDirectory, ".dsh-plus");
@@ -446,4 +572,4 @@ function runApply(argv) {
446
572
  process.stdout.write("[dsh-plus] applied " + String(selection.patches.length) + " patches; lock " + lock + "\n");
447
573
  }
448
574
  //#endregion
449
- export { runApply };
575
+ export { materializeOfficialPackageScope, parseOfficialWorkspacePackages, runApply };
@@ -1,4 +1,23 @@
1
1
  /** Materialize the Plus distribution's independent patch packages without Desktop. */
2
+ /** One official workspace package available as a profile peer dependency. */
3
+ export interface OfficialWorkspacePackage {
4
+ name: string;
5
+ directory: string;
6
+ }
7
+ /**
8
+ * Parse pnpm's workspace roster into exact official package directories.
9
+ * @param dshRoot - exact official DSH checkout root.
10
+ * @param stdout - JSON emitted by `pnpm -r list --json --depth -1`.
11
+ * @returns sorted official package names and directories inside the checkout.
12
+ */
13
+ export declare function parseOfficialWorkspacePackages(dshRoot: string, stdout: string): OfficialWorkspacePackage[];
14
+ /**
15
+ * Build the profile's official scope from the CLI closure plus source workspaces.
16
+ * @param profileDirectory - materialized Plus profile root.
17
+ * @param cliScope - official packages already installed under the DSH CLI.
18
+ * @param workspacePackages - additional official source workspaces required by external peers.
19
+ */
20
+ export declare function materializeOfficialPackageScope(profileDirectory: string, cliScope: string, workspacePackages: readonly OfficialWorkspacePackage[]): void;
2
21
  /**
3
22
  * Apply the installed Plus distribution metadata from a DSH profile directory.
4
23
  * @param argv - Explicit `apply --dsh-root <path>` command arguments.
package/package.json CHANGED
@@ -3,32 +3,42 @@
3
3
  "dsh-plus": "lib/bin.js"
4
4
  },
5
5
  "dependencies": {
6
- "@changfenhuang/dsh-genui": ">=0.9.6",
7
- "@sparkelf/dsh-mobile-bridge": ">=0.2.8",
8
- "@sparkelf/dsh-patch-better-sidebar-app-frame": ">=0.1.0-rc.11",
9
- "@sparkelf/dsh-patch-document-attachments": ">=0.1.0-rc.11",
10
- "@sparkelf/dsh-patch-genui-streaming-echart": ">=0.1.0-rc.11",
11
- "@sparkelf/dsh-patch-mobile-bridge-serialized-actions": ">=0.1.0-rc.11",
12
- "@sparkelf/dsh-patch-mobile-web-layout": ">=0.1.0-rc.11",
13
- "@sparkelf/dsh-patch-responses-reasoning-status": ">=0.1.0-rc.11",
14
- "@sparkelf/dsh-patch-subagent-settings-presets": ">=0.1.0-rc.11",
15
- "@sparkelf/dsh-patch-web-base-path": ">=0.1.0-rc.11",
16
- "@sparkelf/dsh-patch-workspace-storage-restore": ">=0.1.0-rc.11",
17
- "@sparkelf/dsh-plugin-backup": ">=0.1.0-rc.11",
18
- "@sparkelf/dsh-plugin-dataops": ">=0.1.0-rc.11",
19
- "@sparkelf/dsh-plugin-document-attachments": ">=0.1.0-rc.11",
20
- "@sparkelf/dsh-plugin-mcp-credentials": ">=0.1.0-rc.11",
21
- "@sparkelf/dsh-plugin-subagent-settings": ">=0.1.0-rc.11",
22
- "dshmarket": ">=1.29.2",
6
+ "@sparkelf/dsh-mobile-bridge": ">=0.2.10",
7
+ "@sparkelf/dsh-patch-better-sidebar-alpha2-settings": ">=0.1.0-rc.13",
8
+ "@sparkelf/dsh-patch-better-sidebar-app-frame": ">=0.1.0-rc.13",
9
+ "@sparkelf/dsh-patch-browser-auth-mode": ">=0.1.0-rc.13",
10
+ "@sparkelf/dsh-patch-document-attachments": ">=0.1.0-rc.13",
11
+ "@sparkelf/dsh-patch-genui-skill-chart-contract": ">=0.1.0-rc.13",
12
+ "@sparkelf/dsh-patch-genui-streaming-echart": ">=0.1.0-rc.13",
13
+ "@sparkelf/dsh-patch-legacy-code-preset": ">=0.1.0-rc.13",
14
+ "@sparkelf/dsh-patch-mobile-web-layout": ">=0.1.0-rc.13",
15
+ "@sparkelf/dsh-patch-ptc-mcp-schema-types": ">=0.1.0-rc.13",
16
+ "@sparkelf/dsh-patch-responses-reasoning-status": ">=0.1.0-rc.13",
17
+ "@sparkelf/dsh-patch-session-export-chinese": ">=0.1.0-rc.13",
18
+ "@sparkelf/dsh-patch-session-log-trajectory-toolbar": ">=0.1.0-rc.13",
19
+ "@sparkelf/dsh-patch-subagent-settings-presets": ">=0.1.0-rc.13",
20
+ "@sparkelf/dsh-patch-univer-office-alpha2": ">=0.1.0-rc.13",
21
+ "@sparkelf/dsh-patch-web-base-path": ">=0.1.0-rc.13",
22
+ "@sparkelf/dsh-patch-workspace-storage-restore": ">=0.1.0-rc.13",
23
+ "@sparkelf/dsh-plugin-backup": ">=0.1.0-rc.13",
24
+ "@sparkelf/dsh-plugin-dataops": ">=0.1.0-rc.13",
25
+ "@sparkelf/dsh-plugin-document-attachments": ">=0.1.0-rc.13",
26
+ "@sparkelf/dsh-plugin-mcp-credentials": ">=0.1.0-rc.13",
27
+ "@sparkelf/dsh-plugin-subagent-settings": ">=0.1.0-rc.13",
28
+ "dshmarket": ">=1.38.1",
23
29
  "semver": ">=7.7.3",
24
30
  "yaml": ">=2.9.0"
25
31
  },
26
32
  "description": "DeepSeek Harness Plus official-base Web distribution profile and ranged compatibility patchset",
27
33
  "devDependencies": {
28
- "@deepseek-ai/cordis": "^4.0.1",
29
- "@deepseek-ai/dsh-invariants": "^0.1.2-alpha.1",
34
+ "@changfenhuang/dsh-genui": "0.9.6",
35
+ "@deepseek-ai/cordis": "^4.0.2",
36
+ "@deepseek-ai/dsh-invariants": "^0.1.2-alpha.2",
37
+ "@huanlin/dsh-plugin-better-sidebar-plugin-office": "0.1.2",
30
38
  "@types/semver": ">=7.7.1",
31
- "dsh-better-sidebar": "0.17.1"
39
+ "dsh-better-sidebar": "0.17.1",
40
+ "dsh-univer-office": "0.2.12",
41
+ "dsh-video-preview": "0.1.4"
32
42
  },
33
43
  "dsh": {
34
44
  "bundle": {
@@ -37,39 +47,56 @@
37
47
  },
38
48
  "dshPlus": {
39
49
  "compatibility": {
40
- "dsh": ">=0.1.2-alpha.1"
50
+ "dsh": ">=0.1.2-alpha.2"
41
51
  },
42
52
  "formatVersion": 1,
43
53
  "patchPackages": [
44
54
  "@sparkelf/dsh-patch-better-sidebar-app-frame",
55
+ "@sparkelf/dsh-patch-better-sidebar-alpha2-settings",
56
+ "@sparkelf/dsh-patch-univer-office-alpha2",
45
57
  "@sparkelf/dsh-patch-genui-streaming-echart",
46
- "@sparkelf/dsh-patch-mobile-bridge-serialized-actions",
58
+ "@sparkelf/dsh-patch-genui-skill-chart-contract",
59
+ "@sparkelf/dsh-patch-browser-auth-mode",
47
60
  "@sparkelf/dsh-patch-workspace-storage-restore",
48
61
  "@sparkelf/dsh-patch-subagent-settings-presets",
49
62
  "@sparkelf/dsh-patch-document-attachments",
63
+ "@sparkelf/dsh-patch-legacy-code-preset",
64
+ "@sparkelf/dsh-patch-session-export-chinese",
65
+ "@sparkelf/dsh-patch-session-log-trajectory-toolbar",
50
66
  "@sparkelf/dsh-patch-responses-reasoning-status",
67
+ "@sparkelf/dsh-patch-ptc-mcp-schema-types",
51
68
  "@sparkelf/dsh-patch-mobile-web-layout",
52
69
  "@sparkelf/dsh-patch-web-base-path"
53
70
  ],
54
71
  "profile": {
55
72
  "allowBuilds": {
56
- "node-pty": true
73
+ "node-pty": true,
74
+ "protobufjs": false
57
75
  },
58
76
  "bundles": [
59
77
  "@deepseek-ai/dsh-base",
60
78
  "@deepseek-ai/dsh-web-app",
61
79
  "dsh-better-sidebar",
80
+ "@huanlin/dsh-plugin-better-sidebar-plugin-office",
81
+ "dsh-video-preview",
82
+ "dsh-univer-office",
62
83
  "@sparkelf/dsh-mobile-bridge",
63
84
  "dshmarket",
64
85
  "@changfenhuang/dsh-genui",
86
+ "@sparkelf/dsh-plugin-supervisor",
65
87
  "@sparkelf/dsh-plus"
66
88
  ],
67
89
  "dependencies": {
68
- "dsh-better-sidebar": "0.17.1"
90
+ "@changfenhuang/dsh-genui": "0.9.6",
91
+ "@huanlin/dsh-plugin-better-sidebar-plugin-office": "0.1.2",
92
+ "@sparkelf/dsh-plugin-supervisor": "0.1.1",
93
+ "dsh-better-sidebar": "0.17.1",
94
+ "dsh-univer-office": "0.2.12",
95
+ "dsh-video-preview": "0.1.4"
69
96
  }
70
97
  },
71
98
  "sourceBase": {
72
- "revision": "cd5ef8148158c3a752a658978873241fdf8e2bbc"
99
+ "revision": "0a53fb55bea101816fa226bb964ae2bed71c343b"
73
100
  }
74
101
  },
75
102
  "exports": {
@@ -101,7 +128,7 @@
101
128
  "name": "@sparkelf/dsh-plus",
102
129
  "peerDependencies": {
103
130
  "@deepseek-ai/cordis": ">=4.0.1",
104
- "@deepseek-ai/dsh-invariants": ">=0.1.2-alpha.1"
131
+ "@deepseek-ai/dsh-invariants": ">=0.1.2-alpha.2"
105
132
  },
106
133
  "publishConfig": {
107
134
  "access": "public"
@@ -113,5 +140,5 @@
113
140
  },
114
141
  "type": "module",
115
142
  "types": "lib/types/index.d.ts",
116
- "version": "0.1.0-rc.11"
143
+ "version": "0.1.0-rc.13"
117
144
  }