dsh-last-turn-delete 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kaiqiang Duan
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.
@@ -0,0 +1,5 @@
1
+ # Bilingual-pair consistency record: the git blob hash of each side as of the
2
+ # last confirmed-consistent state. After editing either side, bring the other
3
+ # along and re-record with `git hash-object <file>`.
4
+ README.md: baa50d7d7cd2813e71a6f182d23e90f9ea189adc
5
+ README.zh.md: e8b23fc2da0349ccebc3c9961304a70cb2e7eb90
package/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # dsh-last-turn-delete
2
+
3
+ English | [中文](README.zh.md)
4
+
5
+ [![npm version](https://img.shields.io/npm/v/dsh-last-turn-delete.svg)](https://www.npmjs.com/package/dsh-last-turn-delete)
6
+
7
+ DeepSeek Harness (DSH) plugin bundle: a **trash-can button** on the newest deletable item of a conversation — the **last user message**, or a **failed `/compact` card**. A click (confirmed in a small bubble) **soft-deletes** it, then the button walks back to the previous item until a real compact boundary or nothing is left.
8
+
9
+ ## Why
10
+
11
+ Long agentic sessions pile up turns you no longer want the model to remember — and failed `/compact` cards that sit in the way. DSH's session log is append-only by design, so there is no built-in "remove this turn"; this plugin deletes on the model-visible **surface** using the same mechanism compaction uses, leaving your durable log untouched.
12
+
13
+ ## What "delete" means
14
+
15
+ - **User message + its whole reply tail** are shadowed from the model surface by one replacement event — they stop entering the context of every later request. Original events stay on disk; the turn is dimmed in place ("soft delete", nothing is lost).
16
+ - **Failed `/compact` cards** never compacted anything, so they are **not** compact boundaries — they can be deleted too. Deleting one records the command id in a small private sidecar (the `dsh_last_turn_delete` storage domain) and the chain simply continues past it. **Successful compactions remain real boundaries**: everything they covered (already off the model surface) is not deletable.
17
+ - The button only appears once the agent has **finished replying** (the host reports `running`); it is hidden mid-stream.
18
+
19
+ ## Install
20
+
21
+ Requires [pnpm](https://pnpm.io/installation) on your PATH — `dsh plugin` forwards profile package operations to pnpm.
22
+
23
+ ```bash
24
+ dsh plugin --profile web add dsh-last-turn-delete
25
+ ```
26
+
27
+ Installs the npm package into the `web` profile and activates it as a bundle (the package declares `dsh.bundle.patch`). **One command, no manual patch editing.** Restart `dsh web`, then refresh the page.
28
+
29
+ Other profiles: replace `web` with the profile name, e.g. `dsh plugin --profile <name> add dsh-last-turn-delete`.
30
+
31
+ ## Behavior
32
+
33
+ - **Button**: the same `IconTrashOutline16` the pending-message queue uses, inserted into the message action strip right next to the copy button; it clones the native action button's class, so its resting/hover look matches the copy button exactly (no custom colors). Works in every conversation — old or new — while the session is open in the GUI.
34
+ - **Delete flow**: click the trash can → a small confirm bubble (`确认删除` / `取消`; Esc or clicking elsewhere cancels) → confirm → the host soft-deletes and the button moves to the previous item.
35
+ - **Walk-back**: repeat; the chain walks backward through failed-compact cards and user turns until a real (successful) compact boundary or no user message remains.
36
+ - **Persistence**: deleted user messages are re-derived from the log on reload; deleted failed-compact ids stay in the sidecar — dimmed state and button placement survive page refreshes.
37
+ - **Safety**: the host decides the deletable tail via the `tail` Remote (which folds in streaming, boundaries and prior deletions) and only deletes while the agent is idle; a stale click is rejected and the UI re-anchors on the real tail.
38
+
39
+ ## How it works
40
+
41
+ ```
42
+ browser (client half)
43
+ trash button on the newest deletable row (message action strip)
44
+ click → inline confirm bubble → delete
45
+ │ lastTurnDelete/delete { sessionId, messageId }
46
+ │ lastTurnDelete/deleteCompact { sessionId }
47
+
48
+ host (lib/index.js, lastTurnDelete Remote service)
49
+ delete agent.runMaintenance (idle-only, serialized with the driver)
50
+ session.surface.nodes → last on-surface user message
51
+ session.append("user/message", marker, {
52
+ surfaceOp: { op: "replace", start, end },
53
+ sourceEventSeqs: shadowed
54
+ }) + ctx.sessions.flush() ← the span leaves the surface
55
+ deleteCompact newest failed /compact group → sidecar record
56
+ tail newest deletable item + agent running flag
57
+ deleted previously deleted messages + forgotten compact ids
58
+ ```
59
+
60
+ Host-authoritative answers travel back over `lastTurnDelete/tail`: the newest deletable item (`{kind: "message", messageId}` / `{kind: "compact", commandId}` / `{kind: null}`) plus `running`. Pure selection logic lives in `lib/core.js` (unit-tested, no DSH runtime dependency); the marker/user-message payloads use the plugin's own `source` identity so compaction checkpoints are never mistaken for deletions. All button/popover styling is inline on created nodes — injected `<style>` blocks are managed by the host module system and cannot be relied on.
61
+
62
+ ## Development
63
+
64
+ ```bash
65
+ pnpm install
66
+ pnpm test # node:test pure-function tests, no DSH runtime dependency
67
+ ```
68
+
69
+ ## Publishing
70
+
71
+ ```bash
72
+ cd plugins/dsh-last-turn-delete
73
+ pnpm publish --access public
74
+ ```
package/README.zh.md ADDED
@@ -0,0 +1,74 @@
1
+ # dsh-last-turn-delete
2
+
3
+ [English](README.md) | 中文
4
+
5
+ [![npm version](https://img.shields.io/npm/v/dsh-last-turn-delete.svg)](https://www.npmjs.com/package/dsh-last-turn-delete)
6
+
7
+ DeepSeek Harness (DSH) 插件 bundle:在会话**最新可删项**上显示一个**垃圾桶按钮**——它可以是**最后一条用户消息**,也可以是**失败的 `/compact` 卡片**。点击后(在小气泡中确认)即**软删除**该项,随后按钮自动移到上一条,直到真正(成功)的 compact 边界或无消息为止。
8
+
9
+ ## 为什么
10
+
11
+ 长时间的 agent 会话会积累你不再希望模型记住的轮次,以及挡在中间的“失败的 /compact”卡片。DSH 的会话日志按设计只追加,没有内置“删除这一轮”的能力;本插件用与 compact 相同的机制在**模型可见 surface** 上删除,不动你的持久化日志。
12
+
13
+ ## “删除”的含义
14
+
15
+ - **用户消息 + 其整段回复**会被一条替换事件从模型 surface 上遮蔽,之后不再进入任何后续请求的上下文。原始事件仍在磁盘上;该一轮在界面中变暗(软删除,不丢数据)。
16
+ - **失败的 `/compact` 卡片**没有成功压缩任何内容,因此**不是 compact 边界**——同样可以删除。删除时把该命令 id 记入一个小的私有侧表(`dsh_last_turn_delete` storage domain),删除链随后继续越过它。**成功的 compact 仍是真正的边界**:它覆盖的内容(已离开模型 surface)不可删除。
17
+ - 按钮只在 agent **回复完全结束**后出现(宿主报告 `running`);回复过程中隐藏。
18
+
19
+ ## 安装
20
+
21
+ 需要 PATH 上有 [pnpm](https://pnpm.io/installation) —— `dsh plugin` 会把 profile 的包操作转发给 pnpm。
22
+
23
+ ```bash
24
+ dsh plugin --profile web add dsh-last-turn-delete
25
+ ```
26
+
27
+ 把 npm 包装进 `web` profile 并作为 bundle 激活(本包声明了 `dsh.bundle.patch`)。**一条命令,无需手动改 patch。** 重启 `dsh web` 后刷新页面。
28
+
29
+ 其他 profile:把 `web` 换成对应名字,例如 `dsh plugin --profile <名字> add dsh-last-turn-delete`。
30
+
31
+ ## 行为
32
+
33
+ - **按钮**:与待发消息队列同款的 `IconTrashOutline16`,插入到消息操作条中、紧挨复制按钮;它克隆原生操作按钮的类,因此静置/悬停外观与复制按钮完全一致(无自定义颜色)。任意会话(新旧均可)只要在 GUI 中打开即可使用。
34
+ - **删除流程**:点垃圾桶 → 弹出小气泡(`确认删除` / `取消`;Esc 或点击其它位置取消)→ 确认 → 宿主软删除,按钮移到上一项。
35
+ - **链式前进**:可连续删除;删除链向后穿过“失败的 compact 卡片”与用户消息,直到真正(成功)的 compact 边界或无用户消息。
36
+ - **刷新恢复**:已删除的用户消息从日志重新推导,已删除的失败 compact id 记在侧表——变暗状态与按钮位置在刷新后依然正确。
37
+ - **安全**:可删尾由宿主的 `tail` Remote 判定(已并入流式、边界与先行删除),且只在 agent 空闲时删除;过期点击会被拒绝并重新锚定到真实尾部。
38
+
39
+ ## 实现原理
40
+
41
+ ```
42
+ 浏览器(client 半边)
43
+ 垃圾桶按钮挂在最新可删行(消息操作条)
44
+ 点击 → 内联确认气泡 → 删除
45
+ │ lastTurnDelete/delete { sessionId, messageId }
46
+ │ lastTurnDelete/deleteCompact { sessionId }
47
+
48
+ 宿主(lib/index.js,lastTurnDelete Remote 服务)
49
+ delete agent.runMaintenance(仅空闲、与 driver 串行)
50
+ session.surface.nodes → 最后一个 on-surface 用户消息
51
+ session.append("user/message", marker, {
52
+ surfaceOp: { op: "replace", start, end },
53
+ sourceEventSeqs: shadowed
54
+ }) + ctx.sessions.flush() ← 该段离开 surface
55
+ deleteCompact 最新失败 /compact 组 → 侧表记录
56
+ tail 最新可删项 + agent running 标志
57
+ deleted 已删除消息 + 已遗忘的 compact id
58
+ ```
59
+
60
+ 宿主权威结果通过 `lastTurnDelete/tail` 回传:最新可删项(`{kind: "message", messageId}` / `{kind: "compact", commandId}` / `{kind: null}`)外加 `running`。纯选取逻辑在 `lib/core.js`(有单测、不依赖 DSH 运行时);标记/用户消息载荷使用插件自己的 `source` 身份,因此不会把 compact 检查点误判为删除。按钮与气泡全部使用创建节点上的内联样式——注入的 `<style>` 由宿主模块系统接管、不可依赖。
61
+
62
+ ## 开发
63
+
64
+ ```bash
65
+ pnpm install
66
+ pnpm test # node:test 纯函数测试,不依赖 DSH 运行时
67
+ ```
68
+
69
+ ## 发布
70
+
71
+ ```bash
72
+ cd plugins/dsh-last-turn-delete
73
+ pnpm publish --access public
74
+ ```
@@ -0,0 +1,7 @@
1
+ # dsh-last-turn-delete bundle patch: one dual-face row — the node half mounts
2
+ # the lastTurnDelete Remote service; the same row is picked up by the
3
+ # client-modules scanner (package.json dsh.client.platform: web) as the
4
+ # browser half under /plugins/dsh-last-turn-delete/client.js.
5
+ - insert:
6
+ - id: last-turn-delete
7
+ name: dsh-last-turn-delete