dsh-plugin-marketplace 0.2.6 → 0.2.7

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 CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Scorp1o117
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.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Scorp1o117
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/README.md CHANGED
@@ -50,13 +50,10 @@ Manual mount in `$DSH_HOME/profiles/web/cordis.patch.yml`:
50
50
  Then restart `dsh web` (new client plugins require a process restart to be
51
51
  scanned into the browser roster) and open **Settings → Plugin Marketplace**.
52
52
 
53
- **If the install button answers `settings namespace "plugin-marketplace" is
54
- not exposed to configuration clients`**: the host apiproxy only lets a
55
- hard-coded allowlist through, and this plugin patches that allowlist on its
56
- first boot — the running process still answers `settings-not-exposed` until
57
- `dsh web` is restarted. Restart once; if the error persists, check the boot
58
- log for `[settings-expose]` lines (the fix line names the file to edit —
59
- `WEB_SETTINGS_NAMESPACES` in `dsh-host-apiproxy/lib/index.js`).
53
+ DSH `0.1.1-rc.1` and newer expose every registered settings namespace, so the
54
+ marketplace works without patching official files. Older hosts that return
55
+ `settings-not-exposed` should be upgraded instead of modifying
56
+ `dsh-host-apiproxy` in `node_modules`.
60
57
 
61
58
  ## How it works
62
59
 
package/README.zh.md CHANGED
@@ -41,11 +41,9 @@ dsh plugin --profile web add dsh-plugin-marketplace
41
41
 
42
42
  然后重启 `dsh web`(新客户端插件需要重启进程才会被扫描进浏览器清单),打开 **设置 → 插件市场**。
43
43
 
44
- **如果点安装按钮报 `settings namespace "plugin-marketplace" is not exposed to
45
- configuration clients`**:宿主 apiproxy 只放行硬编码白名单里的命名空间,本插件会在
46
- 首次启动时自动把命名空间补进白名单——但当前进程要到**重启 `dsh web`** 之后才会放行。
47
- 重启一次即可;若重启后仍报错,看启动日志里的 `[settings-expose]` 提示(它会指出要手动
48
- 编辑的文件:`dsh-host-apiproxy/lib/index.js` 的 `WEB_SETTINGS_NAMESPACES`)。
44
+ DSH `0.1.1-rc.1` 起会公开全部已注册的 settings 命名空间,插件市场无需再修改官方文件。
45
+ 旧宿主若返回 `settings-not-exposed`,请升级 DSH,不要手动修改 `node_modules` 中的
46
+ `dsh-host-apiproxy`。
49
47
 
50
48
  ## 实现方式
51
49
 
package/client.js CHANGED
@@ -82,7 +82,7 @@ window.__ModuleLoader__.load({
82
82
  aiExplain: "🤖 AI 解释",
83
83
  aiExplaining: "AI 解释中,请稍候…",
84
84
  aiExplainErr: "AI 解释失败:{msg}",
85
- notExposed: "设置通道未就绪:插件市场的命名空间还没被配置客户端放行。刚安装/升级过的话,请重启 dsh web;若重启后仍报错,请查看启动日志里的 [settings-expose] 提示(可能需要手动把 \"plugin-marketplace\" 加入 dsh-host-apiproxy 的 WEB_SETTINGS_NAMESPACES)。"
85
+ notExposed: "当前 DSH 版本没有公开插件市场的设置通道;请升级到 DSH 0.1.1-rc.1 或更高版本并重启 dsh web。"
86
86
  };
87
87
  var en = {
88
88
  nav: "Plugin Marketplace",
@@ -113,7 +113,7 @@ window.__ModuleLoader__.load({
113
113
  aiExplain: "🤖 AI Explain",
114
114
  aiExplaining: "AI is explaining…",
115
115
  aiExplainErr: "AI explain failed: {msg}",
116
- notExposed: "Settings channel not ready: the plugin-marketplace namespace is not yet exposed to configuration clients. If you just installed/upgraded, restart dsh web; if it persists, check the [settings-expose] lines in the boot log (you may need to add \"plugin-marketplace\" to WEB_SETTINGS_NAMESPACES in dsh-host-apiproxy/lib/index.js manually)."
116
+ notExposed: "This DSH version does not expose the plugin-marketplace settings channel. Upgrade to DSH 0.1.1-rc.1 or newer and restart dsh web."
117
117
  };
118
118
 
119
119
  // ── GitHub API ────────────────────────────────────────────────────────
@@ -297,8 +297,8 @@ window.__ModuleLoader__.load({
297
297
  var un = typeof scope.subscribe === "function" ? scope.subscribe(sync) : null;
298
298
  return function () { alive = false; if (un) un(); if (scope.dispose) scope.dispose(); };
299
299
  }, [scope]);
300
- // settings-not-exposed means the host allowlist gate refused the write:
301
- // explain the restart/manual-fix path instead of showing the raw code.
300
+ // Older hosts can still return settings-not-exposed. Recommend upgrading
301
+ // instead of mutating the installed DSH package on disk.
302
302
  var mutateError = function (detail, fallback) {
303
303
  if (detail && detail.code === "settings-not-exposed") return t("notExposed");
304
304
  return String(detail && (detail.message || detail.code) || fallback);
package/index.js CHANGED
@@ -17,7 +17,6 @@ import os from "node:os";
17
17
  import z from "@deepseek-ai/schemastery";
18
18
  import { BlockAssembler, createUserMessage } from "@deepseek-ai/dsh-llm";
19
19
  import { installSettingsSection, settingsNamespace } from "@deepseek-ai/dsh-settings";
20
- import { ensureSettingsNamespaceExposed } from "./vendor/dsh-settings-expose.js";
21
20
 
22
21
  /** Cordis plugin name. */
23
22
  const name = "plugin-marketplace";
@@ -78,8 +77,6 @@ function apply(ctx, config) {
78
77
 
79
78
  // dsh-host-apiproxy hard-codes which namespaces the Web client may touch;
80
79
  // patch the allowlist idempotently so the client can write install requests.
81
- ensureSettingsNamespaceExposed(ctx, "plugin-marketplace", ctx.logger);
82
-
83
80
  /** Resolved current config (settings layer over the entry). */
84
81
  function current() {
85
82
  return sourceGetter ? sourceGetter() : config;
@@ -214,7 +211,10 @@ function apply(ctx, config) {
214
211
  await report("running", `installing ${pkg}…`, pkg);
215
212
  const result = await runInstall(pkg, profile);
216
213
  if (result.code !== 0) {
217
- const tail = (result.stderr || result.stdout || "").trim().split("\n").slice(-3).join(" ");
214
+ const output = (result.stderr || result.stdout || "").trim();
215
+ const tail = output.includes("ERR_PNPM_IGNORED_BUILDS")
216
+ ? "dependency build scripts were blocked by pnpm; the plugin author must make native build dependencies opt-in"
217
+ : output.split("\n").slice(-3).join(" ");
218
218
  ctx.logger.warn(`[plugin-marketplace] install failed (${result.code}): ${tail}`);
219
219
  await report("error", `install failed: ${tail || "unknown error"}`, pkg);
220
220
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-marketplace",
3
- "version": "0.2.6",
3
+ "version": "0.2.7",
4
4
  "description": "DeepSeek Harness Web UI 内置插件市场:在设置页直接浏览 github.com/topics/dsh-plugin,支持搜索、按 Star 排序、查看安装方式。",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -47,10 +47,10 @@
47
47
  },
48
48
  "peerDependencies": {
49
49
  "react": "^18.2.0",
50
- "@deepseek-ai/dsh-settings": "^0.1.0-rc.6",
51
- "@deepseek-ai/dsh-llm": "^0.1.0-rc.6"
50
+ "@deepseek-ai/dsh-settings": "^0.1.0-rc.6 || ^0.1.1-rc.1",
51
+ "@deepseek-ai/dsh-llm": "^0.1.0-rc.6 || ^0.1.1-rc.1"
52
52
  },
53
53
  "dependencies": {
54
54
  "@deepseek-ai/schemastery": "^3.18.1"
55
55
  }
56
- }
56
+ }
@@ -1,106 +0,0 @@
1
- /**
2
- * dsh-host-apiproxy exposes only namespaces listed in its hard-coded
3
- * WEB_SETTINGS_NAMESPACES allowlist to the Web settings client. A namespace
4
- * registered by a third-party plugin answers `settings-not-exposed` even
5
- * though it is registered — upstream explicitly defers letting plugins
6
- * expose their own configuration.
7
- *
8
- * This module idempotently patches that allowlist in the dsh installation
9
- * actually loaded by the host process, so the plugin's settings section
10
- * becomes visible in the Web UI without manual edits. A dsh update
11
- * overwrites the file; the next plugin start re-patches it.
12
- *
13
- * NOTE: dsh-host-apiproxy is an ESM package, so it never appears in the
14
- * CommonJS `Module._cache` (lookup 1 only helps CJS hosts). Lookup 2 anchors
15
- * on the running dsh bin, which always resolves the apiproxy as the app's
16
- * own dependency; lookup 3 walks up from `@deepseek-ai/dsh-settings` for
17
- * other npm layouts. pnpm-installed hosts resolve into an immutable store —
18
- * the write then fails and the manual instruction below applies.
19
- *
20
- * Also note that patching the file only affects the NEXT process start: the
21
- * running apiproxy already evaluated its allowlist at module load, so a
22
- * settings channel opened mid-session still answers `settings-not-exposed`
23
- * until `dsh web` is restarted.
24
- */
25
- import { existsSync, readFileSync, writeFileSync } from "node:fs";
26
- import { createRequire } from "node:module";
27
- import { dirname, join, sep } from "node:path";
28
-
29
- /**
30
- * Ensure `nsName` is present in dsh-host-apiproxy's WEB_SETTINGS_NAMESPACES.
31
- * No-op when already exposed or when the file cannot be located/patched.
32
- * @param {import("cordis").Context} ctx
33
- * @param {string} nsName - settings namespace short name (e.g. "tdai-memory").
34
- * @param {{info?: Function, warn?: Function}} logger - dsh logger.
35
- */
36
- export function ensureSettingsNamespaceExposed(ctx, nsName, logger) {
37
- void ctx;
38
- try {
39
- const target = findApiproxyIndex();
40
- if (!target) {
41
- logger?.warn?.(`[settings-expose] could not locate dsh-host-apiproxy in this dsh install; the "${nsName}" settings channel will answer "not exposed". Fix: add "${nsName}" to WEB_SETTINGS_NAMESPACES in <dsh>/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/index.js and restart dsh web`);
42
- return;
43
- }
44
- let src;
45
- try {
46
- src = readFileSync(target, "utf8");
47
- } catch (error) {
48
- logger?.warn?.(`[settings-expose] cannot read ${target}: ${String(error)}`);
49
- return;
50
- }
51
- const body = src.match(/const WEB_SETTINGS_NAMESPACES = \[([\s\S]*?)\];/)?.[1] ?? "";
52
- if (body.includes(`"${nsName}"`)) return; // already exposed (manual or previous patch)
53
- const patched = src.replace(/(const WEB_SETTINGS_NAMESPACES = \[[\s\S]*?)(\n\s*\];)/, (_, pre, post) => {
54
- const trailingComma = /,\s*$/.test(pre) ? "" : ",";
55
- const sep2 = pre.trimEnd().endsWith("[") ? "" : trailingComma;
56
- return `${pre}${sep2}\n\t"${nsName}"${post}`;
57
- });
58
- if (patched === src) {
59
- logger?.warn?.(`[settings-expose] allowlist pattern not found in ${target}; add "${nsName}" to WEB_SETTINGS_NAMESPACES manually`);
60
- return;
61
- }
62
- writeFileSync(target, patched, "utf8");
63
- logger?.info?.(`[settings-expose] added "${nsName}" to WEB_SETTINGS_NAMESPACES (${target}) — restart dsh web: the settings channel opens only in the NEXT process start`);
64
- } catch (error) {
65
- logger?.warn?.(`[settings-expose] failed to expose "${nsName}" (${String(error)}); add it to WEB_SETTINGS_NAMESPACES in dsh-host-apiproxy/lib/index.js manually, then restart dsh web`);
66
- }
67
- }
68
-
69
- function findApiproxyIndex() {
70
- // 1) The host process has already loaded dsh-host-apiproxy: read the real
71
- // module path from the CommonJS module cache (any install layout; ESM
72
- // hosts — every modern dsh — skip this).
73
- try {
74
- const Module = createRequire(import.meta.url)("module");
75
- const cache = Module._cache ?? {};
76
- for (const key of Object.keys(cache)) {
77
- if (key.includes(`${sep}dsh-host-apiproxy${sep}`) && key.endsWith(`${sep}index.js`)) return key;
78
- }
79
- } catch { /* fall through */ }
80
- // 2) Resolve the apiproxy as a dependency of the running dsh app: the bin
81
- // (`node <dsh>/lib/bin.js`) anchors the app root in both shipped and
82
- // source layouts, and dsh-host-apiproxy is always one of its deps.
83
- try {
84
- const appRoot = dirname(dirname(process.argv[1] ?? ""));
85
- const requireFromApp = createRequire(join(appRoot, "package.json"));
86
- const entry = requireFromApp.resolve("@deepseek-ai/dsh-host-apiproxy");
87
- if (entry.endsWith(`${sep}index.js`)) return entry;
88
- } catch { /* fall through */ }
89
- // 3) Walk up from @deepseek-ai/dsh-settings: the apiproxy is a scoped
90
- // sibling in the same dependency tree (flat/global and nested layouts).
91
- try {
92
- const require = createRequire(import.meta.url);
93
- const settingsEntry = require.resolve("@deepseek-ai/dsh-settings");
94
- let dir = dirname(settingsEntry);
95
- while (true) {
96
- const scoped = join(dir, "@deepseek-ai", "dsh-host-apiproxy", "lib", "index.js");
97
- if (existsSync(scoped)) return scoped;
98
- const bare = join(dir, "dsh-host-apiproxy", "lib", "index.js");
99
- if (existsSync(bare)) return bare;
100
- const parent = dirname(dir);
101
- if (parent === dir) break;
102
- dir = parent;
103
- }
104
- } catch { /* fall through */ }
105
- return "";
106
- }