dsh-rewind-plugin 0.1.2 → 0.1.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 +5 -4
- package/lib/client.js +50 -1
- package/lib/index.js +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
DeepSeek Harness 插件:**同一会话窗口的 in-place 对话回退**(Claude Code `/rewind` 语义)。主交互为**用户消息旁的「回退」按钮**,点击后选择回退模式;命令仅作辅助。
|
|
4
4
|
|
|
5
|
-
> 状态:v0.1.
|
|
5
|
+
> 状态:v0.1.3 已实现并发布(`dsh-rewind-plugin`,npm + GitHub Actions Trusted Publishing)。交互以 Claude Code 行为为参考,并贴合 dsh Web 实际 UI(利用现有 DOM 锚点与运行时快照,纯插件、不改仓库核心)。
|
|
6
6
|
|
|
7
|
-
## 实现状态(v0.1.
|
|
7
|
+
## 实现状态(v0.1.3)
|
|
8
8
|
|
|
9
9
|
- ✅ host 端 `/rewind` 命令(两步文本引导 + 直接执行 + `preview` 影响清单)
|
|
10
10
|
- ✅ host 端变更台账(`tools/execute` 捕获 before、`tools/post-execute` 提交),按会话隔离
|
|
@@ -73,8 +73,9 @@ git push --tags # push v<version> tag → 触发 .github/workflows/publish.
|
|
|
73
73
|
提示"已撤回 seq N,可重新发送"。
|
|
74
74
|
- 键盘流:`/rewind` → 选消息 → `/rewind <序号> chat|both`;`/rewind preview <目标>`
|
|
75
75
|
只输出影响清单不执行。
|
|
76
|
-
-
|
|
77
|
-
|
|
76
|
+
- **回退后前端与 Agent 一致**:回退/撤回后,client 端自动隐藏回退标记、`/rewind`
|
|
77
|
+
命令结果以及被回退范围内的消息(含 agent 回复),可见对话回到回退点之前的样子;
|
|
78
|
+
之后新发的消息正常显示。会话日志(append-only 审计)不受影响。
|
|
78
79
|
|
|
79
80
|
## 已知限制(v0.1)
|
|
80
81
|
|
package/lib/client.js
CHANGED
|
@@ -385,10 +385,43 @@ var name = "dsh-rewind";
|
|
|
385
385
|
var inject = ["sessions", "locale"];
|
|
386
386
|
var NS = "rewind";
|
|
387
387
|
var USER_SEAT_SELECTOR = '[data-chat-flow-kind="user"]';
|
|
388
|
+
var CHAT_SEAT_SELECTOR = "[data-chat-anchor-key]";
|
|
388
389
|
var ACTIONS_ROOT_SELECTOR = "[data-time-hover-root]";
|
|
390
|
+
var REWIND_MARKER_RE = /__DSH_REWIND__:\{"target":(\d+)\}/;
|
|
389
391
|
function messagePreviewOf(node) {
|
|
390
392
|
return node.content.map((block) => block.type === "text" && typeof block.text === "string" ? block.text : "").join("").replace(/\s+/g, " ").trim().slice(0, 80);
|
|
391
393
|
}
|
|
394
|
+
function hiddenSeqsOf(session) {
|
|
395
|
+
const hidden = /* @__PURE__ */ new Set();
|
|
396
|
+
const snap = session.getSnapshot();
|
|
397
|
+
let latest = null;
|
|
398
|
+
for (const key of snap.chat.order) {
|
|
399
|
+
const node = snap.chat.nodes.get(key);
|
|
400
|
+
if (node === void 0) continue;
|
|
401
|
+
if (node.kind === "command") {
|
|
402
|
+
const command = node.data;
|
|
403
|
+
if (command.name === "rewind") hidden.add(command.seq);
|
|
404
|
+
} else if (node.kind === "user") {
|
|
405
|
+
const user = node.data;
|
|
406
|
+
const text = user.content.map((block) => block.type === "text" && typeof block.text === "string" ? block.text : "").join("");
|
|
407
|
+
const match = text.match(REWIND_MARKER_RE);
|
|
408
|
+
if (match !== null) {
|
|
409
|
+
hidden.add(user.seq);
|
|
410
|
+
const target = Number(match[1]);
|
|
411
|
+
if (latest === null || user.seq > latest.marker) latest = { marker: user.seq, target };
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
if (latest !== null) {
|
|
416
|
+
for (const key of snap.chat.order) {
|
|
417
|
+
const node = snap.chat.nodes.get(key);
|
|
418
|
+
if (node === void 0) continue;
|
|
419
|
+
const anchor = node.anchorSeq;
|
|
420
|
+
if (anchor > latest.target && anchor <= latest.marker) hidden.add(anchor);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
return hidden;
|
|
424
|
+
}
|
|
392
425
|
function apply(ctx) {
|
|
393
426
|
ctx.effect(function* () {
|
|
394
427
|
yield ctx.locale.register(NS, { zh, en });
|
|
@@ -398,6 +431,7 @@ function apply(ctx) {
|
|
|
398
431
|
style.textContent = STYLE;
|
|
399
432
|
document.head.appendChild(style);
|
|
400
433
|
const attached = /* @__PURE__ */ new WeakSet();
|
|
434
|
+
const hidden = /* @__PURE__ */ new WeakSet();
|
|
401
435
|
const buttons = /* @__PURE__ */ new Map();
|
|
402
436
|
let observer = null;
|
|
403
437
|
const sessionFor = () => {
|
|
@@ -449,7 +483,22 @@ function apply(ctx) {
|
|
|
449
483
|
for (const [key, button] of buttons) {
|
|
450
484
|
if (!button.isConnected) buttons.delete(key);
|
|
451
485
|
}
|
|
452
|
-
|
|
486
|
+
const session = sessionFor();
|
|
487
|
+
const hiddenSeqs = session !== void 0 ? hiddenSeqsOf(session) : /* @__PURE__ */ new Set();
|
|
488
|
+
for (const seat of document.querySelectorAll(CHAT_SEAT_SELECTOR)) {
|
|
489
|
+
const key = seat.dataset.chatAnchorKey;
|
|
490
|
+
const anchor = key !== void 0 && session !== void 0 ? session.getSnapshot().chat.nodes.get(key)?.anchorSeq : void 0;
|
|
491
|
+
if (anchor !== void 0 && hiddenSeqs.has(anchor)) {
|
|
492
|
+
seat.style.display = "none";
|
|
493
|
+
hidden.add(seat);
|
|
494
|
+
} else if (hidden.has(seat)) {
|
|
495
|
+
seat.style.display = "";
|
|
496
|
+
hidden.delete(seat);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
for (const seat of document.querySelectorAll(USER_SEAT_SELECTOR)) {
|
|
500
|
+
if (!hidden.has(seat)) attach(seat);
|
|
501
|
+
}
|
|
453
502
|
};
|
|
454
503
|
observer = new MutationObserver(scan);
|
|
455
504
|
observer.observe(document.body, { childList: true, subtree: true });
|
package/lib/index.js
CHANGED
|
@@ -284,7 +284,8 @@ function buildMarker(targetSeq) {
|
|
|
284
284
|
return createUserMessage({
|
|
285
285
|
content: [{
|
|
286
286
|
type: "text",
|
|
287
|
-
text: `
|
|
287
|
+
text: `__DSH_REWIND__:{"target":${targetSeq}}
|
|
288
|
+
[\u56DE\u9000\u6807\u8BB0 / rewind marker] \u5BF9\u8BDD\u5DF2\u56DE\u9000\u5230 seq ${targetSeq}\uFF0C\u6B64\u6807\u8BB0\u4E4B\u540E\u7684\u5386\u53F2\u5DF2\u4ECE\u6A21\u578B\u4E0A\u4E0B\u6587\u4E2D\u79FB\u9664\u3002\u8BF7\u5FFD\u7565\u6B64\u6807\u8BB0\u672C\u8EAB\uFF0C\u7B49\u5F85\u7528\u6237\u7684\u4E0B\u4E00\u6761\u6D88\u606F\u3002`
|
|
288
289
|
}],
|
|
289
290
|
source: { kind: "user" }
|
|
290
291
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-rewind-plugin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.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",
|