dsh-yolo-mode 0.5.2-beta.0 → 0.5.3

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/CHANGELOG.md CHANGED
@@ -2,17 +2,48 @@
2
2
 
3
3
  本项目遵循 [Semantic Versioning](https://semver.org/)。
4
4
 
5
- ## [0.5.2-beta.0] - 2026-09-24
5
+ ## [0.5.3] - 2026-09-25
6
+
7
+ ### 兼容:适配 DSH 0.1.7-rc.2
8
+
9
+ - 在本机 **0.1.7-rc.2** 上真实装载运行通过:全部入口激活、零错误、无 pending
10
+ (`did not activate` 告警不出现);设置读写(`settingsView` / `settingsMutate`
11
+ 乐观锁)实测往返成功。`dsh.compatibility.dshReleases` 新增
12
+ `"0.1.7-rc.2": "compatible"`;README 徽章与兼容性说明同步。
13
+ - 0.1.7-rc.1 → rc.2 的官方 `@deepseek-ai/dsh-*` 公开 API **无移除、无改名**
14
+ (`dsh-settings` / `dsh-client-connection` / `dsh-client-ui-slots` 逐字节相同,
15
+ 其余为增量新增),本插件无源码适配需求。
16
+
17
+ ### 修复:设置页「供应商」下拉为空
18
+
19
+ 设置页 `judgeProvider` 下拉始终为空。根因:0.1.7 起客户端 `connection.api.llm`
20
+ 已不存在,store 构造时 `this.llm` 恒为 `null`,`_fetchLlmDirectory()` 直接返回空数组。
21
+ 本次改为经客户端 Remote 服务读取:
22
+
23
+ - **供应商**:`ctx.remote.llm.listProviders()`(已注册路由)与
24
+ `listConfigurableProviders()`(已声明可配置)经 `joinProviderDirectory` 合并为与官方
25
+ settings-models 页一致的 `{provider, displayName}` 行。
26
+ - **模型**:`ctx.remote.session.modelCatalog()` 的 `groups`(按 provider 分组),
27
+ 与官方同一数据源。
28
+ - **inject**:`package.json` 的 `dsh.client.inject` 与客户端 `inject` 数组新增
29
+ `"remote.llm"`。
30
+ - **降级保留**:无 `remote.llm` 命名空间时回退旧 `connection.api.llm`;目录读取失败
31
+ 不致命,仍回退自由文本输入(既有设计不变)。
6
32
 
7
- ### Beta(DSH 0.1.7-rc.1 适配,测试版)
33
+ ### 测试
34
+
35
+ - 新增 `store-logic.joinProviderDirectory` 与 4 项 `YoloStore` `remote.llm` /
36
+ `remote.session` 单测(目录填充、失败非致命、legacy 回退、remote 优先);
37
+ `npm test` 137 项全绿。
38
+ - 本机无浏览器,客户端 UI 未在浏览器中实际渲染验证;已核对 `npm pack` 产物经
39
+ 0.1.7-rc.2 profile 装载后**被服务的**客户端 bundle 含 `remote.llm.listProviders`
40
+ / `listConfigurableProviders` / `session.modelCatalog`,且宿主 `llm/listProviders`、
41
+ `session/modelCatalog` 实测返回非空目录(供应商下拉将填充 5 项)。
42
+
43
+ ### Beta 说明
8
44
 
9
- - 本分支(`dev-0.1.7.rc1`,尚未合并 `main`)相对 `main` 的适配改动:设置子系统按
10
- 0.1.7 的 `SettingsForms` 新模型重写(`lib/settings.js` / `lib/index.js` /
11
- `lib/remote.js`),`@deepseek-ai/dsh-llm`、`dsh-timeout`、`dsh-settings`、
12
- `dsh-client-connection`、`dsh-client-ui-slots`、`dsh-client-locale` 的 peer 范围升至
13
- `^0.1.7-rc.1`,`dsh.compatibility.dshReleases` 新增 `"0.1.7-rc.1": "compatible"`,
14
- README 徽章与兼容性说明同步。详见下方 `0.5.2` 条目。
15
- - 发布为 npm 测试版(`--tag beta`);`latest` 保持不变。正式版 `0.5.2` 待 `main` 合并后发布。
45
+ - 测试版 `0.5.2-beta.0`(`--tag beta`)的内容——设置子系统迁移至 DSH 0.1.7 的
46
+ `SettingsForms`——随本版一并正式发布,详见下方 `0.5.2` 条目。
16
47
 
17
48
  ## [0.5.2] - 2026-09-24
18
49
 
package/README.md CHANGED
@@ -6,10 +6,12 @@
6
6
 
7
7
  [![npm version](https://img.shields.io/npm/v/dsh-yolo-mode)](https://www.npmjs.com/package/dsh-yolo-mode)
8
8
  [![license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
9
- [![DeepSeek Harness](https://img.shields.io/badge/DSH%200.1.5--rc.1%20%2F%20rc.2%20%2F%200.1.6--alpha.2%20%2F%200.1.7--rc.1-blue)](https://github.com/deepseek-ai/deepseek-harness)
9
+ [![DeepSeek Harness](https://img.shields.io/badge/DSH%200.1.5--rc.1%20%2F%20rc.2%20%2F%200.1.6--alpha.2%20%2F%200.1.7--rc.1%20%2F%20rc.2-blue)](https://github.com/deepseek-ai/deepseek-harness)
10
10
  [![Awesome DSH Plugin](https://awesome-dsh-plugin.com/badge.svg)](https://awesome-dsh-plugin.com)
11
11
 
12
- > **兼容性**:v0.5.2 支持 DSH **0.1.5-rc.1+**,已在 **0.1.5-rc.1 / 0.1.5-rc.2 / 0.1.6-alpha.2 / 0.1.7-rc.1** 实测(真实-Cordis 探针通过;设置子系统已迁移至 0.1.7 的 `SettingsForms`——插件 Config schema + volatile 热更 + 自建设置页)。旧版 DSH(0.1.0-rc.6 / rc.8)请使用最后兼容的 npm 版本 **0.4.1**。
12
+ > **维护状态**:官方已在 DSH 中提供实验性 Auto review 能力(`@deepseek-ai/dsh-experimental-auto-review`,LLM 逐工具授权审查,在 `ask` 审批策略下替代人工审批),与本插件的「LLM 裁判自动审批」功能重叠。因此本插件**可能在未来停止维护**;如需官方原生的自动审批,可评估该实验性功能。当前版本仍会跟进 DSH 兼容(最近实测 **0.1.7-rc.2**)。
13
+
14
+ > **兼容性**:v0.5.3 支持 DSH **0.1.5-rc.1+**,已在 **0.1.5-rc.1 / 0.1.5-rc.2 / 0.1.6-alpha.2 / 0.1.7-rc.1 / 0.1.7-rc.2** 实测(真实-Cordis 探针通过;设置子系统已迁移至 0.1.7 的 `SettingsForms`——插件 Config schema + volatile 热更 + 自建设置页;0.1.7-rc.2 上 provider/model 目录改由 client `remote.llm` + `remote.session` 读取)。旧版 DSH(0.1.0-rc.6 / rc.8)请使用最后兼容的 npm 版本 **0.4.1**。
13
15
 
14
16
  ---
15
17
 
@@ -234,6 +234,42 @@ window.__ModuleLoader__.load({
234
234
  if (code === "settings-rejected" || code === "schema-validation") return "rejected";
235
235
  return "fatal";
236
236
  }
237
+ /**
238
+ * Join the live provider routes (`remote.llm.listProviders`, rows `{id, name}`)
239
+ * with the declared configurable providers
240
+ * (`remote.llm.listConfigurableProviders`, rows `{provider, displayName, …}`)
241
+ * into one directory of `{ provider, displayName }` rows the select consumes.
242
+ * Declared entries lead (so a configured-but-not-yet-registered provider still
243
+ * appears), then any registered route the declaration does not name. Mirrors
244
+ * the official settings-models `joinProviderDirectory`.
245
+ */
246
+ function joinProviderDirectory(registered, declared) {
247
+ const routes = Array.isArray(registered) ? registered : [];
248
+ const directory = Array.isArray(declared) ? declared : [];
249
+ const rows = [];
250
+ const named = /* @__PURE__ */ new Set();
251
+ for (const entry of directory) {
252
+ if (entry === null || typeof entry !== "object") continue;
253
+ if (typeof entry.provider !== "string" || entry.provider === "") continue;
254
+ named.add(entry.provider);
255
+ rows.push({
256
+ provider: entry.provider,
257
+ displayName: typeof entry.displayName === "string" && entry.displayName !== "" ? entry.displayName : void 0,
258
+ active: routes.some((route) => route && route.id === entry.provider)
259
+ });
260
+ }
261
+ for (const route of routes) {
262
+ if (route === null || typeof route !== "object") continue;
263
+ if (typeof route.id !== "string" || route.id === "") continue;
264
+ if (named.has(route.id)) continue;
265
+ rows.push({
266
+ provider: route.id,
267
+ displayName: typeof route.name === "string" && route.name !== "" ? route.name : void 0,
268
+ active: true
269
+ });
270
+ }
271
+ return rows;
272
+ }
237
273
  //#endregion
238
274
  //#region src/client/store.js
239
275
  /**
@@ -266,9 +302,9 @@ window.__ModuleLoader__.load({
266
302
  writable: true,
267
303
  error: void 0,
268
304
  open: false,
269
- /** Configurable provider directory (llm.providers). */
305
+ /** Provider directory: remote.llm joined rows, or legacy llm.providers. */
270
306
  providers: [],
271
- /** Model catalog groups (llm.models). */
307
+ /** Model catalog groups: remote.session.modelCatalog, or legacy llm.models. */
272
308
  models: []
273
309
  };
274
310
  }
@@ -279,14 +315,20 @@ window.__ModuleLoader__.load({
279
315
  * @param {{ call: (channel: string, endpoint: string, payload: any) => Promise<any> }} options.rpc
280
316
  * rpc.call(channel, endpoint, payload) resolves to { ok: true, value } |
281
317
  * { ok: false, error }.
282
- * @param {object|null} [options.llm] - optional `connection.api.llm` face
318
+ * @param {object|null} [options.llm] - optional legacy `connection.api.llm` face
283
319
  * ({ providers(), models() } returning { result: { ok, value } }); when null
284
320
  * the directory stays empty and the judge fields fall back to free text.
321
+ * @param {object|null} [options.remote] - optional client Remote service; when
322
+ * it carries an `llm` namespace the directory comes from
323
+ * `llm.listProviders()` + `llm.listConfigurableProviders()` (0.1.7+) and the
324
+ * model catalog from `session.modelCatalog()`. Falls back to `llm` when the
325
+ * Remote namespace is absent.
285
326
  */
286
327
  var YoloStore = class {
287
- constructor({ rpc, llm }) {
328
+ constructor({ rpc, llm, remote }) {
288
329
  this.rpc = rpc;
289
330
  this.llm = llm == null ? null : llm;
331
+ this.remote = remote == null ? null : remote;
290
332
  this._state = initialYoloState();
291
333
  this._listeners = /* @__PURE__ */ new Set();
292
334
  this._generation = 0;
@@ -331,12 +373,54 @@ window.__ModuleLoader__.load({
331
373
  if (error !== null && typeof error === "object" && typeof error.code === "string") return error.code;
332
374
  }
333
375
  /**
334
- * Fetch the optional LLM directory (provider list + model catalog) when the
335
- * store was constructed with an llm face. Directory failures are NOT fatal:
336
- * they leave the snapshot's providers/models empty without flipping status
337
- * to 'error' — only the settings/status bridge calls can do that.
376
+ * Fetch the optional LLM directory (provider list + model catalog).
377
+ *
378
+ * 0.1.7+ exposes it through the client Remote service: the provider directory
379
+ * is the join of `remote.llm.listProviders()` (registered routes) and
380
+ * `remote.llm.listConfigurableProviders()` (declared providers), and the model
381
+ * catalog is `remote.session.modelCatalog().value.groups` — the same sources
382
+ * the official settings-models page reads. Older hosts without a Remote `llm`
383
+ * namespace fall back to the legacy `connection.api.llm` face.
384
+ *
385
+ * Directory failures are NOT fatal: they leave the snapshot's providers/models
386
+ * empty without flipping status to 'error' — only the settings/status bridge
387
+ * calls can do that.
338
388
  */
339
389
  async _fetchLlmDirectory() {
390
+ const fromRemote = await this._fetchRemoteDirectory();
391
+ if (fromRemote !== void 0) return fromRemote;
392
+ return await this._fetchLegacyDirectory();
393
+ }
394
+ /**
395
+ * Read the directory from the client Remote service. Returns undefined when
396
+ * no `remote.llm` namespace is present, so the caller can fall back.
397
+ */
398
+ async _fetchRemoteDirectory() {
399
+ const llm = this.remote ? this.remote.llm : null;
400
+ if (llm === null || llm === void 0) return void 0;
401
+ let providers = [];
402
+ let models = [];
403
+ try {
404
+ const [registered, declared] = await Promise.all([typeof llm.listProviders === "function" ? llm.listProviders() : void 0, typeof llm.listConfigurableProviders === "function" ? llm.listConfigurableProviders() : void 0]);
405
+ providers = joinProviderDirectory(registered && registered.ok === true && Array.isArray(registered.value) ? registered.value : [], declared && declared.ok === true && Array.isArray(declared.value) ? declared.value : []);
406
+ } catch {
407
+ providers = [];
408
+ }
409
+ const session = this.remote ? this.remote.session : null;
410
+ if (session && typeof session.modelCatalog === "function") try {
411
+ const response = await session.modelCatalog();
412
+ const value = response && response.ok === true ? response.value : void 0;
413
+ if (value && Array.isArray(value.groups)) models = value.groups;
414
+ } catch {
415
+ models = [];
416
+ }
417
+ return {
418
+ providers,
419
+ models
420
+ };
421
+ }
422
+ /** Legacy directory read for hosts whose transport still exposes `api.llm`. */
423
+ async _fetchLegacyDirectory() {
340
424
  if (this.llm === null || this.llm === void 0) return {
341
425
  providers: [],
342
426
  models: []
@@ -1349,13 +1433,15 @@ window.__ModuleLoader__.load({
1349
1433
  */
1350
1434
  /**
1351
1435
  * Services required by these slot registrations (dsh.client.inject is the same
1352
- * short-name set): slots, locale, connection, remote.
1436
+ * short-name set): slots, locale, connection, remote, remote.llm. The dotted
1437
+ * `remote.llm` namespace carries the provider/model directory on 0.1.7+.
1353
1438
  */
1354
1439
  const inject = [
1355
1440
  "slots",
1356
1441
  "locale",
1357
1442
  "connection",
1358
- "remote"
1443
+ "remote",
1444
+ "remote.llm"
1359
1445
  ];
1360
1446
  /**
1361
1447
  * Register the YOLO section/chip/popup once the slot declarations are on the
@@ -1374,6 +1460,7 @@ window.__ModuleLoader__.load({
1374
1460
  const t = ctx.locale.bind(NS);
1375
1461
  const store = new YoloStore({
1376
1462
  rpc: connection.rpc,
1463
+ remote: ctx.get("remote") ?? null,
1377
1464
  llm: connection.api ? connection.api.llm : null
1378
1465
  });
1379
1466
  const useSnapshot = bindSnapshotSelector(store);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-yolo-mode",
3
- "version": "0.5.2-beta.0",
3
+ "version": "0.5.3",
4
4
  "description": "dsh-yolo-mode —— DeepSeek Harness 双面包插件:当会话处于可写沙箱模式且审批策略为 ask 时,用大模型自动裁决沙箱升权申请,支持内置预设与自定义权限层级,并提供宿主 settings + 自发布设置桥(/yolo-mode)与 Web 客户端 UI。",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -74,7 +74,8 @@
74
74
  "slots",
75
75
  "locale",
76
76
  "connection",
77
- "remote"
77
+ "remote",
78
+ "remote.llm"
78
79
  ]
79
80
  },
80
81
  "compatibility": {
@@ -82,7 +83,8 @@
82
83
  "0.1.5-rc.1": "compatible",
83
84
  "0.1.5-rc.2": "compatible",
84
85
  "0.1.6-alpha.2": "compatible",
85
- "0.1.7-rc.1": "compatible"
86
+ "0.1.7-rc.1": "compatible",
87
+ "0.1.7-rc.2": "compatible"
86
88
  },
87
89
  "node": ">=20"
88
90
  }