dsh-multiline-input 0.0.0-stage → 0.1.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 +22 -0
- package/LICENSE +21 -0
- package/README.md +136 -2
- package/ROADMAP.md +33 -0
- package/assets/icon-180.png +0 -0
- package/assets/screenshot-1-single-line.png +0 -0
- package/assets/screenshot-2-multiline.png +0 -0
- package/client.js +644 -0
- package/cordis.patch.yml +9 -0
- package/docs/PLAN-2026-10-27.md +227 -0
- package/docs/RELEASE-CHECKLIST-0.1.0.md +69 -0
- package/docs/RELEASE-CHECKLIST-0.1.1.md +58 -0
- package/icon.svg +4 -0
- package/index.js +17 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +70 -4
- package/screenshots.json +4 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# dsh-ml-input 0.1.0 实施计划(按 DSH 源码修订)
|
|
2
|
+
|
|
3
|
+
> 本文件按获批时的内容原样存档,不再随实施更新;实施与计划的差异记录在文末「实施偏差(事后补记)」小节。
|
|
4
|
+
|
|
5
|
+
## 0. 先回答两个问题
|
|
6
|
+
|
|
7
|
+
**Q1:为什么之前把目标写成「DSH 0.2.1-rc.3 / 桌面版 / profile main / 52043」?**
|
|
8
|
+
写窄了,已改。目标应是 **DSH 插件契约本身**:一个遵循 `dsh.client` + Slots + Shortcuts 契约的第三方客户端插件,兼容当前发布线(源码 master 即 `0.2.1-rc.3`)。版本号只用于声明兼容边界与回归范围;`profile main`、端口、桌面版 2.0.20-next 只是本机验收环境,不再进入目标定义。
|
|
9
|
+
|
|
10
|
+
**Q2:为什么去拆 app.asar?**
|
|
11
|
+
我的错误。运行上下文把 app.asar 标成了 checkout,我顺手用了它;既然本机有完整源码克隆 `/Users/zilong/zWork/frontend/deepseek-harness`(master,`22ddee3`,2026-10-23,与运行版构建同日;根版本 `0.2.1-rc.3`),就该直接读源码。该路径已记入长期记忆;本修订版的所有依据都改为源码路径,不再引用解包结果。
|
|
12
|
+
|
|
13
|
+
## 1. 目标与验收标准
|
|
14
|
+
|
|
15
|
+
**目标**:纯客户端第三方插件 `dsh-ml-input`,不改 DSH 源码,把对话输入框在「单行(现状)/ 多行」之间循环切换:
|
|
16
|
+
|
|
17
|
+
1. 输入框右上角显示当前生效的切换快捷键(默认 `Ctrl+E`)+「多行输入」;输入框为空时显示,有草稿/附件时隐藏,避免压字。
|
|
18
|
+
2. 按快捷键循环:单行 → 多行 → 单行。
|
|
19
|
+
3. 多行模式默认高度 **4 行**(落在需求的 3–5 行区间),内容变多继续长高,到原生 336px 上限后滚动。
|
|
20
|
+
4. 多行模式下 **Enter 换行、Shift+Enter 提交**;单行模式保持 DSH 现状(Enter 提交、Shift+Enter 换行)。
|
|
21
|
+
5. 快捷键可在官方「设置 → 通用 → 快捷键」里改绑,提示实时跟随。
|
|
22
|
+
|
|
23
|
+
**验收标准**:
|
|
24
|
+
|
|
25
|
+
- 空输入右上角出现 `Ctrl+E 多行输入`;输入后消失,清空重现。
|
|
26
|
+
- `Ctrl+E` 在编辑器内、页面空白处都能切换;设置/其它输入框里不抢键。
|
|
27
|
+
- 多行最小高度 4 行;切回单行立即恢复;草稿不丢。
|
|
28
|
+
- 多行:Enter 换行(可撤销)、Shift+Enter 发送;`Cmd/Ctrl+Enter` 仍是加速提交;`/`、`@` 菜单打开时 Enter 仍是选中菜单项;输入法候选态不误触。
|
|
29
|
+
- 刷新后模式保持;设置里改键后提示立即变化、冲突有官方提示。
|
|
30
|
+
- 禁用/卸载后无 `<html data-dsh-ml-input>`、无 `<style>`、无键盘监听、无快捷键命令残留。
|
|
31
|
+
|
|
32
|
+
## 2. 源码依据(`/Users/zilong/zWork/frontend/deepseek-harness`,commit `22ddee3`)
|
|
33
|
+
|
|
34
|
+
| 事实 | 源码位置 |
|
|
35
|
+
|---|---|
|
|
36
|
+
| 输入卡片 `<div data-composer-card>`(`position:relative`)与覆盖层锚点 `<div data-composer-overlay>`(`position:absolute; inset:0 0 auto; height:0`) | `packages/client/ui-conversation/src/client/skeleton/InputBar.tsx`(~423 行)、`InputBar.module.css`(`.overlayAnchor`) |
|
|
37
|
+
| 可编辑面是 Lexical contenteditable:`data-composer-input`、`role="textbox"`、`aria-multiline="true"`,带 `data-phase`、`data-placeholder` | `.../input/editor/ComposerContentEditable.tsx`、`.../input/editor/DraftEditor.tsx` |
|
|
38
|
+
| 占位符 `[data-composer-placeholder]` 只在 `draft === '' && 无附件 && 无命令 claim` 时渲染 | `.../input/editor/DraftEditor.tsx` + `InputBar.tsx` 的 `showPlaceholder` |
|
|
39
|
+
| 高度:`.input { min-height:36px }`、hero 52px;滚动上限 `--dsh-composer-text-max-height:336px`(约 14 行) | `InputBar.module.css`、`ConversationRoot.module.css`(~411 行) |
|
|
40
|
+
| Enter 语义:`KEY_ENTER_COMMAND` 注册在 `COMMAND_PRIORITY_CRITICAL`;**`event.shiftKey === true` 时 return false**(落到 `@lexical/plain-text` 的换行默认),否则提交 | `.../input/editor/keymap.ts`(~257-270 行,文件头注释写明该回退语义) |
|
|
41
|
+
| 公开输入动作面:`InputActions` 提供 `captureInsertion / insertText / setDraft / submit` 等 | `.../contract/input.ts`(~250-285 行) |
|
|
42
|
+
| Session 级座位标准 props:`sessionId`、`useSession`、`useConversation`、`useInput`、`inputActions`;`conversation.input.overlay` 为 `{kind:'list', scope:'session'}`("Floating entries rendered inside the resident composer card") | `.../contract/slots.ts`(~292、~350-365 行) |
|
|
43
|
+
| 斜杠/引用菜单在覆盖层内渲染 `[role="listbox"]`,且以 `[data-composer-card]` 为定位锚点 | `packages/client/ui-input-trigger/src/client/MenuView.tsx`(~86、132 行) |
|
|
44
|
+
| 快捷键命令契约:`ShortcutCommand{id,label,aliases,defaults,regions,modals,resolve}`;`ShortcutContext{source,region,modal,target}`;Web 白名单 `isWebBindingAllowed` 允许 `primary+shift+字母` | `packages/client/shortcuts/src/client/types.ts`、`packages/client/shortcuts/src/binding.ts`(~96-112 行)、`packages/client/shortcuts/README.zh.md` |
|
|
45
|
+
| 客户端插件清单:`DshClientManifest{platform, inject?, immediately?, external?}`;包需 `exports['./client']` + `dsh.bundle.patch`(无 bundle patch 会被标 `not-bundle`) | `packages/util/package-manifest/src/types.ts`、`packages/client/modules/README.zh.md`、`packages/boot/plugin-manager/src/index.ts`(~459 行) |
|
|
46
|
+
| 第三方手写 bundle 的可行样本:`dsh-session-titler`(`window.__ModuleLoader__.load({id, factory})`,React 走 `require('react')`,模块级 store + `useSyncExternalStore`) | 已装插件 `~/.dsh/profiles/web/node_modules/dsh-session-titler/client.js` |
|
|
47
|
+
|
|
48
|
+
补充:源码 master 与运行中的桌面版(2.0.20-next,内置 dsh 0.2.1-rc.3,构建于 10-23)为同一版本线;`ShortcutCommand` 所需的 `regions/modals/aliases` 都已核对。现有已装插件里没有占用 `KeyE` 的默认绑定(唯一命中是 `apiKeyEnv` 文本)。
|
|
49
|
+
|
|
50
|
+
## 3. 交付物(工作区即插件包根目录)
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
dsh-ml-input/
|
|
54
|
+
├── package.json # name=dsh-ml-input, dsh.bundle.patch + dsh.client
|
|
55
|
+
├── cordis.patch.yml # insert 一行 host 插件(id: ml-input)
|
|
56
|
+
├── index.js # Host 半:空实现,满足 bundle patch 契约
|
|
57
|
+
├── client.js # 手写 Client 半(状态 / 快捷键 / 提示 / 键位接管 / CSS)
|
|
58
|
+
├── icon.svg
|
|
59
|
+
├── locale/zh.json # {"meta":{title,description}}
|
|
60
|
+
├── locale/en.json
|
|
61
|
+
├── test/core.test.js # node --test
|
|
62
|
+
├── test/harness.js # Node 里的 __ModuleLoader__ 垫片
|
|
63
|
+
├── README.md / ROADMAP.md / CHANGELOG.md / LICENSE / .gitignore
|
|
64
|
+
└── docs/
|
|
65
|
+
├── PLAN-2026-10-27.md
|
|
66
|
+
└── RELEASE-CHECKLIST-0.1.0.md
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
无第三方依赖、无构建。插件仍放在 `zl-plugins/dsh-ml-input`(与 dsh-session-titler 等一致),DSH 仓库只作契约依据与回归参考。
|
|
70
|
+
|
|
71
|
+
## 4. 实现设计
|
|
72
|
+
|
|
73
|
+
### 4.1 清单与 Host 半
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"name": "dsh-ml-input",
|
|
78
|
+
"version": "0.1.0",
|
|
79
|
+
"type": "module",
|
|
80
|
+
"exports": { ".": "./index.js", "./client": "./client.js",
|
|
81
|
+
"./package.json": "./package.json", "./locale/*.json": "./locale/*.json" },
|
|
82
|
+
"dsh": {
|
|
83
|
+
"bundle": { "patch": "./cordis.patch.yml" },
|
|
84
|
+
"client": {
|
|
85
|
+
"platform": "web",
|
|
86
|
+
"immediately": true,
|
|
87
|
+
"inject": ["@deepseek-ai/dsh-client-locale", "@deepseek-ai/dsh-client-ui-conversation"]
|
|
88
|
+
},
|
|
89
|
+
"compatibility": { "dsh": ">=0.2.1-rc.3 <0.3.0-0" }
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`cordis.patch.yml`:
|
|
95
|
+
|
|
96
|
+
```yaml
|
|
97
|
+
- insert:
|
|
98
|
+
- id: ml-input
|
|
99
|
+
name: 'dsh-ml-input'
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`index.js` 只导出 `name` 与空的 `apply(){}`,让包成为可安装/启停的 bundle row;客户端半由 `dsh.client` 自动发现。
|
|
103
|
+
|
|
104
|
+
### 4.2 模式状态
|
|
105
|
+
|
|
106
|
+
- `'single' | 'multi'`,默认 `single`;`localStorage['dsh-ml-input.mode.v1']`(读写 try/catch,失败退化内存态)。
|
|
107
|
+
- 生效:`<html data-dsh-ml-input="multi">`,单行时移除;`apply()` 时同步设置,卸载时清理。
|
|
108
|
+
- 模块级 store:`getSnapshot / subscribe / toggle`,提示组件用 `useSyncExternalStore` 订阅(与 dsh-session-titler 同款)。
|
|
109
|
+
- 切换不清空草稿、不抢焦点;点提示时 `mousedown.preventDefault()` 保焦点。
|
|
110
|
+
|
|
111
|
+
### 4.3 快捷键(官方命令,可编辑)
|
|
112
|
+
|
|
113
|
+
- id `ml-input.toggle`(满足 `a.b` 持久化格式);label zh「切换多行输入」/ en「Toggle multiline input」;aliases 含「多行输入 / 单行输入 / multiline / ml-input」。
|
|
114
|
+
- 默认:`desktop:macos|windows|linux` = `{code:'KeyE', modifiers:['control']}`(显示 `Ctrl+E`);`web:macos|windows` = `{code:'KeyE', modifiers:['primary','shift']}`(Web 白名单允许);`web:linux` 不设默认。
|
|
115
|
+
- `regions: ['page','editable']`,`modals: []`。
|
|
116
|
+
- `resolve(context)`:`modal !== null` → pass;目标在 composer 之外的输入框 → pass(保留系统/浏览器原生 Ctrl+E);否则 handled → `toggle()`。
|
|
117
|
+
- 注册放在 `ctx.inject(['shortcuts'], scope => scope.effect(() => scope.shortcuts.register(...)))`,try/catch:与其它插件默认组合冲突时降级为「点击切换」+ console.warn,不让插件激活失败。
|
|
118
|
+
- 修改入口即官方设置:注册后自动出现在「设置 → 通用 → 快捷键」弹窗(可搜索、录制、冲突提示、按设备持久化)。
|
|
119
|
+
- 提示键位来自 `ctx.shortcuts.catalog` 快照,自绘格式(control→Ctrl、meta→Cmd、alt→Alt、shift→Shift,code 去 `Key` 前缀),macOS 也显示 `Ctrl+E`。
|
|
120
|
+
|
|
121
|
+
### 4.4 右上角提示
|
|
122
|
+
|
|
123
|
+
- 座位 `conversation.input.overlay`(list,`order:10`),渲染 `<button class="dml-hint">`。
|
|
124
|
+
- 可见性用标准 hook `useInput(s => s.draft === '' && s.attachmentIds.length === 0)`,与 `showPlaceholder` 语义一致;不做订阅机制。
|
|
125
|
+
- 内容:`<span class="dml-key">Ctrl+E</span><span class="dml-label">多行输入</span>`;多行模式加 `<span class="dml-meta">Shift+Enter 提交</span>`,label 变「单行输入」。
|
|
126
|
+
- 定位 `position:absolute; top:8px; right:12px`(相对 `[data-composer-overlay]`),12px 字,key 用 `--dsw-alias-label-secondary`、label 用 `--dsw-alias-label-tertiary`。
|
|
127
|
+
- 点击切换;`click.stopPropagation()` 防止 hero 卡片触发工作区选择;`title` 说明可在设置中修改。
|
|
128
|
+
|
|
129
|
+
### 4.5 多行高度
|
|
130
|
+
|
|
131
|
+
```css
|
|
132
|
+
html[data-dsh-ml-input="multi"] [data-composer-card] [data-composer-input] {
|
|
133
|
+
min-height: calc(4 * 1lh + 8px); /* 4 行正文 + 上下 padding;不支持 lh 时回退 calc(4 * 24px + 8px) */
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
只依赖 `data-*` 锚点;specificity 高于 `.input` 与 hero 的 52px;不提高 336px 的滚动上限(4 行起步、最多约 14 行后滚动)。
|
|
138
|
+
|
|
139
|
+
### 4.6 Enter / Shift+Enter
|
|
140
|
+
|
|
141
|
+
document 捕获阶段 keydown(`ctx.effect` 卸载),全部满足才接管:多行模式;`key==='Enter'` 且无 `ctrl/meta/alt`;非输入法(`isComposing` / `keyCode 229`);目标在 `[data-composer-card]` 内且是 `[data-composer-input][contenteditable="true"]`;`data-phase === 'plain'`;覆盖层内无 `[role="listbox"]`。
|
|
142
|
+
|
|
143
|
+
接管:`preventDefault + stopPropagation`,向编辑器派发翻转 `shiftKey` 的合成 `KeyboardEvent`(打标防递归):
|
|
144
|
+
|
|
145
|
+
- Enter → 派发 Shift+Enter:走 DSH 自己的换行分支(LineBreak,进 undo);
|
|
146
|
+
- Shift+Enter → 派发 Enter:走 DSH 自己的提交分支(busy-enter / canSubmit / 菜单仲裁全部保留)。
|
|
147
|
+
|
|
148
|
+
兜底(实机若合成事件不生效):改用 `inputActions.captureInsertion()` + `insertText('\n', span)` 换行、`inputActions.submit()` 提交,判定条件不变。
|
|
149
|
+
|
|
150
|
+
## 5. 边界与失败模式
|
|
151
|
+
|
|
152
|
+
| 场景 | 处理 |
|
|
153
|
+
|---|---|
|
|
154
|
+
| 输入法候选态 Enter | 放行 |
|
|
155
|
+
| `/`、`@` 菜单打开 | 检测 `[role=listbox]`,放行 |
|
|
156
|
+
| 命令 claim / 提交中 | `data-phase !== 'plain'` 放行 |
|
|
157
|
+
| Cmd/Ctrl+Enter、Alt+Enter | 放行 |
|
|
158
|
+
| 其它输入框里的 Ctrl+E | resolve 返回 pass |
|
|
159
|
+
| 设置弹窗/录制中 | `modal !== null` → pass |
|
|
160
|
+
| 快捷键冲突 | catch 降级,提示仍可点 |
|
|
161
|
+
| 快捷键被清空 | 提示只显示文案 |
|
|
162
|
+
| 无 shortcuts 服务 | `ctx.inject` 不触发,其余功能照常 |
|
|
163
|
+
| localStorage 不可用 | 内存态 |
|
|
164
|
+
| 两个 composer | 高度统一生效,提示各自渲染,监听一份 |
|
|
165
|
+
| 只读 composer | `contenteditable="true"` 才接管 |
|
|
166
|
+
| DSH DOM 锚点变化 | 首次挂载自检,缺锚点只 warn 一次,不崩 |
|
|
167
|
+
| 卸载 | 移除 style / 属性 / 监听 / 命令 |
|
|
168
|
+
|
|
169
|
+
## 6. 测试与验收
|
|
170
|
+
|
|
171
|
+
**自动**(`npm test` = `node --test`):harness 垫 `window.__ModuleLoader__` 与 `require('react')`,取 `client.js` 的 `__test` 纯函数,覆盖:模式循环与非法值归一;存储异常;`formatShortcut`;默认组合常量(桌面 control+KeyE、web primary+shift+KeyE、web:linux 无);`shouldIntercept` 全分支(多行/单行、Shift、修饰键、IME、phase、菜单、目标);属性 set/remove。
|
|
172
|
+
**静态**:`node --check`、locale JSON 解析、`npm --cache .npm-cache pack --dry-run` 文件清单。
|
|
173
|
+
**实机**(安装后逐条):提示出现/隐藏;切换高度 4 行;Enter 换行、Shift+Enter 发送;Cmd/Ctrl+Enter 不变;斜杠菜单 Enter 不变;输入法不误触;刷新保持;设置改键生效;禁用后恢复原样。
|
|
174
|
+
|
|
175
|
+
## 7. 安装与验证
|
|
176
|
+
|
|
177
|
+
- 先重新读一遍第 2 节源码文件,确认 master 未漂移。
|
|
178
|
+
- 装进正在使用的 profile(当前 `main`):优先应用内「插件」页 → 添加插件 → 绝对路径 `/Users/zilong/zWork/ai/zl-plugins/dsh-ml-input` → 安装 → 启用 → 刷新;备选 `dsh plugin --profile main add link:/Users/zilong/zWork/ai/zl-plugins/dsh-ml-input`(执行前单独确认)。
|
|
179
|
+
- 之后改 `client.js`/CSS 刷新页面即可;清单变更才需重启。
|
|
180
|
+
- 回滚:插件页关闭/卸载,或 `dsh plugin --profile main remove dsh-ml-input`。
|
|
181
|
+
|
|
182
|
+
## 8. 文档与存档(按既有规则)
|
|
183
|
+
|
|
184
|
+
- 获批后把本方案原文存到 `docs/PLAN-2026-10-27.md`,实施后追加「实施偏差(事后补记)」。
|
|
185
|
+
- 新建 `docs/RELEASE-CHECKLIST-0.1.0.md`;README 加文档索引,ROADMAP 挂链接;CHANGELOG 记 0.1.0。
|
|
186
|
+
- README 写明源码依据文件与 commit,便于 DSH 升级后回归。
|
|
187
|
+
|
|
188
|
+
## 9. 不做(v0.1.0)
|
|
189
|
+
|
|
190
|
+
不改 DSH 源码;不做内联录制器(用官方设置页);不做 Host 路由/配置页;不做按会话记忆;不发 npm、不做市场条目、不建远端;不处理 TUI/CLI。
|
|
191
|
+
|
|
192
|
+
## 10. 假设与风险
|
|
193
|
+
|
|
194
|
+
- 合成键盘事件能触发 Lexical 根监听(源码已确认监听在编辑根节点、Enter handler 只看 `shiftKey`);不成立则走 `InputActions` 兜底。
|
|
195
|
+
- 依赖的 `data-*` 锚点与 `role=listbox` 属内部实现,已在 rc.3 源码确认;升级 DSH 需回归,插件做缺锚点 warn。
|
|
196
|
+
- `Ctrl+E` 默认组合与已装插件不冲突(已查);运行期冲突仍由 try/catch 兜底。
|
|
197
|
+
- `1lh` 需要较新 Chromium;桌面版满足,且保留固定 px 回退。
|
|
198
|
+
- 我无法直接操作你屏幕上的 Electron 窗口,UI 观感与交互需你按第 6 节确认,我按反馈迭代。
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## 实施偏差(事后补记)
|
|
203
|
+
1. **目标 profile 判断错误**:计划里写「当前 `main`」,实际当前运行的是 **DeepSeek Harness.app + `desktop` profile**。依据:运行中的 Host 进程 cwd 与打开的 `~/.dsh/profiles/desktop/package.json`、`cordis.patch.yml`;本会话可用的 zotero / im / univer 工具只出现在 desktop 的 bundle 列表;desktop profile 的 `.plugin-manager` 日志显示最近的本地 link 安装。`main` 属于同时运行的 DSH NEXT(监听 58501,日志 `desktop-next.log`),与当前 GUI 不是同一实例。
|
|
204
|
+
|
|
205
|
+
2. **安装方式**:`dsh plugin --profile desktop add ...` 被应用独占拒绝(`profile "desktop" is managed exclusively by the Electron application`)。改为等价的手动 link:用应用自带的 pnpm 11.28.5 在 desktop profile 执行 `pnpm add link:/Users/zilong/zWork/ai/zl-plugins/dsh-ml-input`,并把 `dsh-ml-input` 追加进 `dsh.profile.bundles`。profile 的 `patchReload: live` 让 HMR 监听 `package.json`,改动后自动 reconcile。
|
|
206
|
+
|
|
207
|
+
3. **Host 行激活验证**:曾临时在 `index.js` 的 `apply()` 里写文件哨兵,并在 profile 补丁里临时加 `- id: ml-input` 的 disable/enable 行强制重载;哨兵于 `2026-10-27T16:30:37Z` 出现,证明 Host 已组合并激活插件行。随后已删除哨兵、恢复补丁文件并还原 `index.js`。
|
|
208
|
+
|
|
209
|
+
4. **浏览器半验证**:曾临时在 `apply()` 写 `localStorage['dsh-ml-input.selfcheck']`,在 Electron 的 LevelDB 中读到该键,证明客户端 bundle 已加载且 `apply()` 真正执行;随后用一次性 removeItem 版本清除并恢复最终代码。
|
|
210
|
+
|
|
211
|
+
5. 实现与计划一致:单文件手写 `client.js`、`conversation.input.overlay` 提示、`ctx.shortcuts` 命令、捕获阶段翻转 `shiftKey` 的 Enter 接管、`data-*` 锚点。(计划里“用 `useInput` 判断空草稿”在后续样式调整中已移除,提示改为常驻。)
|
|
212
|
+
|
|
213
|
+
6. **开发热更新更正**:计划第 7 节写「改 client.js 刷新页面即可」,实测不成立——HMR 默认忽略 `**/node_modules`(`packages/boot/hmr/src/index.ts`),链接安装的 `client.js` 改动不会被 `rebuilt()` 拾取。实际做法:在插件页把本插件关/开一次(或重启应用)触发客户端 bundle 重组,再刷新页面;`package.json` / 补丁文件的改动仍会被 profile 监听自动 reconcile。README 已同步。
|
|
214
|
+
|
|
215
|
+
7. **验收后的用户调整(2026-10-28)**:按子龙反馈——① 桌面默认键从字面 `Control+E` 改为 `primary+KeyE`(macOS 显示并生效为 `Cmd+E`,Windows/Linux 为 `Ctrl+E`);② 提示改为**常驻**,不再随输入隐藏。
|
|
216
|
+
|
|
217
|
+
8. **提示样式再调整(2026-10-28)**:试过“与卡片一体的顶部窄条”(同底色、底部淡线、给卡片预留 `padding-top`),但子龙要的是**贴着输入框上沿、像给输入框加一个 tab** 的形态。
|
|
218
|
+
|
|
219
|
+
9. **最终形态(2026-10-28)**:提示改为输入框上沿右侧的小 tab——`position:absolute; right: calc(var(--dsw-radius-panel) + 4px); bottom: 100%`(浮在卡片上方、不占输入区布局)、背景 `--dsw-specific-input-major`(同卡片底色)、宽度 `max-content`(只包文字)、顶部 `--dsw-radius-md` 圆角、底部 `0.5px solid --dsw-alias-border-l2`(与卡片描边同色,视觉上连成一体);原先的卡片 `padding-top` 预留已移除。
|
|
220
|
+
|
|
221
|
+
10. **改名(2026-10-28)**:开源前把包名从 `dsh-ml-input` 改为 **`dsh-multiline-input`**(`ml` 在 LLM 插件市场易被读成 machine learning;新名与 `dsh-composer-*` 命名簇一致、可搜索)。同步改了模块 id、locale NS、快捷键命令 id(`multiline-input.toggle`)、storage key、宿主 row id、CSS 前缀(`dml-`→`dmi-`)、profile 依赖与 bundle 列表;本地目录名保持 `dsh-ml-input`(会话工作区不便改名,包名以 package.json 为准)。
|
|
222
|
+
|
|
223
|
+
11. **开源与市场收录(2026-10-28)**:改名为 `dsh-multiline-input` 后建公开仓库、打 `v0.1.0` tag 与 Release、`npm publish`,并向 awesome-dsh-plugin 提交单文件 PR #9938(`data/plugins/ZilongYang__dsh-multiline-input.yml`,category `ui`);仓库与 npm 包都带 `screenshots.json` + `assets/` 截图。
|
|
224
|
+
|
|
225
|
+
12. **市场截图与 PR 门槛(2026-10-28 补记)**:子龙指出首版市场截图过宽、单行图卡片底部被裁;按其调整后的输入框宽度重截——单行用子龙提供的 1360×330 原图,多行裁成同宽 1360×464,两张都完整保留卡片底部与状态行,并更新 `assets/` 与 commit `8036ab6`。awesome-dsh-plugin PR #9938 的 `check` 已通过;`Submission gate` 失败的唯一原因是新建仓库仅 0.0 天(规则要求满 1 天),CI 会自动重跑、约 24h 后转绿。npm 0.1.0 tarball 中的截图仍是首发旧图(市场读取仓库 `screenshots.json`,不受影响)。
|
|
226
|
+
|
|
227
|
+
13. **提示 tab 的布局重叠修复(2026-10-29 补记,对应 plan 第 8/9 条的最终形态)**:子龙反馈「顶部红框里排版重叠」——目标条(ui-goal `GoalBar`,`conversation.input.dock` order 10)的文案与暂停 / 编辑 / 清除按钮被浮在上方的 tab 压住,tab 的按钮还会截走这部分点击。根因是 tab 走 `conversation.input.overlay` 座位、`position:absolute; bottom:100%` 浮在卡片外且 `z-index:2`,而 DSH 的输入区是「卡片上下文栈」(`ConversationContent.tsx` 里 `conversation.input.dock` 的条目按 order 排在卡片正上方),只要紧贴卡片上方那一行铺到右边缘就会撞。修复方案(子龙 2026-10-29 选定 A):tab 改注册到 `conversation.input.dock`(`order: 1000`,排在 todo 0 / 额度横条 5 / 目标条 10 / 队列 20 之后)成为**在流内的一行**,整行 24px、宽度按卡片列(`--dsh-composer-card-max-width` / `--dsh-composer-side-clearance`)右对齐,`margin-bottom: -实际 row-gap` 让 tab 底边与卡片上沿齐平,保留「卡片肩上的 tab」外观但不再与任何上方卡片重叠;`row-gap` 在运行时读取(dock 6px / hero 8px,用 `ResizeObserver` 覆盖 hero→dock 切换)。副作用:输入区高 18px、dock 卡片整体上移 24px。未选方案:B「被占时隐藏 tab」(长任务会话里反而看不到快捷键提示)、C「挪进工具行 `conversation.input.right`」(视觉变化大、与模型选择器抢空间)。子龙 2026-10-29 刷新验证通过后同日发版 **0.1.1**(版本号、CHANGELOG、`npm publish`、GitHub Release `v0.1.1`),发版清单见 `docs/RELEASE-CHECKLIST-0.1.1.md`。
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# dsh-multiline-input 0.1.0 发版 / 执行检查清单
|
|
2
|
+
|
|
3
|
+
> 状态(2026-10-28):0.1.0 已发布到 npm 与 GitHub;市场 PR #9938 的条目校验已通过,仅剩「仓库满 24h」的自动门槛。勾选为实测结果,未勾选项注明原因。
|
|
4
|
+
|
|
5
|
+
## 1. 代码与静态检查
|
|
6
|
+
|
|
7
|
+
- [x] `node --check client.js`
|
|
8
|
+
- [x] `node --check index.js`
|
|
9
|
+
- [x] `npm test`(`node --test`)13 条全绿
|
|
10
|
+
- [x] `locale/zh.json`、`locale/en.json`、`package.json` 可被 JSON 解析
|
|
11
|
+
- [x] `npm --cache /tmp/dsh-npm-cache pack --dry-run`:17 个文件,含 `client.js`、`cordis.patch.yml`、`locale/*`、`assets/*`、`screenshots.json`、README、docs
|
|
12
|
+
- [x] `package.json` 版本 = `0.1.0`,`dsh.compatibility.dsh` = `>=0.2.1-rc.3 <0.3.0-0`
|
|
13
|
+
|
|
14
|
+
## 2. 发布结果(2026-10-28)
|
|
15
|
+
|
|
16
|
+
- GitHub:https://github.com/ZilongYang/dsh-multiline-input
|
|
17
|
+
- tag `v0.1.0`;Release:https://github.com/ZilongYang/dsh-multiline-input/releases/tag/v0.1.0
|
|
18
|
+
- topics:`dsh-plugin` / `deepseek-harness` / `dsh` / `ui` / `composer` / `multiline`
|
|
19
|
+
- npm:`dsh-multiline-input@0.1.0`
|
|
20
|
+
- `npm publish` 成功;公开版本端点 `https://registry.npmjs.org/dsh-multiline-input/0.1.0` = 200
|
|
21
|
+
- `npm view dsh-multiline-input version dist.fileCount` = `0.1.0` / `17`
|
|
22
|
+
- 市场条目:https://github.com/awesome-dsh-plugin/awesome-dsh-plugin/pull/9938
|
|
23
|
+
- 只新增 `data/plugins/ZilongYang__dsh-multiline-input.yml`(category `ui`)
|
|
24
|
+
- `check` 通过;`Submission gate` 失败原因仅 **仓库 0.0 天 < 1 天**,提示会自动重跑、约 24h 后转绿,无需重提
|
|
25
|
+
- 市场截图(1360 宽,含卡片底部与状态行):`assets/screenshot-1-single-line.png`(1360×330)、`assets/screenshot-2-multiline.png`(1360×464);`screenshots.json` 已提交
|
|
26
|
+
- npm tarball 内的截图仍是首发旧图(市场读取仓库,不受影响;如需同步可发 0.1.1)
|
|
27
|
+
|
|
28
|
+
## 3. 安装
|
|
29
|
+
|
|
30
|
+
> 本机 DeepSeek Harness 使用 `desktop` profile,由应用独占;`dsh plugin --profile desktop` 会报 `profile "desktop" is managed exclusively by the Electron application`。
|
|
31
|
+
|
|
32
|
+
- [x] 方式一(应用内):「插件」页 → 添加插件 → 绝对路径本目录 → 安装 → 启用
|
|
33
|
+
- [x] 方式二(开发期手动 link):
|
|
34
|
+
`cd ~/.dsh/profiles/desktop && pnpm add link:<本目录>`,并把 `dsh-multiline-input` 追加进 `package.json` 的 `dsh.profile.bundles`
|
|
35
|
+
- [x] 插件出现在已安装列表,且能启用 / 禁用(改名后重新安装并确认)
|
|
36
|
+
- [x] 刷新 / 重启应用后插件加载(重命名后重启验证,控制台无报错)
|
|
37
|
+
|
|
38
|
+
## 4. 实机验收
|
|
39
|
+
|
|
40
|
+
- [x] 输入框上方右侧常驻显示 `Cmd+E 多行输入`(macOS)
|
|
41
|
+
- [x] 输入文字后提示仍在(常驻)
|
|
42
|
+
- [x] `Cmd+E` 切换单行 / 多行;页面空白处也可切换(用户实测)
|
|
43
|
+
- [x] 多行模式最小高度 4 行;切回单行恢复原高度(截图对比)
|
|
44
|
+
- [x] 多行模式 `Shift+Enter` 发送、`Enter` 换行(用户实测)
|
|
45
|
+
- [ ] `Cmd/Ctrl+Enter` 加速提交(未专项回归)
|
|
46
|
+
- [ ] `/`、`@` 菜单打开时 `Enter` 选中菜单项(未专项回归)
|
|
47
|
+
- [ ] 中文输入法候选态 `Enter` 不误触(未专项回归)
|
|
48
|
+
- [ ] 设置搜索框 / 会话重命名框内 `Ctrl+E` 不切换(未专项回归)
|
|
49
|
+
- [ ] 改名后刷新 / 重启模式保持(storage key 变更,需再验一次)
|
|
50
|
+
- [ ] `设置 → 通用 → 快捷键` 出现「切换多行输入」,可改绑 / 恢复默认(未在界面逐项复核)
|
|
51
|
+
- [ ] 改绑后 tab 文案立即更新;清空绑定后只显示文案且可点击(未复核)
|
|
52
|
+
- [ ] 禁用插件后提示消失、高度恢复、无残留 DOM / 监听(未专项复核)
|
|
53
|
+
|
|
54
|
+
## 5. 回滚
|
|
55
|
+
|
|
56
|
+
- [ ] 插件页关闭或卸载;或 `dsh plugin --profile <profile> remove dsh-multiline-input`
|
|
57
|
+
- [ ] 回滚后与安装前一致(原输入框行为、快捷键条目消失)
|
|
58
|
+
|
|
59
|
+
## 6. 存档
|
|
60
|
+
|
|
61
|
+
- [x] `docs/PLAN-2026-10-27.md` 已保存获批原文
|
|
62
|
+
- [x] 实施偏差已回填到计划文末(含改名、发布、截图调整)
|
|
63
|
+
- [x] README 文档索引、ROADMAP 链接已更新
|
|
64
|
+
- [x] git 提交与远端推送完成
|
|
65
|
+
|
|
66
|
+
## 备注
|
|
67
|
+
|
|
68
|
+
- 0.1.0 已发布(npm + GitHub);市场 PR 只等仓库满 24h 的 CI 门槛。
|
|
69
|
+
- 依赖 DSH `0.2.1-rc.3` 的 composer DOM 锚点;升级 DSH 后按第 4 节重新验收。
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# dsh-multiline-input 0.1.1 发版 / 执行检查清单
|
|
2
|
+
|
|
3
|
+
> 状态(2026-10-29):0.1.1 为布局修复版(tab 不再压住 composer 上方卡片)。勾选为实测结果,未勾选项注明原因。
|
|
4
|
+
|
|
5
|
+
## 1. 变更范围
|
|
6
|
+
|
|
7
|
+
- [x] `client.js`:tab 从 `conversation.input.overlay` 浮层改到 `conversation.input.dock` 一行(`order: 1000`);行宽按卡片列(`--dsh-composer-card-max-width` / `--dsh-composer-side-clearance`)右对齐;`margin-bottom: -实际 row-gap`(运行时读 `row-gap`,dock 6px / hero 8px,用 `ResizeObserver` 覆盖 hero→dock 切换)让 tab 底边与卡片上沿齐平
|
|
8
|
+
- [x] `client.js`:`__test` 增加 `HINT_SLOT` / `HINT_ID` / `HINT_ORDER`
|
|
9
|
+
- [x] `test/core.test.js`:新增「tab 座位必须是 `conversation.input.dock`、order 排在全部内置 dock 条目之后」的断言(13 条用例)
|
|
10
|
+
- [x] 文档:README(使用 / 实现说明 / 兼容性 / 已知限制 / 源码依据表)、ROADMAP、CHANGELOG、plan 事后补记第 13 条
|
|
11
|
+
|
|
12
|
+
## 2. 代码与静态检查
|
|
13
|
+
|
|
14
|
+
- [x] `node --check client.js`
|
|
15
|
+
- [x] `node --check index.js`
|
|
16
|
+
- [x] `npm test`(`node --test`)14 个测试节点全绿(13 条用例 + harness)
|
|
17
|
+
- [x] `locale/zh.json`、`locale/en.json`、`package.json` 可被 JSON 解析
|
|
18
|
+
- [x] `npm pack --dry-run`:tarball 文件清单含 `client.js`、`cordis.patch.yml`、`locale/*`、`assets/*`、`screenshots.json`、README、docs
|
|
19
|
+
- [x] `package.json` 版本 = `0.1.1`,`dsh.compatibility.dsh` = `>=0.2.1-rc.3 <0.3.0-0`
|
|
20
|
+
|
|
21
|
+
## 3. 布局几何验证(无 GUI,静态复刻)
|
|
22
|
+
|
|
23
|
+
用 Chrome 无头模式复刻 DSH `0.2.1-rc.3` 的 composer 栈(`.body` / `.scrollBody` / `.composerSeat` / `.composerStack` / InputBar `.root`+`.card` 的真实几何 CSS),插件 CSS 直接从 `client.js` 抽取后注入:
|
|
24
|
+
|
|
25
|
+
- [x] `tab.bottom - card.top = 0.00px`(tab 底边与卡片上沿齐平)
|
|
26
|
+
- [x] `tab.right - (card.right - (radius + 4)) = 0.00px`(右边缘与 0.1.0 位置一致)
|
|
27
|
+
- [x] 目标条底边在 tab 上方 6px,**无重叠**;目标条三个图标按钮落在 tab 的 x 范围之外
|
|
28
|
+
- [x] 1600 / 1400 两种宽度、栈间距 6px 与 8px(hero)两种情形结论一致
|
|
29
|
+
|
|
30
|
+
## 4. 实机验收(子龙,2026-10-29)
|
|
31
|
+
|
|
32
|
+
- [x] 目标条(进行中的目标)文案与暂停 / 编辑 / 清除三个图标完整可见、可点击
|
|
33
|
+
- [x] tab 仍在输入卡片上沿右侧、贴着卡片
|
|
34
|
+
- [x] 输入区比 0.1.0 高约 18px、composer 上方 dock 卡片整体上移 24px(预期变化,子龙确认可接受)
|
|
35
|
+
- [ ] 待办面板 / 队列面板与 tab 的同框观感(本次会话未出现这两种卡片,未专项复核)
|
|
36
|
+
- [ ] `Cmd+E` 切换、多行 `Shift+Enter` 发送(0.1.0 已验证,本次改动未触碰该逻辑,未重跑)
|
|
37
|
+
|
|
38
|
+
## 5. 发布结果(2026-10-29)
|
|
39
|
+
|
|
40
|
+
- GitHub:https://github.com/ZilongYang/dsh-multiline-input
|
|
41
|
+
- tag `v0.1.1`;Release:https://github.com/ZilongYang/dsh-multiline-input/releases/tag/v0.1.1
|
|
42
|
+
- npm:`dsh-multiline-input@0.1.1`
|
|
43
|
+
- `npm publish` 成功;`npm view dsh-multiline-input version` = `0.1.1`
|
|
44
|
+
- 市场:首版 PR #9938 已收录,市场读取仓库 + npm,无需重新提 PR;`assets/` 截图沿用 0.1.0(tab 外观与位置未变,仅上方状态行上移 24px,未重截)
|
|
45
|
+
|
|
46
|
+
## 6. 本机安装(desktop profile,link 安装)
|
|
47
|
+
|
|
48
|
+
- [x] profile 里 `dsh-multiline-input` 指向本目录(`link:`),代码改动即时生效;`package.json` 版本变化由 `patchReload: live` reconcile
|
|
49
|
+
- [x] 插件页关 / 开一次 + 刷新页面即可加载新 `client.js`(HMR 忽略 `node_modules`,见 plan 偏差 #6)
|
|
50
|
+
|
|
51
|
+
## 7. 回滚
|
|
52
|
+
|
|
53
|
+
- 插件页关闭 / 卸载,或 `dsh plugin --profile <profile> remove dsh-multiline-input`
|
|
54
|
+
- 代码回滚:`git revert <0.1.1 commit>`;npm 侧如需回退版本,`npm deprecate dsh-multiline-input@0.1.1 "..."` 并发布修正版
|
|
55
|
+
|
|
56
|
+
## 备注
|
|
57
|
+
|
|
58
|
+
- 依赖 DSH `0.2.1-rc.3` 的 composer 栈与布局变量;升级 DSH 后按第 3、4 节回归(tab 与卡片右边缘错位 / 出现缝隙即为变量或栈间距变了)。
|
package/icon.svg
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
|
|
2
|
+
<rect x="3" y="4" width="18" height="16" rx="4" stroke="currentColor" stroke-width="1.6"/>
|
|
3
|
+
<path d="M7 9h10M7 12h10M7 15h6" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/>
|
|
4
|
+
</svg>
|
package/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host half of dsh-multiline-input.
|
|
3
|
+
*
|
|
4
|
+
* The feature is browser-only. This row exists so the package is a real
|
|
5
|
+
* bundle row that the Plugins page can install, enable and disable; the
|
|
6
|
+
* browser half is discovered through package.json's `dsh.client`
|
|
7
|
+
* declaration and served by client-modules.
|
|
8
|
+
*
|
|
9
|
+
* Reference contracts (source checkout `deepseek-harness`, 0.2.1-rc.3):
|
|
10
|
+
* - packages/client/modules/README.zh.md
|
|
11
|
+
* - packages/util/package-manifest/src/types.ts (DshClientManifest)
|
|
12
|
+
* - packages/boot/plugin-manager/src/index.ts ("not-bundle")
|
|
13
|
+
*/
|
|
14
|
+
export const name = 'multiline-input'
|
|
15
|
+
|
|
16
|
+
/** The Host half owns no services; it only keeps the bundle row alive. */
|
|
17
|
+
export function apply() {}
|
package/locale/en.json
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"meta": {
|
|
3
|
+
"title": "Multiline input",
|
|
4
|
+
"description": "Toggle the conversation composer between single-line and multi-line: Ctrl+E by default (editable in Settings → General → Keyboard shortcuts), Enter inserts a newline and Shift+Enter sends while multi-line."
|
|
5
|
+
}
|
|
6
|
+
}
|
package/locale/zh.json
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,72 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-multiline-input",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"description": "
|
|
6
|
-
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Single/multi-line composer toggle for DeepSeek Harness: an editable Cmd/Ctrl+E shortcut, a tab hint on the composer, a 4-line floor for multi-line drafts, and Shift+Enter to send.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "ZilongYang",
|
|
8
|
+
"icon": "./icon.svg",
|
|
9
|
+
"keywords": [
|
|
10
|
+
"deepseek",
|
|
11
|
+
"deepseek-harness",
|
|
12
|
+
"dsh",
|
|
13
|
+
"dsh-plugin",
|
|
14
|
+
"client-plugin",
|
|
15
|
+
"composer",
|
|
16
|
+
"multiline",
|
|
17
|
+
"input",
|
|
18
|
+
"keyboard-shortcut",
|
|
19
|
+
"web"
|
|
20
|
+
],
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=20.3"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"test": "node --test"
|
|
26
|
+
},
|
|
27
|
+
"exports": {
|
|
28
|
+
".": "./index.js",
|
|
29
|
+
"./client": "./client.js",
|
|
30
|
+
"./package.json": "./package.json",
|
|
31
|
+
"./locale/*.json": "./locale/*.json"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"index.js",
|
|
35
|
+
"client.js",
|
|
36
|
+
"cordis.patch.yml",
|
|
37
|
+
"icon.svg",
|
|
38
|
+
"locale/zh.json",
|
|
39
|
+
"locale/en.json",
|
|
40
|
+
"screenshots.json",
|
|
41
|
+
"assets",
|
|
42
|
+
"README.md",
|
|
43
|
+
"ROADMAP.md",
|
|
44
|
+
"CHANGELOG.md",
|
|
45
|
+
"LICENSE",
|
|
46
|
+
"docs"
|
|
47
|
+
],
|
|
48
|
+
"dsh": {
|
|
49
|
+
"bundle": {
|
|
50
|
+
"patch": "./cordis.patch.yml"
|
|
51
|
+
},
|
|
52
|
+
"client": {
|
|
53
|
+
"platform": "web",
|
|
54
|
+
"immediately": true,
|
|
55
|
+
"inject": [
|
|
56
|
+
"@deepseek-ai/dsh-client-locale",
|
|
57
|
+
"@deepseek-ai/dsh-client-ui-conversation"
|
|
58
|
+
]
|
|
59
|
+
},
|
|
60
|
+
"compatibility": {
|
|
61
|
+
"dsh": ">=0.2.1-rc.3 <0.3.0-0"
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"repository": {
|
|
65
|
+
"type": "git",
|
|
66
|
+
"url": "git+https://github.com/ZilongYang/dsh-multiline-input.git"
|
|
67
|
+
},
|
|
68
|
+
"homepage": "https://dsh.zlmix.com/multiline-input/",
|
|
69
|
+
"bugs": {
|
|
70
|
+
"url": "https://github.com/ZilongYang/dsh-multiline-input/issues"
|
|
71
|
+
}
|
|
72
|
+
}
|
package/screenshots.json
ADDED