dsh-sidecard-ask 1.2.0 → 1.2.1

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
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.2.1
4
+
5
+ **主题:核对 DSH 0.2.0-rc.1 的适配性,并修掉由此暴露的一个真实缺陷。**
6
+
7
+ 核对(本机运行中的就是 0.2.0-rc.1,`@deepseek-ai/dsh` 的 `next` 通道):
8
+
9
+ - 包内容层面:`node tools/compat-probe.mjs 0.1.7-rc.2 0.2.0-rc.1` → 16 项能力**逐项一致**,没有任何依赖被移除或改名;
10
+ - 运行实例上:宿主半 `v1.2.0` 正常(`sideEngine`、provider `spawn,fork`、`capabilities.parent` 均可用);
11
+ 客户端半在 `shell.overlay` / `conversation.input.right` 都已注册;`standardProps` 仍含 `sessionId` 与 `inputActions`;
12
+ 真机端到端作答 `start→delta×31→status→done`(1.36 s)通过。新增的 `sessions.fork`/`uiWorkspace.forkSession`
13
+ 可选参数 `onCreated` 是纯增量,不影响既有调用。
14
+
15
+ **修掉的缺陷**:`sidebar.right.pane.tab` 的运行清单里只有 `dsh-better-sidebar:sidecard-ask:card`,
16
+ 没有本插件原生右侧栏的 `sidecard-ask:card`——两个适配器用了同一个 tab kind,而 better-sidebar 会把每个 tab 描述符
17
+ 镜像注册进**同一个**原生注册表(band `extension`),该注册表对同 band 同 kind 的二次注册抛错,后注册的一方静默失败。
18
+
19
+ - better-sidebar 承载面改用独立类型 `sidecard-ask:card:workbench`(`CARD_KIND_BETTER`),两端不再重叠;
20
+ - `contract-test` 新增"surface kinds must not collide"一节:**在测试里模拟该注册表的重复 kind 抛错规则**
21
+ 与 better-sidebar 的镜像注册行为,若两者再共用 kind,测试立即失败;
22
+ - 设置页自检行改为同时报告**两个适配器**(原先原生适配器的错误在界面上不可见,只能靠翻槽位清单发现)。
23
+
24
+ 自测 289 → **295 项**(verify 53 / contract 124 / smoke 118)。
25
+
3
26
  ## 1.2.0
4
27
 
5
28
  **主题:核对并加固与 dsh-better-sidebar 0.22.1 的适配。**
package/README.md CHANGED
@@ -183,6 +183,35 @@ plugin_manager(action="install_bundle", target="D:\\Users\\34332\\AI\\dsh-sideca
183
183
 
184
184
  > 注意:`version` 是加载到浏览器里的那份模块报告的版本。页面刷新后即可用它确认"跑的是不是 0.22.1"。
185
185
 
186
+ ### 5.2 与 DSH 0.2.0-rc.1 的适配核对(2026-09-29)
187
+
188
+ 本机实际运行的就是 **0.2.0-rc.1**(`@deepseek-ai/dsh` 的 `next` 通道;`latest` 仍是 0.1.7-rc.2)。核对分两层:
189
+
190
+ **① 包内容层面**(`node tools/compat-probe.mjs 0.1.7-rc.2 0.2.0-rc.1`):
191
+ 16 项能力**逐项与 0.1.7-rc.2 完全一致**——`shell.overlay`、`conversation.input.right`、`settings.section`、
192
+ `data-slot` 锚点、原生右侧栏、`sessions.using/retain`、归档门、`agent/assistant-stream`、子代理、`tools.schemas`、
193
+ `webServer` 路由……全部 ✅。
194
+
195
+ **② 在运行中的实例上实测**:
196
+
197
+ | 检查 | 结果 |
198
+ |---|---|
199
+ | 宿主半是否加载 | ✅ `/sidecard-ask/api/state` 返回 `dsh-sidecard-ask v1.2.0`,`sideEngine=true`(provider `spawn,fork`)、`capabilities.parent` 正常 |
200
+ | 客户端半是否注册 | ✅ `shell.overlay` 有 `sidecard-ask`(order 45、active)、`conversation.input.right` 有 `sidecard-ask-session-probe`、`settings.section` 有设置页 |
201
+ | 依赖的槽位与标准 prop | ✅ `conversation.input.right` 仍是 list/session,`standardProps` 仍含 **`sessionId`** 与 **`inputActions`** |
202
+ | 依赖的客户端服务 | ✅ `sessions`(`retain`/`using`/`scope`)、`slots`、`locale`、`layout`、`theme` 全在;`sessions.fork`/`uiWorkspace.forkSession` 只是**新增**了可选 `onCreated`,不影响既有调用 |
203
+ | 端到端作答 | ✅ 真机 `start→delta×31→status→done`(1.36 s,`streamSource=frames`),只读工具白名单照常生效 |
204
+
205
+ **③ 由此发现并修掉的真实缺陷(1.2.1)**:运行中的 `sidebar.right.pane.tab` 清单里只有
206
+ `dsh-better-sidebar:sidecard-ask:card`,**没有我的原生 `sidecard-ask:card`**。原因是两个适配器用了**同一个 tab kind**:
207
+ better-sidebar 会把收到的每个 tab 描述符**镜像注册进同一个原生注册表**(`sidebarRightTabs.register`,band `extension`),
208
+ 而该注册表对*同 band 同 kind 的二次注册直接抛错*(源码注释:*"Everything else colliding on a kind throws"*)——
209
+ 后注册的那一方就此失败,而且**在界面上不可见**。修法:
210
+
211
+ 1. better-sidebar 承载面改用独立类型 **`sidecard-ask:card:workbench`**,两端 kind 不再重叠;
212
+ 2. `contract-test` **模拟该注册表的"重复 kind 抛错"规则**,此类冲突今后会直接让测试失败;
213
+ 3. 设置页自检行改为**同时报告两个适配器**的状态(此前原生适配器的错误压根看不到)。
214
+
186
215
  ---
187
216
 
188
217
  ## 六、未知 DSH API:占位接口与替换方式
@@ -353,7 +382,7 @@ node test/smoke-test.mjs # 端到端:流式/截断/取消/持久化/失
353
382
  ```
354
383
 
355
384
  三个脚本都以 `process.exitCode` 反映结果,失败会列出具体条目;测试会把 `DSH_HOME` 指向临时目录,不会污染真实配置。
356
- 当前规模:verify 53 项 + contract 105 项 + smoke 118 项 = **276 项全部通过**。
385
+ 当前规模:verify 53 项 + contract 118 项 + smoke 118 项 = **289 项全部通过**。
357
386
 
358
387
  ### 10.2 版本能力探测(§7 矩阵的来源)
359
388
 
@@ -471,5 +500,5 @@ npm deprecate "<旧包名>@*" "Renamed to <新包名> - <原因>" # 旧名
471
500
  本仓库当前文件比运行中的宿主模块新(1.0.1 的「归档父会话不再一刀切 / 持久化 chunk 流式源 / 能力门控 / 路由降级」),
472
501
  **重启后**这些改动才生效;`/state` 的 `version` 与 `capabilities.parent` 字段可以直接确认是否已加载新版。
473
502
  6. **除 0.1.7-rc.2 外,其余版本只做了产物层验证**:见 §7.3——插件在 0.1.2-rc.1 … 0.1.6-alpha.2 上安装启动过**没有**得到验证,
474
- 验证到的是"这些版本缺哪些 API + 插件对每个缺失都有分支",分支本身由 276 项自测覆盖。
503
+ 验证到的是"这些版本缺哪些 API + 插件对每个缺失都有分支",分支本身由 289 项自测覆盖。
475
504
 
package/client.js CHANGED
@@ -42,9 +42,27 @@ window.__ModuleLoader__.load({
42
42
  settings: 'sidecard-ask-settings',
43
43
  sessionProbe: 'sidecard-ask-session-probe',
44
44
  }
45
- /** Side-card tab type registered in a side-card host. */
45
+ /**
46
+ * Tab kind served by the DSH native right rail (also its implementation id).
47
+ */
46
48
  const CARD_KIND = 'sidecard-ask:card'
47
49
 
50
+ /**
51
+ * Tab type served by the dsh-better-sidebar plugin.
52
+ *
53
+ * It MUST differ from {@link CARD_KIND}: better-sidebar mirrors every tab
54
+ * descriptor it is given into the SAME native registry
55
+ * (`sidebarRightTabs.register`, id `dsh-better-sidebar:<id>`, band
56
+ * `extension`), and that registry THROWS when a kind already has a
57
+ * registration in the same band ("Everything else colliding on a kind
58
+ * throws"). Sharing one kind made the two adapters collide: whichever
59
+ * registered second failed — observed live on 0.2.0-rc.1, where the pane
60
+ * listed `dsh-better-sidebar:sidecard-ask:card` and no native
61
+ * `sidecard-ask:card` at all. `test/contract-test.mjs` now emulates that
62
+ * registry rule so the collision cannot come back.
63
+ */
64
+ const CARD_KIND_BETTER = 'sidecard-ask:card:workbench'
65
+
48
66
  /**
49
67
  * Client-side mirror of the Host `DEFAULT_CONFIG`. The client needs values
50
68
  * before `/state` answers (first paint) and when the Host is unreachable;
@@ -170,6 +188,7 @@ window.__ModuleLoader__.load({
170
188
  diagSidecard: '侧边卡片插件(dsh-better-sidebar)',
171
189
  diagFeatures: '项能力',
172
190
  diagNoTabMeta: '版本过旧:没有 tabMeta 能力,已跳过它改用其它承载面',
191
+ diagNativeKind: 'kind',
173
192
  toolGuardUnavailable: '该 provider 不支持工具白名单,本次作答继承了当前会话的工具',
174
193
  toolGuardInherited: '按配置继承当前会话的工具',
175
194
  diagUnreachable: '宿主接口不可达:{msg}',
@@ -272,6 +291,7 @@ window.__ModuleLoader__.load({
272
291
  diagSidecard: 'Side-card plugin (dsh-better-sidebar)',
273
292
  diagFeatures: 'capabilities',
274
293
  diagNoTabMeta: 'too old: no tabMeta capability, skipped in favour of another surface',
294
+ diagNativeKind: 'kind',
275
295
  toolGuardUnavailable: 'This provider supports no tool allow-list, so the answer inherited the session tools',
276
296
  toolGuardInherited: 'Inherits the session tools, as configured',
277
297
  diagUnreachable: 'Host API unreachable: {msg}',
@@ -889,20 +909,20 @@ window.__ModuleLoader__.load({
889
909
  },
890
910
  open(card) {
891
911
  if (!this.available() || typeof this.service.openTab !== 'function') return false
892
- const tabId = `${CARD_KIND}:${card.id}`
912
+ const tabId = `${CARD_KIND_BETTER}:${card.id}`
893
913
  // `meta` is the transport for the card id (feature `tabMeta`), and
894
914
  // `dedupeKey` on our descriptor is what collapses repeat opens onto
895
915
  // the same tab; both are part of the stable consumer contract
896
916
  // (`lib/types/client/service.d.ts`, unchanged across 0.22.0 → 0.22.1).
897
917
  this.service.openTab(
898
- { type: CARD_KIND, id: tabId, title: card.question.slice(0, 32), meta: { cardId: card.id } },
918
+ { type: CARD_KIND_BETTER, id: tabId, title: card.question.slice(0, 32), meta: { cardId: card.id } },
899
919
  store.state.sessionId === null ? undefined : { sessionId: store.state.sessionId },
900
920
  )
901
921
  return true
902
922
  },
903
923
  close(card) {
904
924
  if (!this.available() || typeof this.service.closeTab !== 'function') return false
905
- this.service.closeTab(`${CARD_KIND}:${card.id}`)
925
+ this.service.closeTab(`${CARD_KIND_BETTER}:${card.id}`)
906
926
  return true
907
927
  },
908
928
  },
@@ -1554,7 +1574,7 @@ window.__ModuleLoader__.load({
1554
1574
  h('div', { key: 'slots' }, `${t('diagSlots')}: ${Object.entries(state.slots).map(([k, v]) => `${k}=${v}`).join(' · ')}`),
1555
1575
  // The side-card plugin's own report: which version is loaded and
1556
1576
  // whether it advertises the capability this adapter needs.
1557
- h('div', { key: 'sidecard' }, `${t('diagSidecard')}: ${describeSidecardAdapter()}`),
1577
+ h('div', { key: 'sidecard' }, `${t('diagSidecard')}: ${describeSurfaces()}`),
1558
1578
  h('div', { key: 'path' }, `${t('settingsTitle')} → ${diag.provenance?.persistedPath ?? ''}`),
1559
1579
  ])
1560
1580
  : null)
@@ -1582,10 +1602,22 @@ window.__ModuleLoader__.load({
1582
1602
  }
1583
1603
 
1584
1604
  /**
1585
- * One line describing how the optional side-card plugin resolved, for the
1586
- * settings page's capability check. Reported from the plugin's OWN
1587
- * `version`/`features` fields, so the answer is what is running, not what
1588
- * package.json claims.
1605
+ * One line describing how each optional side-card surface resolved, for the
1606
+ * settings page's capability check. Both adapters are reported, because a
1607
+ * failing NATIVE registration was previously invisible here (it only showed
1608
+ * up as a missing entry in the pane's own slot inventory).
1609
+ * @returns {string} human-readable state.
1610
+ */
1611
+ function describeSurfaces() {
1612
+ const native = surfaces.native.available()
1613
+ ? `${t('yes')} · ${t('diagNativeKind')}=${CARD_KIND}`
1614
+ : `${t('no')}${surfaces.native.error === null ? '' : `(${surfaces.native.error})`}`
1615
+ return `${t('surfaceNative')}: ${native} / ${t('surfaceBetter')}: ${describeSidecardAdapter()}`
1616
+ }
1617
+
1618
+ /**
1619
+ * The optional side-card plugin's own report: which version is loaded and
1620
+ * whether it advertises the capability this adapter needs.
1589
1621
  * @returns {string} human-readable state.
1590
1622
  */
1591
1623
  function describeSidecardAdapter() {
@@ -2245,7 +2277,11 @@ window.__ModuleLoader__.load({
2245
2277
  return
2246
2278
  }
2247
2279
  const off = service.registerTab({
2248
- id: CARD_KIND,
2280
+ // A DIFFERENT type from the native rail's: better-sidebar mirrors
2281
+ // this descriptor into `sidebarRightTabs` as an `extension`-band
2282
+ // registration, and a second registration of the same kind in
2283
+ // that band throws (see CARD_KIND_BETTER).
2284
+ id: CARD_KIND_BETTER,
2249
2285
  title: () => t('answerTitle'),
2250
2286
  description: () => t('settingsDesc'),
2251
2287
  order: 120,
@@ -2337,13 +2373,14 @@ window.__ModuleLoader__.load({
2337
2373
  * `window` and exercises these without a browser.
2338
2374
  */
2339
2375
  api: Object.freeze({
2340
- version: '1.2.0',
2376
+ version: '1.2.1',
2341
2377
  /** Read-only state accessor for diagnostics and the test harness. */
2342
2378
  snapshot: () => store.state,
2343
2379
  pure: Object.freeze({
2344
2380
  CLIENT_DEFAULTS,
2345
2381
  IDS,
2346
2382
  CARD_KIND,
2383
+ CARD_KIND_BETTER,
2347
2384
  parseSseBlock,
2348
2385
  truncateSelection,
2349
2386
  parseShortcut,
package/index.js CHANGED
@@ -42,7 +42,7 @@ export const name = 'dsh-sidecard-ask'
42
42
  export const inject = ['webServer']
43
43
 
44
44
  /** Version of this plugin (kept in step with package.json by test/verify.mjs). */
45
- export const PLUGIN_VERSION = '1.2.0'
45
+ export const PLUGIN_VERSION = '1.2.1'
46
46
 
47
47
  /** Route prefix of the plugin's own API. */
48
48
  export const ROUTE_PREFIX = '/sidecard-ask/api'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-sidecard-ask",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "DSH 划词追问(侧边卡片作答):在聊天区与任务区选中文本就地追问,答案由独立子代理在侧边卡片里流式呈现,也可选择落回主对话。",
5
5
  "type": "module",
6
6
  "main": "index.js",