@deepseek-ai/dsh-client-ui-conversation 0.1.5-alpha.1 → 0.1.5-alpha.2

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/README.i18n.yaml CHANGED
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/client/ui-conversation/README.md
5
- README.md: edfcb83193d4513fba846f673d3572c35e8c0d1e
6
- README.zh.md: f92e4c77ba3d3a2ceb96758e5817e447ba2ec1ac
5
+ README.md: 7d5f370644f90f57ce1c27c59becf47c4cf2e684
6
+ README.zh.md: e7c5204b763aad92dc057d122537d592952afcd5
package/README.md CHANGED
@@ -36,13 +36,15 @@ Target packages declaration-merge their snapshot and Location data maps, then re
36
36
  <a id="shell-and-standard-props"></a>
37
37
  ## Shell and standard props
38
38
 
39
- The package registers the optional-Session `conversation` shell, strict Session header/body entries, View list, composer chain and bar, input regions, Hero regions, queue dock, draft persistence, and phase calculation. `ctx.uiSession.provide()` materializes the Conversation and input sources from the same Session binding and supplies `inputActions` as a stable standard prop.
39
+ Workspace selection uses `uiWorkspace.openWorkspace` to prepare the target and commit navigation. Draft text and attachments move in its synchronous preparation callback only while that request is current; later navigation or owner disposal leaves the original draft intact.
40
+
41
+ The package occupies the root-scoped `main` key `conversation`, whose wrapper declares the optional-Session `main.conversation` shell. It registers strict Session header/body entries, View list, composer chain and bar, input regions, Hero regions, queue dock, draft persistence, and phase calculation. `ctx.uiSession.provide()` materializes the Conversation and input sources from the same Session binding and supplies `inputActions` as a stable standard prop.
40
42
 
41
43
  View selection is deterministic: a registered persisted selection wins, otherwise registered `chat` wins, otherwise no View renders. It never chooses the first registered View. Shell phase combines Session lifecycle with the active-target set; no target-specific snapshot is read by the shell.
42
44
 
43
45
  The shell reads the persisted View preference before rendering when a Session first binds or a cached Session becomes current, activates the registered preferred View or Chat fallback, and activates later tab or focus selections before committing them to the store. A blank Session still omits the `conversation.view` slot; no unselected target is activated.
44
46
 
45
- The resident composer survives no-Session and Session transitions. The no-Session state keeps the same composer surface mounted but inert while the Workspace picker connects a blank Session. The surface is a shell-owned Lexical editor: reference chips are atomic decorator nodes carrying the owner's serialization identity (submission expands them through the owner codec), claimed slash commands stay styled leading text, folder text references carry the folder glyph as an icon prefix, and the draft's clipboard projection is mirrored into the per-Session Conversation store. Queue operations address exact queue occurrences through the scoped `ctx.conversation` service; queue previews render sent text through the shared inline reference projection from `ui-primitives` (wire session forms fold to their label) and show local or durable images and files in original attachment order. Images use thumbnails; files use compact name-and-size cards. An edit exposes the literal sent text, and durable thumbnails resolve through the session image URL cache. Busy Enter behavior is stored in the Host-backed `ui-conversation` settings namespace.
47
+ The resident composer survives no-Session and Session transitions. Whitespace hides its placeholder; a whitespace-only draft without attachments cannot be sent. The no-Session state keeps the same composer surface mounted but inert while the Workspace picker connects a blank Session. The surface is a shell-owned Lexical editor: reference chips are atomic decorator nodes carrying the owner's serialization identity (submission expands them through the owner codec), claimed slash commands stay styled leading text, folder text references carry the folder glyph as an icon prefix, and the draft's clipboard projection is mirrored into the per-Session Conversation store. Queue operations address exact queue occurrences through the scoped `ctx.conversation` service; queue previews render sent text through the shared inline reference projection from `ui-primitives` (wire session forms fold to their label) and show local or durable images and files in original attachment order. Images use thumbnails; files use compact name-and-size cards. An edit exposes the literal sent text, and durable thumbnails resolve through the session image URL cache. Busy Enter behavior is stored in the Host-backed `ui-conversation` settings namespace.
46
48
 
47
49
  Default sends commit optimistically: Enter clears the draft, occurrence table, and undo history in the same transaction, keeps the composer in `plain`, and runs the send as a detached attempt, so typing and further sends continue during the flight. `sendSession` registers a Session submission echo (`session.beginSubmission`) with the delivery mode before serializing, preserving selected image and file order in `pendingSubmissions`; Session derives the placement from that mode and its current running state, so idle sends use the transcript, busy Queue sends use QueueDock, and busy Steer sends use the pending-steering surface. It then yields one paint, encodes images through the browser's native `FileReader` data-URL path, and cites staged file receipts. Command submissions use the same receipts for generic files, so sending `/goal` or `/plan` never reads those browser files again. The prompt reuses the submission `requestId`; queue and history observation by that `rpcId` retires the echo once. Concurrent failures are restored together in submission order until the user edits the restored content; command submissions keep the frozen `submitting` phase. Detached attempts retain their attachment ids through admission and Session scope disposal. An observed retirement immediately exposes each image preview through the durable cache, replaces it with the canonical URL after fetching the admitted attachment, revokes each URL after its use ends, and releases file cards. Selected generic files enter one FIFO background-upload queue; `maxConcurrentFileUploads` defaults to two active Worker transports, the Conversation service retains queued and active operations plus byte progress across Session navigation, and removing a draft skips its queued transfer or aborts its active transport. Continuable subagents disable attachment intake and skip local echoes because their transport does not preserve the browser request id.
48
50
 
package/README.zh.md CHANGED
@@ -36,13 +36,15 @@ target package 通过 declaration merge 扩展 snapshot 与 Location data map,
36
36
  <a id="shell-and-standard-props"></a>
37
37
  ## Shell 与标准 props
38
38
 
39
- 本包注册 optional-Session `conversation` shell、strict Session header/body、View list、composer chain 与 bar、输入区域、Hero 区域、queue dock、草稿持久化和 phase 计算。`ctx.uiSession.provide()` 从同一个 Session binding 物化 Conversation 与 input source,并将 `inputActions` 作为稳定标准 prop 提供。
39
+ 工作区选择使用 `uiWorkspace.openWorkspace` 准备目标并提交导航。草稿文字和附件仅在请求仍有效时,通过它的同步准备回调搬移;后续导航或所有者释放会保留原草稿。
40
+
41
+ 本包占据 root 作用域 `main` 中的 `conversation` key,其包装层声明 optional-Session `main.conversation` shell。本包注册strict Session header/body、View list、composer chain 与 bar、输入区域、Hero 区域、queue dock、草稿持久化和 phase 计算。`ctx.uiSession.provide()` 从同一个 Session binding 物化 Conversation 与 input source,并将 `inputActions` 作为稳定标准 prop 提供。
40
42
 
41
43
  View 选择规则固定:有效且已注册的持久化选择优先,其次是已注册的 `chat`,否则不渲染 View;绝不选择第一个已注册 View。Shell phase 只组合 Session lifecycle 与 active-target set,不读取任何 target-specific snapshot。
42
44
 
43
45
  Session 首次绑定或缓存的 Session 成为 current 时,shell 会在渲染前读取持久化 View 偏好,激活已注册的偏好 View 或 Chat fallback,并在后续 tab 或 focus 选择写入 store 前先激活对应 target。blank Session 仍不渲染 `conversation.view` slot;未选中的 target 不会激活。
44
46
 
45
- 常驻 composer 在无 Session 与有 Session 之间保持挂载。无 Session 时,同一个编辑器表面保持 inert,Workspace picker 连接 blank Session。该表面是 shell 所有的 Lexical 编辑器:引用 chip 是携带 owner 序列化身份的原子 decorator 节点(提交时经 owner codec 展开),已认领的 slash command 保持为带样式的行首文本,文件夹文本引用以图标前缀携带文件夹图形,草稿的剪贴板投影镜像到逐 Session Conversation store。Queue 操作通过 scoped `ctx.conversation` service 寻址准确的 queue occurrence;queue 预览经 `ui-primitives` 的共享行内引用投影渲染已发送文本(wire 会话形式折叠为其标签),并按原始附件顺序展示本地或持久化的图片和文件。图片使用缩略图,文件使用紧凑的名称与大小卡片。编辑态展示字面发送文本,持久化缩略图通过会话图片 URL 缓存解析。繁忙时 Enter 行为保存在 Host-backed `ui-conversation` settings namespace。
47
+ 常驻 composer 在无 Session 与有 Session 之间保持挂载。输入空白字符会隐藏占位提示;没有附件的纯空白草稿无法发送。无 Session 时,同一个编辑器表面保持 inert,Workspace picker 连接 blank Session。该表面是 shell 所有的 Lexical 编辑器:引用 chip 是携带 owner 序列化身份的原子 decorator 节点(提交时经 owner codec 展开),已认领的 slash command 保持为带样式的行首文本,文件夹文本引用以图标前缀携带文件夹图形,草稿的剪贴板投影镜像到逐 Session Conversation store。Queue 操作通过 scoped `ctx.conversation` service 寻址准确的 queue occurrence;queue 预览经 `ui-primitives` 的共享行内引用投影渲染已发送文本(wire 会话形式折叠为其标签),并按原始附件顺序展示本地或持久化的图片和文件。图片使用缩略图,文件使用紧凑的名称与大小卡片。编辑态展示字面发送文本,持久化缩略图通过会话图片 URL 缓存解析。繁忙时 Enter 行为保存在 Host-backed `ui-conversation` settings namespace。
46
48
 
47
49
  默认发送采用乐观提交:Enter 在同一事务里清空草稿、occurrence 表和撤销历史,composer 保持 `plain`,发送作为 detached attempt 运行,发送期间可以继续输入和提交。`sendSession` 在序列化之前用投递模式注册 Session 提交回显(`session.beginSubmission`),并在 `pendingSubmissions` 中保留图片与文件的选择顺序;Session 根据该模式与当前运行状态推导位置,因此空闲发送进入 transcript,繁忙时 Queue 进入 QueueDock,繁忙时 Steer 进入 pending-steering 区域。随后让出一帧,图片经浏览器原生 `FileReader` data-URL 路径编码,文件则引用已暂存凭证。命令提交也用同一凭证表示通用文件,因此发送 `/goal` 或 `/plan` 时不会再次读取这些浏览器文件。prompt 复用提交 `requestId`;queue 或历史以同一 `rpcId` 被观察后,回显只退休一次。多个并发发送失败时,在用户编辑还原内容之前按提交顺序合并还原;命令提交保持冻结的 `submitting` 阶段。Detached attempt 持有附件 id,直到 admission 完成或 Session scope 销毁。回显以 observed 退休时,durable 图片缓存立即公开每个预览 URL,读取 admitted 附件后用规范化 URL 替换预览,并在各 URL 停止使用后撤销,同时释放文件卡。选中的通用文件进入同一个先进先出的后台上传队列;`maxConcurrentFileUploads` 默认允许两个 Worker transport 同时运行,Conversation service 在切换 Session 时继续持有排队和运行中的传输操作及字节进度,移除草稿会跳过排队中的传输或中止正在运行的传输。continuable 子代理禁用附件入口,也不创建本地回显,因为其 transport 不保留浏览器 request id。
48
50
 
package/lib/client.js CHANGED
@@ -14026,7 +14026,10 @@ window.__ModuleLoader__.load({
14026
14026
  (0, react_jsx_runtime.jsx)("span", {
14027
14027
  className: QueueDock_module_css_default.fileIcon,
14028
14028
  "aria-hidden": true,
14029
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.DocumentFileIcon, {})
14029
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.FileTypeIcon, {
14030
+ path: attachment.name,
14031
+ size: 16
14032
+ })
14030
14033
  }),
14031
14034
  (0, react_jsx_runtime.jsx)("span", {
14032
14035
  className: QueueDock_module_css_default.fileName,
@@ -14646,7 +14649,7 @@ window.__ModuleLoader__.load({
14646
14649
  }
14647
14650
  //#endregion
14648
14651
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.module.css.mjs
14649
- const css$4 = ".wSkVaW_root{background:var(--dsw-alias-bg-base);--dsh-chat-content-width:var(--dsh-chat-user-width,clamp(680px, calc(var(--dsh-conversation-column-width,0px) * .64), 920px));--dsh-composer-card-max-width:calc(var(--dsh-chat-content-width) + 32px);--dsh-composer-side-clearance:16px;--dsh-composer-dock-inset:8px;flex-direction:column;min-width:0;height:100%;display:flex;position:relative}.wSkVaW_header{border-bottom:1px solid #0000;flex:none;padding:12px 28px 0 20px;position:relative}.wSkVaW_header:after{content:\"\";z-index:0;background:var(--dsw-alias-border-l3);pointer-events:none;height:.5px;position:absolute;bottom:1px;left:0;right:0}.wSkVaW_headerHidden{display:none}.wSkVaW_titleRow{align-items:center;gap:0;min-height:32px;display:flex}.wSkVaW_titleCluster{flex:1;align-items:center;gap:10px;min-width:0;display:flex}.wSkVaW_crumbs{white-space:nowrap;align-items:center;gap:4px;min-width:0;display:flex;overflow:hidden}.wSkVaW_crumbSeg{align-items:center;gap:4px;min-width:0;display:inline-flex}.wSkVaW_crumbSep{color:var(--dsw-alias-label-caption);font-size:14px;line-height:20px}.wSkVaW_crumb{max-width:220px;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;cursor:pointer;background:0 0;border:none;border-radius:12px;padding:4px 8px;font-size:14px;line-height:20px;overflow:hidden}.wSkVaW_crumbSubagent{font-size:12px;line-height:18px}.wSkVaW_crumb:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.wSkVaW_crumbCurrent{color:var(--dsw-alias-label-primary);cursor:default;font-weight:500}.wSkVaW_headerActions{flex:none;align-items:center;gap:8px;display:flex}.wSkVaW_headerUtilities{flex:none;align-items:center;gap:8px;margin-left:20px;display:flex}.wSkVaW_headerUtilities:empty{display:none}.wSkVaW_headerCorner{flex:none;align-items:center;margin-left:12px;margin-right:-16px;display:flex}.wSkVaW_headerCorner:empty{display:none}.wSkVaW_tabs{z-index:1;gap:36px;margin-top:4px;padding-left:8px;display:flex;position:relative}.wSkVaW_tab{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;padding:0 0 11px;font-size:13px;font-weight:500;line-height:16px;position:relative}.wSkVaW_tab:after{content:\"\";background:0 0;border-radius:2px;height:2px;position:absolute;bottom:1px;left:0;right:0}.wSkVaW_tabActive{color:var(--dsw-alias-state-business-primary)}.wSkVaW_tabActive:after{background:var(--dsw-alias-state-business-primary)}.wSkVaW_viewArea{flex-direction:column;flex:1;min-height:0;display:flex}.wSkVaW_widthHandle{z-index:8;width:min(40px, calc((100% - var(--dsh-chat-content-width)) / 2 - 24px - 24px));cursor:col-resize;position:absolute;top:0;bottom:0}.wSkVaW_widthHandle[data-side=left]{right:calc(50% + var(--dsh-chat-content-width) / 2 + 24px)}.wSkVaW_widthHandle[data-side=right]{left:calc(50% + var(--dsh-chat-content-width) / 2 + 24px)}.wSkVaW_widthHandle:after{content:\"\";background:linear-gradient(to bottom, transparent calc(var(--dsh-width-handle-pointer-y,50%) - 52px), var(--dsw-alias-scrollbar-hover-l1) calc(var(--dsh-width-handle-pointer-y,50%) - 12px), var(--dsw-alias-scrollbar-hover-l1) calc(var(--dsh-width-handle-pointer-y,50%) + 12px), transparent calc(var(--dsh-width-handle-pointer-y,50%) + 52px));opacity:0;pointer-events:none;border-radius:3px;width:3px;position:absolute;top:0;bottom:0}.wSkVaW_widthHandle[data-side=left]:after{right:16px}.wSkVaW_widthHandle[data-side=right]:after{left:16px}.wSkVaW_widthHandle:hover:after,.wSkVaW_widthHandle[data-dragging]:after{opacity:1}.wSkVaW_root:has([data-conversation-composer-overlay]) .wSkVaW_widthHandle{display:none}.wSkVaW_composerStack{--dsh-composer-stack-gap:6px;gap:var(--dsh-composer-stack-gap);flex-direction:column;display:flex}.wSkVaW_composerSeat{--dsh-composer-text-max-height:336px;flex-direction:column;flex:none;display:flex}.wSkVaW_root[data-phase=active]{overflow:hidden}.wSkVaW_root[data-phase=active] .wSkVaW_header{flex:none}.wSkVaW_body{flex-direction:column;flex:1;min-height:0;display:flex;position:relative}.wSkVaW_scrollBody{scrollbar-gutter:stable;flex-direction:column;flex:1;min-height:0;display:flex;overflow-y:auto}.wSkVaW_root[data-phase=active] .wSkVaW_viewArea{flex:1 0 auto;min-height:auto}.wSkVaW_root[data-phase=active] .wSkVaW_composerSeat{z-index:7;background:linear-gradient(180deg, color-mix(in srgb, var(--dsw-alias-bg-base) 0%, transparent) 0px, var(--dsw-alias-bg-base) 36px);position:sticky;bottom:0}.wSkVaW_root[data-phase=active] .wSkVaW_composerSeat:has([data-trigger-menu]){z-index:9}.wSkVaW_scrollBody:has([data-conversation-composer-overlay]){scrollbar-gutter:auto;position:relative;overflow:hidden auto}.wSkVaW_scrollBody:has([data-conversation-composer-overlay])>[data-slot=conversation\\.session]>.wSkVaW_viewArea{flex:1 1 0;min-height:0;overflow:hidden}.wSkVaW_scrollBody:has([data-conversation-composer-overlay])>.wSkVaW_composerSeat{right:var(--dsh-scrollbar-width);position:absolute;bottom:0;left:0}.wSkVaW_composerHero{width:min(calc(var(--dsh-composer-card-max-width) + 2 * var(--dsh-composer-side-clearance)), 100%);z-index:1;align-self:center;gap:8px;padding-bottom:32px}.wSkVaW_heroWorkspaceRow{align-items:center;gap:2px;min-width:0;margin-top:4px;padding:0 16px 0 20px;display:flex}.wSkVaW_root[data-phase=hero] .wSkVaW_scrollBody{justify-content:center;overflow-y:auto}.wSkVaW_root[data-phase=settling] .wSkVaW_composerSeat{visibility:hidden}";
14652
+ const css$4 = ".wSkVaW_root{background:var(--dsw-alias-bg-base);--dsh-chat-content-width:var(--dsh-chat-user-width,clamp(680px, calc(var(--dsh-conversation-column-width,0px) * .64), 920px));--dsh-composer-card-max-width:calc(var(--dsh-chat-content-width) + 32px);--dsh-composer-side-clearance:16px;--dsh-composer-dock-inset:8px;flex-direction:column;min-width:0;height:100%;display:flex;position:relative}.wSkVaW_header{box-sizing:border-box;border-bottom:.5px solid var(--dsw-alias-border-l3);flex:none;min-height:76px;padding:10px 28px 0 20px}.wSkVaW_headerHidden{display:none}.wSkVaW_titleRow{align-items:center;gap:0;min-height:30px;display:flex}.wSkVaW_titleCluster{flex:1;align-items:center;gap:10px;min-width:0;display:flex}.wSkVaW_crumbs{white-space:nowrap;align-items:center;gap:4px;min-width:0;display:flex;overflow:hidden}.wSkVaW_crumbSeg{align-items:center;gap:4px;min-width:0;display:inline-flex}.wSkVaW_crumbSep{color:var(--dsw-alias-label-caption);font-size:14px;line-height:20px}.wSkVaW_crumb{max-width:220px;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;cursor:pointer;background:0 0;border:none;border-radius:12px;padding:4px 8px;font-size:14px;line-height:20px;overflow:hidden}.wSkVaW_crumbSubagent{font-size:12px;line-height:18px}.wSkVaW_crumb:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.wSkVaW_crumbCurrent{color:var(--dsw-alias-label-primary);cursor:default;font-weight:500}.wSkVaW_headerActions{flex:none;align-items:center;gap:8px;display:flex}.wSkVaW_headerUtilities{flex:none;align-items:center;gap:8px;margin-left:20px;display:flex}.wSkVaW_headerUtilities:empty{display:none}.wSkVaW_headerCorner{flex:none;align-items:center;margin-left:8px;margin-right:-16px;display:flex}.wSkVaW_headerCorner:empty{display:none}.wSkVaW_tabs{z-index:1;gap:36px;margin-top:10px;padding-left:8px;display:flex;position:relative}.wSkVaW_tab{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;padding:0 0 9px;font-size:13px;font-weight:500;line-height:16px;position:relative}.wSkVaW_tab:after{content:\"\";background:0 0;border-radius:2px;height:2px;position:absolute;bottom:-1px;left:0;right:0}.wSkVaW_tabActive{color:var(--dsw-alias-state-business-primary)}.wSkVaW_tabActive:after{background:var(--dsw-alias-state-business-primary)}.wSkVaW_viewArea{flex-direction:column;flex:1;min-height:0;display:flex}.wSkVaW_widthHandle{z-index:8;width:min(40px, calc((100% - var(--dsh-chat-content-width)) / 2 - 24px - 24px));cursor:col-resize;position:absolute;top:0;bottom:0}.wSkVaW_widthHandle[data-side=left]{right:calc(50% + var(--dsh-chat-content-width) / 2 + 24px)}.wSkVaW_widthHandle[data-side=right]{left:calc(50% + var(--dsh-chat-content-width) / 2 + 24px)}.wSkVaW_widthHandle:after{content:\"\";background:linear-gradient(to bottom, transparent calc(var(--dsh-width-handle-pointer-y,50%) - 52px), var(--dsw-alias-scrollbar-hover-l1) calc(var(--dsh-width-handle-pointer-y,50%) - 12px), var(--dsw-alias-scrollbar-hover-l1) calc(var(--dsh-width-handle-pointer-y,50%) + 12px), transparent calc(var(--dsh-width-handle-pointer-y,50%) + 52px));opacity:0;pointer-events:none;border-radius:3px;width:3px;position:absolute;top:0;bottom:0}.wSkVaW_widthHandle[data-side=left]:after{right:16px}.wSkVaW_widthHandle[data-side=right]:after{left:16px}.wSkVaW_widthHandle:hover:after,.wSkVaW_widthHandle[data-dragging]:after{opacity:1}.wSkVaW_root:has([data-conversation-composer-overlay]) .wSkVaW_widthHandle{display:none}.wSkVaW_composerStack{--dsh-composer-stack-gap:6px;gap:var(--dsh-composer-stack-gap);flex-direction:column;display:flex}.wSkVaW_composerSeat{--dsh-composer-text-max-height:336px;flex-direction:column;flex:none;display:flex}.wSkVaW_root[data-phase=active]{overflow:hidden}.wSkVaW_root[data-phase=active] .wSkVaW_header{flex:none}.wSkVaW_body{flex-direction:column;flex:1;min-height:0;display:flex;position:relative}.wSkVaW_scrollBody{scrollbar-gutter:stable;flex-direction:column;flex:1;min-height:0;margin-right:2px;display:flex;overflow-y:auto}.wSkVaW_scrollBody::-webkit-scrollbar-track{margin:2px}.wSkVaW_root[data-phase=active] .wSkVaW_viewArea{flex:1 0 auto;min-height:auto}.wSkVaW_root[data-phase=active] .wSkVaW_composerSeat{z-index:7;background:linear-gradient(180deg, color-mix(in srgb, var(--dsw-alias-bg-base) 0%, transparent) 0px, var(--dsw-alias-bg-base) 36px);position:sticky;bottom:0}.wSkVaW_root[data-phase=active] .wSkVaW_composerSeat:has([data-trigger-menu]){z-index:9}.wSkVaW_scrollBody:has([data-conversation-composer-overlay]){scrollbar-gutter:auto;position:relative;overflow:hidden auto}.wSkVaW_scrollBody:has([data-conversation-composer-overlay])>[data-slot=conversation\\.session]>.wSkVaW_viewArea{flex:1 1 0;min-height:0;overflow:hidden}.wSkVaW_scrollBody:has([data-conversation-composer-overlay])>.wSkVaW_composerSeat{right:var(--dsh-scrollbar-width);position:absolute;bottom:0;left:0}.wSkVaW_composerHero{width:min(calc(var(--dsh-composer-card-max-width) + 2 * var(--dsh-composer-side-clearance)), 100%);z-index:1;align-self:center;gap:8px;padding-bottom:32px}.wSkVaW_heroWorkspaceRow{align-items:center;gap:2px;min-width:0;margin-top:4px;padding:0 16px 0 20px;display:flex}.wSkVaW_root[data-phase=hero] .wSkVaW_scrollBody{justify-content:center;overflow-y:auto}.wSkVaW_root[data-phase=settling] .wSkVaW_composerSeat{visibility:hidden}";
14650
14653
  const tagId$4 = "@deepseek-ai/dsh-client-ui-conversation/ConversationRoot.module.css";
14651
14654
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$4) + "]") === null) {
14652
14655
  const tag = document.createElement("style");
@@ -14962,6 +14965,16 @@ window.__ModuleLoader__.load({
14962
14965
  });
14963
14966
  }
14964
14967
  //#endregion
14968
+ //#region lib/types/client/skeleton/ConversationPanel.js
14969
+ /**
14970
+ * Render the Conversation with optional current-Session binding.
14971
+ * @param props - main-slot inputs and the declared Conversation renderer.
14972
+ * @returns the Conversation subtree.
14973
+ */
14974
+ function ConversationPanel({ renderSlot }) {
14975
+ return renderSlot("main.conversation", {});
14976
+ }
14977
+ //#endregion
14965
14978
  //#region lib/types/client/view-selection.js
14966
14979
  const DEFAULT_VIEW_ID = "chat";
14967
14980
  /**
@@ -16103,7 +16116,7 @@ window.__ModuleLoader__.load({
16103
16116
  onKeyDown: workspaceTrigger ? onWorkspaceKeyDown : void 0,
16104
16117
  style: hint === null ? void 0 : { "--dsh-composer-hint": JSON.stringify(hint) }
16105
16118
  }),
16106
- empty && !claimActive && (0, react_jsx_runtime.jsx)("div", {
16119
+ draft === "" && attachments.length === 0 && !claimActive && (0, react_jsx_runtime.jsx)("div", {
16107
16120
  "aria-hidden": true,
16108
16121
  className: InputBar_module_css_default.placeholder,
16109
16122
  "data-composer-placeholder": true,
@@ -16594,7 +16607,7 @@ window.__ModuleLoader__.load({
16594
16607
  }
16595
16608
  });
16596
16609
  const registerConversationRoot = () => slots.register({
16597
- name: "conversation",
16610
+ name: "main.conversation",
16598
16611
  locale: NS,
16599
16612
  children: {
16600
16613
  "conversation.session": {
@@ -16632,8 +16645,7 @@ window.__ModuleLoader__.load({
16632
16645
  },
16633
16646
  inject: (sessionId) => ({
16634
16647
  hooks: { composerBlock: sessionId === void 0 ? ABSENT_BLOCK : composerBlocks.storeFor(sessionId) },
16635
- selectWorkspace: async (workspaceId) => {
16636
- const nextId = await workspaceNavigation.connectWorkspace(workspaceId);
16648
+ selectWorkspace: (workspaceId) => workspaceNavigation.openWorkspace(workspaceId, (nextId) => {
16637
16649
  if (sessionId !== void 0 && nextId !== sessionId) {
16638
16650
  const from = inputHub.shell(sessionId);
16639
16651
  const draft = from.snapshot.draft;
@@ -16649,8 +16661,7 @@ window.__ModuleLoader__.load({
16649
16661
  if (attachmentIds.length > 0) for (const id of attachmentIds) from.removeAttachment(id);
16650
16662
  }
16651
16663
  }
16652
- sessions.open(nextId);
16653
- }
16664
+ })
16654
16665
  })
16655
16666
  }, ConversationRoot);
16656
16667
  const registerConversationSession = () => slots.register({
@@ -16694,7 +16705,7 @@ window.__ModuleLoader__.load({
16694
16705
  inject: (sessionId, actions) => ({
16695
16706
  hooks: { conversationViews },
16696
16707
  open: (id) => {
16697
- sessions.open(id);
16708
+ workspaceNavigation.openSession(id);
16698
16709
  },
16699
16710
  selectView: (view) => {
16700
16711
  activateView(sessionId, view);
@@ -16809,7 +16820,15 @@ window.__ModuleLoader__.load({
16809
16820
  };
16810
16821
  }
16811
16822
  }, InputBar);
16812
- slots.inject("conversation", function* () {
16823
+ slots.inject("main", function* () {
16824
+ yield slots.register({
16825
+ name: "main",
16826
+ key: "conversation",
16827
+ children: { "main.conversation": {
16828
+ kind: "single",
16829
+ scope: "session-maybe"
16830
+ } }
16831
+ }, ConversationPanel);
16813
16832
  yield registerConversationRoot();
16814
16833
  yield registerConversationSession();
16815
16834
  yield registerConversationHeader();
@@ -109,6 +109,11 @@ export type UseConversation = SnapshotSelectorHook<ConversationSnapshot>;
109
109
  export type UseConversationViews = SnapshotSelectorHook<readonly ViewTab[]>;
110
110
  declare module '@deepseek-ai/dsh-client-ui-slots' {
111
111
  interface SlotMap {
112
+ /** Conversation shell beneath its root-scoped main-panel entry. */
113
+ 'main.conversation': {
114
+ kind: 'single';
115
+ scope: 'session-maybe';
116
+ };
112
117
  /** Strict per-Session Conversation body. */
113
118
  'conversation.session': {
114
119
  kind: 'single';
@@ -139,10 +144,9 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
139
144
  };
140
145
  /**
141
146
  * The header's far-right corner, past the utilities' edge and into the
142
- * header's own padding, for one control that must keep its place whether or
143
- * not it currently shows anything. The corner reserves its width while an
144
- * occupant is registered, so the utilities beside it never move; an
145
- * occupant with nothing to show renders a same-size placeholder.
147
+ * header's own padding, for one control. The corner is laid out only while
148
+ * its occupant renders something; an occupant with nothing to show renders
149
+ * nothing, and the utilities take the header's edge.
146
150
  */
147
151
  'conversation.session.header.corner': {
148
152
  kind: 'single';
@@ -388,7 +392,7 @@ export interface HeroBrandMarkOwnerProps {
388
392
  className?: string | undefined;
389
393
  }
390
394
  /** Full props of the resident optional-Session Conversation shell. */
391
- export type ConversationSlotProps = PropsRuntime<'conversation'> & PropsRenderSlots<'conversation.session' | 'conversation.session.header' | 'conversation.composer' | 'conversation.composer.bar' | 'conversation.input.dock' | 'conversation.hero.brand.mark' | 'conversation.hero.workspace' | 'conversation.hero.agentPreset'> & InjectFace<ConversationInjected> & PropsLocale<'conversation'>;
395
+ export type ConversationSlotProps = PropsRuntime<'main.conversation'> & PropsRenderSlots<'conversation.session' | 'conversation.session.header' | 'conversation.composer' | 'conversation.composer.bar' | 'conversation.input.dock' | 'conversation.hero.brand.mark' | 'conversation.hero.workspace' | 'conversation.hero.agentPreset'> & InjectFace<ConversationInjected> & PropsLocale<'conversation'>;
392
396
  /** Shared target-neutral Conversation store handle. */
393
397
  export type ConversationStore = ReturnType<typeof createConversationStore>;
394
398
  /** Full props of the strict Session body. */
@@ -0,0 +1,9 @@
1
+ /** Root-scoped main occupant; Session binding belongs to its Conversation child. */
2
+ import type { PropsRenderSlots, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
3
+ /**
4
+ * Render the Conversation with optional current-Session binding.
5
+ * @param props - main-slot inputs and the declared Conversation renderer.
6
+ * @returns the Conversation subtree.
7
+ */
8
+ export declare function ConversationPanel({ renderSlot }: PropsRuntime<'main'> & PropsRenderSlots<'main.conversation'>): import("react").ReactNode;
9
+ //# sourceMappingURL=ConversationPanel.d.ts.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-client-ui-conversation",
3
3
  "description": "Target-neutral Conversation assembly, shell, composer, queue, and view navigation",
4
- "version": "0.1.5-alpha.1",
4
+ "version": "0.1.5-alpha.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -42,12 +42,6 @@
42
42
  },
43
43
  "license": "MIT",
44
44
  "dependencies": {
45
- "clsx": "^2.0.0",
46
- "@lexical/history": "^0.49.0",
47
- "@lexical/plain-text": "^0.49.0",
48
- "@lexical/text": "^0.49.0",
49
- "@lexical/utils": "^0.49.0",
50
- "lexical": "^0.49.0",
51
45
  "@deepseek-ai/schemastery": "^3.18.2"
52
46
  },
53
47
  "peerDependencies": {
@@ -60,36 +54,42 @@
60
54
  "react-dom": "^18.2.0",
61
55
  "@types/react-dom": "~18.3.0",
62
56
  "zod": "^4.4.3",
57
+ "lexical": "^0.49.0",
58
+ "clsx": "^2.0.0",
59
+ "@lexical/utils": "^0.49.0",
60
+ "@lexical/text": "^0.49.0",
61
+ "@lexical/plain-text": "^0.49.0",
62
+ "@lexical/history": "^0.49.0",
63
63
  "@deepseek-ai/cordis": "^4.0.2",
64
- "@deepseek-ai/dsh-api-remotes": "^0.1.5-alpha.1",
65
- "@deepseek-ai/dsh-api-session-controller": "^0.1.5-alpha.1",
66
- "@deepseek-ai/dsh-api-workspace-controller": "^0.1.5-alpha.1",
67
- "@deepseek-ai/dsh-attachment": "^0.1.5-alpha.1",
68
- "@deepseek-ai/dsh-brand": "^0.1.5-alpha.1",
69
- "@deepseek-ai/dsh-client-locale": "^0.1.5-alpha.1",
70
- "@deepseek-ai/dsh-client-store": "^0.1.5-alpha.1",
71
- "@deepseek-ai/dsh-client-test-runtime": "^0.1.5-alpha.1",
72
- "@deepseek-ai/dsh-client-ui-layout": "^0.1.5-alpha.1",
73
- "@deepseek-ai/dsh-client-ui-primitives": "^0.1.5-alpha.1",
74
- "@deepseek-ai/dsh-client-ui-renderer": "^0.1.5-alpha.1",
75
- "@deepseek-ai/dsh-client-ui-session": "^0.1.5-alpha.1",
76
- "@deepseek-ai/dsh-client-ui-settings": "^0.1.5-alpha.1",
77
- "@deepseek-ai/dsh-client-ui-workspace": "^0.1.5-alpha.1",
78
- "@deepseek-ai/dsh-commands": "^0.1.5-alpha.1",
79
- "@deepseek-ai/dsh-goal": "^0.1.5-alpha.1",
80
- "@deepseek-ai/dsh-llm": "^0.1.5-alpha.1",
81
- "@deepseek-ai/dsh-llm-retry": "^0.1.5-alpha.1",
82
- "@deepseek-ai/dsh-permission-presets": "^0.1.5-alpha.1",
83
- "@deepseek-ai/dsh-plan-mode": "^0.1.5-alpha.1",
84
- "@deepseek-ai/dsh-client-ui-slots": "^0.1.5-alpha.1",
85
- "@deepseek-ai/dsh-tool-todo": "^0.1.5-alpha.1",
86
- "@deepseek-ai/dsh-util-crypto": "^0.1.5-alpha.1",
87
- "@deepseek-ai/dsh-workspace": "^0.1.5-alpha.1",
88
- "@deepseek-ai/dsh-util-workspace-path": "^0.1.5-alpha.1",
89
- "@deepseek-ai/dsh-settings": "^0.1.5-alpha.1",
90
- "@deepseek-ai/dsh-token-meter": "^0.1.5-alpha.1",
91
- "@deepseek-ai/dsh-session": "^0.1.5-alpha.1",
92
- "@deepseek-ai/dsh-client-file-upload": "^0.1.5-alpha.1"
64
+ "@deepseek-ai/dsh-api-session-controller": "^0.1.5-alpha.2",
65
+ "@deepseek-ai/dsh-api-remotes": "^0.1.5-alpha.2",
66
+ "@deepseek-ai/dsh-attachment": "^0.1.5-alpha.2",
67
+ "@deepseek-ai/dsh-api-workspace-controller": "^0.1.5-alpha.2",
68
+ "@deepseek-ai/dsh-client-locale": "^0.1.5-alpha.2",
69
+ "@deepseek-ai/dsh-client-file-upload": "^0.1.5-alpha.2",
70
+ "@deepseek-ai/dsh-client-store": "^0.1.5-alpha.2",
71
+ "@deepseek-ai/dsh-client-test-runtime": "^0.1.5-alpha.2",
72
+ "@deepseek-ai/dsh-client-ui-layout": "^0.1.5-alpha.2",
73
+ "@deepseek-ai/dsh-client-ui-primitives": "^0.1.5-alpha.2",
74
+ "@deepseek-ai/dsh-client-ui-renderer": "^0.1.5-alpha.2",
75
+ "@deepseek-ai/dsh-client-ui-session": "^0.1.5-alpha.2",
76
+ "@deepseek-ai/dsh-client-ui-settings": "^0.1.5-alpha.2",
77
+ "@deepseek-ai/dsh-client-ui-workspace": "^0.1.5-alpha.2",
78
+ "@deepseek-ai/dsh-client-ui-slots": "^0.1.5-alpha.2",
79
+ "@deepseek-ai/dsh-commands": "^0.1.5-alpha.2",
80
+ "@deepseek-ai/dsh-goal": "^0.1.5-alpha.2",
81
+ "@deepseek-ai/dsh-llm": "^0.1.5-alpha.2",
82
+ "@deepseek-ai/dsh-llm-retry": "^0.1.5-alpha.2",
83
+ "@deepseek-ai/dsh-permission-presets": "^0.1.5-alpha.2",
84
+ "@deepseek-ai/dsh-plan-mode": "^0.1.5-alpha.2",
85
+ "@deepseek-ai/dsh-session": "^0.1.5-alpha.2",
86
+ "@deepseek-ai/dsh-token-meter": "^0.1.5-alpha.2",
87
+ "@deepseek-ai/dsh-tool-todo": "^0.1.5-alpha.2",
88
+ "@deepseek-ai/dsh-util-crypto": "^0.1.5-alpha.2",
89
+ "@deepseek-ai/dsh-brand": "^0.1.5-alpha.2",
90
+ "@deepseek-ai/dsh-workspace": "^0.1.5-alpha.2",
91
+ "@deepseek-ai/dsh-util-workspace-path": "^0.1.5-alpha.2",
92
+ "@deepseek-ai/dsh-settings": "^0.1.5-alpha.2"
93
93
  },
94
94
  "files": [
95
95
  "lib/index.js",