dsh-web-search-enhanced 0.1.6 → 0.1.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/CHANGELOG.md CHANGED
@@ -4,6 +4,22 @@
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.1.7] - 2026-10-04
8
+
9
+ ### 配置版本与自动迁移
10
+
11
+ - 沿用 `version` 作为配置 schema 版本,新增前后端共享的当前版本常量与严格判定;独立于插件包版本、宿主版本、并发 revision 和存储版本。
12
+ - 新增逐版本纯迁移入口,显式 V1 和无版本旧模型配置自动执行 1 → 2;无版本连接配置固定兼容为 V2,未来版本及非法版本拒绝读取或提交,不自动降级。
13
+ - 迁移保留已有连接、实时性偏好与显式默认连接;修复跟随会话模式迁移丢失连接配置的问题。
14
+ - 迁移执行中收到配置修改会重新读取最新 revision,继续使用宿主 CAS 提交,避免丢失更新;保留先保存 Credentials、后提交配置的可重试顺序。
15
+ - 客户端编辑与重置拒绝未迁移或未来版本,补充版本判定、输入不变、幂等、真实宿主重启及并发迁移回归。
16
+ - 新增[配置版本设计](docs/config-versioning.zh-CN.md),说明扩展步骤、失败恢复与跨服务事务边界。
17
+
18
+ ### 升级说明
19
+
20
+ - 包版本推进为 0.1.7;配置 version 2、会话 Storage Domain version 1、DSH 0.2.0-rc.2 基线均不变。现有 V2 配置无需格式转换,旧配置自动迁移不影响已有会话选择。
21
+ - 升级前备份 profile 和凭据;安装后重载服务端插件并刷新 Web 页面。
22
+
7
23
  ## [0.1.6] - 2026-09-30
8
24
 
9
25
  ### DSH 0.2.0-rc.2 兼容性
package/README.md CHANGED
@@ -63,16 +63,16 @@
63
63
  - **DeepSeek Harness**:≥ `0.2.0-rc.2`
64
64
  - **Node.js**:`^22.19.0 || >=24.0.0`
65
65
 
66
- 本版将 DSH 基线提升到 0.2.0-rc.2,保留动态配置、插件设置页和会话 projection 架构,无需新的配置或存储迁移。跟随模型仍要求 API Key;使用 pi-ai 内置 DeepSeek 目录时,请重新选择 `deepseek-flash` 并检查旧模型 overrides,本插件不会自动改名。详见[0.2.0-rc.2 影响评估](docs/upstream-0.2.0-rc.2-assessment.zh-CN.md)。升级前请备份 profile 和旧设置。
66
+ 本版沿用 DSH 0.2.0-rc.2 基线,完善配置版本判定与逐版本自动迁移;现有 V2 配置和会话存储格式不变,显式 V1 与无版本旧模型配置可自动升级。详见[配置版本设计](docs/config-versioning.zh-CN.md)。跟随模型仍要求 API Key;使用 pi-ai 内置 DeepSeek 目录时,请重新选择 `deepseek-flash` 并检查旧模型 overrides,本插件不会自动改名。详见[0.2.0-rc.2 影响评估](docs/upstream-0.2.0-rc.2-assessment.zh-CN.md)。升级前请备份 profile 和旧设置。
67
67
 
68
68
  ### 步骤 1:安装插件
69
69
 
70
70
  **方式 A:通过 GitHub Release 离线包安装(推荐)**
71
71
 
72
- 当前版本为 **0.1.6**,最低支持 **DSH 0.2.0-rc.2**。发布后可从 [Releases](https://github.com/Yurzi/dsh-web-search-enhanced/releases) 下载对应版本安装包及 SHA256 校验文件;也可执行 `pnpm install --frozen-lockfile && pnpm run check && pnpm pack` 自行构建。使用绝对路径安装:
72
+ 当前版本为 **0.1.7**,最低支持 **DSH 0.2.0-rc.2**。发布后可从 [Releases](https://github.com/Yurzi/dsh-web-search-enhanced/releases) 下载对应版本安装包及 SHA256 校验文件;也可执行 `pnpm install --frozen-lockfile && pnpm run check && pnpm pack` 自行构建。使用绝对路径安装:
73
73
 
74
74
  ```sh
75
- dsh plugin --profile web add /path/to/dsh-web-search-enhanced-0.1.6.tgz
75
+ dsh plugin --profile web add /path/to/dsh-web-search-enhanced-0.1.7.tgz
76
76
  ```
77
77
 
78
78
  **方式 B:通过 npm 在线安装**
@@ -80,10 +80,10 @@ dsh plugin --profile web add /path/to/dsh-web-search-enhanced-0.1.6.tgz
80
80
  该版本发布到 npm 后,也可直接安装:
81
81
 
82
82
  ```sh
83
- dsh plugin --profile web add dsh-web-search-enhanced@0.1.6
83
+ dsh plugin --profile web add dsh-web-search-enhanced@0.1.7
84
84
  ```
85
85
 
86
- 已安装旧版时,DSH rc.2 不支持直接自动升级:先备份配置和存储,再通过插件管理器移除旧版并安装 0.1.6,核对 profile 补丁与会话选择。Desktop profile 需先启动过一次桌面端。完整步骤见[升级指南](docs/migration.zh-CN.md)。
86
+ 已安装旧版时,DSH rc.2 不支持直接自动升级:先备份配置和存储,再通过插件管理器移除旧版并安装 0.1.7,核对 profile 补丁与会话选择。Desktop profile 需先启动过一次桌面端。完整步骤见[升级指南](docs/migration.zh-CN.md)。
87
87
 
88
88
  ### 步骤 2:生效与刷新
89
89
 
@@ -0,0 +1,50 @@
1
+ # 插件配置版本与自动迁移设计
2
+
3
+ ## 决策
4
+
5
+ 需求合理。沿用已有顶层 `version` 作为 schema version,不另设 `schemaVersion`,避免双字段冲突。当前版本为整数 **2**,由共享的 `CURRENT_CONFIG_VERSION` 管理。它与 npm 包版本、宿主版本、SettingsForms revision(并发控制)、会话 Storage Domain version 相互独立。
6
+
7
+ 不因每次发布而递增;只有配置结构或解释语义发生不兼容变化时递增。新增兼容的可选字段一般不递增。
8
+
9
+ ## 版本判定
10
+
11
+ | 输入 | 行为 |
12
+ | --- | --- |
13
+ | 无版本且包含历史模型字段 | 视为 V1,自动迁移 |
14
+ | 显式 version: 1 | 自动执行 1 → 2,即使没有其他历史字段 |
15
+ | 无版本的连接配置或空配置 | 固定视为历史 V2;不因启动写入版本覆盖 |
16
+ | version: 2 | 校验后直接使用,无重复迁移 |
17
+ | 高于当前版本 | 拒绝读取/提交,不尝试降级或重置 |
18
+ | 非正安全整数、字符串、null | 拒绝,不猜测版本 |
19
+
20
+ 显式版本优先于字段启发式判定。无版本连接格式永久映射到 **2**,以后升级到 V3 也不能把它直接认作 V3。设置卡片实际写入新值时补齐当前版本;无操作或恢复继承不制造无意义覆盖。手工编写的配置建议始终声明版本。版本字段不能设置 schema 默认值,否则宿主合并默认值可能把旧配置伪装成新版。
21
+
22
+ ## 迁移流程
23
+
24
+ 1. Loader schema 接受数字版本,让已知旧版本能够进入迁移校验;插件负责严格的版本范围判定。
25
+ 2. `migrateConfig` 克隆输入,按注册表顺序执行 N → N+1 的纯转换,检查每一步输出版本,最后校验当前连接结构。失败不修改输入,不执行 I/O。
26
+ 3. V1 转换保留现有连接、freshness、显式 defaultConnection 等非历史字段;只有没有显式默认时才选择导入的连接。已有 custom:legacy 冲突则拒绝,而非覆盖。旧 fallbackModel 不再转为备用路由。
27
+ 4. 宿主启动完成及本插件设置更新后,读取该条目的实时 descriptor。仅需要升级时生成迁移结果。
28
+ 5. 对旧明文 Key,先验证无秘密的转换结果,再确保 Credentials 中已有相同值或完成写入;不同值不覆盖。配置版本判定在剥离 Key 前进行,避免仅有 apiKey 的旧配置被误认作 V2。
29
+ 6. 使用宿主 SettingsForms.replace(namespace, migrated, revision) 提交,只修改本插件条目。版本与转换结果一起提交,不先单独写版本。
30
+ 7. 单实例迁移串行执行,执行中收到更新会标记待处理;结束后重新读取最新 revision。CAS 冲突不会覆盖新配置。失败的相同 revision 不持续重试;配置更新、凭据服务重新挂载或插件重启可重试。
31
+ 8. 未迁移完成的旧配置不执行搜索;未来版本由配置校验拒绝。客户端设置编辑和重置也拒绝未迁移/未来版本。
32
+
33
+ ## 边界与恢复
34
+
35
+ - 使用宿主已有的配置编辑与持久化契约,不直接写配置文件,不修改宿主源码。
36
+ - Credentials 与 profile 不是跨服务事务:凭据可能已写入而 profile 提交失败。保留该凭据,重试复用;不回滚删除可能被其他操作引用的凭据。
37
+ - 宿主 replace 会与继承层合并,不能保证清除 bundle 源码中的历史字段或秘密;继承层明文 Key 必须由部署者移走。旧配置备份也不由插件自动销毁。
38
+ - 不自动改变已有会话选择,不探测供应商,不新增联网请求;正在运行的搜索仍使用冻结快照。
39
+ - 不支持自动降级。恢复旧插件前应恢复与之匹配的配置备份,而非手工降低版本数字。
40
+ - 对需要新授权、信息丢失或无法可靠推断的未来变更,迁移步骤应明确失败并提示人工处理;“无感”不是静默猜测的理由。
41
+
42
+ ## 后续新增 V3 的方式
43
+
44
+ 1. 将共享当前版本提升为 3,更新当前配置类型、校验器和客户端。
45
+ 2. 在迁移注册表加入 2 → 3 的纯转换,保留原有 1 → 2。历史步骤的输出版本必须固定,不得改成“当前版本”。
46
+ 3. 在需要时为历史输入保留 Loader schema 字段,不能让宿主在迁移前丢弃/拒绝这些字段。
47
+ 4. 添加 V2 → V3、V1 → V3、无版本历史 V2 → V3、幂等、输入不变、失败保留和 CAS 并发测试。
48
+ 5. 若需要新的外部副作用,显式设计执行顺序和可重试性,不把 I/O 放进纯迁移函数。
49
+
50
+ 当前只存在真实的 1 → 2 步骤,不为演示制造无业务意义的 V3。
@@ -1,6 +1,8 @@
1
- # 0.1.6 配置参考
1
+ # 0.1.7 配置参考
2
2
 
3
- 本指南面向安装版插件。包版本为 **0.1.6**,配置格式的 `version` 为 **2**;两者不是同一版本号。快速开始见 [README](../README.md),旧版用户先读[升级指南](migration.zh-CN.md)。
3
+ 本指南面向安装版插件。包版本为 **0.1.7**,配置格式的 `version` 为 **2**;两者不是同一版本号。快速开始见 [README](../README.md),旧版用户先读[升级指南](migration.zh-CN.md)。
4
+
5
+ 配置版本判定、兼容策略和后续迁移开发方式见[配置版本设计](config-versioning.zh-CN.md)。`version: 1` 会自动迁移;高于当前版本或非法版本会被拒绝,绝不自动降级。
4
6
 
5
7
  ## 配置入口与作用范围
6
8
 
@@ -1,6 +1,6 @@
1
- # 升级到 0.1.6 / DSH 0.2.0-rc.2
1
+ # 升级到 0.1.7 / DSH 0.2.0-rc.2
2
2
 
3
- 0.1.6 将最低宿主版本提高为 **0.2.0-rc.2**,沿用 0.1.3 已完成的 Loader 动态配置、profile-backed SettingsForms、ConfigForms 客户端、惰性 Typert codec 和新版 PTC 适配。从 0.1.3 / 0.1.4 / 0.1.5 升级不需要新的配置或存储迁移;详见 [0.2.0-rc.2 影响评估](upstream-0.2.0-rc.2-assessment.zh-CN.md)。旧版已采用的**会话级搜索连接**保持不变:包版本 0.1.6、设置格式 version 2、会话 Storage Domain version 1 是三个不同概念。完整参数见[配置参考](configuration.zh-CN.md)。
3
+ 0.1.7 沿用最低宿主版本 **0.2.0-rc.2**,沿用 0.1.3 已完成的 Loader 动态配置、profile-backed SettingsForms、ConfigForms 客户端、惰性 Typert codec 和新版 PTC 适配。从 0.1.3 / 0.1.4 / 0.1.5 / 0.1.6 的 V2 配置升级不需要新的配置或存储格式转换,本版增强旧配置迁移的版本识别和并发保护;详见 [0.2.0-rc.2 影响评估](upstream-0.2.0-rc.2-assessment.zh-CN.md)。旧版已采用的**会话级搜索连接**保持不变:包版本 0.1.7、设置格式 version 2、会话 Storage Domain version 1 是三个不同概念。完整参数见[配置参考](configuration.zh-CN.md)。
4
4
 
5
5
  ## 1. 升级前准备
6
6
 
@@ -16,26 +16,28 @@ DSH rc.2 对已安装插件不支持直接自动升级。先完成备份、停
16
16
 
17
17
  若跟随 pi-ai 内置 DeepSeek 目录,升级宿主后重新选择 `deepseek-flash`,检查旧 `deepseek-v4-flash` / `deepseek-v4-flash-vision-exp` 及其 overrides、默认模型和子代理设置。只针对这条目录路由,不机械替换私有端点的 ID;本插件不会改写用户模型配置。
18
18
 
19
- 从当前源码运行 `pnpm install --frozen-lockfile && pnpm run check && pnpm pack`,或使用 [Releases](https://github.com/Yurzi/dsh-web-search-enhanced/releases) 中实际发布的 0.1.6 构建包。使用绝对路径交给 DSH 插件管理器:
19
+ 从当前源码运行 `pnpm install --frozen-lockfile && pnpm run check && pnpm pack`,或使用 [Releases](https://github.com/Yurzi/dsh-web-search-enhanced/releases) 中实际发布的 0.1.7 构建包。使用绝对路径交给 DSH 插件管理器:
20
20
 
21
21
  ```sh
22
- dsh plugin --profile web add /absolute/path/to/dsh-web-search-enhanced-0.1.6.tgz
22
+ dsh plugin --profile web add /absolute/path/to/dsh-web-search-enhanced-0.1.7.tgz
23
23
  ```
24
24
 
25
25
  若该版本已在 npm 发布,也可安装固定版本:
26
26
 
27
27
  ```sh
28
- dsh plugin --profile web add dsh-web-search-enhanced@0.1.6
28
+ dsh plugin --profile web add dsh-web-search-enhanced@0.1.7
29
29
  ```
30
30
 
31
31
  发布附件中的构建 tgz 与 GitHub 自动生成的 Source code archive 不同:后者是源码,不能假定含 `lib/` 构建产物。npm 可用性须以 registry 实际发布结果为准,GitHub 标签 / Release 存在不代表 npm 已完成。
32
32
 
33
33
  安装补丁选择 enhanced-search、禁用默认 web-search-deepseek,并明确将新会话默认设为 Exa;不改 fetchProvider。已有部署请审阅插件管理器反馈和 Web profile,避免重复注册条目,不要用整份示例覆盖所有宿主配置。
34
34
 
35
- 本次未改变插件前后端业务契约,但宿主依赖与构建产物已更新。重新加载插件或重启 DSH,**然后刷新 Web 页面**;只刷新浏览器不足以更新服务端。此操作可能影响运行中任务,应在合适时机进行。
35
+ 本次未改变搜索业务契约和宿主依赖基线,但配置迁移逻辑与前后端构建产物已更新。重新加载插件或重启 DSH,**然后刷新 Web 页面**;只刷新浏览器不足以更新服务端。此操作可能影响运行中任务,应在合适时机进行。
36
36
 
37
37
  ## 3. 启动时自动迁移旧配置
38
38
 
39
+ 配置版本机制沿用 `version`,现已统一到逐版本迁移入口:显式 `version: 1` 与无版本旧模型配置均可自动升级;无版本连接配置保持 V2 兼容,未来版本拒绝降级。迁移保留已有连接、freshness 与显式 defaultConnection,执行中收到并发编辑会在结束后重新读取最新 revision。完整设计与事务边界见[配置版本设计](config-versioning.zh-CN.md)。
40
+
39
41
  插件不再自行注册 Settings section 或直接改写 settings.yaml。DSH 0.1.7 在 Loader 就绪后将旧 settings.yaml 重命名为 settings.yaml.imported,并尝试导入到 profile 条目;插件监听该条目的表单 / volatile 更新,再迁移成 V2 连接结构。保存使用 revision CAS,不能覆盖并发编辑。新旧宿主的配置持久化架构不同,不应只修改版本号或复制整份旧 YAML 到 profile。未完成迁移时搜索 fail-closed,普通聊天不因此被替换或阻断。
40
42
 
41
43
  自动迁移覆盖以下旧字段:
package/lib/client.js CHANGED
@@ -6158,6 +6158,28 @@ window.__ModuleLoader__.load({
6158
6158
  visit: () => visit$1,
6159
6159
  visitAsync: () => visitAsync
6160
6160
  });
6161
+ const LEGACY_FIELDS = [
6162
+ "modelMode",
6163
+ "protocol",
6164
+ "baseURL",
6165
+ "model",
6166
+ "fallbackModel",
6167
+ "apiKey",
6168
+ "apiKeyEnv",
6169
+ "apiVersion",
6170
+ "toolIdentifier",
6171
+ "maxTokens",
6172
+ "maxUses",
6173
+ "chatSearchMode",
6174
+ "searchContextSize"
6175
+ ];
6176
+ function configVersion(raw) {
6177
+ const version = raw.version;
6178
+ if (version === void 0) return LEGACY_FIELDS.some((key) => raw[key] !== void 0) ? 1 : 2;
6179
+ if (typeof version !== "number" || !Number.isSafeInteger(version) || version < 1) throw new Error("settings version must be a positive safe integer");
6180
+ if (version > 2) throw new Error("unsupported settings version; upgrade the plugin (automatic downgrade is disabled)");
6181
+ return version;
6182
+ }
6161
6183
  //#endregion
6162
6184
  //#region lib/types/catalog.js
6163
6185
  const CATALOG = Object.freeze({
@@ -7250,6 +7272,11 @@ window.__ModuleLoader__.load({
7250
7272
  };
7251
7273
  /** Update only the edited path; catalog defaults never materialize as settings. */
7252
7274
  function sparseSettingOperations(snapshot, path, target, fallback) {
7275
+ const effective = {
7276
+ ...object$1(snapshot.base),
7277
+ ...object$1(snapshot.user)
7278
+ };
7279
+ if (configVersion(effective) !== 2) throw new Error("settings migration required");
7253
7280
  const at = (root) => path.reduce((v, key) => object$1(v)[key], root);
7254
7281
  const inherited = at(snapshot.base) ?? fallback;
7255
7282
  const user = at(snapshot.user);
@@ -7270,7 +7297,7 @@ window.__ModuleLoader__.load({
7270
7297
  path,
7271
7298
  value: sparse
7272
7299
  });
7273
- if (ops.some((op) => op.op === "set") && object$1(snapshot.base).version !== 2 && object$1(snapshot.user).version !== 2) ops.push({
7300
+ if (ops.some((op) => op.op === "set") && effective.version !== 2) ops.push({
7274
7301
  op: "set",
7275
7302
  path: ["version"],
7276
7303
  value: 2
@@ -7278,6 +7305,10 @@ window.__ModuleLoader__.load({
7278
7305
  return ops;
7279
7306
  }
7280
7307
  function resetSettingsOperations(snapshot) {
7308
+ if (configVersion({
7309
+ ...object$1(snapshot.base),
7310
+ ...object$1(snapshot.user)
7311
+ }) !== 2) throw new Error("settings migration required");
7281
7312
  return [
7282
7313
  "version",
7283
7314
  "freshness",