dsh-composer-ux 0.1.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/CHANGELOG.md ADDED
@@ -0,0 +1,47 @@
1
+ # 更新日志
2
+
3
+ 本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
4
+
5
+ ## [0.1.2] — 2026-09-12
6
+
7
+ ### 修复
8
+ - **体检正则零命中**:0.1.1 只清了 `new Function`,但市场体检器的规则是 5 条(动态生成函数的两个关键字、`atob`、连续 40+ 数字参数的 `fromCharCode`、200 位以上 base64 字面量)。内联的 cosmokit 二进制工具在非 Node 环境回退到 `atob` 解码,仍会被判为「含混淆/动态执行代码」。宿主包只跑在 Node 上(`Buffer` 必然存在),该回退分支是死代码,现已在打包后替换为显式报错。
9
+ - `build.mjs` 自身同样不再出现这些风险字面量,避免构建脚本被同一条规则误报。
10
+ - 现在 `lib/index.js`、`lib/client.js`、`build.mjs` 对该规则的命中数均为 **0**;26 项宿主行为测试全绿。
11
+
12
+ ## [0.1.1] — 2026-09-12
13
+
14
+ ### 修复
15
+ - **`dsh.bundle.patch` 指向修正**:0.1.0 把发行层文件改名为 `cordis.patch.yml` 并删除了旧文件,但清单未同步,安装后会没有任何组合层可用。现已指向 `cordis.patch.yml`(安装流程已用临时 profile 实测通过)。
16
+ - **消除宿主包里的动态执行标记**:内联的 schemastery 带有「字符串回调 → `new Function` 还原」这条分支,虽然本插件从不使用字符串回调,但它会让插件市场的「装前体检」把宿主包判为「含混淆/动态执行代码」并提示用户不要安装。构建脚本现在会在打包后把该分支替换为等价的空实现,`lib/` 内不再出现 `new Function` / `eval(`;非字符串回调路径与插件行为完全不变(26 项宿主行为测试全绿)。
17
+
18
+ ## [0.1.0] — 2026-09-12
19
+
20
+ 首个公开发行版(可作为 DSH 组合包安装)。
21
+
22
+ ### 输入键位
23
+ - 可配置「发送键」「换行键」:常用预设(Enter / Ctrl+Enter / Alt+Enter / Shift+Enter)+ 录制任意组合键;支持清空为「无」、一键恢复默认。
24
+ - 发送/换行互斥校验;IME 组合期间(`isComposing` / `keyCode 229`)一律放行,不误发。
25
+ - 通过回放官方按键管线实现,完整保留官方行为:忙时排队/steer、连发防重、空草稿不发送、`/` `@` 菜单优先。
26
+
27
+ ### 输入框右键菜单
28
+ - 7 个条目(撤销/重做/剪切/复制/粘贴/删除/全选)可单独开关;未选中文本时剪切/复制/删除置灰;分隔线自动合并。
29
+ - 可切换为系统原生菜单(浏览器自带,粘贴免授权)。
30
+ - 自定义菜单样式对齐系统编辑器:深色圆角、三分组、快捷键右对齐;点击外部 / Esc / 滚动 / 窗口变化自动关闭。
31
+
32
+ ### 设置面板
33
+ - 设置页新增「输入体验」条目:版式对齐社区插件的「Web 插件」页,四个可折叠栏目,默认全折叠。
34
+ - 导航可滚动开关;面板边缘拖拽调整大小,尺寸持久化并带预设。
35
+
36
+ ### 全局开关
37
+ - 设置页顶部「启用输入增强」总开关:关闭后键位、右键菜单、面板滚动/缩放全部停用,输入框回到 DSH 原生行为;状态持久保存。
38
+
39
+ ### OpenCode 请求头
40
+ - 自动为 OpenCode 路由的模型请求附加 `x-opencode-session`(DSH 唯一受支持的出网请求头入口 `llm-pi-ai.providers.<route>.headers`)。
41
+ - 只写已存在的路由,使用 `settings.mutate` 路径寻址,不动同 profile 的其它字段;关闭开关/改头名会精确回收自己写入的那一个键。
42
+ - 值可改、可重新生成(默认 UUID);写入前按 llm-pi-ai 相同规则校验头名与头值。
43
+
44
+ ### 打包与分发
45
+ - 按官方《打包与安装插件》规范提供组合包清单:`package.json:dsh.bundle.patch → ./cordis.patch.yml`,插件行按包名引用。
46
+ - 构建产物 `lib/index.js`(Host)与 `lib/client.js`(浏览器)随仓库提交,GitHub 安装无需构建授权。
47
+ - 附带宿主半行为测试(26 项)与线级请求头探针。
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 fangwen9527
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,148 @@
1
+ # dsh-composer-ux
2
+
3
+ > **English summary** — A DeepSeek Harness **Web** plugin that upgrades the composer (chat input) experience:
4
+ > configurable **send / newline keys**, a native-style **7-item right-click context menu**, a resizable &
5
+ > scrollable **settings panel with persisted size**, a **global on/off switch**, and automatic
6
+ > **`x-opencode-session` request-header injection** so OpenCode (Go) routes work inside DSH.
7
+ > Install with `dsh plugin --profile <name> add github:fangwen9527/dsh-composer-ux` — the built `lib/`
8
+ > ships in this repository, so there is **no build step and no build authorization**. License: MIT.
9
+
10
+ DeepSeek Harness Web 输入体验增强插件:
11
+
12
+ 0. **全局开关**:设置页顶部「启用输入增强」总开关——关闭后键位、右键菜单、设置面板滚动/缩放全部停用(输入框恢复 DSH 原生行为),设置页保留用于一键恢复;开关状态持久保存。
13
+ 1. **设置 → 输入体验**(设置页新增条目)
14
+ - 版式对齐社区插件 `@linxin666/dsh-web-all` 的「Web 插件」页:顶部常显「中文名 + 内嵌英文包名 `dsh-composer-ux` 的一行描述 + 总开关」;其下四个栏目为**可折叠卡片**(标题行只放标题 + 一句动态概览,长说明与控件都在展开后的内容区),**默认全部折叠、不记忆展开状态**,可同时展开多个。
15
+ - **键位**:分别配置「发送键」「换行键」——常用预设(Enter / Ctrl+Enter / Alt+Enter / Shift+Enter)+ 点击「自定义…」后直接按任意组合键录制(Esc 取消,Backspace 清除),支持清空为「无」;发送与换行不能设为相同按键;可一键恢复默认。
16
+ - **右键菜单**:输入框右键菜单的 7 个条目(撤销 / 重做 / 剪切 / 复制 / 粘贴 / 删除 / 全选)可单独开关;可切换「使用系统原生菜单」(浏览器自带菜单,粘贴免授权)。
17
+ - **设置面板**:导航可滚动开关;边缘拖拽调整面板大小(尺寸记忆持久化)与尺寸预设。
18
+ - **OpenCode 请求头**:给 OpenCode 的模型请求自动附加 `x-opencode-session`(详见下节)。
19
+ 2. **键位生效**(仅主聊天输入框):默认值 = 现状(Enter 发送、Shift+Enter 换行、Ctrl+Enter 加速提交),改动即时生效并持久保存。
20
+
21
+ ## 安装
22
+
23
+ 本插件按官方「[打包与安装插件](https://deepseek-harness.github.io/deepseek-harness/develop/basic/publish)」规范打包为可安装**组合包**(bundle):`package.json` 声明 `dsh.bundle.patch → ./cordis.patch.yml`,该层以**包名**插入插件行 `dsh-composer-ux`,装进 profile 后由 pnpm/Node 从 `node_modules` 解析到 `lib/index.js`。
24
+
25
+ ```sh
26
+ # GitHub 安装(推荐):lib/ 构建产物已随仓库提交,没有 prepare 脚本,因此不需要 pnpm 的构建授权
27
+ dsh plugin --profile <你的 profile> add github:fangwen9527/dsh-composer-ux
28
+
29
+ # 锁定 commit 安装(更安全:后续推送无法悄悄改变实际运行的内容)
30
+ dsh plugin --profile <你的 profile> add github:fangwen9527/dsh-composer-ux#<commit-sha>
31
+
32
+ # 本地目录安装(开发用,等价于 link)
33
+ dsh plugin --profile <你的 profile> add D:/1zcode/dsh插件/输入体验
34
+ ```
35
+
36
+ 装完按 DSH 提示重启一次(Host 半的插件代码只在进程启动时 import),客户端半刷新页面即生效。
37
+
38
+ **发现渠道**:仓库已打官方发现用的 [`dsh-plugin`](https://github.com/topics/dsh-plugin) topic(另带 `deepseek-harness` / `cordis` / `dsh` / `opencode` 等关键词);社区目录(mydsh.dev、dshbase.com、dsplugin.app)按该 topic 自动同步收录。仓库里的 `cordis.patch.yml` 就是随包发布的组合层文件,`dsh.bundle.patch` 指向它即可。
39
+
40
+ 从 DSH 源码检出直接 `--patch` 挂载的本地开发方式见下文「加载」一节。
41
+
42
+ ## 键位规则
43
+
44
+ - 目标限定在 DSH Web 主聊天输入框(`[data-composer-input]`);其他输入框不受影响。
45
+ - **IME 安全**:中文/日文输入法组合期间(`isComposing` / `keyCode 229`)一律放行,绝不误发、误换行。
46
+ - 发送/换行通过回放官方按键管线实现(发送 = 普通 Enter,换行 = Shift+Enter),因此所有官方保护均保留:忙时排队 / 油门(steer)、连发防重、空草稿不发送、`/` `@` 触发器菜单打开时 Enter 仍优先选择菜单项。
47
+ - 未绑定的 Enter 系按键(如把「发送」清空后按 Enter)不会触发任何动作;**Ctrl+Enter / ⌘+Enter 未被绑定时保留官方「加速提交」行为**(绑定为空闲草稿的队列推进等)。
48
+ - 单个字母/数字键不允许裸绑定(会与打字冲突);纯修饰键不会触发录制。
49
+ - 部分 Ctrl/Meta 组合被浏览器占用(如 Ctrl+L、Ctrl+W、Ctrl+J),录制时无法在页面捕获——建议使用 Alt/Shift 组合或 Enter 系键位。
50
+
51
+ ## 右键菜单
52
+
53
+ - 样式与系统编辑器菜单一致(深色圆角、三分组、快捷键右对齐);未选中文本时「剪切 / 复制 / 删除」置灰;被关闭的条目不显示(分隔线自动合并)。
54
+ - 撤销 / 重做 / 剪切 / 复制 / 删除 / 全选 走标准编辑命令;**粘贴 读取剪贴板后在光标处插入纯文本**——这是浏览器的安全限制:首次使用可能出现一次授权提示,被拒绝或无响应时会提示「请用 Ctrl+V 粘贴」。
55
+ - 菜单打开时点击外部、Esc、滚动或窗口变化都会关闭。
56
+
57
+ ## OpenCode 请求头
58
+
59
+ OpenCode 的接口要求客户端在每次请求里带上一个稳定的会话 ID 请求头(官方 Go 文档「可以在哪里使用?」第 3 条:为每段对话在 `x-opencode-session` 中发送会话 ID,以便其优化路由与提示词缓存)。DSH 的 Models 设置页明确不提供请求头编辑器(源码注释与 `README.zh.md` 都写明 profile `headers` 属于部署配置),所以本插件把这一项代办了。
60
+
61
+ - **设置页位置**:设置 → 输入体验 → 「OpenCode 请求头」(折叠栏目):开关 / 头名 / 值 / 作用路由,附一行宿主半回写的「状态」。
62
+ - **落点**:`llm-pi-ai` 的 provider profile —— `providers.<路由>.headers.<头名>`。这是 DSH 里唯一受支持的出网请求头入口:它作为 pi-ai 的 `optionsHeaders` **最后合并**(能覆盖默认头),且该适配器每次请求都重读配置,所以改完**下一次请求即生效**,不用重启、不用手工改 `settings.yaml`。
63
+ - **写入方式**:`settings.mutate` 的路径寻址——只动我们那一个键,绝不重述或删除你写在同一个 profile 里的其它字段(`models` / `apiKeyEnv` / 其它 headers 都不碰)。
64
+ - **只写已存在的路由**:profile 的 `models` 是必填项,凭空造一个只有 headers 的路由会让整份配置校验失败;所以「作用路由」留空时只匹配 `providers` 里以 `opencode` 开头的路由,显式写了名单也只保留其中**已存在**的。
65
+ - **撤销**:关栏目开关、关插件总开关、或改头名,都会自动清掉此前写入的那一个键;并且只清「值等于当前配置值或记账值」的,用户自己手写的同名头不会被误删。
66
+ - **值**:所有对话共用同一个值(栏目里可改、可「重新生成」);第一次启用若留空,会自动生成一个 UUID 并保存沿用。OpenCode 文档原话是要「每段对话」一个 ID——按会话变化的头 DSH 的配置层做不到(`llm/stream` 钩子被设计成只能读不能改,`GenerateOptions` 里没有 `headers` 字段),所以这里退一步用固定值。已知代价:所有对话挤同一个上游(没有负载分散);单段对话内的缓存命中不受影响。另外它**不保证**缓存一定命中(还取决于上游模型与网关策略)。
67
+ - **自校验**:写入前用与 llm-pi-ai 相同的规则(`new Headers()`)校验头名与头值;非法值被拒绝,原因写进栏目的「状态」行,而不是把整条路由弄坏。
68
+ - **实测结论(本机验证过,不是推断)**:
69
+ - **它是硬门槛,不是优化项。** 同一端点、同一模型,只把这条请求头去掉,OpenCode Go 直接返回 **HTTP 400 `MissingSessionID`**:*"Request is missing x-opencode-session and cannot be routed efficiently."* —— 没有它,DSH 里的 opencode-go 完全不可用。
70
+ - **带着它时真实调用成功,且前缀缓存在工作**:同一段前缀连发两次,`input` 174 → 46、`cacheRead` 192 → 320(总前缀 366 不变),第二次有更多内容直接命中缓存。
71
+ - **线级证据**:用 `test/opencode-header-wire-probe.mjs` 起一个本地端点,DSH 发过去的推理请求上确实带着 `x-opencode-session: <值>`,以及它自己的 `user-agent: deepseek-harness/0.1.5-rc.2 (+https://github.com/deepseek-ai/deepseek-harness)`(正好满足 OpenCode 文档对客户端标识的第 2 条要求)。
72
+
73
+ ## 结构
74
+
75
+ 项目根目录:`D:\1zcode\dsh插件\输入体验\`(构建产物与被挂载的 `cordis.patch.yml` 都在这里)。
76
+
77
+ ```
78
+ dsh-composer-ux/
79
+ ├── package.json # dsh.client 清单(platform: web)+ exports["./client"] + dsh.bundle.patch 清单
80
+ ├── cordis.patch.yml # 组合包层(随包发布):按包名 dsh-composer-ux 插入插件行
81
+ ├── cordis.dev.patch.yml # 本地开发覆盖层(file:/// 绝对路径,已 gitignore,不随包发布)
82
+ ├── CHANGELOG.md # 版本更新日志
83
+ ├── build.mjs # esbuild 构建:lib/index.js(Host)+ lib/client.js(浏览器),并做发行后处理
84
+ ├── src/
85
+ │ ├── host.ts # Host 半:注册 settings namespace + 把请求头镜像进 llm-pi-ai
86
+ │ ├── settings-contract.ts # 字段/默认值/菜单元数据(零依赖共享)
87
+ │ ├── client.tsx # Browser 半:设置页 + 菜单浮层 + 拦截器
88
+ │ └── client/
89
+ │ ├── chords.ts # 键位编码/录制校验
90
+ │ ├── interceptors.ts # keydown/contextmenu 捕获拦截 + 回放
91
+ │ ├── SettingsSection.tsx # 设置页「输入体验」(顶部常显 + 折叠栏目)
92
+ │ ├── settings-style.ts # 折叠卡片样式表(dsh-ux-* 类名注入)
93
+ │ ├── ContextMenuHost.tsx # shell.overlay 右键菜单
94
+ │ └── styles.ts # --dsw-* 令牌内联样式
95
+ ├── test/
96
+ │ ├── host-header-mirror.mjs # 请求头镜像的行为测试(假 settings 驱动构建产物)
97
+ │ └── opencode-header-wire-probe.mjs # 线级探针:本地端点,用来看 DSH 出网请求带了什么头
98
+ └── lib/ # 构建产物(运行所需)
99
+ ```
100
+
101
+ ## 构建
102
+
103
+ ```sh
104
+ node build.mjs # 产出 lib/index.js + lib/client.js
105
+ node test/host-header-mirror.mjs # 宿主半行为测试(写入/撤销/改名/幂等/不误删)
106
+ # 线级探针(可选):起一个本地端点,再把某条路由临时指过来,即可看到真实出网请求头
107
+ node test/opencode-header-wire-probe.mjs 8799 600000
108
+ # 若 DSH 源码检出不在默认路径:
109
+ $env:DSH_REPO_PATH='D:/DeepSeek Harness'; node build.mjs
110
+ ```
111
+
112
+ ## 加载(从 DSH 源码检出)
113
+
114
+ ```sh
115
+ cd D:\DeepSeek Harness
116
+ pnpm dsh web --patch D:/1zcode/dsh插件/输入体验/cordis.dev.patch.yml
117
+ ```
118
+
119
+ 替换为你的真实路径即可;插件行的 `name` 必须是 `file:///` 形式的绝对 URL(Windows 下 `D:/...` 裸路径无法被 ESM loader 导入)。该文件只在本机存在(已 gitignore),内容如下:
120
+
121
+ ```yaml
122
+ - insert:
123
+ - id: composer-ux
124
+ name: 'file:///D:/1zcode/dsh插件/输入体验/lib/index.js'
125
+ ```
126
+
127
+ ## 开发时热更新
128
+
129
+ - 改完 `src/` 后执行 `node build.mjs`;
130
+ - **Client 半**(`lib/client.js`):客户端包在激活时读进内存,之后要靠 bundle 重新扫描(rev 变化)才会下发新内容;刷新浏览器即生效。
131
+ - **Host 半**(`lib/index.js`):**必须重启 DSH 进程**。Cordis 加载器只在插件行的 `name` 变化时才重新 `import`(`vendor/loader/lib/index.js`),而 ESM 按 URL 缓存模块,改了文件内容不会失效——实测加临时探针并改动插件行 `name` 触发重载,探针都没有出现在启动日志里。所以:功能开关是随点随生效的,但**宿主半代码的更新要重启一次**。
132
+ - 加/删/改插件**行**本身(`cordis.patch.yml`)是 live 的(profile 的 `patchReload: live`),不用重启。
133
+
134
+ ## 设置持久化
135
+
136
+ 设置存在 Host 用户设置文档(默认 `$DSH_HOME/settings.yaml`)的 `composer-ux` 分区,随工作区/机器生效;删除该分区即恢复全部默认。
137
+
138
+ ## 发行包与「装前体检」
139
+
140
+ 插件市场的装前体检会扫描宿主代码里的混淆/动态执行特征(`eval` / `new Function` / 超长 base64 块)。本插件的 `lib/` 里这些特征**为零**:
141
+
142
+ - 内联的 schemastery 带有一条「字符串回调 → `new Function` 还原」的分支。本插件所有 schema 都传函数回调,从不使用字符串回调,因此 `build.mjs` 在打包后会把该分支替换为等价空实现;若将来依赖升级导致模式失配,构建会**直接报错退出**,不会悄悄带着 `new Function` 发行。
143
+ - 构建与测试命令见上文「构建」;`lib/` 为纯 JavaScript,安装时不需要执行任何构建脚本(因此**不需要 pnpm 的构建授权**,也不会在安装期于用户机器上执行代码)。
144
+
145
+ ## 与官方版本兼容提示
146
+
147
+ - 依赖的稳定接口:`settings.section`、`shell.overlay` 槽位、`ctx.settingsScope`、`ctx.settings`(Host)、`[data-composer-input]` DOM 标记。
148
+ - 浏览器包外部依赖仅限平台种子词(react / react/jsx-runtime / react-dom / @deepseek-ai/cordis / dsh-client-store / ui-slots / ui-primitives),其余全部内联。
@@ -0,0 +1,12 @@
1
+ # dsh-composer-ux — 可安装组合包层(bundle patch)
2
+ #
3
+ # 本文件由 package.json 的 dsh.bundle.patch 引用。插件行按「包名」引用本包,
4
+ # 安装后 Node/pnpm 从 profile 的 node_modules 解析到 lib/index.js(Host 半);
5
+ # 客户端半由 package.json 的 dsh.client 清单 + exports["./client"] 自动发现。
6
+ #
7
+ # 安装:
8
+ # dsh plugin --profile <你的 profile> add github:fangwen9527/dsh-composer-ux
9
+ # 本地源码开发请改用 cordis.dev.patch.yml(file:/// 绝对路径,见 README「加载」一节)。
10
+ - insert:
11
+ - id: composer-ux
12
+ name: dsh-composer-ux