dsh-recall-plugin 2.3.14 → 2.3.16
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 +12 -0
- package/README.en.md +6 -6
- package/README.md +5 -4
- package/lib/client.js +88 -10
- package/lib/config.js +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
本文件格式遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),版本号遵循语义化版本。
|
|
4
4
|
|
|
5
|
+
## [2.3.16] - 2026-09-11
|
|
6
|
+
|
|
7
|
+
### 变更
|
|
8
|
+
|
|
9
|
+
- **插件描述与双语 README 文案重写**:包描述由「是什么 / 怎么做」改为「能做什么」——撤回自己发过的消息,工作区文件与对话历史一起回到那条消息发出之前,消息的文本与附件自动放回输入框(文件走独立影子 git 快照、对话走官方 `sessions.fork`、原会话归档可找回)。双语摘要补齐「撤回后可重发」;英文侧去掉过时的 DSH 版本标注;徽章由历史版本(`0.1.2-rc.1` / `0.1.3-alpha.1`,英文侧 `0.1.1-rc.x`)统一为当前核验版本 `0.1.5-rc.2`(兼容范围仍以「安装」节的 peer 声明为权威);两侧同步新增「撤回完就能重发」亮点与预览区的回填要点。功能、接口与构建产物零变化。
|
|
10
|
+
|
|
11
|
+
## [2.3.15] - 2026-09-11
|
|
12
|
+
|
|
13
|
+
### 新增
|
|
14
|
+
|
|
15
|
+
- **撤回回填扩展为「文本 + 附件」**:此前撤回只把被撤回消息的文本回填到输入框,消息里的附件(图片/文件)不会回来;现在两者一起回填,改完可直接重发。实现沿用官方 composer 自己的附件链路(`dsh-client-ui-conversation` 的 `addFiles` 实证):**早读**——撤回执行一开始(源会话仍在册、附件引用可解析时)经 `sessions.binding(sessionId).session.readAttachment(attachmentId)` 取回原始字节与 mediaType,重建为浏览器 `File`(缺文件名按 mediaType 派生 `attachment-N.<subtype>`);**后写**——fork + open 完成后在子会话里 `conversation.createDrafts(sessionId, files)` 注册草稿附件、`shell.actions.addAttachments(ids)` 进入输入态(未接纳时 `releaseDraftAttachments` 释放,与官方 `addFiles` 的失败回滚一致)。附件读取授权绑定「消息所在会话」,故必须用源会话早读——被撤回消息不在 fork 出的子会话日志中,直读子会话拿不到授权。附件读取与草稿注册均逐项 try/catch、服务面全部 typeof 探测:任一步缺失只降级附件,文本回填与撤回主流程不受影响(旧版 dsh 无 `conversation`/`createDrafts`/`readAttachment` 时恒降级)。`refillDraft` 开关语义同步为「文本与附件」(设置描述与 README 双语同步);新增 `attachmentRefsFromBlocks` / `defaultAttachmentName` 纯函数与 3 例单测,compat-audit 新增 I34。客户端 bundle 结构与既有行为零变化。
|
|
16
|
+
|
|
5
17
|
## [2.3.14] - 2026-09-11
|
|
6
18
|
|
|
7
19
|
### 修复
|
package/README.en.md
CHANGED
|
@@ -7,14 +7,13 @@
|
|
|
7
7
|

|
|
8
8
|

|
|
9
9
|
|
|
10
|
-

|
|
10
|
+
[](https://github.com/deepseek-ai/deepseek-harness/releases/tag/dsh-v0.1.5-rc.2)
|
|
12
11
|

|
|
13
12
|
---
|
|
14
|
-
Under any message you've sent, click "↶ Recall" — **
|
|
13
|
+
Under any message you've sent, click "↶ Recall" — **your workspace files and the conversation history roll back to just before that message was sent**.
|
|
15
14
|
---
|
|
16
15
|
|
|
17
|
-
Files and conversation roll back together: the workspace is first snapshotted into an independent shadow git repository, and a recall uses it to restore files to their state before that message; the conversation is rewound through DSH's official `sessions.fork` to the turn boundary before it. Snapshots never touch your project's own git and live under `$DSH_HOME` by default
|
|
16
|
+
Files and conversation roll back together: the workspace is first snapshotted into an independent shadow git repository, and a recall uses it to restore files to their state before that message; the conversation is rewound through DSH's official `sessions.fork` to the turn boundary before it, with the original session archived and recoverable. After a recall, the message's text and attachments are placed back into the input box, ready to edit and resend. Snapshots never touch your project's own git and live under `$DSH_HOME` by default. The main boundary: snapshots are created only **when a message is sent** — messages from before the plugin was enabled have no snapshot and show no recall button.
|
|
18
17
|
|
|
19
18
|
[Changelog](CHANGELOG.md)
|
|
20
19
|
|
|
@@ -37,7 +36,7 @@ Files and conversation roll back together: the workspace is first snapshotted in
|
|
|
37
36
|
| --- | --- |
|
|
38
37
|
|  |  |
|
|
39
38
|
|
|
40
|
-
- After a recall, the message text
|
|
39
|
+
- After a recall, the message's text and attachments are placed back into the input box for quick editing and resending (can be disabled in the settings card)
|
|
41
40
|
- Settings · plugin config card (config form / exclusions / snapshot manager, saved changes apply live)
|
|
42
41
|
|
|
43
42
|

|
|
@@ -49,6 +48,7 @@ Abilities with a version in parentheses require that version or later; the rest
|
|
|
49
48
|
- **Files + conversation, rolled back together**: recalling isn't just about chat history — files the agent modified go back to their original state too; immune to your project's `.gitattributes` conversion, with byte-level fidelity for line endings and binary content (2.1.1+).
|
|
50
49
|
- **Never touches your project's own git, and keeps it clean**: snapshots live in an independent shadow git repository — branches, staging area, and uncommitted changes are untouched; storage stays under `$DSH_HOME` regardless of the session's sandbox permission (workspace-write / read-only sessions work as usual), falling back to an in-project `.dsh-recall-snapshots` only when home itself is unwritable.
|
|
51
50
|
- **See the list before you act — and change your mind as often as you like**: recall first shows the list of files that will change (modified / restored / deleted); nothing runs until you confirm. After a recall you can recall again to an even earlier point, and files overwritten during a recall always remain recoverable (up to 500 snapshots per workspace by default).
|
|
51
|
+
- **Resend right after a recall** (2.3.15+): a recall places the message's text and attachments back into the input box — images and files return as well, so you can edit and send again without picking the attachments over.
|
|
52
52
|
- **A guarded recall path** (2.0+; auto-rescue 2.1+): recall is refused while an agent is running, and a new snapshot after the preview forces a fresh preview; a "pre-rollback" safety snapshot is taken before every recall, a failed rollback is rescued automatically, and a failed rescue gives you a copy-paste-ready manual recovery command.
|
|
53
53
|
- **Disk-friendly, self-maintaining**: snapshots use git delta compression and large files are skipped automatically (threshold configurable); periodic lossless `git gc`, session-deletion cleanup, and optional cleanup by cap or retention age — plus a **workspace → session → snapshot** tree manager on the settings page with search and per-level deletion.
|
|
54
54
|
- **Failures speak up and heal** (self-healing 2.1+): failures are classified by root cause (git missing / disk full / permission denied / lock conflict / directory conflict) with actionable guidance (the same fault only bothers you once per 10 minutes; reasons land in the settings card's "Recent errors"); leftover objects are pruned, 3 consecutive failures trigger exponential backoff, concurrent instances yield via heartbeats, and unindexable paths are skipped with a notice instead of failing the whole snapshot (they are neither restored nor deleted on recall).
|
|
@@ -107,7 +107,7 @@ All options can be edited visually in the "**Settings → Plugin Config → Reca
|
|
|
107
107
|
| `maxSnapshotsPerWorkspace` | 500 | Maximum snapshots kept per workspace; oldest pruned beyond the cap. 0 = unlimited |
|
|
108
108
|
| `retentionDays` | 0 | Keep snapshots for this many days; older ones are deleted. 0 = disabled (works independently of the cap) |
|
|
109
109
|
| `baseExcludes` | `.git`, `node_modules/`, `.dsh-recall-snapshots/`, `dsh-recall-snapshots/` | Base exclusion list (gitignore syntax, lower priority than exclude.txt) |
|
|
110
|
-
| `refillDraft` | true | Refill the recalled message text into the input box after a recall |
|
|
110
|
+
| `refillDraft` | true | Refill the recalled message (text and attachments) into the input box after a recall |
|
|
111
111
|
| `snapshotEnabled` | true | Master snapshot switch (off = no new snapshots; existing snapshots remain recallable) |
|
|
112
112
|
| `archiveOriginal` | true | Archive the original session after a recall (off = the original session stays in the session list) |
|
|
113
113
|
|
package/README.md
CHANGED
|
@@ -5,13 +5,12 @@
|
|
|
5
5
|
[](https://www.npmjs.com/package/dsh-recall-plugin)
|
|
6
6
|
[](https://www.npmjs.com/package/dsh-recall-plugin)
|
|
7
7
|

|
|
8
|
-
[](https://github.com/deepseek-ai/deepseek-harness/releases/tag/dsh-v0.1.3-alpha.1)
|
|
8
|
+
[](https://github.com/deepseek-ai/deepseek-harness/releases/tag/dsh-v0.1.5-rc.2)
|
|
10
9
|
---
|
|
11
10
|
在任意一条你发过的消息下方点「↶ 撤回」——**工作区文件和对话历史一起回到那条消息发出之前的状态**。
|
|
12
11
|
---
|
|
13
12
|
|
|
14
|
-
撤回时文件与对话一起回退:工作区先被快照进一个独立的影子 git 仓库,撤回就用它把文件恢复到那条消息发出之前;对话通过 DSH 官方的 `sessions.fork` 切到该消息之前的 turn
|
|
13
|
+
撤回时文件与对话一起回退:工作区先被快照进一个独立的影子 git 仓库,撤回就用它把文件恢复到那条消息发出之前;对话通过 DSH 官方的 `sessions.fork` 切到该消息之前的 turn 边界,原会话归档保留、随时可找回。撤回后,这条消息的文本与附件会自动放回输入框,改完即可重发。快照全程不触碰项目自身的 git,存储默认落在 `$DSH_HOME` 下。最主要的边界:快照只在**消息发送时**创建,插件启用前的历史消息没有快照、不显示撤回按钮。
|
|
15
14
|
|
|
16
15
|
[更新日志](CHANGELOG.md)
|
|
17
16
|
|
|
@@ -34,6 +33,7 @@
|
|
|
34
33
|
| --- | --- |
|
|
35
34
|
|  |  |
|
|
36
35
|
|
|
36
|
+
- 撤回后,这条消息的文本与附件自动放回输入框,改完即可重发(可在设置卡片关闭)
|
|
37
37
|
- 设置页 · 插件配置卡片(配置表单 / 排除表 / 快照管理,保存即热生效)
|
|
38
38
|
|
|
39
39
|

|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
- **文件 + 对话,整段回退**:撤回的不只是聊天记录,agent 改过的文件也一并回到原样;不受项目 `.gitattributes` 转换影响,换行与二进制内容字节级保真(2.1.1+)。
|
|
47
47
|
- **不碰你项目自己的 git,目录保持干净**:快照存在独立的影子 git 仓库里,分支、暂存区、未提交改动统统不受影响;存储默认落在 `$DSH_HOME` 下,与会话的沙箱权限无关(workspace-write / read-only 照常工作),仅当 home 不可写才降级到项目内 `.dsh-recall-snapshots`。
|
|
48
48
|
- **先看清单再动手,可反复后悔**:撤回前展示将变更的文件清单(修改 / 恢复 / 删除),确认后才执行;撤回后还能再撤到更早,被覆盖的文件一直找得回来(默认每工作区保留 500 条)。
|
|
49
|
+
- **撤回完就能重发**(2.3.15+):撤回会把这条消息的文本与附件一起放回输入框——图片、文件原样回来,改完直接发送,不必重新挑一遍附件。
|
|
49
50
|
- **撤回全程有防护**(2.0+,救援 2.1+):agent 运行中拒绝撤回,预览后出现新快照会强制重新预览;执行前自动打「回退前」安全快照,回退失败自动救援,救援失败给出可直接复制执行的手动恢复命令。
|
|
50
51
|
- **磁盘友好、自动维护**:快照走 git delta 增量压缩,大文件自动跳过(阈值可配);定期无损 `git gc`,会话删除联动清理,可按条数与保留天数自动清理;设置页提供**工作区 → 会话 → 快照**三级树形管理,支持搜索与分级删除。
|
|
51
52
|
- **失败不静默、能自愈**(自愈 2.1+):失败按根因分类(git 缺失 / 磁盘满 / 无权限 / 锁冲突 / 目录冲突)给出可行动提示,同类故障 10 分钟只打扰一次,失败原因进设置卡片「最近错误」;自动清理残骸、连续 3 次失败指数退避、多实例按心跳互让;无法索引的路径跳过并告知,不中断整条快照(撤回时也不触碰它们)。
|
|
@@ -109,7 +110,7 @@ dsh plugin --profile web remove dsh-recall-plugin
|
|
|
109
110
|
| `maxSnapshotsPerWorkspace` | 500 | 每个工作区保留的最大快照数,超限自动删除最旧的;0 = 不限制 |
|
|
110
111
|
| `retentionDays` | 0 | 按天数保留快照,超期自动删除;0 = 不启用(与条数上限各自独立生效) |
|
|
111
112
|
| `baseExcludes` | `.git`、`node_modules/`、`.dsh-recall-snapshots/`、`dsh-recall-snapshots/` | 基础排除表(gitignore 语法,优先级低于 exclude.txt) |
|
|
112
|
-
| `refillDraft` | true |
|
|
113
|
+
| `refillDraft` | true | 撤回后把被撤回的消息(文本与附件)回填到输入框 |
|
|
113
114
|
| `snapshotEnabled` | true | 快照总开关(关闭只冻结新建,已有快照仍可撤回) |
|
|
114
115
|
| `archiveOriginal` | true | 撤回后归档原会话(关闭后原会话保留在会话列表中) |
|
|
115
116
|
|
package/lib/client.js
CHANGED
|
@@ -380,6 +380,24 @@ function buildUtil() {
|
|
|
380
380
|
}
|
|
381
381
|
|
|
382
382
|
// src/client/recall-node.ts
|
|
383
|
+
function attachmentRefsFromBlocks(blocks) {
|
|
384
|
+
const refs = [];
|
|
385
|
+
for (const block of blocks) {
|
|
386
|
+
if (!block || block.type !== "image" && block.type !== "file") continue;
|
|
387
|
+
const ref = block.attachment;
|
|
388
|
+
if (!ref || typeof ref.attachmentId !== "string" || ref.attachmentId === "") continue;
|
|
389
|
+
const entry = { attachmentId: ref.attachmentId };
|
|
390
|
+
if (typeof ref.name === "string" && ref.name !== "") entry.name = ref.name;
|
|
391
|
+
refs.push(entry);
|
|
392
|
+
}
|
|
393
|
+
return refs;
|
|
394
|
+
}
|
|
395
|
+
function defaultAttachmentName(mediaType, index) {
|
|
396
|
+
const text = String(mediaType || "");
|
|
397
|
+
const slash = text.indexOf("/");
|
|
398
|
+
const sub = (slash >= 0 ? text.slice(slash + 1) : text).replace(/[^a-z0-9.+-]/gi, "");
|
|
399
|
+
return "attachment-" + String(index + 1) + "." + (sub || "bin");
|
|
400
|
+
}
|
|
383
401
|
var KIND_INFO = {
|
|
384
402
|
modified: { label: "\u4FEE\u6539", cls: "modified" },
|
|
385
403
|
restored: { label: "\u6062\u590D", cls: "restored" },
|
|
@@ -507,31 +525,89 @@ function buildRecallNode(React, util, ctx, sessionsSvc, workspacesSvc) {
|
|
|
507
525
|
}
|
|
508
526
|
return null;
|
|
509
527
|
}
|
|
510
|
-
function fillDraft(targetSessionId, draftText) {
|
|
511
|
-
if (!
|
|
528
|
+
function fillDraft(targetSessionId, draftText, attachmentFiles) {
|
|
529
|
+
if (!targetSessionId || !draftText && attachmentFiles === null) return;
|
|
512
530
|
let attempts = 0;
|
|
531
|
+
let attachStarted = false;
|
|
513
532
|
const attempt = () => {
|
|
533
|
+
let textDone = draftText === "";
|
|
514
534
|
try {
|
|
515
535
|
const conversation = ctx.get("conversation");
|
|
516
536
|
if (conversation && conversation.input && typeof conversation.input.shell === "function") {
|
|
517
537
|
const shell = conversation.input.shell(targetSessionId);
|
|
518
538
|
if (shell) {
|
|
519
|
-
if (
|
|
520
|
-
shell.actions.setDraft
|
|
521
|
-
|
|
539
|
+
if (!textDone) {
|
|
540
|
+
if (shell.actions && typeof shell.actions.setDraft === "function") {
|
|
541
|
+
shell.actions.setDraft(draftText);
|
|
542
|
+
textDone = true;
|
|
543
|
+
} else if (typeof shell.setDraft === "function") {
|
|
544
|
+
shell.setDraft(draftText);
|
|
545
|
+
textDone = true;
|
|
546
|
+
}
|
|
522
547
|
}
|
|
523
|
-
if (
|
|
524
|
-
shell
|
|
525
|
-
return;
|
|
548
|
+
if (!attachStarted && attachmentFiles !== null) {
|
|
549
|
+
attachStarted = startAttachDrafts(conversation, shell, targetSessionId, attachmentFiles);
|
|
526
550
|
}
|
|
527
551
|
}
|
|
528
552
|
}
|
|
529
553
|
} catch (e) {
|
|
530
554
|
}
|
|
531
|
-
|
|
555
|
+
const attachDone = attachmentFiles === null || attachStarted;
|
|
556
|
+
if ((!textDone || !attachDone) && attempts++ < 8) setTimeout(attempt, 150);
|
|
532
557
|
};
|
|
533
558
|
attempt();
|
|
534
559
|
}
|
|
560
|
+
function startAttachDrafts(conversation, shell, sessionId, files) {
|
|
561
|
+
if (typeof conversation.createDrafts !== "function") return false;
|
|
562
|
+
const actions = shell.actions;
|
|
563
|
+
let add = null;
|
|
564
|
+
if (actions && typeof actions.addAttachments === "function") add = (ids) => actions.addAttachments ? actions.addAttachments(ids) : false;
|
|
565
|
+
else if (typeof shell.addAttachments === "function") add = (ids) => shell.addAttachments ? shell.addAttachments(ids) : false;
|
|
566
|
+
if (add === null) return false;
|
|
567
|
+
(async () => {
|
|
568
|
+
let list = [];
|
|
569
|
+
try {
|
|
570
|
+
list = await files;
|
|
571
|
+
} catch (e) {
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
if (!Array.isArray(list) || list.length === 0) return;
|
|
575
|
+
try {
|
|
576
|
+
const drafts = conversation.createDrafts ? conversation.createDrafts(sessionId, list) : [];
|
|
577
|
+
const descriptors = Array.isArray(drafts) ? drafts : [];
|
|
578
|
+
const ids = descriptors.map((draft) => draft && draft.id).filter((id) => typeof id === "string" && id !== "");
|
|
579
|
+
if (ids.length === 0) return;
|
|
580
|
+
const accepted = add(ids);
|
|
581
|
+
if (accepted === false && typeof conversation.releaseDraftAttachments === "function") conversation.releaseDraftAttachments(descriptors);
|
|
582
|
+
} catch (e) {
|
|
583
|
+
}
|
|
584
|
+
})();
|
|
585
|
+
return true;
|
|
586
|
+
}
|
|
587
|
+
function preloadAttachmentFiles(sourceSessionId, refs) {
|
|
588
|
+
return (async () => {
|
|
589
|
+
const sessions = ctx.sessions;
|
|
590
|
+
const binding = sessions && typeof sessions.binding === "function" ? sessions.binding(sourceSessionId) : void 0;
|
|
591
|
+
const session = binding && binding.session;
|
|
592
|
+
if (!session || typeof session.readAttachment !== "function") return [];
|
|
593
|
+
const out = [];
|
|
594
|
+
for (const ref of refs) {
|
|
595
|
+
try {
|
|
596
|
+
const result = await session.readAttachment(ref.attachmentId);
|
|
597
|
+
if (!result || result.ok !== true || !result.value || result.value.data === void 0 || result.value.data === null) continue;
|
|
598
|
+
const raw = result.value.data;
|
|
599
|
+
const bytes = raw instanceof Uint8Array ? raw : Uint8Array.from(raw);
|
|
600
|
+
const meta = result.value.attachment;
|
|
601
|
+
const mediaType = meta && typeof meta.mediaType === "string" && meta.mediaType !== "" ? meta.mediaType : "application/octet-stream";
|
|
602
|
+
const name = ref.name || (meta && typeof meta.name === "string" && meta.name !== "" ? meta.name : defaultAttachmentName(mediaType, out.length));
|
|
603
|
+
const buffer = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
|
|
604
|
+
out.push(new File([buffer], name, { type: mediaType }));
|
|
605
|
+
} catch (e) {
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
return out;
|
|
609
|
+
})();
|
|
610
|
+
}
|
|
535
611
|
function UserRecallNode(props) {
|
|
536
612
|
const node = props && props.node;
|
|
537
613
|
const renderMessageImages = props && props.renderMessageImages;
|
|
@@ -542,6 +618,7 @@ function buildRecallNode(React, util, ctx, sessionsSvc, workspacesSvc) {
|
|
|
542
618
|
const text = blocks.filter((b) => b && b.type === "text" && typeof b.text === "string").map((b) => b.text).join("");
|
|
543
619
|
const imageBlocks = blocks.filter((b) => b && b.type === "image" && b.attachment).map((b) => ({ attachment: b.attachment }));
|
|
544
620
|
const rest = blocks.filter((b) => !b || !(b.type === "text" && typeof b.text === "string") && !(b.type === "image" && b.attachment));
|
|
621
|
+
const attachmentRefs = attachmentRefsFromBlocks(blocks);
|
|
545
622
|
const [copied, setCopied] = React.useState(false);
|
|
546
623
|
const [hasSnapshot, setHasSnapshot] = React.useState(false);
|
|
547
624
|
const [recall, setRecall] = React.useState({ stage: "idle" });
|
|
@@ -625,6 +702,7 @@ function buildRecallNode(React, util, ctx, sessionsSvc, workspacesSvc) {
|
|
|
625
702
|
const changes = recall.changes || [];
|
|
626
703
|
const previewCut = typeof recall.cutSeq === "number" ? recall.cutSeq : null;
|
|
627
704
|
const previewTotal = typeof recall.total === "number" ? recall.total : changes.length;
|
|
705
|
+
const attachmentFiles = pluginConfig.refillDraft && attachmentRefs.length > 0 && sessionId ? preloadAttachmentFiles(sessionId, attachmentRefs) : null;
|
|
628
706
|
setRecall({ stage: "executing", changes });
|
|
629
707
|
api("execute", { messageId, sessionId, previewTotal, previewTreeId: recall.treeId || void 0, previewAt: Date.now() }).then(async (res) => {
|
|
630
708
|
if (!res || !res.ok) {
|
|
@@ -676,7 +754,7 @@ function buildRecallNode(React, util, ctx, sessionsSvc, workspacesSvc) {
|
|
|
676
754
|
chatError = String(error);
|
|
677
755
|
}
|
|
678
756
|
}
|
|
679
|
-
if (pluginConfig.refillDraft) fillDraft(fillTarget, text);
|
|
757
|
+
if (pluginConfig.refillDraft) fillDraft(fillTarget, text, attachmentFiles);
|
|
680
758
|
setHasSnapshot(false);
|
|
681
759
|
setRecall({ stage: "done", count: typeof res.count === "number" ? res.count : changes.length, chatReverted, chatError });
|
|
682
760
|
}).catch((error) => {
|
package/lib/config.js
CHANGED
|
@@ -9,7 +9,7 @@ const Config = Schema.object({
|
|
|
9
9
|
// HOME 时(容器 root=/root 等)它落在工作区内,漏排除会让 git add -A
|
|
10
10
|
// 把影子仓库自己吞进去、快照全部失败(issue #6)
|
|
11
11
|
baseExcludes: Schema.array(Schema.string()).default([".git", "node_modules/", ".dsh-recall-snapshots/", "dsh-recall-snapshots/"]).description("\u57FA\u7840\u6392\u9664\u8868\uFF08gitignore \u8BED\u6CD5\uFF0C\u4F18\u5148\u7EA7\u4F4E\u4E8E exclude.txt\uFF09"),
|
|
12
|
-
refillDraft: Schema.boolean().default(true).description("\u64A4\u56DE\u540E\u628A\u88AB\u64A4\u56DE\u7684\u6D88\u606F\u6587\u672C\u56DE\u586B\u5230\u8F93\u5165\u6846"),
|
|
12
|
+
refillDraft: Schema.boolean().default(true).description("\u64A4\u56DE\u540E\u628A\u88AB\u64A4\u56DE\u7684\u6D88\u606F\uFF08\u6587\u672C\u4E0E\u9644\u4EF6\uFF09\u56DE\u586B\u5230\u8F93\u5165\u6846"),
|
|
13
13
|
snapshotEnabled: Schema.boolean().default(true).description("\u542F\u7528\u6D88\u606F\u5FEB\u7167\uFF08\u5173\u95ED\u540E\u4E0D\u518D\u65B0\u5EFA\uFF0C\u5DF2\u6709\u5FEB\u7167\u4ECD\u53EF\u64A4\u56DE\uFF09"),
|
|
14
14
|
archiveOriginal: Schema.boolean().default(true).description("\u64A4\u56DE\u540E\u5F52\u6863\u539F\u4F1A\u8BDD\uFF08\u5173\u95ED\u540E\u539F\u4F1A\u8BDD\u4FDD\u7559\u5728\u5217\u8868\u4E2D\uFF09"),
|
|
15
15
|
retentionDays: Schema.number().default(0).description("\u6309\u5929\u6570\u4FDD\u7559\u5FEB\u7167\uFF0C\u8D85\u671F\u81EA\u52A8\u5220\u9664\uFF1B0 \u8868\u793A\u4E0D\u542F\u7528")
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-recall-plugin",
|
|
3
|
-
"version": "2.3.
|
|
4
|
-
"description": "DSH
|
|
3
|
+
"version": "2.3.16",
|
|
4
|
+
"description": "在 DSH 中撤回自己发过的消息:工作区文件与对话历史一起回到那条消息发出之前,消息的文本与附件自动放回输入框,改完即可重发。文件走独立影子 git 快照(不碰项目自身的 git),对话走官方 sessions.fork,原会话归档可找回。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|