dsh-edit-turn 0.3.3 → 0.5.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.md +88 -1
- package/lib/client.js +1613 -134
- package/lib/index.js +170 -12
- package/lib/patch.js +27 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -74,12 +74,16 @@ dsh plugin --profile web add /path/to/dsh-edit-turn
|
|
|
74
74
|
config:
|
|
75
75
|
confirm: false # 默认 false:一次点击即执行;置 true 才要求二次确认
|
|
76
76
|
replyMode: auto # auto | patch | replay
|
|
77
|
+
editorStyle: frame # frame | bubble | center
|
|
77
78
|
```
|
|
78
79
|
|
|
79
80
|
| 字段 | 默认 | 含义 |
|
|
80
81
|
|---|---|---|
|
|
81
82
|
| `confirm` | `false` | 客户端保存后是否先要求一次确认。默认**关闭**(一次点击即执行:编辑器本身已是用户主动打开的动作;设为 `true` 时确认步里会写明这次保存会丢弃什么); |
|
|
82
83
|
| `replyMode` | `auto` | 回复编辑怎么落地。`auto`:宿主有 plugin record + message projection 就用就地补丁,否则退回重放;`patch`:强制就地补丁,缺能力时加载/保存直接报错;`replay`:始终使用 0.2.21 的回退 + 重放路径。提示词编辑不受影响,始终走 surface-replace。 |
|
|
84
|
+
| `editorHeight` | `fill` | 编辑器高度。`fill`(默认):普通块按一轮最大,「全部」时铺满对话区到输入框之间的整段高度;`max`:一轮最大;`content`:跟着当前块走。设置页可切换。 |
|
|
85
|
+
| `editorPlacement` | `overlay` | 编辑器位置。`overlay`:悬浮在视口内,按当前块取框;`inline`:按页面坐标铺在消息上、跟随页面滚动,高度按内容展开;`legacy`:整行旧版,套整条 assistant 行。**浮层 / 整行旧版 / 居中默认夹紧在对话区内**:上不越过对话区顶部、下不压到输入框,长内容框内滚动;`inline` 保持页面坐标与页面滚动,不夹。 |
|
|
86
|
+
| `editorStyle` | `frame` | 编辑器外观。`frame`:一圈描边套住整条消息行,正文输入框落在消息文字上、按钮在右上角(参考图);`bubble`:编辑框精确等于消息气泡的 rect;`center`:居中大面板。插件页 `/#/panel/plugins/dsh-edit-turn/dsh-edit-turn` 现在有「编辑器样式」下拉(和 dsh-delete-turn 同一套 `plugins.row.config` 槽位),选择会记住;编辑器对话框里不再放样式下拉,样式只从这里设置。 |
|
|
83
87
|
|
|
84
88
|
### 工作原理
|
|
85
89
|
|
|
@@ -164,7 +168,7 @@ ctx.sessions.registerMessageProjection({
|
|
|
164
168
|
| 运行中的实例是否真的挂载了本插件(只读路由守卫探针,无需 token) | `npm run probe:loaded [端口]` | 通过:`/state` 返 400、`/apply` 返 405 —— 这两个状态码只有本插件会返回 |
|
|
165
169
|
| 浏览器半部到底问了什么、拿回了什么(只读诊断,含失败记录) | `GET /dsh-edit-turn/debug` | 通过:真实浏览器里确认客户端确实拿到 replies;并复现了旧 v3 会话的 session-not-found |
|
|
166
170
|
| 官方 append **与读取**契约(真实校验器,进程内) | `npm run verify:contract` | 96 项通过(每段写入后都用加载器重读整份日志):替换事件被接受、派生历史真的收缩、日志 append-only、工具结果与调用同进同退、空 developer 载体不产生模型消息、**连续两次回退都被接受**、**编辑模型回答的完整机制被接受**、**回复编辑后的尾部重放(后续提问/回答/tool 调用与结果按新 turn 号回到修正回答之后,顺序正确、日志仍可加载)**、**跨插件依赖的不变量(单节点窗口 / 同事件类型 / 全窗口 sourceEventSeqs / 每个替换都带 `editedBy` 标记 / 改写后的 `source.kind` 不是 `user` / 修正回复不带 `sourceEventSeqs`)**,以及**就地补丁:一条 ignorable 记录、surface 不变、去掉投影后原文回来、后续轮次与 tool 结果不动、第二条记录可叠加** |
|
|
167
|
-
| 纯逻辑 + 宿主集成 + 客户端 DOM 行为(真 HTTP、真校验器、桩服务、DOM 桩) | `npm test` |
|
|
171
|
+
| 纯逻辑 + 宿主集成 + 客户端 DOM 行为(真 HTTP、真校验器、桩服务、DOM 桩) | `npm test` | 227 项通过(含回复编辑的尾部重放用例:窗口/重放区间、新 turn 号与新 messageId、tool 调用与结果成对重映射、上一轮修正可再次编辑,以及与 `dsh-rerun-turn` builder 的逐字段对照;另含「文本没变 → 不写」的四条,以及块随消息一起改的 35 条:未动的块逐字节保留、删块少一块、文字位置不变、no-op 语义升级、附件服务缺失时降级且不写坏数据、自定义 `quote-card` 块的通用性、录用与拒绝、`/state` 的块描述与能力、附件字节路由、编辑器芯片/删除/添加/缩略图/降级警告) |
|
|
168
172
|
| 客户端半部静态检查(注册、i18n 完整性、样式、皮肤可读性、版本三处同步、线协议、块契约) | `npm run verify:client` | 184 项全部通过(含 12 条块契约检查:能力上报、服务现场探测、录用是唯一建块路径、录用先于 append、**两侧都不特判块类型**、块逐字节复制、文字归位、`dropped` 上报、只在无服务时警告、芯片靠 `error` 事件自证) |
|
|
169
173
|
| 实机前端产物校验(运行中的 DSH 是否在下发当前代码) | `npm run verify:live -- --token-file ~/path/to/dsh.log` | 全部通过(含**宿主节点形状锚点**) |
|
|
170
174
|
| **真实浏览器渲染冒烟**(CDP 驱动已开着的标签页,只读) | `npm run verify:ui` | 全部通过:下发的字节就是刚改的字节、无槽位崩溃留下的空占位、回复铅笔在平台动作条里、被回滚的行保住动作条、**被回滚的用户行一定显示替代文本(消息不会凭空消失)**、**替代气泡一定排在时间/复制之上(顺序与正常消息一致)**、**改写后那颗铅笔一定在还活着的动作条末尾(已在原始会话、切走的会话、切回后三处现场确认)**、**回复铅笔一定排在动作条最左(复制之前,已现场确认)**、气泡上没有 `.dshet-floating` 压着文字、切走再切回入口仍在 |
|
|
@@ -248,8 +252,89 @@ ln -s /path/to/dsh-install/node_modules ./node_modules
|
|
|
248
252
|
|
|
249
253
|
**「点了保存没反应」先看这里**:记录里有没有 `apply`。没有 → 点击丢在浏览器半边(此前的成因是宿主在 mousedown/mouseup 之间重建了行,按钮已改为 pointerdown 激活);有 `apply` 但 `ok:false` → 宿主拒绝了,`code` 就是原因(`busy`/`stale`/...)。
|
|
250
254
|
|
|
255
|
+
### 为什么没有 `replyMode: replace`(把回复也走 surface 替换)
|
|
256
|
+
|
|
257
|
+
试过:像 `dsh-chat-thinking-editor` 那样 append 一条新的 `assistant/message`、用 replace op 遮蔽旧的那条,让宿主原生渲染。**当前宿主(0.2.1-rc.2)的 surface 校验直接拒绝**,两条独立规则:
|
|
258
|
+
|
|
259
|
+
1. `session event "assistant/message" carries an invalid replace surfaceOp` —— replace op 的键必须是 `{op, startSeq, endSeq}`(对方的代码用 `{start, end}`)
|
|
260
|
+
2. `assistant/message embeds its source stream and cannot carry sourceEventSeqs`,而同一校验又要求 `surface replace: sourceEventSeqs must include every shadowed surface node; missing N` —— 两条互相矛盾 ⇒ **assistant 消息不能被另一条 assistant 消息替换**
|
|
261
|
+
|
|
262
|
+
### 为什么没有走 `conversation.chat.reasoning.body` 槽位渲染
|
|
263
|
+
|
|
264
|
+
也试过:注册官方 `conversation.chat.reasoning.body`(assistant-step 的子槽,`kind: single`、`scope: session`,宿主默认实现 `priority: 100`,并转交工厂槽 `conversation.chat.reasoning.content` 画 markdown),用它原生渲染改写后的思维链。
|
|
265
|
+
|
|
266
|
+
实测(真页面,2026-10-22):**注册成功但拿不到槽位**——
|
|
267
|
+
|
|
268
|
+
- 注入回调确实执行(在 `document.documentElement.dataset` 上留了标记,读到 `1`)
|
|
269
|
+
- 组件从不渲染:`[data-dshet-reason-body]` 计数恒为 0
|
|
270
|
+
- `priority: 200` / `priority: 50` / 不传(由 runner 分配负值)三种都试过,宿主默认实现始终是渲染者
|
|
271
|
+
- 没有出现任何「registration refused」告警,说明注册被接受、但 `single` 槽位仍由宿主持有
|
|
272
|
+
|
|
273
|
+
结论:**当前版本下第三方插件无法接管这个 single 子槽位**。所以「原生渲染」的两条路都封着:assistant 替换被 session 校验拒绝;思维链正文槽位不可顶替。界面侧只能继续用本插件的 DOM 补丁(已验证可用:`[data-dshet-patch]` 落在 `_text_*` 思维链节点上,内容为投影后的文本)。
|
|
274
|
+
|
|
275
|
+
要真正摆脱 DOM 补丁,需要上游给投影一个原生渲染口,或者允许 assistant 替换、或允许插件 shadow 一个 single 子槽位。
|
|
276
|
+
|
|
251
277
|
### 更新日志
|
|
252
278
|
|
|
279
|
+
**0.5.2(工作区)** —— 回复编辑不再等这一轮回复结束;编辑器跟着当前皮肤走。
|
|
280
|
+
|
|
281
|
+
- **回复编辑不再被「正在回复中」挡住**:就地记录(patch)只 append 一条 `ignorable` 事件,不改任何 surface 节点,所以它可以在 agent 还在写的时候落盘 —— 模型下一次折叠就读到。宿主侧只在**会移动 surface** 的路径上保留忙时拒绝:改写提示词(surface replace)和 replay 兜底(遮蔽窗口 + 重放尾部)。客户端同步:回复就地编辑不再禁用保存、不再显示「该会话正在回复中」横幅;提示词编辑与 replay 路径照旧拦下并说明。
|
|
282
|
+
- **测试**:回复编辑在未闭合的 turn 中保存成功、提示词改写仍被拒、整轮多块在忙时保存成功。
|
|
283
|
+
|
|
284
|
+
- **颜色/圆角/阴影改用主题令牌**:文字、次级文字、三级文字、描边、主色、圆角(`--dsw-radius-panel/xl/lg/md/sm`)、阴影(`--dsw-shadow-lv3`)都读当前主题的令牌,取不到时退回本插件原来的值;悬停底色用 `color-mix` 从主题墨色算出来。
|
|
285
|
+
- **面板底色取皮肤的“色相”,不取它的透明**:皮肤把界面画在插画上时会把表面色做成半透明(靠自己的文字描边保证可读),插件元素没有描边。现在运行时探测 `--dsw-alias-bg-layer-1/2`:把它的**颜色**原样拿来、透明度强制为 1,于是「中秋」这类**深色插画皮肤**得到的是同色系的深色面板,而不是插件自带的浅色面板(这类皮肤不设 `data-ds-dark-theme`,旧代码只能退回浅色)。
|
|
286
|
+
- **调色板挂在 `body` 上**:主题令牌声明在 `body`,而自定义属性是在**定义处**作用域内做替换的 —— 原来挂在 `:root` 上,所有 `var(--dsw-*)` 都静默取了 fallback(实测:改了等于没改)。
|
|
287
|
+
- **就地编辑器不再刷白底**:`pageBackground()` 原来读 `body` 背景,插画皮肤下 `body` 是透明的 → 退回 `#ffffff`,于是深色皮肤上出现一个白框。现在优先用已解析的 `--dshet-panel`(按上面规则一定不透明)。
|
|
288
|
+
- **改写后的提示词气泡用皮肤自己的气泡色**(`--dsw-specific-bubble`),圆角用 `--dsw-radius-xl`,与真实用户气泡一致。
|
|
289
|
+
- **测试**:`npm test` **241/241**、`npm run verify:contract` **96** 项、`npm run verify:client` **192** 项。
|
|
290
|
+
|
|
291
|
+
**0.5.1(工作区)** —— 思维链就地画出来、保存不再“点不动”、同一个块可以反复编辑。
|
|
292
|
+
|
|
293
|
+
- **删掉「思维链已改写(模型可见)」卡片**:reasoning 正文只要在 DOM 里就就地改写;没有正文时不再插入任何占位卡片。
|
|
294
|
+
- **无限次编辑**:记录「上一次画上去的文本」,第二、第三次编辑同一个块时仍能找到元素并更新。
|
|
295
|
+
- **projection 缺失不再 500**:宿主用 `... was removed or replaced` 拒绝时,单块回复保存自动降级走 replay 路径;「全部」多块保存返回 `projection-missing`,提示重启 DSH。
|
|
296
|
+
- **忙时不再假死**:客户端从 `/state` 读 `busy`,会话还在回复时直接禁用保存并显示整条提示「该会话正在回复中…」,每 3 秒复查一次,回复结束自动解除。
|
|
297
|
+
- **失败提示变醒目**:in-place 的 `.dshet-error` 从底栏左侧小字改成整条横幅(左右 8px、底 52px、带边框/阴影)。
|
|
298
|
+
- **确认步不再死循环**:保存键处理函数改读实时 controller 状态;确认步给按钮加可见强调圈;`/apply` 增加 20 秒超时,宿主挂住时恢复按钮并报错。
|
|
299
|
+
- **从「全部」切回单块不再残留**:选择器切回某一块时没有把 `allBlocks` 置回 false,重绘又画成「全部」视图、选择器却写着「正文」(两个输入框 + 单块选择)。现在切回单块会明确退出全部视图,`allBlocks` 也进了编辑器重建标记;选到不存在的块时同样退出全部视图并保留原先选中的块。
|
|
300
|
+
- **思考行找对了**:官方把 reasoning 画在**它自己那一行**(flow key 带 `,reasoning` 分组),而按 seq 找到的行是**正文行** —— 旧代码只在那一行里找,所以思维链改写永远落不到 DOM(正文改写正常,因为正文就在那一行)。现在思维链的搜索改为**在整个会话里找“文本等于记录原文”的最深节点**,并和其它块一样登记 `data-dshet-patch`(可回退)。
|
|
301
|
+
- **折叠的思考也能看到改写**:思考面板收起时正文根本不在 DOM 里,而头部那行 `思考 · <截断片段>` 是宿主按**记录的原文**画的 —— 于是改了模型上下文、界面却像没生效。现在保存后连**头部片段**一起按改写后的文本重画(保留宿主的省略号与截断长度、不碰它自己的标签)。
|
|
302
|
+
- **长内容不再被底栏压住**:输入框高度原来只减了顶栏(`height - offsetTop - 8`),底部 40px 落在控制带下面 —— 框内能滚动,但最后几行永远被 X/保存那条带子盖住。现在按底栏实际高度(`offsetHeight`,取不到时用 46px 常量)预留,输入框正好停在控制带上方;内容更高时在框内滚动。
|
|
303
|
+
- **测试**:`npm test` **235/235**、`npm run verify:contract` **96** 项、`npm run verify:client` **184** 项。
|
|
304
|
+
|
|
305
|
+
**0.5.0** —— 从「一个气泡的编辑器」长成「整轮可编辑 + 可导航的文档」。
|
|
306
|
+
|
|
307
|
+
- **整轮所有块**:一条回答里每个 step 的 reasoning 与每个 text 都进 picker,同类自动编号(思维链 1 / 正文 1 …),每块带自己的 seq,保存时 patch 到它所在的消息。
|
|
308
|
+
- **「全部」视图**:一页同时看到整轮所有块,每块一个自动增高的 textarea,上面一条轻量分割线 + 标签;顶部有 sticky 块导航(可点跳转),只有外层容器一个滚动条;宽度与 composer 卡片对齐。
|
|
309
|
+
- **编辑器高度**:`fill`(默认,普通块按一轮最大;「全部」时铺满对话区顶部到输入框之间的整段高度)/ `max` / `content`,设置页可选。
|
|
310
|
+
- **编辑器位置**:`overlay` / `inline` / `legacy`;除 `inline` 外默认夹紧在对话区顶部与输入框之间,识别不到时从视口底部预留 120px。
|
|
311
|
+
- **输入体验**:粘贴图片/文件、拖拽文件进框,与左下角「+」进入同一 chip 列表。
|
|
312
|
+
- **官方式图标**:取消 X / 重跑环形箭头 / 保存双勾,28×28、15px SVG、`#81858c`;「+」为官方 composer 同款 28×28 `#f5f6f7` 圆钮;「编辑哪一块」在底栏最右(文字仅无障碍可见)。
|
|
313
|
+
- **性能**:滚动放置走 rAF 节流并跳过无变化帧;边界/高度缓存;MutationObserver 忽略插件自身层;DOM 注入改用 `useLayoutEffect` 并在按钮被 React 删除时同步补回。
|
|
314
|
+
- **随窗口自适应**:`resize`/全屏切换/缩放会清缓存并重新放置;有 `ResizeObserver` 时也观察 body。
|
|
315
|
+
- **宿主**:`/apply` 支持 `targets` 数组,一次保存写一条 patch 记录;`/state` 的回复块带 `seq`,reasoning 文本字段兼容 `text`/`reasoning`/`thinking`。
|
|
316
|
+
- **测试**:`npm test` **228/228**、`npm run verify:contract` **96** 项、`npm run verify:client` **184** 项。
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
- 编辑提示词时取**输入气泡**的宽度、左边界和位置(右对齐);编辑回答时取**输出内容块**的宽度和位置。编辑框直接覆盖在被编辑的消息上,高度再向下吃到 row/action bar 底部并多留 48px 动作带,把官方那排复制/删除/分享按钮整条盖住。
|
|
320
|
+
- **一圈描边套住整条消息行**:作者行、正文、宿主的点赞/菜单都在框内,正文输入框精确落在消息文字的位置上(输入气泡右对齐、回答内容块左对齐)。
|
|
321
|
+
- **操作按钮在框内左下**:样式/取消/重跑/保存与「添加附件」排在同一行,从「+」右侧开始,底部对齐;图片 chip 在顶部,正文不再被按钮压住。**取消/重跑/保存都是官方式纯图标**:28×28、15px SVG、`stroke-width:1.2`、颜色 `#81858c`,取消 X、重跑环形箭头、保存双勾,文字只留在 aria-label / 隐藏标签里。
|
|
322
|
+
- **取对行**:回答的 seq 同时被 assistant-step 行和带操作条的 turn-tail 行覆盖,之前后写的 turn-tail 把编辑框锚到了那条小操作条上,尺寸只有 120px;现在按行类型排序,assistant-step(提示词则是 user 行)优先。
|
|
323
|
+
- **回复编辑按当前块取框**:正文框正文块、思维链框思维链块,textarea 填到框底,不再出现“大框小输入区+底部空白”。
|
|
324
|
+
- **「全部」视图**:picker 里选「全部」后,这一轮所有思维链/正文同时铺在一页,每块一个自动增高的 textarea、上面一条轻量分割线 + 标签;**宽度与输入框卡片对齐**(从输入元素向上找第一个有圆角、有底色的 composer card,取它的 left/width;编辑框 `box-sizing:border-box`,不再超出);**顶部有一条 sticky 块导航**(思维链 1 / 正文…,单行横向滚动、12px 胶囊,点一下滚到该块;「全部」不再预留 38px 顶部控制带,块间距也收紧到 6/8px),**只有外层容器有一个滚动条**,分割线只是视觉区分,textareas 自己不滚动(它们被就地样式强制 `position:static`,不再被 in-place 的 `textarea{position:absolute}` 规则拉去压住标签行);保存时把改过的块合成**一条** patch 记录(`/apply` 接受 `targets`,每块带自己的 seq)。
|
|
325
|
+
- **整轮的所有块都进 picker**:一轮里每个 step 的 assistant message 各自带一个 reasoning,答案行会把整轮所有 step 的 reasoning 和所有 text 都列出来,每个块带自己的 seq,保存时 patch 到它所在的那条消息;同类多块自动编号;同类多块自动编号(思维链 1、正文 1、思维链 2、正文 2);reasoning 文本字段兼容 `text` / `reasoning` / `thinking`,按读到的字段写回。
|
|
326
|
+
- **宽度放宽**:回复编辑用整条 conversation row 的宽度(不再被正文块窄框限制),textarea 同步用满;居中面板上限放宽到视口内 1400px。
|
|
327
|
+
- **高度贴着最后一行**:浮层/内联/居中模式按内容高度收尾(框 = 正文内容 + 顶部偏移 + 46px 功能带),正文下面不再留空;带图片 chip 最小 190px、普通最小 150px。`legacy` 只是外框仍套整行,高度同样按实测内容收尾。
|
|
328
|
+
- **功能键独占一条底栏**:footer 是 46px 高的独立带(自带背景,**不画分隔线**);按消息方向排布——用户输入(右对齐)功能键在右、`+` 在左;模型输出(左对齐)功能键在左、picker 在右(回复只要有 block 就显示,单个「正文」也显示);浮层/旧版 textarea 底部预留 64px,居中模式 footer 直接参与文档流(`position:static`),不再浮在文字上。
|
|
329
|
+
- **随窗口自适应**:放置签名包含视口尺寸,`resize`(含全屏切换/缩放)会清掉对话区缓存并重新放置;有 `ResizeObserver` 时也监听 body 尺寸变化。
|
|
330
|
+
- **夹紧边界更准**:顶部取「slot top」与「编辑行最近的可滚动祖先 top」的较大值;底部取所有 composer 包裹层里最靠下的那个 top(不再拿第一个匹配),识别不到时从视口底部预留 120px。
|
|
331
|
+
- **性能**:滚动时 `placeEditor` 走 rAF 节流并跳过无变化帧;action bar / turn-tail 的全局查询只在 legacy 需要时做;对话区/输入框边界缓存 250ms;「一轮最大」的高度按块签名缓存;MutationObserver 忽略插件自己层的变更,打字不再触发整页重扫。
|
|
332
|
+
- **高度可选**:设置页「编辑器高度」= 全部铺满(默认;普通块按一轮最大,选「全部」时自动铺满上下边界)/ 一轮最大 / 随内容。
|
|
333
|
+
- **三个位置 + 默认夹紧**:设置页「编辑器位置」= 浮层 / 页面内联 / 整行旧版;除页面内联外都自动夹在「对话区顶部 ~ 输入框顶部」之间,长内容框内滚动。
|
|
334
|
+
- **输入体验**:提示词框支持粘贴图片/文件、拖拽文件进框,和「+」进同一 chip 列表。
|
|
335
|
+
- 说明:按用户要求,这一版只在工作区,不 commit / 不 push / 不 release / 不发 npm。
|
|
336
|
+
- **测试**:`npm test` **227/227**、`npm run verify:contract` **96** 项、`npm run verify:client` **184** 项。
|
|
337
|
+
|
|
253
338
|
**0.3.3** —— 编辑器锚定到刚按下的铅笔,位置不再跑到屏幕另一端。
|
|
254
339
|
|
|
255
340
|
- 回复的编辑按钮在 turn-tail 操作条里,而编辑器的锚点行可能是比屏幕还高的回答行;0.3.2 会把它钳到视口顶部,按钮可达但离点击处很远。现在把锚点记为按下的按钮本身:优先贴在按钮下方,放不下就贴在按钮上方,再按视口钳制。
|
|
@@ -571,12 +656,14 @@ editable and the editor warns that tool calls and reasoning cannot survive.
|
|
|
571
656
|
config:
|
|
572
657
|
confirm: false # default: apply in one click; true restores the two-step flow
|
|
573
658
|
replyMode: auto # auto | patch | replay
|
|
659
|
+
editorStyle: frame # frame | bubble | center
|
|
574
660
|
```
|
|
575
661
|
|
|
576
662
|
| Field | Default | Meaning |
|
|
577
663
|
|---|---|---|
|
|
578
664
|
| `confirm` | `false` | Whether the client asks for a second confirmation before applying. Off by default - one click applies, because the editor is already an explicit action the user opened; with `true` the confirmation step states what this save will discard. |
|
|
579
665
|
| `replyMode` | `auto` | How a reply edit lands. `auto`: use the plugin-record projection when the host exposes it, otherwise the replay splice; `patch`: require the in-place path; `replay`: always use the historical replay path. Prompt edits are unaffected. |
|
|
666
|
+
| `editorStyle` | `frame` | Editor presentation. `frame`: outline the whole message row with the textarea on the message text and actions top-right (reference UI); `bubble`: the editor is exactly the message bubble's rect; `center`: a large centred panel. Switch it in the plugin settings panel: `/#/panel/plugins/dsh-edit-turn/dsh-edit-turn`. |
|
|
580
667
|
|
|
581
668
|
### How it works
|
|
582
669
|
|