dsh-edit-diff 0.3.0 → 0.4.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/README.md +45 -4
- package/cordis.patch.yml +10 -11
- package/lib/client.js +85 -15
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +31 -12
- package/lib/index.js +25 -11
- package/package.json +19 -6
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
接管 DSH 浏览器的 `edit` / `write` 工具卡片,用近线性行级 diff 做真正的差异展示,消除内置 DiffBlock 把「未变化的相同行」在删除区红 `-` 行和新增区绿 `+` 行各渲染一遍的重复。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
渲染全在浏览器端,主机端半身只负责把配置转成 settings 命名空间。单击即换新渲染,不碰 DSH 源码。
|
|
6
6
|
|
|
7
7
|
## 引言
|
|
8
8
|
|
|
@@ -23,6 +23,47 @@
|
|
|
23
23
|
- **复制与统计**:复制只含差异行,`- `/`+ ` 前缀;底部 `└ +A -R · N file(s)` 变更统计。
|
|
24
24
|
- **单文件与多文件**:`edit` / `write` 双双接管,覆盖新建只显示绿色新增,纯删、多 hunk 等场景。
|
|
25
25
|
- **PTC 模式兼容**:`run_code` 子调用中的 `edit` / `write` 同样显示优化后的修改 diff,通过 `callId` 中的 `:code:` 标记识别子调用。注意 `write` 是全文件覆写,无旧内容,只能显示全新增;想看精确 diff 应使用 `edit`。
|
|
26
|
+
- **接管其他工具**:`extraTools` 让 [dsh-remote-file-system](https://github.com/better-er/dsh-remote-file-system) 的 `edit_remote`、`write_remote` 一并使用优化显示,插件已默认开启这两个,参数名不同的工具可逐项覆盖。
|
|
27
|
+
|
|
28
|
+
## 配置
|
|
29
|
+
|
|
30
|
+
`extraTools` 列出 `edit` 与 `write` 之外要接管的工具。每条写工具名和读取参数用的参数名,参数名省略时按 `file_path`、`old_string`、`new_string`、`content` 取值。
|
|
31
|
+
|
|
32
|
+
插件自带的 `cordis.patch.yml` 已经默认接管 [dsh-remote-file-system](https://github.com/better-er/dsh-remote-file-system) 的这两个远程工具:
|
|
33
|
+
|
|
34
|
+
```yaml
|
|
35
|
+
- insert:
|
|
36
|
+
- id: dsh-edit-diff
|
|
37
|
+
name: dsh-edit-diff
|
|
38
|
+
config:
|
|
39
|
+
extraTools:
|
|
40
|
+
- name: edit_remote
|
|
41
|
+
- name: write_remote
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
它们的参数名和原生一致,只写名字即可。参数名不同的工具再补:
|
|
45
|
+
|
|
46
|
+
```yaml
|
|
47
|
+
extraTools:
|
|
48
|
+
- name: some_tool
|
|
49
|
+
pathKey: target
|
|
50
|
+
oldKey: before
|
|
51
|
+
newKey: after
|
|
52
|
+
contentKey: body
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
要改这份默认,在 profile 的 `cordis.patch.yml` 里按 id 覆盖:
|
|
56
|
+
|
|
57
|
+
```yaml
|
|
58
|
+
- id: dsh-edit-diff
|
|
59
|
+
config:
|
|
60
|
+
extraTools:
|
|
61
|
+
- name: some_tool
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
判断规则:参数里同时有旧文本与新文本就按 edit 型渲染,否则有整文件内容就按 write 型渲染。
|
|
65
|
+
|
|
66
|
+
配置经 settings 命名空间 `dsh-edit-diff` 送到浏览器端,settings 变化会让浏览器端重建这批 key 的注册。
|
|
26
67
|
|
|
27
68
|
## 它长什么样
|
|
28
69
|
|
|
@@ -67,12 +108,12 @@ dsh plugin --profile web remove dsh-edit-diff
|
|
|
67
108
|
|
|
68
109
|
- 是**标准形态的 dsh client 插件**,声明 `dsh.client`,导出 `./client`。
|
|
69
110
|
- 同时声明了 `dsh.bundle`,因此也是一个**自挂载的 bundle 层插件**:用 `dsh plugin --profile <name> add` 从 GitHub 安装后,会被自动识别为 profile layer 并挂载,无需手工写组合 entry。
|
|
70
|
-
-
|
|
71
|
-
- **UI 挂载点**:接管 keyed 槽位 `tool.call.toolview` 的 `edit` 与 `write` 两个 key
|
|
111
|
+
- 主机端半身只做一件事:用 `ctx.settings.installSection()` 把 entry 配置注册成 settings 命名空间 `dsh-edit-diff`。浏览器端拿不到 cordis 配置,这是双半插件传配置的唯一通道。
|
|
112
|
+
- **UI 挂载点**:接管 keyed 槽位 `tool.call.toolview` 的 `edit` 与 `write` 两个 key,以及 `extraTools` 里声明的每个工具名。
|
|
72
113
|
- **遮蔽而非冲突**:注册时显式传 `priority: -1`低于内置 `file-mutation-toolview` 的默认 0,用更低优先级遮蔽默认渲染,而不是在同一优先级上 clash。
|
|
73
114
|
- **PTC 模式**:通过 `callId` 包含 `:code:` 判断是否为 `run_code` 子调用,从 `argsRaw` 中提取 `old_string`/`new_string` 即 edit 或 `content` 即 write 动态构建 diff。
|
|
74
115
|
- **构建型**:TypeScript 源码位于 `src/`,`pnpm build` 通过 tsdown 生成 `lib/index.js`、`lib/index.d.ts`、`lib/client.js` 与 sourcemap,运行时只加载 `lib/` 发布产物。
|
|
75
|
-
-
|
|
116
|
+
- diff 算法就地内联,浏览器端只向宿主模块表请求 react;主机端向宿主解析 `@deepseek-ai/schemastery`。
|
|
76
117
|
|
|
77
118
|
本地开发:
|
|
78
119
|
|
package/cordis.patch.yml
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
# dsh-edit-diff bundle patch
|
|
2
|
-
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
# dsh.client declaration + exports["./client"]. It registers two keyed
|
|
7
|
-
# `tool.call.toolview` occupants (`edit`, `write`) that replace the shipped
|
|
8
|
-
# DiffBlock render, eliminating same-line duplication with a near-linear
|
|
9
|
-
# line diff + intra-line character highlight.
|
|
10
|
-
|
|
1
|
+
# dsh-edit-diff bundle patch:把 edit/write 的 diff 卡片插件插进 profile 的 layer stack。
|
|
2
|
+
# profile 引用本 bundle 时自动挂载。
|
|
3
|
+
# 浏览器半身由 dsh.client 声明自动发现,注册 tool.call.toolview 的 edit、write 与 extraTools 里的每个工具名,替换内置 DiffBlock。
|
|
4
|
+
# 主机端半身把 entry 配置注册成 settings 命名空间 dsh-edit-diff,浏览器端只能从这里拿到配置。
|
|
5
|
+
# 下面的默认顺带接管两个远程文件工具,参数名与原生一致,按 id 覆盖 extraTools 即可改。
|
|
11
6
|
- insert:
|
|
12
7
|
- id: dsh-edit-diff
|
|
13
|
-
name: dsh-edit-diff
|
|
8
|
+
name: dsh-edit-diff
|
|
9
|
+
config:
|
|
10
|
+
extraTools:
|
|
11
|
+
- name: edit_remote
|
|
12
|
+
- name: write_remote
|
package/lib/client.js
CHANGED
|
@@ -34,6 +34,30 @@ window.__ModuleLoader__.load({
|
|
|
34
34
|
//#region src/client.ts
|
|
35
35
|
/** 文档对象,非浏览器环境下为 null。 */
|
|
36
36
|
const DOC = typeof document !== "undefined" ? document : null;
|
|
37
|
+
/** 原生 edit 与 write 的参数名,也是未声明覆盖时的默认值。 */
|
|
38
|
+
const DEFAULT_SPEC = {
|
|
39
|
+
pathKey: "file_path",
|
|
40
|
+
oldKey: "old_string",
|
|
41
|
+
newKey: "new_string",
|
|
42
|
+
contentKey: "content"
|
|
43
|
+
};
|
|
44
|
+
/** 额外接管的工具名到参数名,由 settings 的 extraTools 填充。 */
|
|
45
|
+
const extraSpecs = /* @__PURE__ */ new Map();
|
|
46
|
+
/** 把配置条目补全成完整参数名。 */
|
|
47
|
+
function toKeySpec(tool) {
|
|
48
|
+
return {
|
|
49
|
+
pathKey: tool.pathKey ?? DEFAULT_SPEC.pathKey,
|
|
50
|
+
oldKey: tool.oldKey ?? DEFAULT_SPEC.oldKey,
|
|
51
|
+
newKey: tool.newKey ?? DEFAULT_SPEC.newKey,
|
|
52
|
+
contentKey: tool.contentKey ?? DEFAULT_SPEC.contentKey
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/** 取工具名对应的参数名,非本插件接管的工具返回 null。 */
|
|
56
|
+
function specFor(toolName) {
|
|
57
|
+
if (toolName === "edit" || toolName === "write") return DEFAULT_SPEC;
|
|
58
|
+
if (toolName === void 0) return null;
|
|
59
|
+
return extraSpecs.get(toolName) ?? null;
|
|
60
|
+
}
|
|
37
61
|
/** 行级 Myers:前缀/后缀收缩后仅对中间核心区跑 diff,返回 op 数组。 */
|
|
38
62
|
function myersDiff(aList, bList) {
|
|
39
63
|
const N = aList.length;
|
|
@@ -260,7 +284,7 @@ window.__ModuleLoader__.load({
|
|
|
260
284
|
return out;
|
|
261
285
|
}
|
|
262
286
|
/** 从卡片数据块中取出 diff,取不到时回退到参数意图。 */
|
|
263
|
-
function extractDiffs(block) {
|
|
287
|
+
function extractDiffs(block, spec) {
|
|
264
288
|
const done = "kind" in block;
|
|
265
289
|
const subCall = block.parentCallId !== void 0 || typeof block.callId === "string" && block.callId.includes(":code:");
|
|
266
290
|
if (done && !subCall && block.isError !== true) {
|
|
@@ -276,22 +300,23 @@ window.__ModuleLoader__.load({
|
|
|
276
300
|
if (done && !subCall && block.isError === true) return null;
|
|
277
301
|
const rawArgs = (block.call !== void 0 ? block.call.argsRaw : block.argsRaw) ?? "";
|
|
278
302
|
const argsRaw = typeof rawArgs === "string" ? rawArgs : "";
|
|
279
|
-
|
|
280
|
-
if (name === "edit" || name === "write") try {
|
|
303
|
+
if (spec !== null) try {
|
|
281
304
|
const args = JSON.parse(argsRaw);
|
|
282
305
|
if (args !== null && typeof args === "object") {
|
|
283
306
|
const record = args;
|
|
284
|
-
const filePath = record.
|
|
307
|
+
const filePath = record[spec.pathKey];
|
|
285
308
|
if (typeof filePath === "string" && filePath !== "") {
|
|
286
|
-
|
|
309
|
+
const oldText = record[spec.oldKey];
|
|
310
|
+
const newText = record[spec.newKey];
|
|
311
|
+
if (typeof oldText === "string" && typeof newText === "string") return narrowDiffs([{
|
|
287
312
|
path: filePath,
|
|
288
|
-
oldText: null,
|
|
289
|
-
newText
|
|
313
|
+
oldText: oldText || null,
|
|
314
|
+
newText
|
|
290
315
|
}]);
|
|
291
|
-
if (
|
|
316
|
+
if (typeof record[spec.contentKey] === "string") return narrowDiffs([{
|
|
292
317
|
path: filePath,
|
|
293
|
-
oldText:
|
|
294
|
-
newText: record.
|
|
318
|
+
oldText: null,
|
|
319
|
+
newText: record[spec.contentKey]
|
|
295
320
|
}]);
|
|
296
321
|
}
|
|
297
322
|
}
|
|
@@ -325,17 +350,25 @@ window.__ModuleLoader__.load({
|
|
|
325
350
|
/** 由数据块推导卡片模型。 */
|
|
326
351
|
function buildCardModel(block, toolName, cwd) {
|
|
327
352
|
const done = "kind" in block;
|
|
353
|
+
const spec = specFor(toolName);
|
|
328
354
|
const rawArgs = done ? block.call?.argsRaw ?? "" : block.argsRaw ?? "";
|
|
329
355
|
const argsRaw = typeof rawArgs === "string" ? rawArgs : "";
|
|
330
356
|
const state = !done ? "running" : block.error?.code === "interrupted" ? "stopped" : block.isError === true ? "error" : "ok";
|
|
357
|
+
let kind = toolName === "edit" ? "edit" : toolName === "write" ? "write" : null;
|
|
331
358
|
let filePath;
|
|
332
359
|
let summary = "";
|
|
333
360
|
try {
|
|
334
361
|
const parsed = JSON.parse(argsRaw);
|
|
335
362
|
if (parsed !== null && typeof parsed === "object") {
|
|
336
363
|
const record = parsed;
|
|
337
|
-
const p = record.
|
|
364
|
+
const p = (spec === null ? void 0 : record[spec.pathKey]) ?? record.path;
|
|
338
365
|
if (typeof p === "string" && p !== "") filePath = firstLine(p);
|
|
366
|
+
if (kind === null && spec !== null) {
|
|
367
|
+
const oldText = record[spec.oldKey];
|
|
368
|
+
const newText = record[spec.newKey];
|
|
369
|
+
if (typeof oldText === "string" && typeof newText === "string") kind = "edit";
|
|
370
|
+
else if (typeof record[spec.contentKey] === "string") kind = "write";
|
|
371
|
+
}
|
|
339
372
|
const values = Object.values(record).filter((v) => typeof v === "string" && v !== "");
|
|
340
373
|
summary = values.length > 0 ? firstLine(values[0]) : argsRaw;
|
|
341
374
|
} else summary = firstLine(argsRaw);
|
|
@@ -347,8 +380,8 @@ window.__ModuleLoader__.load({
|
|
|
347
380
|
const root = cwd.replace(/[/\\]+$/, "");
|
|
348
381
|
if (filePath.startsWith(root + "/") || filePath.startsWith(root + "\\")) summary = filePath.slice(root.length + 1);
|
|
349
382
|
}
|
|
350
|
-
const title =
|
|
351
|
-
const diffs = extractDiffs(block);
|
|
383
|
+
const title = kind === "edit" ? "Edit" : kind === "write" ? "Write" : toolName ?? "";
|
|
384
|
+
const diffs = extractDiffs(block, spec);
|
|
352
385
|
const output = done ? resultText(block) || null : null;
|
|
353
386
|
return {
|
|
354
387
|
title,
|
|
@@ -578,16 +611,53 @@ window.__ModuleLoader__.load({
|
|
|
578
611
|
};
|
|
579
612
|
});
|
|
580
613
|
slots.inject("tool.call.toolview", () => {
|
|
581
|
-
slots.register({
|
|
614
|
+
const disposeEdit = slots.register({
|
|
582
615
|
name: "tool.call.toolview",
|
|
583
616
|
key: "edit",
|
|
584
617
|
priority: -1
|
|
585
618
|
}, DiffCard);
|
|
586
|
-
slots.register({
|
|
619
|
+
const disposeWrite = slots.register({
|
|
587
620
|
name: "tool.call.toolview",
|
|
588
621
|
key: "write",
|
|
589
622
|
priority: -1
|
|
590
623
|
}, DiffCard);
|
|
624
|
+
return () => {
|
|
625
|
+
disposeEdit();
|
|
626
|
+
disposeWrite();
|
|
627
|
+
};
|
|
628
|
+
});
|
|
629
|
+
if (typeof ctx.inject !== "function") return;
|
|
630
|
+
ctx.inject(["settingsScope"], (settingsCtx) => {
|
|
631
|
+
const settingsScope = settingsCtx.get?.("settingsScope");
|
|
632
|
+
if (settingsScope === void 0 || typeof settingsScope.bind !== "function") return;
|
|
633
|
+
const scope = settingsScope.bind({ namespace: "dsh-edit-diff" });
|
|
634
|
+
let disposeExtra;
|
|
635
|
+
const sync = () => {
|
|
636
|
+
if (typeof disposeExtra === "function") disposeExtra();
|
|
637
|
+
const value = scope.getSnapshot().value;
|
|
638
|
+
const tools = Array.isArray(value?.extraTools) ? value.extraTools : [];
|
|
639
|
+
extraSpecs.clear();
|
|
640
|
+
const disposers = [];
|
|
641
|
+
for (const tool of tools) {
|
|
642
|
+
if (tool === null || typeof tool !== "object") continue;
|
|
643
|
+
if (typeof tool.name !== "string" || tool.name === "") continue;
|
|
644
|
+
const toolName = tool.name;
|
|
645
|
+
if (toolName === "edit" || toolName === "write") continue;
|
|
646
|
+
if (extraSpecs.has(toolName)) continue;
|
|
647
|
+
extraSpecs.set(toolName, toKeySpec(tool));
|
|
648
|
+
disposers.push(slots.inject("tool.call.toolview", () => slots.register({
|
|
649
|
+
name: "tool.call.toolview",
|
|
650
|
+
key: toolName,
|
|
651
|
+
priority: -1
|
|
652
|
+
}, DiffCard)));
|
|
653
|
+
}
|
|
654
|
+
disposeExtra = () => {
|
|
655
|
+
for (const dispose of disposers) dispose();
|
|
656
|
+
};
|
|
657
|
+
};
|
|
658
|
+
const unsubscribe = scope.subscribe(sync);
|
|
659
|
+
ctx.effect(() => () => unsubscribe());
|
|
660
|
+
sync();
|
|
591
661
|
});
|
|
592
662
|
}
|
|
593
663
|
};
|
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["React"],"sources":["../src/client.ts"],"sourcesContent":["// dsh-edit-diff 浏览器端源码,由 tsdown 构建为标准 dsh client bundle。\n//\n// 构建产物通过 window.__ModuleLoader__.load 注册模块表条目,React 由宿主模块加载器解析。\n// 默认导出 Cordis 插件对象,由浏览器内核挂载。\n//\n// 接管 edit/write 工具卡片:内置 DiffBlock 对新旧全文逐行染色且不做行级匹配,相同行在红绿两区各渲染一遍。\n// 本插件接管 tool.call.toolview 的 edit/write key,用近线性行级 diff 跳过相同行,替换行做字符级下划线高亮。\n// 视觉对齐内置 DiffBlock/ToolRow。卡片默认收起,长 diff 二次折叠。\n//\n// PTC 模式下 run_code 子调用中的 edit/write 同样显示去重 diff,按 callId 的 :code: 标记识别,从 argsRaw 动态构建。\n\nimport * as React from 'react'\n\n/** 文档对象,非浏览器环境下为 null。 */\nconst DOC: Document | null = typeof document !== 'undefined' ? document : null\n\n/** 单条 diff 操作,a 与 b 是两侧序列下标,缺失侧为 -1。 */\ntype DiffOpType = 'same' | 'del' | 'add'\n\ninterface DiffOp {\n type: DiffOpType\n a: number\n b: number\n}\n\n/** 行内高亮区间,左闭右开。 */\ntype CharRange = readonly [number, number]\n\n/** 渲染行种类,path 为文件标题行,mid 为二次折叠提示行。 */\ntype LineKind = 'del' | 'add' | 'path' | 'mid' | 'plain'\n\ninterface RenderLine {\n kind: LineKind\n text: string\n hl: CharRange[]\n}\n\n/** 单个文件的改动对,oldText 为 null 表示新建。 */\ninterface FileDiff {\n path: string\n oldText: string | null\n newText: string\n}\n\n/** 卡片状态。 */\ntype CardState = 'running' | 'stopped' | 'error' | 'ok'\n\n/** 卡片模型,由 block 推导出的渲染所需全部数据。 */\ninterface CardModel {\n title: string\n summary: string\n filePath: string | undefined\n state: CardState\n diffs: FileDiff[] | null\n output: string | null\n}\n\n/** 工具调用的参数面,running 与 settled 两态的字段位置不同。 */\ninterface CallFace {\n name?: unknown\n argsRaw?: unknown\n}\n\n/** 工具卡片数据块,字段一律按 unknown 收窄。 */\ninterface ToolBlock {\n kind?: unknown\n isError?: unknown\n error?: { name?: unknown; code?: unknown }\n meta?: unknown\n callId?: unknown\n parentCallId?: unknown\n argsRaw?: unknown\n name?: unknown\n call?: CallFace\n content?: unknown\n callView?: unknown\n resultView?: unknown\n}\n\n/** 组件 props,来自 tool.call.toolview 槽位。 */\ninterface DiffCardProps {\n block: ToolBlock\n cwd?: string\n toolName?: string\n openFile?: (path: string) => void\n inspect?: () => void\n}\n\n/** 宿主 slots 服务的最小子集。 */\ninterface SlotsService {\n inject(name: string, register: () => void): void\n register(options: { name: string; key: string; priority: number }, component: (props: DiffCardProps) => React.ReactElement): void\n}\n\n/** 宿主 timer 服务的最小子集。 */\ninterface TimerService {\n timeout(callback: () => void, ms: number): unknown\n}\n\n/** Cordis 上下文的最小子集,插件只用到 get 与 effect。 */\ninterface PluginContext {\n get?(name: string): unknown\n effect(callback: () => void | (() => void)): void\n}\n\n// ==================== 近线性 diff 核心 ====================\n\n/** 行级 Myers:前缀/后缀收缩后仅对中间核心区跑 diff,返回 op 数组。 */\nfunction myersDiff(aList: readonly string[], bList: readonly string[]): DiffOp[] {\n const N = aList.length\n const M = bList.length\n const max = N + M\n let prev: Record<number, number> = { 1: 0 }\n const trace: Array<Record<number, number>> = []\n let dMax = 0\n let found = false\n for (let d = 0; d <= max; d++) {\n trace.push({ ...prev })\n const cur: Record<number, number> = {}\n for (let k = -d; k <= d; k += 2) {\n let x: number\n if (k === -d || (k !== d && (prev[k - 1] ?? -Infinity) < (prev[k + 1] ?? -Infinity))) x = prev[k + 1] ?? 0\n else x = (prev[k - 1] ?? -1) + 1\n let y = x - k\n while (x < N && y < M && aList[x] === bList[y]) { x++; y++ }\n cur[k] = x\n if (x >= N && y >= M) { dMax = d; found = true; break }\n }\n prev = cur\n if (found) break\n }\n if (!found) {\n const ops: DiffOp[] = []\n for (let i = 0; i < N; i++) ops.push({ type: 'del', a: i, b: -1 })\n for (let j = 0; j < M; j++) ops.push({ type: 'add', a: -1, b: j })\n return ops\n }\n const ops: DiffOp[] = []\n let x = N\n let y = M\n for (let d = dMax; d > 0; d--) {\n const t = trace[d] ?? {}\n const k = x - y\n let prevK: number\n if (k === -d || (k !== d && (t[k - 1] ?? -Infinity) < (t[k + 1] ?? -Infinity))) prevK = k + 1\n else prevK = k - 1\n const prevX = t[prevK] ?? 0\n const prevY = prevX - prevK\n while (x > prevX && y > prevY) { ops.push({ type: 'same', a: x - 1, b: y - 1 }); x--; y-- }\n if (x === prevX) { ops.push({ type: 'add', a: -1, b: y - 1 }); y-- }\n else { ops.push({ type: 'del', a: x - 1, b: -1 }); x-- }\n }\n while (x > 0 && y > 0) { ops.push({ type: 'same', a: x - 1, b: y - 1 }); x--; y-- }\n ops.reverse()\n return ops\n}\n\n/** 行级 diff:线性前缀/后缀收缩,仅对中间核心区跑 Myers。 */\nfunction lineDiff(aLines: readonly string[], bLines: readonly string[]): DiffOp[] {\n let p = 0\n const minLen = Math.min(aLines.length, bLines.length)\n while (p < minLen && aLines[p] === bLines[p]) p++\n let s = 0\n const al = aLines.length\n const bl = bLines.length\n while (s < minLen - p && aLines[al - 1 - s] === bLines[bl - 1 - s]) s++\n const ops: DiffOp[] = []\n for (let i = 0; i < p; i++) ops.push({ type: 'same', a: i, b: i })\n const aMid = aLines.slice(p, al - s)\n const bMid = bLines.slice(p, bl - s)\n for (const op of myersDiff(aMid, bMid)) {\n ops.push({ type: op.type, a: op.a === -1 ? -1 : op.a + p, b: op.b === -1 ? -1 : op.b + p })\n }\n for (let i = 0; i < s; i++) ops.push({ type: 'same', a: al - s + i, b: bl - s + i })\n return ops\n}\n\n/** 把字符级 op 汇总成高亮区间 [start, end)。 */\nfunction charRanges(ops: readonly DiffOp[]): { del: CharRange[]; add: CharRange[] } {\n const delIdx: number[] = []\n const addIdx: number[] = []\n for (const op of ops) {\n if (op.type === 'del') delIdx.push(op.a)\n else if (op.type === 'add') addIdx.push(op.b)\n }\n const mk = (idx: number[]): CharRange[] => {\n if (idx.length === 0) return []\n idx.sort((a, b) => a - b)\n const out: CharRange[] = []\n let start = idx[0] as number\n let end = start\n for (let i = 1; i < idx.length; i++) {\n const value = idx[i] as number\n if (value === end + 1) end = value\n else { out.push([start, end + 1]); start = value; end = value }\n }\n out.push([start, end + 1])\n return out\n }\n return { del: mk(delIdx), add: mk(addIdx) }\n}\n\nfunction lineHighlight(oldStr: string, newStr: string): { del: CharRange[]; add: CharRange[] } {\n return charRanges(myersDiff([...oldStr], [...newStr]))\n}\n\nfunction contentLines(text: string): string[] {\n if (text === '') return []\n return (text.endsWith('\\n') ? text.slice(0, -1) : text).split('\\n')\n}\n\n/** 从 ops 构建渲染行,仅含真实差异;替换对删/增行数相等做行内字符高亮。 */\nfunction buildDiffLines(oldLines: readonly string[], newLines: readonly string[]): RenderLine[] {\n const ops = lineDiff(oldLines, newLines)\n const out: RenderLine[] = []\n let i = 0\n while (i < ops.length) {\n if (ops[i]?.type === 'same') { i++; continue }\n const dStart = i\n while (i < ops.length && ops[i]?.type === 'del') i++\n const addStart = i\n while (i < ops.length && ops[i]?.type === 'add') i++\n const delOps = ops.slice(dStart, addStart)\n const addOps = ops.slice(addStart, i)\n if (delOps.length === addOps.length && delOps.length > 0) {\n for (let k = 0; k < delOps.length; k++) {\n const del = delOps[k]\n const add = addOps[k]\n if (del === undefined || add === undefined) continue\n const oldText = oldLines[del.a] ?? ''\n const newText = newLines[add.b] ?? ''\n const hl = lineHighlight(oldText, newText)\n out.push({ kind: 'del', text: oldText, hl: hl.del })\n out.push({ kind: 'add', text: newText, hl: hl.add })\n }\n } else {\n for (const op of delOps) out.push({ kind: 'del', text: oldLines[op.a] ?? '', hl: [] })\n for (const op of addOps) out.push({ kind: 'add', text: newLines[op.b] ?? '', hl: [] })\n }\n }\n return out\n}\n\n// ==================== 卡片模型 ====================\n\n/** 收窄外部 diff 数据,字段不合法时返回 null。 */\nfunction narrowDiffs(diffs: unknown): FileDiff[] | null {\n if (!Array.isArray(diffs) || diffs.length === 0) return null\n const out: FileDiff[] = []\n for (const item of diffs as unknown[]) {\n if (item === null || typeof item !== 'object') return null\n const record = item as { path?: unknown; oldText?: unknown; newText?: unknown }\n if (typeof record.path !== 'string') return null\n if (record.oldText !== null && typeof record.oldText !== 'string') return null\n if (typeof record.newText !== 'string') return null\n out.push({ path: record.path, oldText: record.oldText as string | null, newText: record.newText })\n }\n return out\n}\n\n/** 从卡片数据块中取出 diff,取不到时回退到参数意图。 */\nfunction extractDiffs(block: ToolBlock): FileDiff[] | null {\n const done = 'kind' in block\n // PTC 子调用标记:新版 DSH 用 parentCallId;旧版 callId 含 ':code:',双兼容\n const subCall = block.parentCallId !== void 0 ||\n (typeof block.callId === 'string' && block.callId.includes(':code:'))\n\n // settled 且非错误:取真实应用的 diff,新版 DSH 存放在 block.meta.diffs。\n // 结构与内置 diffCardModel/appliedDiffs 同构,支持多 hunk。\n if (done && !subCall && block.isError !== true) {\n const meta = block.meta\n if (meta !== null && typeof meta === 'object' && !Array.isArray(meta)) {\n const diffs = (meta as { diffs?: unknown }).diffs\n if (Array.isArray(diffs) && diffs.length > 0) {\n const narrowed = narrowDiffs(diffs)\n if (narrowed !== null) return narrowed\n }\n }\n }\n\n // 子调用 / running / 兜底:没有真实 diff,改为从参数意图推断。\n // running 的 argsRaw/name 在 block 顶层,settled 的挪到 block.call 上,两处兼容。\n // settled 失败同样不显示意图 diff,与内置 diffCardModel 一致。\n if (done && !subCall && block.isError === true) return null\n const rawArgs = (block.call !== undefined ? block.call.argsRaw : block.argsRaw) ?? ''\n const argsRaw = typeof rawArgs === 'string' ? rawArgs : ''\n const name = block.call !== undefined ? block.call.name : block.name\n if (name === 'edit' || name === 'write') {\n try {\n const args: unknown = JSON.parse(argsRaw)\n if (args !== null && typeof args === 'object') {\n const record = args as Record<string, unknown>\n const filePath = record.file_path\n if (typeof filePath === 'string' && filePath !== '') {\n if (name === 'write' && typeof record.content === 'string') {\n return narrowDiffs([{ path: filePath, oldText: null, newText: record.content }])\n }\n if (name === 'edit' && typeof record.old_string === 'string' && typeof record.new_string === 'string') {\n return narrowDiffs([{ path: filePath, oldText: record.old_string || null, newText: record.new_string }])\n }\n }\n }\n } catch {}\n }\n\n // 旧版 DSH 在 0.1.x 重构前没有以上字段,回退从 callView/resultView 读 diff。\n if (!done) {\n const callView = block.callView\n if (callView === null || typeof callView !== 'object' || (callView as { card?: unknown }).card !== 'diff') return null\n return narrowDiffs((callView as { diffs?: unknown }).diffs)\n }\n const resultView = block.resultView\n if (resultView === null || typeof resultView !== 'object' || (resultView as { card?: unknown }).card !== 'diff') return null\n return narrowDiffs((resultView as { diffs?: unknown }).diffs)\n}\n\n/** 汇总工具结果文本。 */\nfunction resultText(block: ToolBlock): string {\n if (!('kind' in block)) return ''\n const parts: string[] = []\n const content = Array.isArray(block.content) ? block.content : []\n for (const item of content as unknown[]) {\n const record = item !== null && typeof item === 'object' ? item as { type?: unknown; text?: unknown } : null\n const isText = record !== null && record.type === 'text' && typeof record.text === 'string'\n parts.push(isText ? record.text as string : JSON.stringify(item))\n }\n if (parts.length === 0 && block.error !== undefined) {\n parts.push(String(block.error.name) + ': ' + String(block.error.code))\n }\n return parts.join('\\n')\n}\n\nfunction firstLine(t: string): string {\n const n = t.indexOf('\\n')\n return n === -1 ? t : t.slice(0, n)\n}\n\n/** 由数据块推导卡片模型。 */\nfunction buildCardModel(block: ToolBlock, toolName: string | undefined, cwd: string | undefined): CardModel {\n const done = 'kind' in block\n const rawArgs = done ? (block.call?.argsRaw ?? '') : (block.argsRaw ?? '')\n const argsRaw = typeof rawArgs === 'string' ? rawArgs : ''\n const state: CardState = !done ? 'running' : block.error?.code === 'interrupted' ? 'stopped' : block.isError === true ? 'error' : 'ok'\n let filePath: string | undefined\n let summary = ''\n try {\n const parsed: unknown = JSON.parse(argsRaw)\n if (parsed !== null && typeof parsed === 'object') {\n const record = parsed as Record<string, unknown>\n const p = record.file_path ?? record.path\n if (typeof p === 'string' && p !== '') filePath = firstLine(p)\n const values = Object.values(record).filter((v): v is string => typeof v === 'string' && v !== '')\n summary = values.length > 0 ? firstLine(values[0] as string) : argsRaw\n } else summary = firstLine(argsRaw)\n } catch { summary = firstLine(argsRaw) }\n if (filePath !== undefined) summary = filePath\n if (filePath !== undefined && cwd !== undefined) {\n const root = cwd.replace(/[/\\\\]+$/, '')\n if (filePath.startsWith(root + '/') || filePath.startsWith(root + '\\\\')) summary = filePath.slice(root.length + 1)\n }\n const title = toolName === 'edit' ? 'Edit' : toolName === 'write' ? 'Write' : (toolName ?? '')\n const diffs = extractDiffs(block)\n const output = done ? (resultText(block) || null) : null\n return { title, summary, filePath, state, diffs, output }\n}\n\n// ==================== 组件 ====================\n\nfunction DiffCard(props: DiffCardProps): React.ReactElement {\n const { block, cwd, openFile, inspect, toolName } = props\n // open:点行头展开整个卡片;revealed:展开后点「展开其余」显示全部行\n const [open, setOpen] = React.useState(false)\n const [revealed, setRevealed] = React.useState(false)\n const [copied, setCopied] = React.useState(false)\n const m = buildCardModel(block, toolName, cwd)\n const fileLines = m.diffs === null ? null : m.diffs.map(d => ({ path: d.path, lines: buildDiffLines(contentLines(d.oldText ?? ''), contentLines(d.newText)) }))\n const hasAny = fileLines !== null && fileLines.some(f => f.lines.length > 0)\n const displayLines = hasAny ? fileLines : null\n const addCount = displayLines === null ? 0 : displayLines.reduce((sum, f) => sum + f.lines.filter(l => l.kind === 'add').length, 0)\n const delCount = displayLines === null ? 0 : displayLines.reduce((sum, f) => sum + f.lines.filter(l => l.kind === 'del').length, 0)\n const files = m.diffs === null ? 0 : m.diffs.length\n const hasContent = displayLines !== null || m.output !== null\n const expandable = hasContent\n const status = m.state === 'running' ? '运行中' : m.state === 'error' ? '失败' : m.state === 'stopped' ? '已中断' : null\n const failureSummary = m.state === 'error' && m.output !== null ? firstLine(m.output) : null\n const summaryText = failureSummary !== null ? failureSummary : (m.summary || m.title)\n const fileLink = m.filePath !== undefined && openFile !== undefined && failureSummary === null\n const MAX = 14\n let flatLines: RenderLine[] | null = null\n let hidden = 0\n if (displayLines !== null && open) {\n const rows: RenderLine[] = []\n for (const f of displayLines) {\n rows.push({ kind: 'path', text: f.path, hl: [] })\n rows.push(...f.lines)\n }\n hidden = rows.length - MAX\n if (hidden < 0) hidden = 0\n if (hidden > 0 && !revealed) {\n const headN = Math.ceil(MAX / 2)\n flatLines = [\n ...rows.slice(0, headN),\n { kind: 'mid', text: '⋯ 展开其余 ' + hidden + ' 行差异', hl: [] },\n ...rows.slice(rows.length - (MAX - headN)),\n ]\n } else {\n flatLines = rows\n }\n }\n const onToggle = (): void => { setOpen(v => !v); setRevealed(false) }\n const onOpenFile = (event: React.MouseEvent): void => {\n event.stopPropagation()\n if (m.filePath !== undefined && openFile !== undefined) openFile(m.filePath)\n }\n const onCopy = (): void => {\n if (copied || flatLines === null || flatLines.length === 0) return\n const txt = flatLines.map(l => l.kind === 'del' ? '- ' + l.text : l.kind === 'add' ? '+ ' + l.text : l.text).join('\\n')\n copyTextIntoClipboard(txt)\n setCopied(true)\n const timeout = timerRef.timeout\n if (timeout !== null) timeout(() => setCopied(false), 1200)\n }\n const rowType = m.title === 'Write' ? 'write' : m.title === 'Edit' ? 'edit' : 'file'\n return React.createElement('div', { className: 'edd-root', 'data-variant': rowType, 'data-state': m.state },\n status !== null && React.createElement('span', { className: 'edd-vh' }, status),\n React.createElement('div', { className: 'edd-row', onClick: onToggle, role: 'button', tabIndex: expandable ? 0 : -1, 'aria-expanded': open },\n React.createElement('span', { className: 'edd-icon' }, '✎'),\n React.createElement('span', { className: 'edd-title' }, m.title),\n summaryText !== '' && React.createElement(React.Fragment, null,\n React.createElement('span', { className: 'edd-sep', 'aria-hidden': true }),\n fileLink\n ? React.createElement('button', { type: 'button', className: 'edd-filelink', onClick: onOpenFile }, summaryText)\n : React.createElement('span', { className: 'edd-summary' + (failureSummary !== null ? ' edd-err' : '') }, summaryText)\n ),\n expandable && React.createElement('span', { className: 'edd-chev' + (open ? ' edd-chev-open' : '') }, '›')\n ),\n React.createElement('div', { className: 'edd-bodyWrap' },\n (flatLines === null ? null : React.createElement('div', { className: 'edd-body' },\n React.createElement('button', { type: 'button', className: 'edd-copy', onClick: onCopy }, copied ? '复制成功' : '复制'),\n flatLines.map((line, idx) => {\n if (line.kind === 'mid') return React.createElement('button', { key: idx, type: 'button', className: 'edd-expand', onClick: () => setRevealed(true) }, line.text)\n const prefix = line.kind === 'del' ? '-' : line.kind === 'add' ? '+' : ''\n const kids: React.ReactNode[] = []\n if (prefix !== '') kids.push(React.createElement('span', { key: 'p', className: 'edd-marker' }, prefix))\n if (line.kind === 'del' || line.kind === 'add') {\n if (line.text.length === 0) {\n kids.push(React.createElement('span', { key: 'e', className: 'edd-empty' }, '␣'))\n } else if (line.hl.length > 0) {\n let last = 0\n for (const range of line.hl) {\n if (range[0] > last) kids.push(React.createElement('span', { key: 't' + last, className: 'edd-plain' }, line.text.slice(last, range[0])))\n kids.push(React.createElement('span', { key: 'h' + range[0], className: 'edd-hl' }, line.text.slice(range[0], range[1])))\n last = range[1]\n }\n if (last < line.text.length) kids.push(React.createElement('span', { key: 't' + last, className: 'edd-plain' }, line.text.slice(last)))\n } else {\n kids.push(React.createElement('span', { key: 't', className: 'edd-plain' }, line.text))\n }\n } else {\n kids.push(React.createElement('span', { key: 't', className: 'edd-plain' }, line.text))\n }\n return React.createElement('div', { key: idx, className: 'edd-line ' + (line.kind === 'del' ? 'edd-del' : line.kind === 'add' ? 'edd-add' : line.kind === 'path' ? 'edd-path' : 'edd-plain-line') }, kids)\n })\n )),\n open && m.output !== null && flatLines === null && React.createElement('div', { className: 'edd-io' },\n React.createElement('span', { className: 'edd-iolabel' }, 'OUT'),\n React.createElement('span', { className: 'edd-iotext' }, m.output)\n ),\n open && ((flatLines !== null && flatLines.length > 0) || m.output !== null) && React.createElement('div', { className: 'edd-foot' }, '└ +' + addCount + ' -' + delCount + ' · ' + files + ' file' + (files === 1 ? '' : 's')),\n open && React.createElement('div', { className: 'edd-actions' },\n inspect !== undefined && ((flatLines !== null && flatLines.length > 0) || m.output !== null) && React.createElement('button', { type: 'button', className: 'edd-inspect', onClick: inspect }, 'Inspect')\n )\n )\n )\n}\n\n// ==================== 剪贴板与样式 ====================\n\n/** 宿主 timer 服务的时间回调,未注入时为 null。 */\nconst timerRef: { timeout: ((callback: () => void, ms: number) => void) | null } = { timeout: null }\n\nfunction copyTextIntoClipboard(txt: string): void {\n if (typeof navigator !== 'undefined' && navigator.clipboard !== undefined && navigator.clipboard.writeText !== undefined) {\n navigator.clipboard.writeText(txt).catch(() => {})\n return\n }\n if (DOC === null) return\n const ta = DOC.createElement('textarea')\n ta.value = txt\n ta.style.position = 'fixed'\n ta.style.opacity = '0'\n DOC.body.appendChild(ta)\n ta.select()\n try { DOC.execCommand('copy') } catch {}\n DOC.body.removeChild(ta)\n}\n\n// 视觉对齐内置 DiffBlock / ToolRow:复用同一批主题 token,字号/圆角/背景保持一致。\nconst CSS = [\n '.edd-root{box-sizing:border-box;color:var(--dsw-alias-label-primary);}',\n '.edd-vh{position:absolute;width:1px;height:1px;clip:rect(0 0 0 0);overflow:hidden;white-space:nowrap;}',\n '.edd-row{display:flex;align-items:center;gap:6px;cursor:pointer;min-height:24px;padding:4px 0;font-size:14px;line-height:24px;}',\n '.edd-icon{color:var(--dsw-alias-label-secondary);flex:none;font-style:normal;}',\n '.edd-title{font-weight:400;flex:none;color:var(--dsw-alias-label-primary);}',\n '.edd-sep{flex:none;width:2px;height:2px;border-radius:1px;margin:0 8px;background:var(--dsw-alias-label-caption);}',\n '.edd-summary{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px;line-height:24px;color:var(--dsw-alias-label-tertiary);text-align:left;}',\n '.edd-err{color:var(--dsw-alias-state-error-primary);}',\n '.edd-filelink{flex:1 1 auto;min-width:0;margin:0;padding:0;border:none;background:none;font-family:inherit;font-size:14px;line-height:24px;color:var(--dsw-alias-label-secondary);text-decoration:underline;text-decoration-color:var(--dsw-alias-label-quaternary);text-underline-offset:3px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:left;cursor:pointer;}',\n '.edd-filelink:hover{color:var(--dsw-alias-label-primary);text-decoration-color:currentColor;}',\n '.edd-chev{margin-left:auto;color:var(--dsw-alias-label-secondary);flex:none;transition:transform .12s;display:inline-block;}',\n '.edd-chev-open{transform:rotate(90deg);}',\n '.edd-bodyWrap{overflow:hidden;}',\n '.edd-body{position:relative;margin:8px 0;background:var(--dsw-alias-markdown-code-block);border-radius:12px;font:var(--dsw-font-markdown-code-block);overflow-x:auto;overflow-y:hidden;padding:12px 14px 12px 14px;box-sizing:border-box;}',\n '.edd-copy{position:absolute;top:8px;right:12px;z-index:1;background-color:transparent;border:none;padding:0;margin:0;color:var(--dsw-alias-label-secondary);cursor:pointer;font:var(--dsw-font-xs-13);}',\n '.edd-copy:hover{color:var(--dsw-alias-label-primary);}',\n '.edd-path{color:var(--dsw-alias-label-primary);font-weight:600;padding-right:56px;}',\n '.edd-line{min-height:22px;white-space:pre;}',\n '.edd-del{color:var(--dsw-alias-state-error-primary);}',\n '.edd-add{color:var(--dsw-alias-state-success-primary);}',\n '.edd-marker{color:inherit;opacity:1;user-select:none;}',\n '.edd-plain{white-space:pre;}',\n '.edd-empty{opacity:.5;font-style:italic;}',\n '.edd-hl{text-decoration:underline;text-decoration-thickness:2px;text-decoration-color:currentColor;font-weight:600;}',\n '.edd-expand{display:inline-block;margin:2px 0;padding:1px 0;border:none;background:transparent;color:var(--dsw-alias-label-tertiary);cursor:pointer;font:var(--dsw-font-markdown-code-block);text-align:left;}',\n '.edd-expand:hover{color:var(--dsw-alias-label-secondary);}',\n '.edd-foot{padding:0 14px 12px;font:var(--dsw-font-markdown-code-block);color:var(--dsw-alias-label-tertiary);}',\n '.edd-io{padding:8px 14px;}',\n '.edd-iolabel{margin-right:8px;color:var(--dsw-alias-label-caption);font-weight:600;}',\n '.edd-iotext{color:var(--dsw-alias-label-secondary);white-space:pre-wrap;word-break:break-word;}',\n '.edd-actions{padding:4px 0 2px 4px;}',\n '.edd-inspect{display:inline-flex;align-items:center;gap:4px;margin:0;padding:2px 8px;border:1px solid var(--dsw-alias-border-l2);border-radius:999px;background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-secondary);font-size:11px;line-height:16px;cursor:pointer;opacity:0;transition:opacity .12s ease;}',\n '.edd-root:hover .edd-inspect,.edd-inspect:focus-visible{opacity:1;}',\n '.edd-inspect:hover{background:var(--dsw-alias-interactive-bg-hover-solid);color:var(--dsw-alias-label-primary);}',\n].join('')\n\nlet styleTag: HTMLStyleElement | null = null\n\nfunction ensureStyle(): void {\n if (DOC === null || styleTag !== null) return\n const tag = DOC.createElement('style')\n tag.dataset.plugin = 'dsh-edit-diff'\n tag.textContent = CSS\n DOC.head.appendChild(tag)\n styleTag = tag\n}\n\n// ==================== 插件 ====================\n\nconst plugin = {\n name: 'dsh-edit-diff',\n inject: ['slots', 'timer'],\n apply(ctx: PluginContext): void {\n const slots = ctx.get?.('slots') as SlotsService | undefined\n if (slots === undefined) return\n const timer = ctx.get?.('timer') as TimerService | undefined\n if (timer !== undefined && typeof timer.timeout === 'function') {\n timerRef.timeout = (callback, ms) => { timer.timeout(callback, ms) }\n }\n\n ctx.effect(function () {\n ensureStyle()\n return function () {\n if (styleTag !== null && styleTag.parentNode !== null) styleTag.parentNode.removeChild(styleTag)\n styleTag = null\n }\n })\n\n slots.inject('tool.call.toolview', () => {\n // priority 要低于默认 0,遮蔽 file-mutation-toolview 的 edit/write,最低者渲染。\n // 若也传 0 会在同一 key 上 clash,而非替换。\n slots.register({ name: 'tool.call.toolview', key: 'edit', priority: -1 }, DiffCard)\n slots.register({ name: 'tool.call.toolview', key: 'write', priority: -1 }, DiffCard)\n })\n },\n}\n\nexport default plugin\nexport const name = plugin.name\nexport const inject = plugin.inject\nexport const apply = plugin.apply\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["React"],"sources":["../src/client.ts"],"sourcesContent":["// dsh-edit-diff 浏览器端源码,由 tsdown 构建为标准 dsh client bundle。\n//\n// 构建产物通过 window.__ModuleLoader__.load 注册模块表条目,React 由宿主模块加载器解析。\n// 默认导出 Cordis 插件对象,由浏览器内核挂载。\n//\n// 接管 edit/write 工具卡片:内置 DiffBlock 对新旧全文逐行染色且不做行级匹配,相同行在红绿两区各渲染一遍。\n// 本插件接管 tool.call.toolview 的 edit/write key,用近线性行级 diff 跳过相同行,替换行做字符级下划线高亮。\n// 视觉对齐内置 DiffBlock/ToolRow。卡片默认收起,长 diff 二次折叠。\n//\n// PTC 模式下 run_code 子调用中的 edit/write 同样显示去重 diff,按 callId 的 :code: 标记识别,从 argsRaw 动态构建。\n\nimport * as React from 'react'\n\n/** 文档对象,非浏览器环境下为 null。 */\nconst DOC: Document | null = typeof document !== 'undefined' ? document : null\n\n/** 单条 diff 操作,a 与 b 是两侧序列下标,缺失侧为 -1。 */\ntype DiffOpType = 'same' | 'del' | 'add'\n\ninterface DiffOp {\n type: DiffOpType\n a: number\n b: number\n}\n\n/** 行内高亮区间,左闭右开。 */\ntype CharRange = readonly [number, number]\n\n/** 渲染行种类,path 为文件标题行,mid 为二次折叠提示行。 */\ntype LineKind = 'del' | 'add' | 'path' | 'mid' | 'plain'\n\ninterface RenderLine {\n kind: LineKind\n text: string\n hl: CharRange[]\n}\n\n/** 单个文件的改动对,oldText 为 null 表示新建。 */\ninterface FileDiff {\n path: string\n oldText: string | null\n newText: string\n}\n\n/** 卡片状态。 */\ntype CardState = 'running' | 'stopped' | 'error' | 'ok'\n\n/** 卡片模型,由 block 推导出的渲染所需全部数据。 */\ninterface CardModel {\n title: string\n summary: string\n filePath: string | undefined\n state: CardState\n diffs: FileDiff[] | null\n output: string | null\n}\n\n/** 工具调用的参数面,running 与 settled 两态的字段位置不同。 */\ninterface CallFace {\n name?: unknown\n argsRaw?: unknown\n}\n\n/** 工具卡片数据块,字段一律按 unknown 收窄。 */\ninterface ToolBlock {\n kind?: unknown\n isError?: unknown\n error?: { name?: unknown; code?: unknown }\n meta?: unknown\n callId?: unknown\n parentCallId?: unknown\n argsRaw?: unknown\n name?: unknown\n call?: CallFace\n content?: unknown\n callView?: unknown\n resultView?: unknown\n}\n\n/** 组件 props,来自 tool.call.toolview 槽位。 */\ninterface DiffCardProps {\n block: ToolBlock\n cwd?: string\n toolName?: string\n openFile?: (path: string) => void\n inspect?: () => void\n}\n\n/** 宿主 slots 服务的最小子集。 */\ninterface SlotsService {\n inject(name: string, register: () => void | (() => void)): () => void\n register(options: { name: string; key: string; priority: number }, component: (props: DiffCardProps) => React.ReactElement): () => void\n}\n\n/** 宿主 timer 服务的最小子集。 */\ninterface TimerService {\n timeout(callback: () => void, ms: number): unknown\n}\n\n/** Cordis 上下文的最小子集,插件只用到 get、inject 与 effect。 */\ninterface PluginContext {\n get?(name: string): unknown\n inject?(deps: readonly string[], callback: (ctx: PluginContext) => void): void\n effect(callback: () => void | (() => void)): (() => void) | void\n}\n\n// ==================== 额外工具的参数名 ====================\n\n/** 浏览器端读到的 extraTools 条目。 */\ninterface ExtraToolConfig {\n name: string\n pathKey?: string\n oldKey?: string\n newKey?: string\n contentKey?: string\n}\n\n/** settings 命名空间 dsh-edit-diff 的解析值。 */\ninterface PluginConfig {\n extraTools?: ExtraToolConfig[]\n}\n\n/** settings 服务的最小子集。 */\ninterface SettingsScopeService {\n bind<T>(spec: { namespace: string }): SettingsScopeFace<T>\n}\n\n/** 一个 settings 命名空间的读取面。 */\ninterface SettingsScopeFace<T> {\n getSnapshot(): { value: T | undefined }\n subscribe(listener: () => void): () => void\n}\n\n/** 读取工具参数用的参数名。 */\ninterface KeySpec {\n pathKey: string\n oldKey: string\n newKey: string\n contentKey: string\n}\n\n/** 原生 edit 与 write 的参数名,也是未声明覆盖时的默认值。 */\nconst DEFAULT_SPEC: KeySpec = { pathKey: 'file_path', oldKey: 'old_string', newKey: 'new_string', contentKey: 'content' }\n\n/** 额外接管的工具名到参数名,由 settings 的 extraTools 填充。 */\nconst extraSpecs = new Map<string, KeySpec>()\n\n/** 把配置条目补全成完整参数名。 */\nfunction toKeySpec(tool: ExtraToolConfig): KeySpec {\n return {\n pathKey: tool.pathKey ?? DEFAULT_SPEC.pathKey,\n oldKey: tool.oldKey ?? DEFAULT_SPEC.oldKey,\n newKey: tool.newKey ?? DEFAULT_SPEC.newKey,\n contentKey: tool.contentKey ?? DEFAULT_SPEC.contentKey,\n }\n}\n\n/** 取工具名对应的参数名,非本插件接管的工具返回 null。 */\nfunction specFor(toolName: string | undefined): KeySpec | null {\n if (toolName === 'edit' || toolName === 'write') return DEFAULT_SPEC\n if (toolName === undefined) return null\n return extraSpecs.get(toolName) ?? null\n}\n\n// ==================== 近线性 diff 核心 ====================\n\n/** 行级 Myers:前缀/后缀收缩后仅对中间核心区跑 diff,返回 op 数组。 */\nfunction myersDiff(aList: readonly string[], bList: readonly string[]): DiffOp[] {\n const N = aList.length\n const M = bList.length\n const max = N + M\n let prev: Record<number, number> = { 1: 0 }\n const trace: Array<Record<number, number>> = []\n let dMax = 0\n let found = false\n for (let d = 0; d <= max; d++) {\n trace.push({ ...prev })\n const cur: Record<number, number> = {}\n for (let k = -d; k <= d; k += 2) {\n let x: number\n if (k === -d || (k !== d && (prev[k - 1] ?? -Infinity) < (prev[k + 1] ?? -Infinity))) x = prev[k + 1] ?? 0\n else x = (prev[k - 1] ?? -1) + 1\n let y = x - k\n while (x < N && y < M && aList[x] === bList[y]) { x++; y++ }\n cur[k] = x\n if (x >= N && y >= M) { dMax = d; found = true; break }\n }\n prev = cur\n if (found) break\n }\n if (!found) {\n const ops: DiffOp[] = []\n for (let i = 0; i < N; i++) ops.push({ type: 'del', a: i, b: -1 })\n for (let j = 0; j < M; j++) ops.push({ type: 'add', a: -1, b: j })\n return ops\n }\n const ops: DiffOp[] = []\n let x = N\n let y = M\n for (let d = dMax; d > 0; d--) {\n const t = trace[d] ?? {}\n const k = x - y\n let prevK: number\n if (k === -d || (k !== d && (t[k - 1] ?? -Infinity) < (t[k + 1] ?? -Infinity))) prevK = k + 1\n else prevK = k - 1\n const prevX = t[prevK] ?? 0\n const prevY = prevX - prevK\n while (x > prevX && y > prevY) { ops.push({ type: 'same', a: x - 1, b: y - 1 }); x--; y-- }\n if (x === prevX) { ops.push({ type: 'add', a: -1, b: y - 1 }); y-- }\n else { ops.push({ type: 'del', a: x - 1, b: -1 }); x-- }\n }\n while (x > 0 && y > 0) { ops.push({ type: 'same', a: x - 1, b: y - 1 }); x--; y-- }\n ops.reverse()\n return ops\n}\n\n/** 行级 diff:线性前缀/后缀收缩,仅对中间核心区跑 Myers。 */\nfunction lineDiff(aLines: readonly string[], bLines: readonly string[]): DiffOp[] {\n let p = 0\n const minLen = Math.min(aLines.length, bLines.length)\n while (p < minLen && aLines[p] === bLines[p]) p++\n let s = 0\n const al = aLines.length\n const bl = bLines.length\n while (s < minLen - p && aLines[al - 1 - s] === bLines[bl - 1 - s]) s++\n const ops: DiffOp[] = []\n for (let i = 0; i < p; i++) ops.push({ type: 'same', a: i, b: i })\n const aMid = aLines.slice(p, al - s)\n const bMid = bLines.slice(p, bl - s)\n for (const op of myersDiff(aMid, bMid)) {\n ops.push({ type: op.type, a: op.a === -1 ? -1 : op.a + p, b: op.b === -1 ? -1 : op.b + p })\n }\n for (let i = 0; i < s; i++) ops.push({ type: 'same', a: al - s + i, b: bl - s + i })\n return ops\n}\n\n/** 把字符级 op 汇总成高亮区间 [start, end)。 */\nfunction charRanges(ops: readonly DiffOp[]): { del: CharRange[]; add: CharRange[] } {\n const delIdx: number[] = []\n const addIdx: number[] = []\n for (const op of ops) {\n if (op.type === 'del') delIdx.push(op.a)\n else if (op.type === 'add') addIdx.push(op.b)\n }\n const mk = (idx: number[]): CharRange[] => {\n if (idx.length === 0) return []\n idx.sort((a, b) => a - b)\n const out: CharRange[] = []\n let start = idx[0] as number\n let end = start\n for (let i = 1; i < idx.length; i++) {\n const value = idx[i] as number\n if (value === end + 1) end = value\n else { out.push([start, end + 1]); start = value; end = value }\n }\n out.push([start, end + 1])\n return out\n }\n return { del: mk(delIdx), add: mk(addIdx) }\n}\n\nfunction lineHighlight(oldStr: string, newStr: string): { del: CharRange[]; add: CharRange[] } {\n return charRanges(myersDiff([...oldStr], [...newStr]))\n}\n\nfunction contentLines(text: string): string[] {\n if (text === '') return []\n return (text.endsWith('\\n') ? text.slice(0, -1) : text).split('\\n')\n}\n\n/** 从 ops 构建渲染行,仅含真实差异;替换对删/增行数相等做行内字符高亮。 */\nfunction buildDiffLines(oldLines: readonly string[], newLines: readonly string[]): RenderLine[] {\n const ops = lineDiff(oldLines, newLines)\n const out: RenderLine[] = []\n let i = 0\n while (i < ops.length) {\n if (ops[i]?.type === 'same') { i++; continue }\n const dStart = i\n while (i < ops.length && ops[i]?.type === 'del') i++\n const addStart = i\n while (i < ops.length && ops[i]?.type === 'add') i++\n const delOps = ops.slice(dStart, addStart)\n const addOps = ops.slice(addStart, i)\n if (delOps.length === addOps.length && delOps.length > 0) {\n for (let k = 0; k < delOps.length; k++) {\n const del = delOps[k]\n const add = addOps[k]\n if (del === undefined || add === undefined) continue\n const oldText = oldLines[del.a] ?? ''\n const newText = newLines[add.b] ?? ''\n const hl = lineHighlight(oldText, newText)\n out.push({ kind: 'del', text: oldText, hl: hl.del })\n out.push({ kind: 'add', text: newText, hl: hl.add })\n }\n } else {\n for (const op of delOps) out.push({ kind: 'del', text: oldLines[op.a] ?? '', hl: [] })\n for (const op of addOps) out.push({ kind: 'add', text: newLines[op.b] ?? '', hl: [] })\n }\n }\n return out\n}\n\n// ==================== 卡片模型 ====================\n\n/** 收窄外部 diff 数据,字段不合法时返回 null。 */\nfunction narrowDiffs(diffs: unknown): FileDiff[] | null {\n if (!Array.isArray(diffs) || diffs.length === 0) return null\n const out: FileDiff[] = []\n for (const item of diffs as unknown[]) {\n if (item === null || typeof item !== 'object') return null\n const record = item as { path?: unknown; oldText?: unknown; newText?: unknown }\n if (typeof record.path !== 'string') return null\n if (record.oldText !== null && typeof record.oldText !== 'string') return null\n if (typeof record.newText !== 'string') return null\n out.push({ path: record.path, oldText: record.oldText as string | null, newText: record.newText })\n }\n return out\n}\n\n/** 从卡片数据块中取出 diff,取不到时回退到参数意图。 */\nfunction extractDiffs(block: ToolBlock, spec: KeySpec | null): FileDiff[] | null {\n const done = 'kind' in block\n // PTC 子调用标记:新版 DSH 用 parentCallId;旧版 callId 含 ':code:',双兼容\n const subCall = block.parentCallId !== void 0 ||\n (typeof block.callId === 'string' && block.callId.includes(':code:'))\n\n // settled 且非错误:取真实应用的 diff,新版 DSH 存放在 block.meta.diffs。\n // 结构与内置 diffCardModel/appliedDiffs 同构,支持多 hunk。\n if (done && !subCall && block.isError !== true) {\n const meta = block.meta\n if (meta !== null && typeof meta === 'object' && !Array.isArray(meta)) {\n const diffs = (meta as { diffs?: unknown }).diffs\n if (Array.isArray(diffs) && diffs.length > 0) {\n const narrowed = narrowDiffs(diffs)\n if (narrowed !== null) return narrowed\n }\n }\n }\n\n // 子调用 / running / 兜底:没有真实 diff,改为从参数意图推断。\n // running 的 argsRaw/name 在 block 顶层,settled 的挪到 block.call 上,两处兼容。\n // settled 失败同样不显示意图 diff,与内置 diffCardModel 一致。\n if (done && !subCall && block.isError === true) return null\n const rawArgs = (block.call !== undefined ? block.call.argsRaw : block.argsRaw) ?? ''\n const argsRaw = typeof rawArgs === 'string' ? rawArgs : ''\n if (spec !== null) {\n try {\n const args: unknown = JSON.parse(argsRaw)\n if (args !== null && typeof args === 'object') {\n const record = args as Record<string, unknown>\n const filePath = record[spec.pathKey]\n if (typeof filePath === 'string' && filePath !== '') {\n const oldText = record[spec.oldKey]\n const newText = record[spec.newKey]\n if (typeof oldText === 'string' && typeof newText === 'string') {\n return narrowDiffs([{ path: filePath, oldText: oldText || null, newText }])\n }\n if (typeof record[spec.contentKey] === 'string') {\n return narrowDiffs([{ path: filePath, oldText: null, newText: record[spec.contentKey] as string }])\n }\n }\n }\n } catch {}\n }\n\n // 旧版 DSH 在 0.1.x 重构前没有以上字段,回退从 callView/resultView 读 diff。\n if (!done) {\n const callView = block.callView\n if (callView === null || typeof callView !== 'object' || (callView as { card?: unknown }).card !== 'diff') return null\n return narrowDiffs((callView as { diffs?: unknown }).diffs)\n }\n const resultView = block.resultView\n if (resultView === null || typeof resultView !== 'object' || (resultView as { card?: unknown }).card !== 'diff') return null\n return narrowDiffs((resultView as { diffs?: unknown }).diffs)\n}\n\n/** 汇总工具结果文本。 */\nfunction resultText(block: ToolBlock): string {\n if (!('kind' in block)) return ''\n const parts: string[] = []\n const content = Array.isArray(block.content) ? block.content : []\n for (const item of content as unknown[]) {\n const record = item !== null && typeof item === 'object' ? item as { type?: unknown; text?: unknown } : null\n const isText = record !== null && record.type === 'text' && typeof record.text === 'string'\n parts.push(isText ? record.text as string : JSON.stringify(item))\n }\n if (parts.length === 0 && block.error !== undefined) {\n parts.push(String(block.error.name) + ': ' + String(block.error.code))\n }\n return parts.join('\\n')\n}\n\nfunction firstLine(t: string): string {\n const n = t.indexOf('\\n')\n return n === -1 ? t : t.slice(0, n)\n}\n\n/** 由数据块推导卡片模型。 */\nfunction buildCardModel(block: ToolBlock, toolName: string | undefined, cwd: string | undefined): CardModel {\n const done = 'kind' in block\n const spec = specFor(toolName)\n const rawArgs = done ? (block.call?.argsRaw ?? '') : (block.argsRaw ?? '')\n const argsRaw = typeof rawArgs === 'string' ? rawArgs : ''\n const state: CardState = !done ? 'running' : block.error?.code === 'interrupted' ? 'stopped' : block.isError === true ? 'error' : 'ok'\n let kind: 'edit' | 'write' | null = toolName === 'edit' ? 'edit' : toolName === 'write' ? 'write' : null\n let filePath: string | undefined\n let summary = ''\n try {\n const parsed: unknown = JSON.parse(argsRaw)\n if (parsed !== null && typeof parsed === 'object') {\n const record = parsed as Record<string, unknown>\n const p = (spec === null ? undefined : record[spec.pathKey]) ?? record.path\n if (typeof p === 'string' && p !== '') filePath = firstLine(p)\n if (kind === null && spec !== null) {\n const oldText = record[spec.oldKey]\n const newText = record[spec.newKey]\n if (typeof oldText === 'string' && typeof newText === 'string') kind = 'edit'\n else if (typeof record[spec.contentKey] === 'string') kind = 'write'\n }\n const values = Object.values(record).filter((v): v is string => typeof v === 'string' && v !== '')\n summary = values.length > 0 ? firstLine(values[0] as string) : argsRaw\n } else summary = firstLine(argsRaw)\n } catch { summary = firstLine(argsRaw) }\n if (filePath !== undefined) summary = filePath\n if (filePath !== undefined && cwd !== undefined) {\n const root = cwd.replace(/[/\\\\]+$/, '')\n if (filePath.startsWith(root + '/') || filePath.startsWith(root + '\\\\')) summary = filePath.slice(root.length + 1)\n }\n const title = kind === 'edit' ? 'Edit' : kind === 'write' ? 'Write' : (toolName ?? '')\n const diffs = extractDiffs(block, spec)\n const output = done ? (resultText(block) || null) : null\n return { title, summary, filePath, state, diffs, output }\n}\n\n// ==================== 组件 ====================\n\nfunction DiffCard(props: DiffCardProps): React.ReactElement {\n const { block, cwd, openFile, inspect, toolName } = props\n // open:点行头展开整个卡片;revealed:展开后点「展开其余」显示全部行\n const [open, setOpen] = React.useState(false)\n const [revealed, setRevealed] = React.useState(false)\n const [copied, setCopied] = React.useState(false)\n const m = buildCardModel(block, toolName, cwd)\n const fileLines = m.diffs === null ? null : m.diffs.map(d => ({ path: d.path, lines: buildDiffLines(contentLines(d.oldText ?? ''), contentLines(d.newText)) }))\n const hasAny = fileLines !== null && fileLines.some(f => f.lines.length > 0)\n const displayLines = hasAny ? fileLines : null\n const addCount = displayLines === null ? 0 : displayLines.reduce((sum, f) => sum + f.lines.filter(l => l.kind === 'add').length, 0)\n const delCount = displayLines === null ? 0 : displayLines.reduce((sum, f) => sum + f.lines.filter(l => l.kind === 'del').length, 0)\n const files = m.diffs === null ? 0 : m.diffs.length\n const hasContent = displayLines !== null || m.output !== null\n const expandable = hasContent\n const status = m.state === 'running' ? '运行中' : m.state === 'error' ? '失败' : m.state === 'stopped' ? '已中断' : null\n const failureSummary = m.state === 'error' && m.output !== null ? firstLine(m.output) : null\n const summaryText = failureSummary !== null ? failureSummary : (m.summary || m.title)\n const fileLink = m.filePath !== undefined && openFile !== undefined && failureSummary === null\n const MAX = 14\n let flatLines: RenderLine[] | null = null\n let hidden = 0\n if (displayLines !== null && open) {\n const rows: RenderLine[] = []\n for (const f of displayLines) {\n rows.push({ kind: 'path', text: f.path, hl: [] })\n rows.push(...f.lines)\n }\n hidden = rows.length - MAX\n if (hidden < 0) hidden = 0\n if (hidden > 0 && !revealed) {\n const headN = Math.ceil(MAX / 2)\n flatLines = [\n ...rows.slice(0, headN),\n { kind: 'mid', text: '⋯ 展开其余 ' + hidden + ' 行差异', hl: [] },\n ...rows.slice(rows.length - (MAX - headN)),\n ]\n } else {\n flatLines = rows\n }\n }\n const onToggle = (): void => { setOpen(v => !v); setRevealed(false) }\n const onOpenFile = (event: React.MouseEvent): void => {\n event.stopPropagation()\n if (m.filePath !== undefined && openFile !== undefined) openFile(m.filePath)\n }\n const onCopy = (): void => {\n if (copied || flatLines === null || flatLines.length === 0) return\n const txt = flatLines.map(l => l.kind === 'del' ? '- ' + l.text : l.kind === 'add' ? '+ ' + l.text : l.text).join('\\n')\n copyTextIntoClipboard(txt)\n setCopied(true)\n const timeout = timerRef.timeout\n if (timeout !== null) timeout(() => setCopied(false), 1200)\n }\n const rowType = m.title === 'Write' ? 'write' : m.title === 'Edit' ? 'edit' : 'file'\n return React.createElement('div', { className: 'edd-root', 'data-variant': rowType, 'data-state': m.state },\n status !== null && React.createElement('span', { className: 'edd-vh' }, status),\n React.createElement('div', { className: 'edd-row', onClick: onToggle, role: 'button', tabIndex: expandable ? 0 : -1, 'aria-expanded': open },\n React.createElement('span', { className: 'edd-icon' }, '✎'),\n React.createElement('span', { className: 'edd-title' }, m.title),\n summaryText !== '' && React.createElement(React.Fragment, null,\n React.createElement('span', { className: 'edd-sep', 'aria-hidden': true }),\n fileLink\n ? React.createElement('button', { type: 'button', className: 'edd-filelink', onClick: onOpenFile }, summaryText)\n : React.createElement('span', { className: 'edd-summary' + (failureSummary !== null ? ' edd-err' : '') }, summaryText)\n ),\n expandable && React.createElement('span', { className: 'edd-chev' + (open ? ' edd-chev-open' : '') }, '›')\n ),\n React.createElement('div', { className: 'edd-bodyWrap' },\n (flatLines === null ? null : React.createElement('div', { className: 'edd-body' },\n React.createElement('button', { type: 'button', className: 'edd-copy', onClick: onCopy }, copied ? '复制成功' : '复制'),\n flatLines.map((line, idx) => {\n if (line.kind === 'mid') return React.createElement('button', { key: idx, type: 'button', className: 'edd-expand', onClick: () => setRevealed(true) }, line.text)\n const prefix = line.kind === 'del' ? '-' : line.kind === 'add' ? '+' : ''\n const kids: React.ReactNode[] = []\n if (prefix !== '') kids.push(React.createElement('span', { key: 'p', className: 'edd-marker' }, prefix))\n if (line.kind === 'del' || line.kind === 'add') {\n if (line.text.length === 0) {\n kids.push(React.createElement('span', { key: 'e', className: 'edd-empty' }, '␣'))\n } else if (line.hl.length > 0) {\n let last = 0\n for (const range of line.hl) {\n if (range[0] > last) kids.push(React.createElement('span', { key: 't' + last, className: 'edd-plain' }, line.text.slice(last, range[0])))\n kids.push(React.createElement('span', { key: 'h' + range[0], className: 'edd-hl' }, line.text.slice(range[0], range[1])))\n last = range[1]\n }\n if (last < line.text.length) kids.push(React.createElement('span', { key: 't' + last, className: 'edd-plain' }, line.text.slice(last)))\n } else {\n kids.push(React.createElement('span', { key: 't', className: 'edd-plain' }, line.text))\n }\n } else {\n kids.push(React.createElement('span', { key: 't', className: 'edd-plain' }, line.text))\n }\n return React.createElement('div', { key: idx, className: 'edd-line ' + (line.kind === 'del' ? 'edd-del' : line.kind === 'add' ? 'edd-add' : line.kind === 'path' ? 'edd-path' : 'edd-plain-line') }, kids)\n })\n )),\n open && m.output !== null && flatLines === null && React.createElement('div', { className: 'edd-io' },\n React.createElement('span', { className: 'edd-iolabel' }, 'OUT'),\n React.createElement('span', { className: 'edd-iotext' }, m.output)\n ),\n open && ((flatLines !== null && flatLines.length > 0) || m.output !== null) && React.createElement('div', { className: 'edd-foot' }, '└ +' + addCount + ' -' + delCount + ' · ' + files + ' file' + (files === 1 ? '' : 's')),\n open && React.createElement('div', { className: 'edd-actions' },\n inspect !== undefined && ((flatLines !== null && flatLines.length > 0) || m.output !== null) && React.createElement('button', { type: 'button', className: 'edd-inspect', onClick: inspect }, 'Inspect')\n )\n )\n )\n}\n\n// ==================== 剪贴板与样式 ====================\n\n/** 宿主 timer 服务的时间回调,未注入时为 null。 */\nconst timerRef: { timeout: ((callback: () => void, ms: number) => void) | null } = { timeout: null }\n\nfunction copyTextIntoClipboard(txt: string): void {\n if (typeof navigator !== 'undefined' && navigator.clipboard !== undefined && navigator.clipboard.writeText !== undefined) {\n navigator.clipboard.writeText(txt).catch(() => {})\n return\n }\n if (DOC === null) return\n const ta = DOC.createElement('textarea')\n ta.value = txt\n ta.style.position = 'fixed'\n ta.style.opacity = '0'\n DOC.body.appendChild(ta)\n ta.select()\n try { DOC.execCommand('copy') } catch {}\n DOC.body.removeChild(ta)\n}\n\n// 视觉对齐内置 DiffBlock / ToolRow:复用同一批主题 token,字号/圆角/背景保持一致。\nconst CSS = [\n '.edd-root{box-sizing:border-box;color:var(--dsw-alias-label-primary);}',\n '.edd-vh{position:absolute;width:1px;height:1px;clip:rect(0 0 0 0);overflow:hidden;white-space:nowrap;}',\n '.edd-row{display:flex;align-items:center;gap:6px;cursor:pointer;min-height:24px;padding:4px 0;font-size:14px;line-height:24px;}',\n '.edd-icon{color:var(--dsw-alias-label-secondary);flex:none;font-style:normal;}',\n '.edd-title{font-weight:400;flex:none;color:var(--dsw-alias-label-primary);}',\n '.edd-sep{flex:none;width:2px;height:2px;border-radius:1px;margin:0 8px;background:var(--dsw-alias-label-caption);}',\n '.edd-summary{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px;line-height:24px;color:var(--dsw-alias-label-tertiary);text-align:left;}',\n '.edd-err{color:var(--dsw-alias-state-error-primary);}',\n '.edd-filelink{flex:1 1 auto;min-width:0;margin:0;padding:0;border:none;background:none;font-family:inherit;font-size:14px;line-height:24px;color:var(--dsw-alias-label-secondary);text-decoration:underline;text-decoration-color:var(--dsw-alias-label-quaternary);text-underline-offset:3px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:left;cursor:pointer;}',\n '.edd-filelink:hover{color:var(--dsw-alias-label-primary);text-decoration-color:currentColor;}',\n '.edd-chev{margin-left:auto;color:var(--dsw-alias-label-secondary);flex:none;transition:transform .12s;display:inline-block;}',\n '.edd-chev-open{transform:rotate(90deg);}',\n '.edd-bodyWrap{overflow:hidden;}',\n '.edd-body{position:relative;margin:8px 0;background:var(--dsw-alias-markdown-code-block);border-radius:12px;font:var(--dsw-font-markdown-code-block);overflow-x:auto;overflow-y:hidden;padding:12px 14px 12px 14px;box-sizing:border-box;}',\n '.edd-copy{position:absolute;top:8px;right:12px;z-index:1;background-color:transparent;border:none;padding:0;margin:0;color:var(--dsw-alias-label-secondary);cursor:pointer;font:var(--dsw-font-xs-13);}',\n '.edd-copy:hover{color:var(--dsw-alias-label-primary);}',\n '.edd-path{color:var(--dsw-alias-label-primary);font-weight:600;padding-right:56px;}',\n '.edd-line{min-height:22px;white-space:pre;}',\n '.edd-del{color:var(--dsw-alias-state-error-primary);}',\n '.edd-add{color:var(--dsw-alias-state-success-primary);}',\n '.edd-marker{color:inherit;opacity:1;user-select:none;}',\n '.edd-plain{white-space:pre;}',\n '.edd-empty{opacity:.5;font-style:italic;}',\n '.edd-hl{text-decoration:underline;text-decoration-thickness:2px;text-decoration-color:currentColor;font-weight:600;}',\n '.edd-expand{display:inline-block;margin:2px 0;padding:1px 0;border:none;background:transparent;color:var(--dsw-alias-label-tertiary);cursor:pointer;font:var(--dsw-font-markdown-code-block);text-align:left;}',\n '.edd-expand:hover{color:var(--dsw-alias-label-secondary);}',\n '.edd-foot{padding:0 14px 12px;font:var(--dsw-font-markdown-code-block);color:var(--dsw-alias-label-tertiary);}',\n '.edd-io{padding:8px 14px;}',\n '.edd-iolabel{margin-right:8px;color:var(--dsw-alias-label-caption);font-weight:600;}',\n '.edd-iotext{color:var(--dsw-alias-label-secondary);white-space:pre-wrap;word-break:break-word;}',\n '.edd-actions{padding:4px 0 2px 4px;}',\n '.edd-inspect{display:inline-flex;align-items:center;gap:4px;margin:0;padding:2px 8px;border:1px solid var(--dsw-alias-border-l2);border-radius:999px;background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-secondary);font-size:11px;line-height:16px;cursor:pointer;opacity:0;transition:opacity .12s ease;}',\n '.edd-root:hover .edd-inspect,.edd-inspect:focus-visible{opacity:1;}',\n '.edd-inspect:hover{background:var(--dsw-alias-interactive-bg-hover-solid);color:var(--dsw-alias-label-primary);}',\n].join('')\n\nlet styleTag: HTMLStyleElement | null = null\n\nfunction ensureStyle(): void {\n if (DOC === null || styleTag !== null) return\n const tag = DOC.createElement('style')\n tag.dataset.plugin = 'dsh-edit-diff'\n tag.textContent = CSS\n DOC.head.appendChild(tag)\n styleTag = tag\n}\n\n// ==================== 插件 ====================\n\nconst plugin = {\n name: 'dsh-edit-diff',\n inject: ['slots', 'timer'],\n apply(ctx: PluginContext): void {\n const slots = ctx.get?.('slots') as SlotsService | undefined\n if (slots === undefined) return\n const timer = ctx.get?.('timer') as TimerService | undefined\n if (timer !== undefined && typeof timer.timeout === 'function') {\n timerRef.timeout = (callback, ms) => { timer.timeout(callback, ms) }\n }\n\n ctx.effect(function () {\n ensureStyle()\n return function () {\n if (styleTag !== null && styleTag.parentNode !== null) styleTag.parentNode.removeChild(styleTag)\n styleTag = null\n }\n })\n\n slots.inject('tool.call.toolview', () => {\n // priority 要低于默认 0,遮蔽 file-mutation-toolview 的 edit/write,最低者渲染。\n // 若也传 0 会在同一 key 上 clash,而非替换。\n const disposeEdit = slots.register({ name: 'tool.call.toolview', key: 'edit', priority: -1 }, DiffCard)\n const disposeWrite = slots.register({ name: 'tool.call.toolview', key: 'write', priority: -1 }, DiffCard)\n return () => {\n disposeEdit()\n disposeWrite()\n }\n })\n\n // extraTools 经 settings 命名空间到达。没有挂载 settings 时上面两张卡片照常工作。\n if (typeof ctx.inject !== 'function') return\n ctx.inject(['settingsScope'], (settingsCtx) => {\n const settingsScope = settingsCtx.get?.('settingsScope') as SettingsScopeService | undefined\n if (settingsScope === undefined || typeof settingsScope.bind !== 'function') return\n const scope = settingsScope.bind<PluginConfig>({ namespace: 'dsh-edit-diff' })\n let disposeExtra: (() => void) | void\n // 配置变化时整批重建:先换参数名表,再重建这批 key 的注册。\n const sync = (): void => {\n if (typeof disposeExtra === 'function') disposeExtra()\n const value = scope.getSnapshot().value\n const tools = Array.isArray(value?.extraTools) ? value.extraTools : []\n extraSpecs.clear()\n // slots.inject 返回注销函数,slots.register 也是;两者都要收起来,否则旧注册留在槽位里,下一次 sync 会对同 key 同 priority 再注册一次并抛错。\n const disposers: Array<() => void> = []\n for (const tool of tools) {\n if (tool === null || typeof tool !== 'object') continue\n if (typeof tool.name !== 'string' || tool.name === '') continue\n const toolName = tool.name\n if (toolName === 'edit' || toolName === 'write') continue\n // 同名条目只认第一次。extraSpecs 刚清空,命中即已注册过。\n if (extraSpecs.has(toolName)) continue\n extraSpecs.set(toolName, toKeySpec(tool))\n disposers.push(slots.inject('tool.call.toolview', () =>\n slots.register({ name: 'tool.call.toolview', key: toolName, priority: -1 }, DiffCard)))\n }\n disposeExtra = () => {\n for (const dispose of disposers) dispose()\n }\n }\n const unsubscribe = scope.subscribe(sync)\n // settingsScope 卸载时撤掉订阅,注册本身由各自的 effect 随 fiber 回收。\n ctx.effect(() => () => unsubscribe())\n sync()\n })\n },\n}\n\nexport default plugin\nexport const name = plugin.name\nexport const inject = plugin.inject\nexport const apply = plugin.apply\n"],"mappings":"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"}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,15 +1,34 @@
|
|
|
1
|
+
import Schema from "@deepseek-ai/schemastery";
|
|
2
|
+
import { Context } from "@deepseek-ai/cordis";
|
|
1
3
|
//#region src/index.d.ts
|
|
4
|
+
/** 插件名,即配置条目 id。 */
|
|
5
|
+
export declare const name = "dsh-edit-diff";
|
|
6
|
+
/** settings 命名空间,与包名一致,浏览器半身按同名绑定。 */
|
|
7
|
+
export declare const NS = "dsh-edit-diff";
|
|
8
|
+
/** 一个额外接管的工具,以及读取其参数用的参数名。 */
|
|
9
|
+
export interface ExtraTool {
|
|
10
|
+
/** wire 工具名,即 tool.call.toolview 的 key。 */
|
|
11
|
+
name: string;
|
|
12
|
+
/** 读取文件路径的参数名,默认 file_path。 */
|
|
13
|
+
pathKey?: string;
|
|
14
|
+
/** 读取旧文本的参数名,默认 old_string。 */
|
|
15
|
+
oldKey?: string;
|
|
16
|
+
/** 读取新文本的参数名,默认 new_string。 */
|
|
17
|
+
newKey?: string;
|
|
18
|
+
/** 读取整文件内容的参数名,默认 content。 */
|
|
19
|
+
contentKey?: string;
|
|
20
|
+
}
|
|
21
|
+
/** 插件配置。 */
|
|
22
|
+
export interface Config {
|
|
23
|
+
/** 除 edit 与 write 外,额外接管 diff 卡片显示的工具。 */
|
|
24
|
+
extraTools?: ExtraTool[];
|
|
25
|
+
}
|
|
26
|
+
/** 配置 schema,默认值直接写在 schema 里。 */
|
|
27
|
+
export declare const Config: Schema<Config>;
|
|
2
28
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* 通过 dsh.bundle 成为自挂载 bundle 层,一条 dsh plugin --profile web add 即可完整激活。
|
|
29
|
+
* 插件 apply:把 entry 配置注册成 settings 命名空间。
|
|
30
|
+
* @param ctx - cordis 上下文。
|
|
31
|
+
* @param config - 插件配置。
|
|
7
32
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
/** 不使用任何主机端服务。 */
|
|
11
|
-
declare const inject: string[];
|
|
12
|
-
/** 本浏览器端插件无主机端行为。 */
|
|
13
|
-
declare function apply(): void;
|
|
14
|
-
//#endregion
|
|
15
|
-
export { apply, inject, name };
|
|
33
|
+
export declare function apply(ctx: Context, config?: Config): void;
|
|
34
|
+
//#endregion
|
package/lib/index.js
CHANGED
|
@@ -1,15 +1,29 @@
|
|
|
1
|
+
import Schema from "@deepseek-ai/schemastery";
|
|
1
2
|
//#region src/index.ts
|
|
2
|
-
/**
|
|
3
|
-
* 主机端:空操作 Cordis 插件。
|
|
4
|
-
* 所有行为在浏览器端 lib/client.js,通过 package.json dsh.client 声明被 web 客户端模块系统发现。
|
|
5
|
-
* 本半身存在是为了让插件根目录成为完整的双面包,在宿主 Loader 中显示为一个条目。
|
|
6
|
-
* 通过 dsh.bundle 成为自挂载 bundle 层,一条 dsh plugin --profile web add 即可完整激活。
|
|
7
|
-
*/
|
|
8
3
|
/** 插件名,即配置条目 id。 */
|
|
9
4
|
const name = "dsh-edit-diff";
|
|
10
|
-
/**
|
|
11
|
-
const
|
|
12
|
-
/**
|
|
13
|
-
|
|
5
|
+
/** settings 命名空间,与包名一致,浏览器半身按同名绑定。 */
|
|
6
|
+
const NS = "dsh-edit-diff";
|
|
7
|
+
/** 配置 schema,默认值直接写在 schema 里。 */
|
|
8
|
+
const Config = Schema.object({ extraTools: Schema.array(Schema.object({
|
|
9
|
+
name: Schema.string().required(),
|
|
10
|
+
pathKey: Schema.string(),
|
|
11
|
+
oldKey: Schema.string(),
|
|
12
|
+
newKey: Schema.string(),
|
|
13
|
+
contentKey: Schema.string()
|
|
14
|
+
})).default([]) });
|
|
15
|
+
/**
|
|
16
|
+
* 插件 apply:把 entry 配置注册成 settings 命名空间。
|
|
17
|
+
* @param ctx - cordis 上下文。
|
|
18
|
+
* @param config - 插件配置。
|
|
19
|
+
*/
|
|
20
|
+
function apply(ctx, config = {}) {
|
|
21
|
+
ctx.inject(["settings"], (settingsCtx) => {
|
|
22
|
+
settingsCtx.settings.installSection(ctx, NS, Config, config, {
|
|
23
|
+
setSource: () => {},
|
|
24
|
+
onChange: () => {}
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
}
|
|
14
28
|
//#endregion
|
|
15
|
-
export {
|
|
29
|
+
export { Config, NS, apply, name };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-edit-diff",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "质量 diff:接管 edit/write
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "质量 diff:接管 edit/write 及 extraTools 配置的其他工具卡片,行级去重与行内高亮,消除相同内容在删除与新增两区的重复;兼容 PTC 模式,标准可安装的 dsh 客户端插件",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek-harness",
|
|
7
7
|
"dsh",
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"type": "git",
|
|
15
15
|
"url": "git+https://github.com/better-er/dsh-edit-diff.git"
|
|
16
16
|
},
|
|
17
|
+
"packageManager": "pnpm@9.15.9",
|
|
17
18
|
"type": "module",
|
|
18
19
|
"main": "lib/index.js",
|
|
19
20
|
"types": "lib/index.d.ts",
|
|
@@ -47,14 +48,26 @@
|
|
|
47
48
|
"cordis.patch.yml",
|
|
48
49
|
"docs/"
|
|
49
50
|
],
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build": "tsdown",
|
|
53
|
+
"prepare": "tsdown",
|
|
54
|
+
"typecheck": "tsc --noEmit"
|
|
55
|
+
},
|
|
56
|
+
"peerDependencies": {
|
|
57
|
+
"@deepseek-ai/cordis": "^4.0.2",
|
|
58
|
+
"@deepseek-ai/dsh-settings": "^0.1.5-rc.2",
|
|
59
|
+
"@deepseek-ai/schemastery": "^3.18.2"
|
|
60
|
+
},
|
|
50
61
|
"devDependencies": {
|
|
62
|
+
"@deepseek-ai/cordis": "^4.0.2",
|
|
63
|
+
"@deepseek-ai/dsh-settings": "^0.1.5-rc.2",
|
|
64
|
+
"@deepseek-ai/schemastery": "^3.18.2",
|
|
51
65
|
"@types/react": "~18.3.1",
|
|
52
66
|
"tsdown": "^0.23.0",
|
|
53
67
|
"typescript": "^5.9.3"
|
|
54
68
|
},
|
|
55
69
|
"license": "MIT",
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"typecheck": "tsc --noEmit"
|
|
70
|
+
"engines": {
|
|
71
|
+
"node": ">=26.3.1"
|
|
59
72
|
}
|
|
60
|
-
}
|
|
73
|
+
}
|