dsh-rewind-plugin 0.2.1 → 0.2.3

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 CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  In-place conversation rewind for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness): the Claude Code `/rewind` semantics inside the **same session window** — cut the model context back to an earlier user message, and optionally restore workspace files from **disk-persisted before-backups**.
6
6
 
7
- > **Status:** published to npm (`dsh-rewind-plugin`, v0.2.0) via GitHub Actions Trusted Publishing + Sigstore provenance. Targets the web profile (`dsh --profile web`). Interaction mirrors Claude Code's rewind, adapted to dsh's real web UI.
7
+ > **Status:** published to npm (`dsh-rewind-plugin`, v0.2.2) via GitHub Actions Trusted Publishing + Sigstore provenance. Targets the web profile (`dsh --profile web`). Interaction mirrors Claude Code's rewind, adapted to dsh's real web UI.
8
8
 
9
9
  [![npm version](https://img.shields.io/npm/v/dsh-rewind-plugin.svg)](https://www.npmjs.com/package/dsh-rewind-plugin)
10
10
  [![npm license](https://img.shields.io/npm/l/dsh-rewind-plugin.svg)](https://github.com/SiriLee/dsh-rewind/blob/main/LICENSE)
@@ -40,9 +40,6 @@ In-place conversation rewind for [DeepSeek Harness](https://github.com/deepseek-
40
40
 
41
41
  ## 📸 Screenshots
42
42
 
43
- All screenshots render at a fixed width, so their size stays consistent
44
- regardless of caption length.
45
-
46
43
  <table>
47
44
  <tr>
48
45
  <td align="center"><img src="assets/screenshots/rewind-button.png" width="440" alt="Per-message ↶ rewind button"><br><sub>Per-message ↶ rewind button</sub></td>
package/README.zh.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 插件:**同一会话窗口的 in-place 对话回退**(Claude Code `/rewind` 语义)——把模型上下文剪回更早的一条用户消息,并可基于**落盘的写前备份**还原工作区文件。
6
6
 
7
- > **状态**:已发布 npm(`dsh-rewind-plugin`,v0.2.0),经 GitHub Actions Trusted Publishing + Sigstore provenance 构建发布。目标为 web 配置档(`dsh --profile web`)。交互以 Claude Code 的 rewind 为参考,并贴合 dsh Web 实际 UI。
7
+ > **状态**:已发布 npm(`dsh-rewind-plugin`,v0.2.2),经 GitHub Actions Trusted Publishing + Sigstore provenance 构建发布。目标为 web 配置档(`dsh --profile web`)。交互以 Claude Code 的 rewind 为参考,并贴合 dsh Web 实际 UI。
8
8
 
9
9
  [![npm version](https://img.shields.io/npm/v/dsh-rewind-plugin.svg)](https://www.npmjs.com/package/dsh-rewind-plugin)
10
10
  [![npm license](https://img.shields.io/npm/l/dsh-rewind-plugin.svg)](https://github.com/SiriLee/dsh-rewind/blob/main/LICENSE)
@@ -40,8 +40,6 @@
40
40
 
41
41
  ## 📸 截图
42
42
 
43
- 所有截图以固定宽度渲染,尺寸不随说明文字长短变化。
44
-
45
43
  <table>
46
44
  <tr>
47
45
  <td align="center"><img src="assets/screenshots/rewind-button.png" width="440" alt="用户消息旁的 ↶ 回退按钮"><br><sub>用户消息旁的 ↶ 回退按钮</sub></td>
package/lib/client.js CHANGED
@@ -38,31 +38,36 @@ function targetOfOutcome(text) {
38
38
  const match = text.match(/seq (\d+)/);
39
39
  return match !== null ? Number(match[1]) : void 0;
40
40
  }
41
+ function isPreviewCommand(command) {
42
+ return (command.args ?? "").includes("preview");
43
+ }
41
44
  function hiddenSeqsOf(snap) {
42
45
  const hidden = /* @__PURE__ */ new Set();
43
- let minTarget = Number.POSITIVE_INFINITY;
44
- let maxMarker = Number.NEGATIVE_INFINITY;
46
+ const spans = [];
45
47
  for (const key of snap.order) {
46
48
  const node = snap.nodes.get(key);
47
49
  if (node === void 0 || node.kind !== "command") continue;
48
50
  const command = node.data;
49
51
  if (command.name !== "rewind") continue;
52
+ if (isPreviewCommand(command)) {
53
+ hidden.add(command.seq);
54
+ continue;
55
+ }
50
56
  if (command.outcome?.kind !== "success") continue;
51
- if (command.outcome.sourceEventSeq === void 0) continue;
52
- hidden.add(command.seq);
53
57
  const marker = command.outcome.sourceEventSeq;
58
+ if (marker === void 0) continue;
59
+ hidden.add(command.seq);
54
60
  const target = targetOfOutcome(command.outcome.text);
55
61
  if (target !== void 0) {
56
- if (target < minTarget) minTarget = target;
57
- if (marker > maxMarker) maxMarker = marker;
62
+ spans.push({ start: target, end: marker });
58
63
  }
59
64
  }
60
- if (Number.isFinite(minTarget)) {
61
- for (const key of snap.order) {
62
- const node = snap.nodes.get(key);
63
- if (node === void 0) continue;
64
- const anchor = node.anchorSeq;
65
- if (anchor >= minTarget && anchor <= maxMarker) hidden.add(anchor);
65
+ for (const key of snap.order) {
66
+ const node = snap.nodes.get(key);
67
+ if (node === void 0) continue;
68
+ const anchor = node.anchorSeq;
69
+ if (spans.some((span) => anchor >= span.start && anchor <= span.end)) {
70
+ hidden.add(anchor);
66
71
  }
67
72
  }
68
73
  return hidden;
@@ -17,16 +17,18 @@ export interface HiddenChat {
17
17
  export declare function targetOfOutcome(text: string | undefined): number | undefined;
18
18
  /**
19
19
  * Anchor seqs that must be hidden from the rendered transcript so the user
20
- * sees the conversation as the agent sees it: every EXECUTED `/rewind`
21
- * command row (one that appended a marker; preview-only rows stay visible
22
- * until a real rewind's range covers them) and every message withdrawn by a
23
- * rewind — the target message itself, everything after it, and the (empty,
24
- * unrendered) marker.
20
+ * sees the conversation as the agent sees it: every impact-preview flow node
21
+ * (pending, succeeded, or errored it only exists to feed the popover) and
22
+ * every SUCCESSFUL executed `/rewind` command row, plus every message
23
+ * withdrawn by a rewind — the target message itself, everything after it, and
24
+ * the (empty, unrendered) marker.
25
25
  *
26
- * The cut span is [min target, max marker] across ALL executed rewinds, not
27
- * just the newest one: every rewind withdraws its target and everything after
28
- * it, and a later rewind to a LATER point (after new traffic) must not re-show
29
- * rows an earlier rewind already cut. Endpoints come from the command nodes:
26
+ * Each executed rewind cuts ONE span `[target, marker]`: the target message
27
+ * and everything after it, up to the marker appended at rewind time. Spans are
28
+ * kept SEPARATE (never collapsed to a single `[min target, max marker]`)
29
+ * because a later rewind to a LATER point leaves a visible gap of new traffic
30
+ * between the earlier marker and the later target — collapsing the spans would
31
+ * hide that still-on-surface gap. Endpoints come from the command nodes:
30
32
  * `sourceEventSeq` is the marker's log seq, and the outcome text carries the
31
33
  * target seq.
32
34
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-rewind-plugin",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "DeepSeek Harness plugin: in-place conversation rewind in the same session window (Claude Code /rewind semantics) with optional workspace file restore",
5
5
  "keywords": [
6
6
  "deepseek-harness",