DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

JHyugou /

JHyugou/dsh-enter-send

Verified

DSH 插件:在输入框工具行「权限」按钮右侧加一个发送键开关,可在 Enter 发送与 Ctrl+Enter 发送之间切换,另一个键自动变为换行(Send-key toggle chip for DeepSeek Harness)

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@861a4eae

dsh-enter-send

给 DeepSeek Harness 的输入框工具行加一个发送键开关:放在「权限(工作区内修改)」控件的右侧, 点一下就能在 Enter 发送 与 Ctrl+Enter 发送 之间切换。

工具行对齐

(截图来自 node tools/browser-check.mjs --shot,是本机 desktop profile 真实渲染的工具行: + / 工作区内修改 / 电脑操控:全自动 / ↵ Ctrl+Enter 发送 / … / 模型 / 发送。 conversation.input.left 是 list 席位,别的插件也可能在这条行里占一格——这里 dsh-computer-use 用 order 0 排在前面;本控件与相邻控件同高、同中线,左右间距就是工具行 自己的 column-gap(12px)。)

用法

操作 结果
点工具行里的 ↵ Enter 发送 弹出菜单:「发送方式」下两项,当前项带对勾
选 Enter 发送(默认) Enter 提交(DSH 原生);Ctrl/Cmd+Enter 换行、Shift+Enter 换行
选 Ctrl+Enter 发送 Ctrl/Cmd+Enter 提交(与按 Enter、点发送按钮同一条路径);Enter 换行、Shift+Enter 换行

两种模式都是「发送键之外的另一个键负责换行」:Enter 发送模式下是 Ctrl+Enter(以及 DSH 原生的 Shift+Enter),Ctrl+Enter 发送模式下是 Enter(以及 Shift+Enter)。

细节:

  • 选择保存在浏览器 localStorage(键 dsh-enter-send.mode.v1,v1 存 {version:1,mode}),跨刷新保留; 换浏览器/清站点数据会回到默认,DSH 本身不受影响。
  • 只在输入框正文里改写按键:队列里的小编辑器、重命名框、终端、其它 contenteditable 一律不碰。
  • 输入法组字中的 Enter 原样放行;Alt/AltGraph 组合原样放行。
  • 补全菜单(/、@)已高亮候选时,Enter 仍然归菜单去选中候选,不会被改成换行。
  • 长按不会连发:重放事件保留 repeat 标志,交给 DSH 自己的「长按不重复发送」判断。
  • 窄卡片(容器宽度 ≤ 460px)下与权限控件一样只留图标,不额外占宽。
  • 默认值就是 Enter 发送:装上插件、不动开关,Enter 提交仍然完全是 DSH 原生行为 (唯一变化是 Ctrl+Enter 从 DSH 的「互补 Queue/Steer 提交」变成换行,见「已知限制」)。

安装(本机 desktop profile 已装好)

# link 方式装进 desktop profile(改代码即时生效;desktop profile 只能由桌面应用管理,
# 用应用里的「插件」面板安装,或在应用内执行等价的 pnpm 操作)
dsh plugin --profile <profile> add <本目录路径>
dsh plugin --profile <profile> remove dsh-enter-send     # 卸载

装好后宿主会热加载(dsh-client-modules 增量扫描 Loader 条目),已经打开的窗口刷新一次页面(Ctrl+R) 即可看到新控件。

验证

node --test                       # 25 项单元测试:偏好读写/迁移、Enter 判定表(两种模式 ×
                                  #   修饰键组合)、DOM 事实提取、捕获阶段改写与重放、注册契约、
                                  #   宿主入口契约(无需浏览器)
node tools/verify.mjs             # 宿主端 7 项:profile 清单/link/包契约 + 启动图收录 +
                                  #   bundle 可取回 + /api 诊断路由
node tools/browser-check.mjs      # 真浏览器 20 项:席位/相邻/对齐/菜单/持久化/窄卡片折叠
                                  #   + 两种模式下 Enter 与 Ctrl+Enter 的真实按键行为
                                  #   (会发送 2 条测试消息)
node tools/browser-check.mjs --no-keys   # 只跑非破坏性检查(不发送任何消息)
node tools/browser-check.mjs --shot      # 额外把证据截图存到 docs/

三个脚本都用 ~/.dsh/.credentials.yaml 的 browser-session secret 现场铸签名 cookie(与浏览器同构), 不读取、不打印其它凭据;browser-check.mjs 用临时 --user-data-dir 起 headless Chrome, 与你正在用的窗口完全隔离,没有 Chrome/Edge 时会明确报错退出。

排障时可以在 DSH 窗口的 DevTools 控制台里看这几处:

localStorage.getItem('dsh-enter-send.mode.v1')                     // 当前选择
document.querySelector('.dsh-es-trigger')?.innerText               // 工具行里的控件
document.querySelector('[data-slot="conversation.input.left"]')    // 它注册到的席位

架构

DSH 插件是「宿主端 + 浏览器端」双半结构,本插件零 npm 依赖、零构建:

文件 角色
src/client.js 浏览器端 bundle(window.__ModuleLoader__.load 手写格式):chip UI、菜单、样式、Enter 改写
src/index.js 宿主端 Cordis 插件:让包成为 Loader 条目(浏览器 bundle 的发现前提)+ /api/dsh-enter-send.status 只读诊断路由
cordis.patch.yml 安装时自激活宿主端入口
package.json dsh.bundle.patch 自激活 + dsh.client.platform = web 浏览器 bundle 声明
test/ 单元测试(把 bundle 用 ModuleLoader 桩加载后直接断言)
tools/ 验证脚本:verify.mjs(宿主)、browser-check.mjs(真浏览器,可 --shot 截图)

界面:为什么用 conversation.input.left

@deepseek-ai/dsh-client-ui-conversation 的输入框工具行是固定结构(InputBar.tsx):

<div class="row">
  <div class="tools">              ← 左组,gap 12px
    [+]  <div class="modes"> 权限控件 / 计划控件 </div>
    {renderSlot('conversation.input.left', {})}   ← 本插件在这里
  </div>
  <div class="trailing"> …模型 / 麦克风 / 发送… </div>
</div>

conversation.input.left 是 list 席位,渲染位置就在权限与计划控件之后、工具行内, 正是截图里红框那一格——不需要 DOM 注入,也不需要 portal。chip 的规格直接照抄 PermissionSelect.module.css 的触发器(28px 高、border-radius: var(--dsw-radius-sm)、 13/20 medium、gap:4px、padding:0 4px 0 8px、--dsw-alias-label-secondary、 悬停 --dsw-alias-interactive-bg-hover、14px 前置图标 + 16px 折叠箭头), 菜单用 ui-primitives 的 Menu(与权限控件同一个组件、同一套样式),所以外观与相邻控件天然一致。

行为:为什么是「捕获阶段改写 + 重放」

DSH 的输入框是 Lexical 编辑器,键位在 KEY_ENTER_COMMAND(critical 优先级)里判定 (ui-conversation/src/client/input/editor/keymap.ts):

if (event?.shiftKey === true) return false        // Shift+Enter → 原生换行
if (handlers.arbitrate('enter', false) !== 'pass') …  // 菜单高亮 → 归菜单
event?.preventDefault()
handlers.submit(event?.ctrlKey === true || event?.metaKey === true)   // 其余 → 提交

本插件不调用任何 DSH 内部 API(也不 import 它的私有模块),而是在 document 捕获阶段先拿到按键, 把语义重放成等价的那一个:

选择 真实按键 重放成
Enter 发送(默认) Ctrl/Cmd+Enter Shift+Enter(→ DSH 原生的换行路径;替代 DSH 原本的「互补」提交)
Enter 发送(默认) Enter / Shift+Enter 不拦,完全交给 DSH
Ctrl+Enter 发送 Ctrl/Cmd+Enter 普通 Enter(→ 与按 Enter、点发送按钮完全同一条提交路径)
Ctrl+Enter 发送 Enter Shift+Enter(→ DSH 原生的换行路径)

重放用的是同元素上的合成 KeyboardEvent:Lexical 的 keydown 监听挂在编辑器根元素上、 不检查 isTrusted,所以合成事件与真实按键走同一条链路;repeat 标志跟着原事件走,长按不会连发。 补全菜单高亮时([role="listbox"][aria-activedescendant])Enter 交给 DSH 的菜单仲裁去选候选, 不会被改成换行。

与 DSH 的耦合点(都有降级)

依赖 变化时的表现
conversation.input.left 席位 席位消失 → ctx.slots.inject 等待/摘除,插件静默失效,不影响 DSH 其它功能
[data-composer-input] / contenteditable="true" 改名 → 按键改写不生效(退化成「只有开关,没有行为」),控制台无异常
Lexical 的 KEY_ENTER_COMMAND 语义(Shift=换行、其余=提交) 语义变化 → 重放结果跟着变;单元测试会先失败
[role="listbox"][aria-activedescendant] 补全菜单改名 → 菜单打开时 Enter 会被改成换行(可接受的降级)
localStorage 不可用(隐私模式) 降级为「本次会话有效」

任何一处失败都只降级本插件自己;插槽渲染器会把崩溃的条目隔离在 [data-slot-error],不会拖累外壳。

已知限制

  • 开关是浏览器本地偏好(localStorage),不写宿主设置,所以同一台机器的另一个浏览器/另一份 profile 数据不会同步;DSH 官方设置里也不会出现这一项。
  • 只覆盖输入框正文的 Enter:队列里那条小编辑器(Enter 保存)按自己的语义走,不受开关影响。
  • conversation.input.left 是 list 席位:别的插件也在用(例如 dsh-computer-use,order 0), 它们按各自 order 排列;本插件用 order 100,所以排在它们之后。想让开关更靠左(比如紧贴权限控件), 把 src/client.js 里 ctx.slots.register({ … order: 100 … }) 的 order 调小即可。
  • 「Ctrl+Enter 发送」模式下,Ctrl+Enter 走的是普通提交语义(与 Enter 相同,遵守 DSH 自己的 队列/转向偏好),不是 DSH 原生的「互补」提交;这正是「Ctrl+Enter 就是发送键」的含义。
  • 「Enter 发送」模式下,Ctrl/Cmd+Enter 被改成换行,因此 DSH 原生的「互补 Queue/Steer 提交」 (固定按键 fixed.complementary)在这个模式下不可用;需要它时切到「Ctrl+Enter 发送」即可 (那里 Ctrl+Enter 是发送键,Enter 是换行键)。快捷键帮助里由 DSH 自己登记的那条说明不会随之变化。
  • 桌面端与 Web 端一致:Windows/macOS 桌面只把可配置快捷键拦在原生层,Enter/Ctrl+Enter 属于 固定动作,仍然走 DOM,所以本插件在桌面应用与浏览器里行为相同。

本机开发备注

  • .ref/ 是本机 DSH 内置包源码摘录与探查脚本(仅本地参考,已 gitignore,不随包发布); 摘录用 dsh-remind 里的 tools/asar.mjs,源码可在 E:\deepseek-harness 查看。
  • 改了 src/client.js 后:宿主会重新计算 bundle 版本(按文件 mtime/size),页面刷新即生效; 宿主端 src/index.js 改动需要重启 DSH(或插件页重载)。
—/ 5

No ratings yet

Verified DSH bundle

Commit 861a4eaeb5ee

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout