dsh-plugin-core 0.26.0 → 0.28.0

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.
Files changed (63) hide show
  1. package/dist/explorer/open.d.ts +5 -4
  2. package/dist/explorer/open.d.ts.map +1 -1
  3. package/dist/explorer/open.js +12 -2
  4. package/dist/explorer/open.js.map +1 -1
  5. package/dist/session/SessionViewModal.d.ts.map +1 -1
  6. package/dist/session/SessionViewModal.js +70 -20
  7. package/dist/session/SessionViewModal.js.map +1 -1
  8. package/dist/session/mirror/ChatView.d.ts.map +1 -1
  9. package/dist/session/mirror/ChatView.js +9 -1
  10. package/dist/session/mirror/ChatView.js.map +1 -1
  11. package/dist/session/mirror/Deliverables.d.ts.map +1 -1
  12. package/dist/session/mirror/Deliverables.js +42 -27
  13. package/dist/session/mirror/Deliverables.js.map +1 -1
  14. package/dist/session/mirror/GenericCommandCard.d.ts.map +1 -1
  15. package/dist/session/mirror/GenericCommandCard.js +2 -3
  16. package/dist/session/mirror/GenericCommandCard.js.map +1 -1
  17. package/dist/session/mirror/MessageIconActions.d.ts.map +1 -1
  18. package/dist/session/mirror/MessageIconActions.js +3 -5
  19. package/dist/session/mirror/MessageIconActions.js.map +1 -1
  20. package/dist/session/mirror/MessageItem.d.ts +5 -0
  21. package/dist/session/mirror/MessageItem.d.ts.map +1 -1
  22. package/dist/session/mirror/MessageItem.js +30 -12
  23. package/dist/session/mirror/MessageItem.js.map +1 -1
  24. package/dist/session/mirror/ReasoningRow.d.ts.map +1 -1
  25. package/dist/session/mirror/ReasoningRow.js +79 -17
  26. package/dist/session/mirror/ReasoningRow.js.map +1 -1
  27. package/dist/session/mirror/RunningStatus.d.ts +12 -0
  28. package/dist/session/mirror/RunningStatus.d.ts.map +1 -0
  29. package/dist/session/mirror/RunningStatus.js +57 -0
  30. package/dist/session/mirror/RunningStatus.js.map +1 -0
  31. package/dist/session/mirror/TurnProcessNodeView.d.ts.map +1 -1
  32. package/dist/session/mirror/TurnProcessNodeView.js +27 -38
  33. package/dist/session/mirror/TurnProcessNodeView.js.map +1 -1
  34. package/dist/session/mirror/TurnTailNodeView.d.ts +25 -0
  35. package/dist/session/mirror/TurnTailNodeView.d.ts.map +1 -1
  36. package/dist/session/mirror/TurnTailNodeView.js +65 -7
  37. package/dist/session/mirror/TurnTailNodeView.js.map +1 -1
  38. package/dist/session/mirror/TurnTriggerNodeView.d.ts.map +1 -1
  39. package/dist/session/mirror/TurnTriggerNodeView.js +36 -20
  40. package/dist/session/mirror/TurnTriggerNodeView.js.map +1 -1
  41. package/dist/session/mirror/message-chrome.d.ts +10 -4
  42. package/dist/session/mirror/message-chrome.d.ts.map +1 -1
  43. package/dist/session/mirror/message-chrome.js +11 -16
  44. package/dist/session/mirror/message-chrome.js.map +1 -1
  45. package/dist/session/official-classes.d.ts.map +1 -1
  46. package/dist/session/official-classes.js +5 -3
  47. package/dist/session/official-classes.js.map +1 -1
  48. package/dist/session/session-css.generated.d.ts +1 -1
  49. package/dist/session/session-css.generated.d.ts.map +1 -1
  50. package/dist/session/session-css.generated.js +1 -1
  51. package/dist/session/session-css.generated.js.map +1 -1
  52. package/dist/utils/i18n.d.ts +1 -1
  53. package/dist/utils/i18n.d.ts.map +1 -1
  54. package/dist/utils/i18n.js +24 -14
  55. package/dist/utils/i18n.js.map +1 -1
  56. package/docs/help/explorer.doc.ts +9 -9
  57. package/docs/help/explorer.md +7 -7
  58. package/docs/help/integration.doc.ts +5 -3
  59. package/docs/help/integration.md +5 -3
  60. package/docs/help/session.doc.ts +4 -3
  61. package/docs/help/session.md +4 -3
  62. package/docs/requirements.md +3 -1
  63. package/package.json +1 -1
@@ -12,10 +12,10 @@ serveFsRoute(ctx, { path: FS_PATH })
12
12
  connectHost(ctx)
13
13
  connectFs({ path: FS_PATH })
14
14
 
15
- // 右侧分栏预览(占宽度、挤窄主区):一个容器 + 一个路径就够
16
- openFilePreview({ mount, path: '/abs/ledger' }) // 文件夹 ⇒ 目录树;文件 ⇒ 直接预览
17
- openFilePreview({ mount, path: 'docs/README.md' }) // 工作区相对路径也行(相对谁见下)
18
- openFilePreview({ mount }) // 不给路径 ⇒ 根节点(工作区清单 + 盘符)
15
+ // 右侧分栏预览(占宽度、挤窄主区):一个落点 + 一个路径就够
16
+ openFilePreview({ mount: pageRowEl, path: '/abs/ledger' }) // 文件夹 ⇒ 目录树;文件 ⇒ 直接预览
17
+ openFilePreview({ mount: '#page-row', path: 'docs/README.md' }) // 落点也可以给选择器;相对路径也收(相对谁见下)
18
+ openFilePreview({ mount: '#page-row' }) // 不给路径 ⇒ 根节点(工作区清单 + 盘符)
19
19
 
20
20
  // 锚定弹窗选文件(Promise 返回**绝对路径**,不自己挂 dock)
21
21
  const r = await pickWorkspaceFile({ anchor, filter: { exts: ['md'] } })
@@ -42,8 +42,8 @@ const doc: DocTopic = {
42
42
  en: '**Core does the wiring, but with two calls**: `serveFsRoute({ path })` on the host side and `connectFs({ path })` with the same constant on the client side (`connectHost(ctx)` still covers the workspace snapshot). Browsing needs **no session**.',
43
43
  },
44
44
  {
45
- zh: '落点只给一个元素:页面里**包住主区**的那个(核心会补成 flex 行、让主区伸展,关闭时还原),不要传 `document.body` 再自己套 fixed——那是浮层,不是分栏。',
46
- en: 'Pass one element: the one wrapping the main area. Core makes it a flex row and lets the main area stretch, restoring it on close. Never pass `document.body` with your own fixed positioning — that is an overlay, not a split.',
45
+ zh: '落点只给一个:页面里**包住主区**的那个(核心会补成 flex 行、让主区伸展,关闭时还原)。给元素或选择器(`\'#page-row\'`)都行,消费方不必存 ref;selector 解析不到就放弃本次打开(不会回落 body)。不要传 `document.body` 再自己套 fixed——那是浮层,不是分栏。',
46
+ en: 'Give exactly one mount: the element wrapping the main area (core makes it a flex row and lets the main area stretch, restoring it on close). Either an element or a selector (`\'#page-row\'`) works, so no ref bookkeeping is needed; an unresolvable selector abandons the open (never falls back to `body`). Never pass `document.body` with your own fixed positioning — that is an overlay, not a split.',
47
47
  },
48
48
  {
49
49
  zh: '面包屑口径不变:路径所属工作区名作根名,其下按相对层级展开。▾ 下拉**根层置顶**(其余仍列各工作区):POSIX 是一条「根目录」,**Windows 没有根目录这东西,列的是盘符**(`C:/`、`D:/`…,由宿主 `op:roots` 探出来)。点其他工作区 = 直接列该区根目录(不需要会话)。',
@@ -85,12 +85,12 @@ const doc: DocTopic = {
85
85
  },
86
86
  {
87
87
  name: 'opts.mount',
88
- type: 'HTMLElement',
88
+ type: 'HTMLElement | string',
89
89
  def: '—',
90
90
  required: '是',
91
91
  desc: {
92
- zh: '页面里**包住主区**的那个元素;不必自己写 flex(核心补成 flex 行并让主区伸展,关闭时还原)。不要传 `document.body`',
93
- en: 'The element wrapping the main area; no flex needed (core turns it into a flex row, stretches the main area, and restores it on close). Never `document.body`',
92
+ zh: '页面里**包住主区**的那个元素,或指向它的选择器(`\'#page-row\'`);不必自己写 flex(核心补成 flex 行并让主区伸展,关闭时还原)。选择器解析不到 ⇒ 返回 `null` 并 warn,不回落 body。不要传 `document.body`',
93
+ en: 'The element wrapping the main area, or a selector pointing at it (`\'#page-row\'`); no flex needed (core turns it into a flex row, stretches the main area, and restores it on close). An unresolvable selector ⇒ `null` + a warning, never a `body` fallback. Never `document.body`',
94
94
  },
95
95
  },
96
96
  {
@@ -18,9 +18,9 @@
18
18
 
19
19
  > EN: **Core does the wiring, but with two calls**: `serveFsRoute({ path })` on the host side and `connectFs({ path })` with the same constant on the client side (`connectHost(ctx)` still covers the workspace snapshot). Browsing needs **no session**.
20
20
 
21
- 落点只给一个元素:页面里**包住主区**的那个(核心会补成 flex 行、让主区伸展,关闭时还原),不要传 `document.body` 再自己套 fixed——那是浮层,不是分栏。
21
+ 落点只给一个:页面里**包住主区**的那个(核心会补成 flex 行、让主区伸展,关闭时还原)。给元素或选择器(`'#page-row'`)都行,消费方不必存 ref;selector 解析不到就放弃本次打开(不会回落 body)。不要传 `document.body` 再自己套 fixed——那是浮层,不是分栏。
22
22
 
23
- > EN: Pass one element: the one wrapping the main area. Core makes it a flex row and lets the main area stretch, restoring it on close. Never pass `document.body` with your own fixed positioning — that is an overlay, not a split.
23
+ > EN: Give exactly one mount: the element wrapping the main area (core makes it a flex row and lets the main area stretch, restoring it on close). Either an element or a selector (`'#page-row'`) works, so no ref bookkeeping is needed; an unresolvable selector abandons the open (never falls back to `body`). Never pass `document.body` with your own fixed positioning — that is an overlay, not a split.
24
24
 
25
25
  面包屑口径不变:路径所属工作区名作根名,其下按相对层级展开。▾ 下拉**根层置顶**(其余仍列各工作区):POSIX 是一条「根目录」,**Windows 没有根目录这东西,列的是盘符**(`C:/`、`D:/`…,由宿主 `op:roots` 探出来)。点其他工作区 = 直接列该区根目录(不需要会话)。
26
26
 
@@ -54,10 +54,10 @@ serveFsRoute(ctx, { path: FS_PATH })
54
54
  connectHost(ctx)
55
55
  connectFs({ path: FS_PATH })
56
56
 
57
- // 右侧分栏预览(占宽度、挤窄主区):一个容器 + 一个路径就够
58
- openFilePreview({ mount, path: '/abs/ledger' }) // 文件夹 ⇒ 目录树;文件 ⇒ 直接预览
59
- openFilePreview({ mount, path: 'docs/README.md' }) // 工作区相对路径也行(相对谁见下)
60
- openFilePreview({ mount }) // 不给路径 ⇒ 根节点(工作区清单 + 盘符)
57
+ // 右侧分栏预览(占宽度、挤窄主区):一个落点 + 一个路径就够
58
+ openFilePreview({ mount: pageRowEl, path: '/abs/ledger' }) // 文件夹 ⇒ 目录树;文件 ⇒ 直接预览
59
+ openFilePreview({ mount: '#page-row', path: 'docs/README.md' }) // 落点也可以给选择器;相对路径也收(相对谁见下)
60
+ openFilePreview({ mount: '#page-row' }) // 不给路径 ⇒ 根节点(工作区清单 + 盘符)
61
61
 
62
62
  // 锚定弹窗选文件(Promise 返回**绝对路径**,不自己挂 dock)
63
63
  const r = await pickWorkspaceFile({ anchor, filter: { exts: ['md'] } })
@@ -75,7 +75,7 @@ await pickWorkspaceFile({ anchor, placement: 'left-start' }) // 左侧、顶
75
75
  | 参数 | 类型 | 必填 | 默认 | 说明(zh) | 说明(en) |
76
76
  |---|---|---|---|---|---|
77
77
  | `openFilePreview(opts)` | `OpenFilePreviewOptions => FilePreviewHandle` | — | — | 在右侧分栏打开文件 / 文件夹预览,返回可关闭它的句柄。预览内容二选一:`path`(核心解析并渲染)或 `content`(由调用方给内容) | Opens a file/folder preview in the right-side dock and returns a handle to close it. Body is one of two: `path` (resolved and rendered by core) or `content` (rendered from your own node) |
78
- | `opts.mount` | `HTMLElement` | 是 | — | 页面里**包住主区**的那个元素;不必自己写 flex(核心补成 flex 行并让主区伸展,关闭时还原)。不要传 `document.body` | The element wrapping the main area; no flex needed (core turns it into a flex row, stretches the main area, and restores it on close). Never `document.body` |
78
+ | `opts.mount` | `HTMLElement \| string` | 是 | — | 页面里**包住主区**的那个元素,或指向它的选择器(`'#page-row'`);不必自己写 flex(核心补成 flex 行并让主区伸展,关闭时还原)。选择器解析不到 ⇒ 返回 `null` 并 warn,不回落 body。不要传 `document.body` | The element wrapping the main area, or a selector pointing at it (`'#page-row'`); no flex needed (core turns it into a flex row, stretches the main area, and restores it on close). An unresolvable selector ⇒ `null` + a warning, never a `body` fallback. Never `document.body` |
79
79
  | `opts.sessionId` | `string` | — | — | **只在两种情况下需要**:① 相对路径的基准工作区;② Office 预览(转 PDF 要一条有效会话,缺省由核心取最近有会话的工作区) | Needed in exactly two cases: (1) the base workspace for a relative path; (2) Office preview (conversion needs one valid session; core falls back to the most recent workspace with one) |
80
80
  | `opts.path` | `string` | — | — | 绝对路径或工作区相对路径(相对路径要有可解析的基准,否则返回 `null` 并 warn);不传 ⇒ 根节点。与 `content` 二选一 | Absolute or workspace-relative (a relative one needs a resolvable base, else `null` + a warning); omitted ⇒ the root node. Mutually exclusive with `content` |
81
81
  | `opts.content` | `() => ReactNode` | — | — | 自定义预览内容,塞进同一个右侧 dock;传它时不需要 `path` | Custom preview body rendered in the same dock; no `path` needed when set |
@@ -36,6 +36,7 @@ serveFsRoute(ctx, { path: FS_PATH })
36
36
  connectFs({ path: FS_PATH })
37
37
 
38
38
  // 预览某文件:右侧分栏(挤窄 row 左边的主区,不是浮在上面);绝对 / 相对都收
39
+ // 落点给元素或选择器都行(openFilePreview({ mount: '#page-row' })),不必存 ref
39
40
  openFilePreview({ mount: pageRowEl, path: '/abs/ws/docs/requirements.md' })
40
41
 
41
42
  // 让用户选:锚定按钮旁弹模态,Promise 返回 { path: 绝对路径, isDir, workspaceRel?, workspace? }
@@ -50,7 +51,8 @@ if (view !== null) {
50
51
  sessionId, view,
51
52
  // 关闭必须释放 retain 引用
52
53
  onClose: () => { view.dispose(); setOpen(false) },
53
- onOpenFile: (path) => openFilePreview({ mount: pageRowEl, path, sessionId }),
54
+ // 文件出口:已经点开的那条会话 id 会作为第二参传进来(相对路径 / Office 都按它定位)
55
+ onOpenFile: (path, sid) => openFilePreview({ mount: pageRowEl, path, sessionId: sid }),
54
56
  })
55
57
  }`
56
58
  const cleanup = `kit.dispose() // 撤掉 <style> 标签并清空登记域(插件卸载 / HMR)`
@@ -74,8 +76,8 @@ const doc: DocTopic = {
74
76
  { zh: '§2 用一个控件', en: '§2 Use a control' },
75
77
  { zh: '§3 用通用方法', en: '§3 Use helpers' },
76
78
  {
77
- zh: '§4 接文件浏览:`mount` 必填(预览面板是布局成员,占宽挤窄主区),传页面那层 flex 行;数据面要在宿主 `serveFsRoute` + client `connectFs` 用同一个 path 常量接上,浏览本身不需要会话。',
78
- en: '§4 Wire file browsing: `mount` is required (the preview panel is a layout member that takes width); pass the page’s flex row. Wire the data face with the same path constant on both sides (`serveFsRoute` / `connectFs`) — browsing itself needs no session.',
79
+ zh: '§4 接文件浏览:`mount` 必填(预览面板是布局成员,占宽挤窄主区),传页面那层 flex 行——元素或选择器都行,解析不到就放弃、不回落 body;数据面要在宿主 `serveFsRoute` + client `connectFs` 用同一个 path 常量接上,浏览本身不需要会话。',
80
+ en: '§4 Wire file browsing: `mount` is required (the preview panel is a layout member that takes width); pass the page’s flex row — an element or a selector, and an unresolvable selector abandons the open instead of falling back to `body`. Wire the data face with the same path constant on both sides (`serveFsRoute` / `connectFs`) — browsing itself needs no session.',
79
81
  },
80
82
  {
81
83
  zh: '§5 接会话预览:`openSessionView` 返回 `null` 表示该会话不可解析;拿到 view 后交给 `SessionViewModal`,关闭时记得 `dispose()`。',
@@ -28,9 +28,9 @@
28
28
 
29
29
  > EN: §3 Use helpers
30
30
 
31
- §4 接文件浏览:`mount` 必填(预览面板是布局成员,占宽挤窄主区),传页面那层 flex 行;数据面要在宿主 `serveFsRoute` + client `connectFs` 用同一个 path 常量接上,浏览本身不需要会话。
31
+ §4 接文件浏览:`mount` 必填(预览面板是布局成员,占宽挤窄主区),传页面那层 flex 行——元素或选择器都行,解析不到就放弃、不回落 body;数据面要在宿主 `serveFsRoute` + client `connectFs` 用同一个 path 常量接上,浏览本身不需要会话。
32
32
 
33
- > EN: §4 Wire file browsing: `mount` is required (the preview panel is a layout member that takes width); pass the page’s flex row. Wire the data face with the same path constant on both sides (`serveFsRoute` / `connectFs`) — browsing itself needs no session.
33
+ > EN: §4 Wire file browsing: `mount` is required (the preview panel is a layout member that takes width); pass the page’s flex row — an element or a selector, and an unresolvable selector abandons the open instead of falling back to `body`. Wire the data face with the same path constant on both sides (`serveFsRoute` / `connectFs`) — browsing itself needs no session.
34
34
 
35
35
  §5 接会话预览:`openSessionView` 返回 `null` 表示该会话不可解析;拿到 view 后交给 `SessionViewModal`,关闭时记得 `dispose()`。
36
36
 
@@ -88,6 +88,7 @@ serveFsRoute(ctx, { path: FS_PATH })
88
88
  connectFs({ path: FS_PATH })
89
89
 
90
90
  // 预览某文件:右侧分栏(挤窄 row 左边的主区,不是浮在上面);绝对 / 相对都收
91
+ // 落点给元素或选择器都行(openFilePreview({ mount: '#page-row' })),不必存 ref
91
92
  openFilePreview({ mount: pageRowEl, path: '/abs/ws/docs/requirements.md' })
92
93
 
93
94
  // 让用户选:锚定按钮旁弹模态,Promise 返回 { path: 绝对路径, isDir, workspaceRel?, workspace? }
@@ -105,7 +106,8 @@ if (view !== null) {
105
106
  sessionId, view,
106
107
  // 关闭必须释放 retain 引用
107
108
  onClose: () => { view.dispose(); setOpen(false) },
108
- onOpenFile: (path) => openFilePreview({ mount: pageRowEl, path, sessionId }),
109
+ // 文件出口:已经点开的那条会话 id 会作为第二参传进来(相对路径 / Office 都按它定位)
110
+ onOpenFile: (path, sid) => openFilePreview({ mount: pageRowEl, path, sessionId: sid }),
109
111
  })
110
112
  }
111
113
  ```
@@ -21,7 +21,8 @@ if (view !== null) {
21
21
  await hostContinue(child, message)
22
22
  openHostSession(child)
23
23
  },
24
- onOpenFile: (path) => openFilePreview(path), // 文件打开出口
24
+ // 文件打开出口:给一个落点即可(元素或选择器),核心自带右侧分栏
25
+ onOpenFile: (path, sid) => openFilePreview({ mount: '#page-row', path, sessionId: sid }),
25
26
  archived, // 是否已归档
26
27
  t, // 可选,覆盖文案
27
28
  })
@@ -56,8 +57,8 @@ const doc: DocTopic = {
56
57
  en: 'The snapshot is read-only, so you cannot type inside the dialog. Continuing means `forkSession` + `openHostSession`; the staging input’s confirm goes through `onContinue` (fork + first turn + navigate).',
57
58
  },
58
59
  {
59
- zh: '文件出口只有一个:工具卡路径、行内引用、交付卡都走 `onOpenFile`;不传则链接降级为纯文本。预览由调用方开在**页面右侧**(`openFilePreview` 的 dock),弹窗不需要任何遮罩参数。',
60
- en: 'There is exactly one file exit: tool-card paths, inline mentions and delivered cards all go through `onOpenFile`; without it links degrade to plain text. The caller opens the preview as a **page-level right column** (the `openFilePreview` dock) — the dialog takes no mask props.',
60
+ zh: '文件出口只有一个:工具卡路径、行内引用、交付卡都走 `onOpenFile`;不传则链接降级为纯文本(可以点但没有出口,不是坏了)。自己已有预览面的,在回调里调你自己的(核心一个 DOM 都不碰);没有的,一行接上核心自带的右侧分栏:`onOpenFile: (path, sid) => openFilePreview({ mount: \'#page-row\', path, sessionId: sid })`——落点给元素或选择器都行,弹窗不需要任何遮罩参数。',
61
+ en: 'There is exactly one file exit: tool-card paths, inline mentions and delivered cards all go through `onOpenFile`; without it links degrade to plain text (clickable-looking but no exit — not a break). If you already own a preview surface, call yours inside the callback (core touches no DOM); otherwise wire core’s dock in one line: `onOpenFile: (path, sid) => openFilePreview({ mount: \'#page-row\', path, sessionId: sid })` — the mount takes an element or a selector, and the dialog needs no mask props.',
61
62
  },
62
63
  {
63
64
  zh: '限制:官方样式未注入时回退自绘观感(功能不受影响);长会话一次全渲染,用「加载更早记录」向前翻页;👍👎 反馈走官方 slots,弹窗没有该插槽。',
@@ -22,9 +22,9 @@
22
22
 
23
23
  > EN: The snapshot is read-only, so you cannot type inside the dialog. Continuing means `forkSession` + `openHostSession`; the staging input’s confirm goes through `onContinue` (fork + first turn + navigate).
24
24
 
25
- 文件出口只有一个:工具卡路径、行内引用、交付卡都走 `onOpenFile`;不传则链接降级为纯文本。预览由调用方开在**页面右侧**(`openFilePreview` 的 dock),弹窗不需要任何遮罩参数。
25
+ 文件出口只有一个:工具卡路径、行内引用、交付卡都走 `onOpenFile`;不传则链接降级为纯文本(可以点但没有出口,不是坏了)。自己已有预览面的,在回调里调你自己的(核心一个 DOM 都不碰);没有的,一行接上核心自带的右侧分栏:`onOpenFile: (path, sid) => openFilePreview({ mount: '#page-row', path, sessionId: sid })`——落点给元素或选择器都行,弹窗不需要任何遮罩参数。
26
26
 
27
- > EN: There is exactly one file exit: tool-card paths, inline mentions and delivered cards all go through `onOpenFile`; without it links degrade to plain text. The caller opens the preview as a **page-level right column** (the `openFilePreview` dock) — the dialog takes no mask props.
27
+ > EN: There is exactly one file exit: tool-card paths, inline mentions and delivered cards all go through `onOpenFile`; without it links degrade to plain text (clickable-looking but no exit — not a break). If you already own a preview surface, call yours inside the callback (core touches no DOM); otherwise wire core’s dock in one line: `onOpenFile: (path, sid) => openFilePreview({ mount: '#page-row', path, sessionId: sid })` — the mount takes an element or a selector, and the dialog needs no mask props.
28
28
 
29
29
  限制:官方样式未注入时回退自绘观感(功能不受影响);长会话一次全渲染,用「加载更早记录」向前翻页;👍👎 反馈走官方 slots,弹窗没有该插槽。
30
30
 
@@ -73,7 +73,8 @@ if (view !== null) {
73
73
  await hostContinue(child, message)
74
74
  openHostSession(child)
75
75
  },
76
- onOpenFile: (path) => openFilePreview(path), // 文件打开出口
76
+ // 文件打开出口:给一个落点即可(元素或选择器),核心自带右侧分栏
77
+ onOpenFile: (path, sid) => openFilePreview({ mount: '#page-row', path, sessionId: sid }),
77
78
  archived, // 是否已归档
78
79
  t, // 可选,覆盖文案
79
80
  })
@@ -156,7 +156,7 @@ dsh-plugin-core/
156
156
  - 读文件服务改由 `connectHost(ctx)` 一次接进来(`remote.workspaceFiles`,核心持有),
157
157
  `openFilePreview` / `pickWorkspaceFile` 不再要求调用方传 `workspaceFiles`(传了以传入为准);
158
158
  - `sessionId` 缺省由「路径 → 所属工作区 → 该区最近会话」解,匹配不出退「最近有会话的工作区」;
159
- - `mount` 仍是一个元素(往哪行塞只有调用方知道),但**不必自己写成 flex**:核心加 `dshpc-dock-host`
159
+ - `mount` 仍必须给(往哪行塞只有调用方知道),但**元素或选择器都收**(2026-11-04 补:`'#page-row'` 这样传即可,消费方不用存 ref;选择器解析不到 ⇒ 返回 `null` 并 warn,**不回落 body**),且**不必自己写成 flex**:核心加 `dshpc-dock-host`
160
160
  类并补 `display:flex`,关闭时还原;子项规则只让第一个非预览子项伸展,不要传 `document.body`;
161
161
  - 依据:插件沙箱里没有 `fs`,读字节唯一通道是 ctx 注入的服务对象 ⇒ 服务只能「接线一次」交进来,
162
162
  不能每次调用各传一遍(这是权限边界,不是能力缺口)。
@@ -168,6 +168,8 @@ dsh-plugin-core/
168
168
  - 会话预览:整体封装(连会话渲染一起),调用方注入取数能力
169
169
  - `variant` 决定承载方式:弹窗 / 侧栏 / 整页(**承载可换**是硬要求)
170
170
  - 必须预留定制扩展点
171
+ - 文件出口只有一个 `onOpenFile(path, sessionId)`(工具卡 / 行内引用 / 交付卡共用):不传 ⇒ 链接纯文本。已有预览面的调用方在回调里开自己的;没有的一行接 `openFilePreview({ mount, path, sessionId })`。**不做「给个 id 让核心塞进第三方面板」**(2026-11-04 定:核心只认识自己的 `PanelDock`,按 id 塞 = 两套布局互相拽)
172
+ - 会话区自动贴底只在两种情况下发生:**首次打开**、**有新内容且当时就在底部**;本地展开 / 折叠历史分组(如「已完成」)改变高度不算新内容,不许把视图拽走(2026-11-04 用户二次拍板)
171
173
 
172
174
  ## 3. 不进(业务,各插件自己写)
173
175
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-core",
3
- "version": "0.26.0",
3
+ "version": "0.28.0",
4
4
  "packageManager": "pnpm@12.3.4",
5
5
  "description": "Shared base for DSH plugins: design tokens, UI controls, utils, workspace explorer, session preview",
6
6
  "keywords": [