dsh-vscode-mode 0.21.0 → 0.21.1
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 +246 -16
- package/lib/client.js.map +2 -2
- package/lib/index.js +210 -1
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
- package/src/client/missingReview.ts +40 -0
- package/src/client/ui/EditorView.ts +118 -14
- package/src/client/ui/SidecarDiffBar.tsx +4 -2
- package/src/missingReview.ts +127 -0
- package/src/rpc.ts +32 -6
- package/src/shared/rpc.ts +5 -1
- package/src/shared/types.ts +9 -0
package/README.md
CHANGED
|
@@ -477,18 +477,18 @@ DSH 每次启动监听随机端口,`http://127.0.0.1:<port>` 就是浏览器 o
|
|
|
477
477
|
|
|
478
478
|
官方 `dsh plugin` 方式,三选一。下面以 `web` profile 为例;Desktop 或其他命名
|
|
479
479
|
profile 请替换为实际目标,不要把示例目录当成当前运行 profile。升级前可阅读
|
|
480
|
-
**v0.21.0** 新增 XLSX 基础编辑与浏览器导出副本,原件不自动写回,高级应用通过官方 Host 打开;官方差异定位统一 BOM 与 LF/CRLF/混合行尾口径,并区分内容缺失和多处命中。定位修复不扩展 CRLF patch Undo 能力,目标官方记录 ↑/↓ 的真实点击验收仍保留缺口。保留 **v0.20.5** 跨 DSH 实例只读互通——桌面端与 Web 端各自运行独立宿主时,官方审查列表/详情与工作区只读接口改按持久化会话头的 cwd 解析,另一实例创建的会话也能只读打开官方差异栏,写入类接口仍要求本端活跃会话。保留 **v0.20.4** 统一两套差异栏外观——非官方记录栏角标由内部术语「侧车记录」改为「历史改动」,悬停说明 Keep 只标记已看过、不改写磁盘,Undo 逐项校验后写回,两者都不影响官方审查;官方元数据不可用时给出可读原因与重试按钮,不再静默降级;「会话没在当前端激活」由红色告警改为中性说明。保留 v0.20.3 修复官方差异全部无法定位时差异栏无提示、上下箭头静默禁用(显示「无可跳转」与失效原因,Keep 说明只标记已采纳、不改写磁盘,会话缺失等宿主错误改为可读提示)、v0.20.2 的 MCP 状态告警收敛与原生确认弹窗,以及 v0.20.1 的文件内差异展示、块级/文件级安全审查和跨分页批量操作。升级后重启 DSH 并刷新页面;持久化与回退边界见 [0.20.0 发布说明](docs/release-0.20.0.md);从 0.14.2 或更旧版本升级还须阅读
|
|
480
|
+
**v0.21.1** 修复缺失历史文件:按完整快照显示整文件删除,Keep 保留删除、Undo 安全恢复快照,预览只读且拒绝覆盖重新出现的文件;真实 GUI 验收缺口已明确保留,见 [0.21.1 发布说明](docs/release-0.21.1.md)。保留 **v0.21.0** 新增 XLSX 基础编辑与浏览器导出副本,原件不自动写回,高级应用通过官方 Host 打开;官方差异定位统一 BOM 与 LF/CRLF/混合行尾口径,并区分内容缺失和多处命中。定位修复不扩展 CRLF patch Undo 能力,目标官方记录 ↑/↓ 的真实点击验收仍保留缺口。保留 **v0.20.5** 跨 DSH 实例只读互通——桌面端与 Web 端各自运行独立宿主时,官方审查列表/详情与工作区只读接口改按持久化会话头的 cwd 解析,另一实例创建的会话也能只读打开官方差异栏,写入类接口仍要求本端活跃会话。保留 **v0.20.4** 统一两套差异栏外观——非官方记录栏角标由内部术语「侧车记录」改为「历史改动」,悬停说明 Keep 只标记已看过、不改写磁盘,Undo 逐项校验后写回,两者都不影响官方审查;官方元数据不可用时给出可读原因与重试按钮,不再静默降级;「会话没在当前端激活」由红色告警改为中性说明。保留 v0.20.3 修复官方差异全部无法定位时差异栏无提示、上下箭头静默禁用(显示「无可跳转」与失效原因,Keep 说明只标记已采纳、不改写磁盘,会话缺失等宿主错误改为可读提示)、v0.20.2 的 MCP 状态告警收敛与原生确认弹窗,以及 v0.20.1 的文件内差异展示、块级/文件级安全审查和跨分页批量操作。升级后重启 DSH 并刷新页面;持久化与回退边界见 [0.20.0 发布说明](docs/release-0.20.0.md);从 0.14.2 或更旧版本升级还须阅读
|
|
481
481
|
[0.14.3 数据迁移与回退说明](docs/release-0.14.3.md)。
|
|
482
482
|
|
|
483
483
|
```bash
|
|
484
484
|
# ① Git 安装(clone + prepare 构建;推荐打固定 tag)
|
|
485
|
-
dsh plugin --profile web add github:Lenonss/DSH_VsCodeMode#v0.21.
|
|
485
|
+
dsh plugin --profile web add github:Lenonss/DSH_VsCodeMode#v0.21.1
|
|
486
486
|
|
|
487
487
|
# ② npm 注册表(发布到 npm 后)
|
|
488
|
-
dsh plugin --profile web add dsh-vscode-mode@0.21.
|
|
488
|
+
dsh plugin --profile web add dsh-vscode-mode@0.21.1
|
|
489
489
|
|
|
490
490
|
# ③ GitHub Release tgz 直装(Release asset 可用后)
|
|
491
|
-
dsh plugin --profile web add https://github.com/Lenonss/DSH_VsCodeMode/releases/download/v0.21.
|
|
491
|
+
dsh plugin --profile web add https://github.com/Lenonss/DSH_VsCodeMode/releases/download/v0.21.1/dsh-vscode-mode-0.21.1.tgz
|
|
492
492
|
```
|
|
493
493
|
|
|
494
494
|
> **DSH 版本政策(0.17.0 起)**:六项 DSH peer 仍统一声明为 `*`,另以
|
|
@@ -829,6 +829,7 @@ Keep All / Undo All 却是亮的。修复:单文件 Keep / Undo 覆盖冲突
|
|
|
829
829
|
完整变更见 [GitHub Releases](https://github.com/Lenonss/DSH_VsCodeMode/releases)。
|
|
830
830
|
近期关键版本:
|
|
831
831
|
|
|
832
|
+
- **v0.21.1**:缺失历史文件读取完整快照并整文件显示删除行;Keep 保留删除,Undo 安全恢复当前展示快照,不覆盖重新出现的文件。删除预览只读,单文件和批量操作统一处理,记录变化或证据不足时停止。真实 GUI 验收缺口已获用户接受;发布不自动部署,升级后重启 DSH 并刷新页面。见 [发布说明](docs/release-0.21.1.md)。
|
|
832
833
|
- **v0.21.0**:新增 XLSX 基础编辑、多工作表与浏览器导出副本,原件不自动写回;不支持结构只读预览,高级应用经官方 Host 打开原件。编辑状态仅在当前页面内保留,不承诺刷新或崩溃恢复。官方差异定位统一 BOM 与 LF/CRLF/混合行尾口径,区分内容缺失与多处命中,保持原始字节及写回校验边界;不扩展 CRLF patch Undo 能力,目标官方记录 ↑/↓ 的真实点击仍未验收。升级后重启 DSH 并刷新页面;发布不自动部署当前实例。
|
|
833
834
|
- **v0.20.5**:**跨实例官方审查数据只读互通**——桌面端与 Web 端各自运行独立 DSH 宿主时,会话只存在于创建它的宿主内存里,插件原先一律用本进程的活跃会话解析工作区,另一端打开官方差异栏会拿到「会话不存在」并退化成历史改动栏。现在官方审查列表/详情与工作区只读接口(文件读取、原始字节、分页文本、记录桶、归档列表、目录列表、界面状态镜像)改为按持久化会话头的 cwd 解析:只要会话在共享的 `~/.dsh/sessions` 下留有会话头,其他实例即可只读访问它的官方审查数据;写入类接口(保存、回滚、采纳/拒绝、批量决策)仍要求本端活跃会话,避免两个宿主并发写同一工作区的审查库。已知限制:会话内 `cd` 过的记录只能按创建时的 cwd 冷读;桌面端本版本未重新部署,反向仍不可用。升级后重启 DSH 并刷新页面。
|
|
834
835
|
- **v0.20.4**:**两套差异栏不再互相冒充,内部术语退出界面**——插件本来并存官方审查栏与另一条历史记录栏(旧机制把每次改动留痕写进工作区 `.dsh-edit-review.json`),过去两者外观相同、无任何标识,容易被误认为插件未升级。现在非官方栏使用与官方栏同一套版式,但角标改为「历史改动」并在悬浮说明里讲清:这些改动没有进入官方审查列表,Keep 只标记看过、不改文件,Undo 会校验后写回,两者都不影响官方审查;设置页的「侧车摘要」一并对齐为日常说法。官方元数据通道失败(`edrv.review.list` 报错,如 `会话不存在`,或宿主未提供官方文件导航)时,在栏上方给出可读原因与重试按钮,不再静默降级;其中「会话没在当前端激活」由红色告警改为中性说明并存原始详情,真正的磁盘/回滚冲突错误仍保持红色。仅调整展示层,未改动数据库结构、决策语义与回退校验。
|
package/lib/client.js
CHANGED
|
@@ -377810,6 +377810,44 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
377810
377810
|
return regions;
|
|
377811
377811
|
}
|
|
377812
377812
|
//#endregion
|
|
377813
|
+
//#region src/client/missingReview.ts
|
|
377814
|
+
/** @public @author ddj 2026年10月28号 @param review Frozen complete snapshot. @returns One whole-file deletion, including empty files; no invented current lines. */
|
|
377815
|
+
function missingRegion(review) {
|
|
377816
|
+
return {
|
|
377817
|
+
callId: review.callIds[0],
|
|
377818
|
+
idx: 0,
|
|
377819
|
+
start: 1,
|
|
377820
|
+
end: 1,
|
|
377821
|
+
oldStart: 1,
|
|
377822
|
+
oldLines: splitLines(review.content.replace(/\r\n/g, "\n")),
|
|
377823
|
+
newLines: [],
|
|
377824
|
+
whole: true,
|
|
377825
|
+
status: "pending",
|
|
377826
|
+
create: false,
|
|
377827
|
+
superseded: false,
|
|
377828
|
+
sourceKind: "missing"
|
|
377829
|
+
};
|
|
377830
|
+
}
|
|
377831
|
+
/** @public @author ddj 2026年10月28号 @param paths Batch paths. @param api Guarded Host access. @returns Missing paths handled once; a partial failure stops before legacy hunk writes. @throws Missing evidence, changed lifecycle or Host decision failure. */
|
|
377832
|
+
async function missingBatch(paths, api) {
|
|
377833
|
+
const candidates = [];
|
|
377834
|
+
for (const path of new Set(paths)) {
|
|
377835
|
+
api.guard();
|
|
377836
|
+
const result = await api.query(path);
|
|
377837
|
+
if (!result.ok) throw new Error(result.error);
|
|
377838
|
+
if (result.review) candidates.push(result.review);
|
|
377839
|
+
}
|
|
377840
|
+
const completed = /* @__PURE__ */ new Set();
|
|
377841
|
+
for (const review of candidates) {
|
|
377842
|
+
api.guard();
|
|
377843
|
+
const result = await api.decide(review, api.operation(review));
|
|
377844
|
+
if (!result.ok) throw new Error(`已处理 ${completed.size} 个删除文件,其余未处理。${result.error}`);
|
|
377845
|
+
completed.add(review.path);
|
|
377846
|
+
api.committed(review, result.callIds);
|
|
377847
|
+
}
|
|
377848
|
+
return completed;
|
|
377849
|
+
}
|
|
377850
|
+
//#endregion
|
|
377813
377851
|
//#region src/client/editorModelState.ts
|
|
377814
377852
|
/** Monaco 编辑器实例选择器(限定在插件编辑器行内,排除官方预览等其它 Monaco)。 */
|
|
377815
377853
|
const EDITOR_MODEL_SELECTOR = ".edrv-editor-row .monaco-editor";
|
|
@@ -382728,7 +382766,10 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
382728
382766
|
onUndoAll: props.onUndoAllFiles,
|
|
382729
382767
|
keepTitle: "把这批历史改动全部标记为已看过(只改记录,不动磁盘文件)",
|
|
382730
382768
|
undoTitle: "逐项撤销这些历史改动;缺少证据或遇到冲突即停止"
|
|
382731
|
-
}),
|
|
382769
|
+
}), props.missingDeletion ? /* @__PURE__ */ react$1.default.createElement("div", {
|
|
382770
|
+
className: "edrv-review-notice",
|
|
382771
|
+
role: "status"
|
|
382772
|
+
}, "文件已删除 · 展示最后记录快照。Keep 保留删除;Undo 恢复展示的完整快照。") : null, busy ? /* @__PURE__ */ react$1.default.createElement("div", {
|
|
382732
382773
|
className: "edrv-review-notice",
|
|
382733
382774
|
role: "status"
|
|
382734
382775
|
}, "正在处理历史改动…") : null, down ? /* @__PURE__ */ react$1.default.createElement("div", {
|
|
@@ -382766,7 +382807,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
382766
382807
|
icon: barIcon("undo"),
|
|
382767
382808
|
onClick: props.onUndoFile,
|
|
382768
382809
|
disabled: !canDecide,
|
|
382769
|
-
title: SIDECAR_UNDO_TITLE
|
|
382810
|
+
title: props.missingDeletion ? "恢复展示的完整历史快照(不会覆盖重新出现的文件)" : SIDECAR_UNDO_TITLE
|
|
382770
382811
|
}, "Undo"), /* @__PURE__ */ react$1.default.createElement(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
382771
382812
|
size: "sm",
|
|
382772
382813
|
variant: "primary",
|
|
@@ -382774,7 +382815,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
382774
382815
|
icon: barIcon("check"),
|
|
382775
382816
|
onClick: props.onAcceptFile,
|
|
382776
382817
|
disabled: !canDecide,
|
|
382777
|
-
title: SIDECAR_KEEP_TITLE
|
|
382818
|
+
title: props.missingDeletion ? "保持文件删除并结清覆盖的待审历史记录,不写文件" : SIDECAR_KEEP_TITLE
|
|
382778
382819
|
}, "Keep"), /* @__PURE__ */ react$1.default.createElement(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
382779
382820
|
size: "sm",
|
|
382780
382821
|
variant: "ghost",
|
|
@@ -393389,6 +393430,9 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
393389
393430
|
const [dirtyMap, setDirtyMap] = react$1.default.useState({});
|
|
393390
393431
|
const [content, setContent] = react$1.default.useState(null);
|
|
393391
393432
|
const [contentPath, setContentPath] = react$1.default.useState(null);
|
|
393433
|
+
const [missingPreview, setMissingPreview] = react$1.default.useState(null);
|
|
393434
|
+
const missingRef = react$1.default.useRef(/* @__PURE__ */ new Map());
|
|
393435
|
+
const missingNow = missingPreview?.path === active && missingPreview?.sessionId === sessionId ? missingPreview : null;
|
|
393392
393436
|
const [receiptLoad, setReceiptLoad] = react$1.default.useState(null);
|
|
393393
393437
|
const [imageSrc, setImageSrc] = react$1.default.useState(null);
|
|
393394
393438
|
const [imgSize, setImgSize] = react$1.default.useState(null);
|
|
@@ -393751,7 +393795,10 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
393751
393795
|
const regions = react$1.default.useMemo(() => {
|
|
393752
393796
|
const trace = isDebug() && contentReady && currentRecords.length > 0;
|
|
393753
393797
|
const start = trace ? performance.now() : 0;
|
|
393754
|
-
|
|
393798
|
+
let next;
|
|
393799
|
+
if (officialDetail) next = reviewRegions(officialDetail.diff, officialDetail.item.id, officialDetail.blocks ?? [], contentReady ? content : null);
|
|
393800
|
+
else if (missingNow && contentReady) next = missingNow.resolved ? [] : [missingRegion(missingNow)];
|
|
393801
|
+
else next = diffRegions(currentRecords, contentReady ? content : null).filter((r) => !r.superseded);
|
|
393755
393802
|
if (trace) try {
|
|
393756
393803
|
dbg(sessionId, `[DEBUG diffRegions] records=${currentRecords.length} bytes=${content.length} regions=${next.length} ms=${(performance.now() - start).toFixed(1)}`);
|
|
393757
393804
|
} catch (e) {}
|
|
@@ -393761,7 +393808,16 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
393761
393808
|
content,
|
|
393762
393809
|
contentPath,
|
|
393763
393810
|
active,
|
|
393764
|
-
officialDetail
|
|
393811
|
+
officialDetail,
|
|
393812
|
+
missingNow
|
|
393813
|
+
]);
|
|
393814
|
+
react$1.default.useEffect(() => {
|
|
393815
|
+
editorRef.current?.updateOptions({ readOnly: !!missingNow });
|
|
393816
|
+
}, [
|
|
393817
|
+
missingNow,
|
|
393818
|
+
active,
|
|
393819
|
+
content,
|
|
393820
|
+
monaco
|
|
393765
393821
|
]);
|
|
393766
393822
|
const pendingRegions = react$1.default.useMemo(() => regions.filter((r) => r.status === ST.PENDING && !r.stale), [regions]);
|
|
393767
393823
|
const staleRegions = react$1.default.useMemo(() => regions.filter((r) => r.status === ST.PENDING && r.stale), [regions]);
|
|
@@ -394236,7 +394292,13 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
394236
394292
|
/** @author ddj 2026年09月28号 @param res Disk content for a still-clean cached model. */
|
|
394237
394293
|
const accept = (res) => {
|
|
394238
394294
|
if (!loadCurrent(path, sequence) || dirtyRef.current[path] || model.getValue() !== before) return;
|
|
394295
|
+
if (res?.code === "file-missing") {
|
|
394296
|
+
loadMissing(path, sid, sequence);
|
|
394297
|
+
return;
|
|
394298
|
+
}
|
|
394239
394299
|
if (!res?.ok) return;
|
|
394300
|
+
missingRef.current.delete(path);
|
|
394301
|
+
setMissingPreview(null);
|
|
394240
394302
|
mark(res.version);
|
|
394241
394303
|
if (res.content === before) return;
|
|
394242
394304
|
saveViewState(path);
|
|
@@ -394259,6 +394321,48 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
394259
394321
|
* @param force 强制走 RPC(reloadFile 用,跳过 model 复用)
|
|
394260
394322
|
* @param version 已知磁盘版本(缺省走 RPC 返回值)
|
|
394261
394323
|
*/
|
|
394324
|
+
/** @private @author ddj 2026年10月28号 @param path Missing text file. @param sid Owning session. @param seq Loader generation. @sideEffects Loads deletion evidence without creating or saving the file. */
|
|
394325
|
+
async function loadMissing(path, sid, seq) {
|
|
394326
|
+
try {
|
|
394327
|
+
const result = await rpc("edrv.missingReview", {
|
|
394328
|
+
sessionId: sid,
|
|
394329
|
+
path
|
|
394330
|
+
});
|
|
394331
|
+
if (!loadCurrent(path, seq)) return;
|
|
394332
|
+
if (!result.ok) {
|
|
394333
|
+
failLoad(path, sid, seq, result.error);
|
|
394334
|
+
return;
|
|
394335
|
+
}
|
|
394336
|
+
if (!result.review) {
|
|
394337
|
+
loadContent(path, sid, true);
|
|
394338
|
+
return;
|
|
394339
|
+
}
|
|
394340
|
+
if (dirtyRef.current[path] || savingRef.current.has(path)) {
|
|
394341
|
+
failLoad(path, sid, seq, "文件已删除,但有未保存编辑;请先处理本地缓冲");
|
|
394342
|
+
return;
|
|
394343
|
+
}
|
|
394344
|
+
const preview = {
|
|
394345
|
+
...result.review,
|
|
394346
|
+
sessionId: sid,
|
|
394347
|
+
keepId: crypto.randomUUID(),
|
|
394348
|
+
undoId: crypto.randomUUID()
|
|
394349
|
+
};
|
|
394350
|
+
missingRef.current.set(path, preview);
|
|
394351
|
+
setMissingPreview(preview);
|
|
394352
|
+
setContent("");
|
|
394353
|
+
setContentPath(path);
|
|
394354
|
+
setLoadError(null);
|
|
394355
|
+
setError(null);
|
|
394356
|
+
stampLoad(path, sid, seq);
|
|
394357
|
+
setLoadStage({
|
|
394358
|
+
progress: 100,
|
|
394359
|
+
message: "文件已删除 · 展示最后记录快照"
|
|
394360
|
+
});
|
|
394361
|
+
setStatus("文件已删除 · 展示最后记录快照(只读)");
|
|
394362
|
+
} catch (cause) {
|
|
394363
|
+
if (loadCurrent(path, seq)) failLoad(path, sid, seq, String(cause));
|
|
394364
|
+
}
|
|
394365
|
+
}
|
|
394262
394366
|
const loadContent = (path, sid, force, version) => {
|
|
394263
394367
|
const seq = ++loadSeqRef.current;
|
|
394264
394368
|
setReceiptLoad({
|
|
@@ -394319,7 +394423,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
394319
394423
|
loadPdf(path, sid, seq, force === true, version);
|
|
394320
394424
|
return;
|
|
394321
394425
|
}
|
|
394322
|
-
const cachedModel = force ? null : modelsRef.current.get(path);
|
|
394426
|
+
const cachedModel = force || missingRef.current.has(path) ? null : modelsRef.current.get(path);
|
|
394323
394427
|
if (cachedModel) {
|
|
394324
394428
|
setContent(cachedModel.getValue());
|
|
394325
394429
|
setContentPath(path);
|
|
@@ -394346,6 +394450,8 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
394346
394450
|
} catch (e) {}
|
|
394347
394451
|
if (!loadCurrent(path, seq)) return;
|
|
394348
394452
|
if (res && res.ok) {
|
|
394453
|
+
missingRef.current.delete(path);
|
|
394454
|
+
setMissingPreview(null);
|
|
394349
394455
|
mark(res.version, true);
|
|
394350
394456
|
setContent(res.content);
|
|
394351
394457
|
setContentPath(path);
|
|
@@ -394356,6 +394462,10 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
394356
394462
|
}));
|
|
394357
394463
|
setStatus("已加载");
|
|
394358
394464
|
} else {
|
|
394465
|
+
if (res?.code === "file-missing") {
|
|
394466
|
+
loadMissing(path, sid, seq);
|
|
394467
|
+
return;
|
|
394468
|
+
}
|
|
394359
394469
|
if (res?.code === "file-too-large") setLargeCandidate(JSON.stringify([
|
|
394360
394470
|
scope,
|
|
394361
394471
|
sid,
|
|
@@ -394606,6 +394716,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
394606
394716
|
});
|
|
394607
394717
|
return;
|
|
394608
394718
|
}
|
|
394719
|
+
if (change.kind === "deleted" && change.path === activeRef.current && !dirtyRef.current[change.path] && !savingRef.current.has(change.path)) loadContent(change.path, sessionId, true);
|
|
394609
394720
|
const kind = change.kind === "deleted" ? "deleted" : "conflict";
|
|
394610
394721
|
markDiskFlag(readSync(scope, change.path) ?? {
|
|
394611
394722
|
path: change.path,
|
|
@@ -395591,6 +395702,10 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
395591
395702
|
/** @private @author ddj 2026年10月14号 @param path Canonical path. @param manual Explicit save. @returns Guarded save, never another pane's content. */
|
|
395592
395703
|
function saveDocument(path, manual) {
|
|
395593
395704
|
if (isExcelPath(path)) return Promise.resolve({ ok: false });
|
|
395705
|
+
if (missingRef.current.has(path)) {
|
|
395706
|
+
setStatus("删除预览只读;请使用 Keep / Undo");
|
|
395707
|
+
return Promise.resolve({ ok: false });
|
|
395708
|
+
}
|
|
395594
395709
|
const model = modelsRef.current.get(path);
|
|
395595
395710
|
if (!model) return Promise.resolve({ ok: false });
|
|
395596
395711
|
const store = documents();
|
|
@@ -395662,7 +395777,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
395662
395777
|
const ed = editorRef.current;
|
|
395663
395778
|
const model = ed?.getModel();
|
|
395664
395779
|
const path = [...modelsRef.current].find(([, item]) => item === model)?.[0];
|
|
395665
|
-
if (!ed || !path) return;
|
|
395780
|
+
if (!ed || !path || missingRef.current.has(path)) return;
|
|
395666
395781
|
setDirtyMap((d) => Object.assign({}, d, { [path]: true }));
|
|
395667
395782
|
touchTab(path);
|
|
395668
395783
|
setStatus("编辑中…");
|
|
@@ -395796,6 +395911,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
395796
395911
|
const side = layoutRef.current === "side";
|
|
395797
395912
|
const ed = m.editor.create(node, {
|
|
395798
395913
|
value: "",
|
|
395914
|
+
readOnly: missingRef.current.has(activeRef.current),
|
|
395799
395915
|
language: "plaintext",
|
|
395800
395916
|
theme: themeNameOf(),
|
|
395801
395917
|
fontFamily: "var(--ds-font-family-code, ui-monospace, monospace)",
|
|
@@ -396443,6 +396559,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
396443
396559
|
* @returns Promise<boolean> 是否成功
|
|
396444
396560
|
*/
|
|
396445
396561
|
const actHunk = (region, reject, silent) => {
|
|
396562
|
+
if (region.sourceKind === "missing") return decideMissing(reject);
|
|
396446
396563
|
if (region.sourceKind === "official") return decideOfficial(reject, region.id);
|
|
396447
396564
|
const method = reject ? "edrv.reject" : "edrv.accept";
|
|
396448
396565
|
const trace = isDebug();
|
|
@@ -396612,7 +396729,57 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
396612
396729
|
batchBusyRef.current = false;
|
|
396613
396730
|
}
|
|
396614
396731
|
}
|
|
396732
|
+
/** @private @author ddj 2026年10月28号 @param reject Restore the shown snapshot instead of keeping absence. @returns Safe whole-file decision, never a hunk reversal. */
|
|
396733
|
+
async function decideMissing(reject) {
|
|
396734
|
+
if (batchBusyRef.current || !missingNow || missingNow.resolved) return false;
|
|
396735
|
+
const preview = missingNow;
|
|
396736
|
+
const lifetime = reviewLifeRef.current;
|
|
396737
|
+
batchBusyRef.current = true;
|
|
396738
|
+
setReviewBatchBusy(true);
|
|
396739
|
+
try {
|
|
396740
|
+
guardReviewAll(reject, lifetime);
|
|
396741
|
+
const result = await rpc("edrv.missingDecide", {
|
|
396742
|
+
sessionId,
|
|
396743
|
+
token: preview.token,
|
|
396744
|
+
operationId: reject ? preview.undoId : preview.keepId,
|
|
396745
|
+
undo: reject
|
|
396746
|
+
});
|
|
396747
|
+
if (!lifetime?.live) return false;
|
|
396748
|
+
if (!result.ok) {
|
|
396749
|
+
setError(result.error);
|
|
396750
|
+
return false;
|
|
396751
|
+
}
|
|
396752
|
+
setRecords((previous) => Object.fromEntries(Object.entries(previous).filter(([id]) => !result.callIds.includes(id))));
|
|
396753
|
+
missingRef.current.set(preview.path, {
|
|
396754
|
+
...preview,
|
|
396755
|
+
resolved: true
|
|
396756
|
+
});
|
|
396757
|
+
if (activeRef.current === preview.path) {
|
|
396758
|
+
if (reject) loadContent(preview.path, sessionId, true);
|
|
396759
|
+
else setMissingPreview({
|
|
396760
|
+
...preview,
|
|
396761
|
+
resolved: true
|
|
396762
|
+
});
|
|
396763
|
+
}
|
|
396764
|
+
refreshRecords();
|
|
396765
|
+
emitRefresh({
|
|
396766
|
+
scope,
|
|
396767
|
+
paths: [preview.path],
|
|
396768
|
+
kind: "structure"
|
|
396769
|
+
});
|
|
396770
|
+
setStatus(reject ? "已恢复展示的完整历史快照" : "已保留文件删除");
|
|
396771
|
+
setError(null);
|
|
396772
|
+
return true;
|
|
396773
|
+
} catch (cause) {
|
|
396774
|
+
if (lifetime?.live) setError(String(cause));
|
|
396775
|
+
return false;
|
|
396776
|
+
} finally {
|
|
396777
|
+
batchBusyRef.current = false;
|
|
396778
|
+
if (lifetime?.live) setReviewBatchBusy(false);
|
|
396779
|
+
}
|
|
396780
|
+
}
|
|
396615
396781
|
const acceptFile = () => {
|
|
396782
|
+
if (missingNow && !officialDetail) return decideMissing(false);
|
|
396616
396783
|
if (officialDetail) return decideOfficial(false);
|
|
396617
396784
|
if (batchBusyRef.current || !decideRegions.length) return;
|
|
396618
396785
|
batchBusyRef.current = true;
|
|
@@ -396631,6 +396798,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
396631
396798
|
});
|
|
396632
396799
|
};
|
|
396633
396800
|
const undoFile = () => {
|
|
396801
|
+
if (missingNow && !officialDetail) return decideMissing(true);
|
|
396634
396802
|
if (officialDetail) return decideOfficial(true);
|
|
396635
396803
|
if (batchBusyRef.current || !decideRegions.length) return;
|
|
396636
396804
|
batchBusyRef.current = true;
|
|
@@ -396668,24 +396836,85 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
396668
396836
|
* @author ddj 2026年08月20号
|
|
396669
396837
|
* @param reject true=全部不采纳(回滚),false=全部采纳
|
|
396670
396838
|
*/
|
|
396671
|
-
const actAllPending = (reject) => {
|
|
396839
|
+
const actAllPending = async (reject) => {
|
|
396672
396840
|
if (batchBusyRef.current || !allPending.length) return;
|
|
396841
|
+
const lifetime = reviewLifeRef.current;
|
|
396673
396842
|
batchBusyRef.current = true;
|
|
396674
396843
|
const list = reject ? [...allPending].sort((a, b) => a.at < b.at ? 1 : a.at > b.at ? -1 : b.idx - a.idx) : allPending;
|
|
396675
396844
|
const paths = [...new Set(list.map((r) => records[r.callId]?.path).filter(Boolean))];
|
|
396676
|
-
|
|
396677
|
-
|
|
396678
|
-
|
|
396845
|
+
try {
|
|
396846
|
+
const handled = await missingBatch(paths, {
|
|
396847
|
+
query: async (path) => {
|
|
396848
|
+
const cached = missingRef.current.get(path);
|
|
396849
|
+
if (cached?.sessionId === sessionId && !cached.resolved) return {
|
|
396850
|
+
ok: true,
|
|
396851
|
+
review: cached
|
|
396852
|
+
};
|
|
396853
|
+
const result = await rpc("edrv.missingReview", {
|
|
396854
|
+
sessionId,
|
|
396855
|
+
path
|
|
396856
|
+
});
|
|
396857
|
+
if (result.ok && result.review) {
|
|
396858
|
+
const preview = {
|
|
396859
|
+
...result.review,
|
|
396860
|
+
sessionId,
|
|
396861
|
+
keepId: crypto.randomUUID(),
|
|
396862
|
+
undoId: crypto.randomUUID()
|
|
396863
|
+
};
|
|
396864
|
+
missingRef.current.set(path, preview);
|
|
396865
|
+
return {
|
|
396866
|
+
ok: true,
|
|
396867
|
+
review: preview
|
|
396868
|
+
};
|
|
396869
|
+
}
|
|
396870
|
+
return result;
|
|
396871
|
+
},
|
|
396872
|
+
decide: (preview, operationId) => rpc("edrv.missingDecide", {
|
|
396873
|
+
sessionId,
|
|
396874
|
+
token: preview.token,
|
|
396875
|
+
operationId,
|
|
396876
|
+
undo: reject
|
|
396877
|
+
}),
|
|
396878
|
+
guard: () => guardReviewAll(reject, lifetime),
|
|
396879
|
+
operation: (preview) => reject ? preview.undoId : preview.keepId,
|
|
396880
|
+
committed: (preview, callIds) => {
|
|
396881
|
+
if (!lifetime?.live) return;
|
|
396882
|
+
missingRef.current.set(preview.path, {
|
|
396883
|
+
...preview,
|
|
396884
|
+
resolved: true
|
|
396885
|
+
});
|
|
396886
|
+
setRecords((previous) => Object.fromEntries(Object.entries(previous).filter(([id]) => !callIds.includes(id))));
|
|
396887
|
+
if (!reject && sameFile(activeRef.current, preview.path)) setMissingPreview({
|
|
396888
|
+
...preview,
|
|
396889
|
+
path: activeRef.current,
|
|
396890
|
+
sessionId,
|
|
396891
|
+
resolved: true
|
|
396892
|
+
});
|
|
396893
|
+
emitRefresh({
|
|
396894
|
+
scope,
|
|
396895
|
+
paths: [preview.path],
|
|
396896
|
+
kind: "structure"
|
|
396897
|
+
});
|
|
396898
|
+
}
|
|
396899
|
+
});
|
|
396900
|
+
guardReviewAll(reject, lifetime);
|
|
396901
|
+
const remaining = list.filter((item) => !handled.has(records[item.callId]?.path));
|
|
396902
|
+
const result = await actMany(remaining.map((item) => itemOf(item, reject)));
|
|
396903
|
+
if (!lifetime?.live) return;
|
|
396904
|
+
if (reject || !missingNow) reloadFile(true);
|
|
396679
396905
|
emitRefresh({
|
|
396680
396906
|
scope,
|
|
396681
|
-
paths
|
|
396907
|
+
paths,
|
|
396682
396908
|
kind: "structure"
|
|
396683
396909
|
});
|
|
396684
|
-
setStatus(decideStatus(reject ? "已不采纳 " : "已采纳 ", result));
|
|
396685
|
-
if (result.fail) setError(result.fail + "
|
|
396686
|
-
}
|
|
396910
|
+
setStatus(decideStatus(reject ? "已不采纳 " : "已采纳 ", result) + `;删除文件 ${handled.size} 个`);
|
|
396911
|
+
if (result.fail) setError(result.fail + " 处差异处理失败,可刷新后重试");
|
|
396912
|
+
} catch (cause) {
|
|
396913
|
+
if (lifetime?.live) setError(String(cause));
|
|
396914
|
+
} finally {
|
|
396687
396915
|
batchBusyRef.current = false;
|
|
396688
|
-
|
|
396916
|
+
if (lifetime?.live) refreshRecords();
|
|
396917
|
+
}
|
|
396689
396918
|
};
|
|
396690
396919
|
/** @private @author ddj 2026年10月27号 @param reject Undo requires every local buffer to be saved. @param token Starting session lifetime. @returns Throws before the next mutation when unsafe. */
|
|
396691
396920
|
function guardReviewAll(reject, token) {
|
|
@@ -398286,6 +398515,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
398286
398515
|
const reviewErrorText = !rawReviewError ? void 0 : sessionDown ? SESSION_DOWN_NOTICE : sessionErrorText(rawReviewError);
|
|
398287
398516
|
const buildDockSnapshot = () => ({
|
|
398288
398517
|
mode: editorDockMode(active),
|
|
398518
|
+
missingDeletion: !!missingNow,
|
|
398289
398519
|
official: officialFile ? {
|
|
398290
398520
|
sessionId,
|
|
398291
398521
|
page: review.page,
|
package/lib/client.js.map
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
[diffend] Oversized file quarantined before diffing.
|
|
2
2
|
name: package/lib/client.js.map
|
|
3
|
-
size:
|
|
4
|
-
sha256:
|
|
3
|
+
size: 35428115 bytes
|
|
4
|
+
sha256: 63bc86413f1d5024f07a58442185c1317ec83567e46c3ab47e5320250dff9c76
|