@huanlin/dsh-plugin-merge-tool-calls 0.2.2 → 0.3.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 +10 -7
- package/lib/client.js +509 -95
- package/lib/client.js.map +1 -1
- package/lib/types/client/card-model.d.ts +19 -19
- package/lib/types/client/dictionaries.d.ts +12 -5
- package/lib/types/client/index.d.ts +1 -1
- package/lib/types/client/locales.d.ts +46 -0
- package/lib/types/client/merge-run.d.ts +5 -2
- package/lib/types/client/rows.d.ts +7 -3
- package/package.json +15 -22
- package/lib/invariant.js +0 -11
- package/lib/types/invariant.d.ts +0 -12
package/lib/client.js
CHANGED
|
@@ -27,8 +27,6 @@ let react = require("react");
|
|
|
27
27
|
react = __toESM(react);
|
|
28
28
|
let __deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
29
29
|
__deepseek_ai_dsh_client_ui_primitives = __toESM(__deepseek_ai_dsh_client_ui_primitives);
|
|
30
|
-
let __deepseek_ai_dsh_client_runtime_client = require("@deepseek-ai/dsh-client-runtime/client");
|
|
31
|
-
__deepseek_ai_dsh_client_runtime_client = __toESM(__deepseek_ai_dsh_client_runtime_client);
|
|
32
30
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
33
31
|
react_jsx_runtime = __toESM(react_jsx_runtime);
|
|
34
32
|
|
|
@@ -576,6 +574,8 @@ const zh = {
|
|
|
576
574
|
countCommands: "{n} 条命令",
|
|
577
575
|
countPrograms: "{n} 段代码",
|
|
578
576
|
countCalls: "{n} 次调用",
|
|
577
|
+
copy: "复制",
|
|
578
|
+
copied: "已复制",
|
|
579
579
|
"terminal.signal": "信号 {signal}",
|
|
580
580
|
"terminal.exitCode": "退出码 {code}",
|
|
581
581
|
"terminal.running": "运行中",
|
|
@@ -587,7 +587,28 @@ const zh = {
|
|
|
587
587
|
"terminal.collapseAria": "收起输出",
|
|
588
588
|
"terminal.collapse": "折叠",
|
|
589
589
|
"terminal.expandAria": "展开其余 {n} 行输出",
|
|
590
|
-
"terminal.expandRest": "… 其余 {n} 行"
|
|
590
|
+
"terminal.expandRest": "… 其余 {n} 行",
|
|
591
|
+
"read.window": "显示 {shown} / {total} 行",
|
|
592
|
+
"read.collapseAria": "收起内容",
|
|
593
|
+
"read.expandAria": "展开其余 {count} 行",
|
|
594
|
+
"read.expandRest": "… 其余 {count} 行",
|
|
595
|
+
"search.paths": "{shown} 个路径",
|
|
596
|
+
"search.paths.truncated": "显示 {shown} / 共 {total} 个路径",
|
|
597
|
+
"search.matches": "{shown} 处匹配 · {files} 个文件",
|
|
598
|
+
"search.matches.truncated": "显示 {shown} / 共 {total} 处匹配 · {files} 个文件",
|
|
599
|
+
"search.noResults": "无结果",
|
|
600
|
+
"search.collapseAria": "收起结果",
|
|
601
|
+
"search.expandAria": "展开其余 {count} 行结果",
|
|
602
|
+
"search.expandRest": "… 其余 {count} 行",
|
|
603
|
+
"diff.collapseAria": "收起差异",
|
|
604
|
+
"diff.expandAria": "展开其余 {count} 行差异",
|
|
605
|
+
"diff.expandRest": "… 其余 {count} 行",
|
|
606
|
+
"diff.files": "{count} 个文件",
|
|
607
|
+
"web.noResults": "未找到结果",
|
|
608
|
+
"web.sourcesTruncated": "来源列表已截断",
|
|
609
|
+
"web.http": "HTTP",
|
|
610
|
+
"web.contentTruncated": "内容已截断",
|
|
611
|
+
"markdown.footnotes": "脚注"
|
|
591
612
|
};
|
|
592
613
|
const en = {
|
|
593
614
|
running: "Running",
|
|
@@ -603,6 +624,8 @@ const en = {
|
|
|
603
624
|
countCommands: "{n} Commands",
|
|
604
625
|
countPrograms: "{n} Programs",
|
|
605
626
|
countCalls: "{n} Calls",
|
|
627
|
+
copy: "Copy",
|
|
628
|
+
copied: "Copied",
|
|
606
629
|
"terminal.signal": "signal {signal}",
|
|
607
630
|
"terminal.exitCode": "exit code {code}",
|
|
608
631
|
"terminal.running": "Running",
|
|
@@ -614,7 +637,28 @@ const en = {
|
|
|
614
637
|
"terminal.collapseAria": "Collapse output",
|
|
615
638
|
"terminal.collapse": "Collapse",
|
|
616
639
|
"terminal.expandAria": "Expand the remaining {n} output lines",
|
|
617
|
-
"terminal.expandRest": "… {n} more lines"
|
|
640
|
+
"terminal.expandRest": "… {n} more lines",
|
|
641
|
+
"read.window": "Showing {shown} of {total} lines",
|
|
642
|
+
"read.collapseAria": "Collapse content",
|
|
643
|
+
"read.expandAria": "Expand {count} more lines",
|
|
644
|
+
"read.expandRest": "… {count} more lines",
|
|
645
|
+
"search.paths": "{shown} paths",
|
|
646
|
+
"search.paths.truncated": "Showing {shown} of {total} paths",
|
|
647
|
+
"search.matches": "{shown} matches · {files} files",
|
|
648
|
+
"search.matches.truncated": "Showing {shown} of {total} matches · {files} files",
|
|
649
|
+
"search.noResults": "No results",
|
|
650
|
+
"search.collapseAria": "Collapse results",
|
|
651
|
+
"search.expandAria": "Expand {count} more result lines",
|
|
652
|
+
"search.expandRest": "… {count} more lines",
|
|
653
|
+
"diff.collapseAria": "Collapse diff",
|
|
654
|
+
"diff.expandAria": "Expand {count} more diff lines",
|
|
655
|
+
"diff.expandRest": "… {count} more lines",
|
|
656
|
+
"diff.files": "{count} files",
|
|
657
|
+
"web.noResults": "No results found",
|
|
658
|
+
"web.sourcesTruncated": "Source list truncated",
|
|
659
|
+
"web.http": "HTTP",
|
|
660
|
+
"web.contentTruncated": "Content truncated",
|
|
661
|
+
"markdown.footnotes": "Footnotes"
|
|
618
662
|
};
|
|
619
663
|
const NS = "merge-tool-calls";
|
|
620
664
|
|
|
@@ -694,6 +738,36 @@ function classifyTool(toolName) {
|
|
|
694
738
|
|
|
695
739
|
//#endregion
|
|
696
740
|
//#region src/client/card-model.ts
|
|
741
|
+
/**
|
|
742
|
+
* Parse the call head paired with one immutable Tool block.
|
|
743
|
+
* @param block - running or settled Tool block.
|
|
744
|
+
* @returns the Tool name and object arguments, or null when unavailable.
|
|
745
|
+
*/
|
|
746
|
+
function parsedArgsOf(block) {
|
|
747
|
+
const call = "kind" in block ? block.call : block;
|
|
748
|
+
if (call === null) return null;
|
|
749
|
+
let value;
|
|
750
|
+
try {
|
|
751
|
+
value = JSON.parse(call.argsRaw);
|
|
752
|
+
} catch {
|
|
753
|
+
return null;
|
|
754
|
+
}
|
|
755
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
|
|
756
|
+
return {
|
|
757
|
+
name: call.name,
|
|
758
|
+
args: value
|
|
759
|
+
};
|
|
760
|
+
}
|
|
761
|
+
/**
|
|
762
|
+
* Read the exact single text block consumed by first-party card derivations.
|
|
763
|
+
* @param block - settled Tool result.
|
|
764
|
+
* @returns its text, or undefined for any other content layout.
|
|
765
|
+
*/
|
|
766
|
+
function singleResultText(block) {
|
|
767
|
+
if (block.content.length !== 1) return void 0;
|
|
768
|
+
const only = block.content[0];
|
|
769
|
+
return only?.type === "text" ? only.text : void 0;
|
|
770
|
+
}
|
|
697
771
|
/** True when a settled terminal card reports a failing exit (mirrors ui-tool). */
|
|
698
772
|
function terminalFailed(model) {
|
|
699
773
|
const { exitCode, signal, running } = model.card;
|
|
@@ -707,7 +781,7 @@ function terminalFailed(model) {
|
|
|
707
781
|
function resultText(node) {
|
|
708
782
|
const parts = [];
|
|
709
783
|
for (const block of node.content) if (block.type === "text") parts.push(block.text);
|
|
710
|
-
else parts.push(JSON.stringify(block));
|
|
784
|
+
else parts.push(JSON.stringify(block, null, 2));
|
|
711
785
|
if (parts.length === 0 && node.error !== void 0) parts.push(`${node.error.name}: ${node.error.code}`);
|
|
712
786
|
return parts.join("\n");
|
|
713
787
|
}
|
|
@@ -722,6 +796,36 @@ function relativizeToCwd(text, cwd) {
|
|
|
722
796
|
if (text.startsWith(`${root}/`) || text.startsWith(`${root}\\`)) return text.slice(root.length + 1);
|
|
723
797
|
return text;
|
|
724
798
|
}
|
|
799
|
+
/**
|
|
800
|
+
* Resolve a Workspace-relative path into the Host-facing spelling (local
|
|
801
|
+
* mirror of `@deepseek-ai/dsh-util-workspace-path`'s `resolveWorkspacePath`:
|
|
802
|
+
* that static utility package is not a dynamic client bundle row, so the
|
|
803
|
+
* browser half carries this one-function copy).
|
|
804
|
+
* @param cwd - Session Workspace root, when known.
|
|
805
|
+
* @param path - Absolute or Workspace-relative path.
|
|
806
|
+
* @returns an absolute path when a Workspace root is available, otherwise the original path.
|
|
807
|
+
*/
|
|
808
|
+
function resolveWorkspacePath(cwd, path) {
|
|
809
|
+
if (path.startsWith("/") || /^[A-Za-z]:[/\\]/.test(path) || path.startsWith("\\\\")) return path;
|
|
810
|
+
if (cwd === void 0 || cwd === "") return path;
|
|
811
|
+
return `${cwd.replace(/[/\\]+$/, "")}/${path.replace(/^[/\\]+/, "")}`;
|
|
812
|
+
}
|
|
813
|
+
/**
|
|
814
|
+
* Abbreviate a POSIX home directory for display (local mirror of
|
|
815
|
+
* `@deepseek-ai/dsh-util-workspace-path`'s `abbreviateHomePath`).
|
|
816
|
+
* @param path - Absolute or already-short display path.
|
|
817
|
+
* @param home - Host account home; absent skips abbreviation.
|
|
818
|
+
* @returns `~` or `~/…` for the POSIX home and its descendants, otherwise `path`.
|
|
819
|
+
*/
|
|
820
|
+
function abbreviateHomePath(path, home) {
|
|
821
|
+
if (home === void 0 || home === "") return path;
|
|
822
|
+
if (/^[A-Za-z]:[/\\]/.test(path) || path.startsWith("\\\\") || /^[A-Za-z]:[/\\]/.test(home) || home.startsWith("\\\\")) return path;
|
|
823
|
+
const root = home.replace(/\/+$/, "");
|
|
824
|
+
if (root === "" || root === "/") return path;
|
|
825
|
+
if (path.replace(/\/+$/, "") === root) return "~";
|
|
826
|
+
if (path.startsWith(`${root}/`)) return `~${path.slice(root.length)}`;
|
|
827
|
+
return path;
|
|
828
|
+
}
|
|
725
829
|
function parseArgs(argsRaw) {
|
|
726
830
|
try {
|
|
727
831
|
const parsed = JSON.parse(argsRaw);
|
|
@@ -757,6 +861,10 @@ const SUMMARY_KEYS = {
|
|
|
757
861
|
function deriveSummary(variant, argsRaw) {
|
|
758
862
|
const parsed = parseArgs(argsRaw);
|
|
759
863
|
if (parsed === void 0) return firstLine(argsRaw);
|
|
864
|
+
if (variant === "search" && Array.isArray(parsed.queries)) {
|
|
865
|
+
const queries = parsed.queries.filter((query) => typeof query === "string" && query !== "");
|
|
866
|
+
if (queries.length > 0) return queries.map(firstLine).join(", ");
|
|
867
|
+
}
|
|
760
868
|
const picked = pickString(parsed, SUMMARY_KEYS[variant]);
|
|
761
869
|
if (picked !== void 0) return firstLine(picked);
|
|
762
870
|
for (const value of Object.values(parsed)) if (typeof value === "string" && value !== "") return firstLine(value);
|
|
@@ -787,23 +895,23 @@ function deriveBody(variant, argsRaw) {
|
|
|
787
895
|
return JSON.stringify(parsed, null, 2);
|
|
788
896
|
}
|
|
789
897
|
/** Derive the row model for one call of a grouped tool. */
|
|
790
|
-
function callRowModel(toolName, block, cwd) {
|
|
898
|
+
function callRowModel(toolName, block, cwd, home) {
|
|
791
899
|
const done = "kind" in block;
|
|
792
900
|
const argsRaw = (done ? block.call?.argsRaw : block.argsRaw) ?? "";
|
|
793
901
|
const state = !done ? "running" : block.error?.code === "interrupted" ? "stopped" : block.isError ? "error" : "ok";
|
|
794
902
|
const variant = classifyTool(toolName);
|
|
795
903
|
const terminal = terminalCardOf(block, cwd);
|
|
796
|
-
const read = readCardOf(block, cwd);
|
|
904
|
+
const read = readCardOf(block, cwd, home);
|
|
797
905
|
const diff = diffCardOf(block);
|
|
798
906
|
const search = searchCardOf(block);
|
|
799
907
|
const web = webCardOf(block);
|
|
800
|
-
const base = argsRaw === "" ? block.callId : relativizeToCwd(deriveSummary(variant, argsRaw), cwd);
|
|
908
|
+
const base = argsRaw === "" ? block.callId : abbreviateHomePath(relativizeToCwd(deriveSummary(variant, argsRaw), cwd), home);
|
|
801
909
|
const toolTitle = TOOL_TITLES[toolName];
|
|
802
910
|
const argsSummary = variant === "others" && toolName !== "" && toolTitle === void 0 ? `${toolName} · ${base}` : base;
|
|
803
911
|
const filePath = deriveFilePath(variant, argsRaw);
|
|
804
912
|
const output = done ? resultText(block) || null : null;
|
|
805
913
|
const errorSummary = state === "error" && output !== null ? firstLine(output) : null;
|
|
806
|
-
const summary = terminal?.description ??
|
|
914
|
+
const summary = terminal?.description ?? argsSummary;
|
|
807
915
|
const body = filePath !== void 0 ? null : deriveBody(variant, argsRaw);
|
|
808
916
|
const finalState = state === "ok" && terminal !== null && terminalFailed(terminal) ? "error" : state;
|
|
809
917
|
const expandable = terminal !== null || diff !== null || read !== null || search !== null || web !== null || body !== null || output !== null;
|
|
@@ -825,20 +933,50 @@ function callRowModel(toolName, block, cwd) {
|
|
|
825
933
|
};
|
|
826
934
|
}
|
|
827
935
|
/** Read-card derivation, or null when this call is not a read card (mirrors ui-tool). */
|
|
828
|
-
function readCardOf(block, cwd) {
|
|
829
|
-
if (!("kind" in block)) return null;
|
|
830
|
-
const
|
|
831
|
-
if (
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
936
|
+
function readCardOf(block, cwd, home) {
|
|
937
|
+
if (block.parentCallId !== void 0 || !("kind" in block) || block.isError) return null;
|
|
938
|
+
const parsed = parsedArgsOf(block);
|
|
939
|
+
if (parsed?.name !== "read") return null;
|
|
940
|
+
const { file_path: path, offset, limit } = parsed.args;
|
|
941
|
+
if (typeof path !== "string" || path.trim() === "") return null;
|
|
942
|
+
if (offset !== void 0 && (typeof offset !== "number" || !Number.isInteger(offset) || offset < 1)) return null;
|
|
943
|
+
if (limit !== void 0 && (typeof limit !== "number" || !Number.isInteger(limit) || limit < 1)) return null;
|
|
944
|
+
const meta = readMeta(block.meta);
|
|
945
|
+
if (meta === null) return null;
|
|
946
|
+
const text = singleResultText(block);
|
|
947
|
+
if (text === void 0) return null;
|
|
948
|
+
if (/^<path>[^\n]*<\/path>\n<type>file<\/type>\n<content>\n([\s\S]*)\n<\/content>$/u.exec(text)?.[1] === void 0) return null;
|
|
949
|
+
return {
|
|
950
|
+
label: abbreviateHomePath(relativizeToCwd(meta.path, cwd), home),
|
|
951
|
+
lines: meta.lines,
|
|
952
|
+
totalLines: meta.totalLines,
|
|
953
|
+
lang: meta.lang
|
|
954
|
+
};
|
|
955
|
+
}
|
|
956
|
+
function readMeta(meta) {
|
|
957
|
+
if (typeof meta !== "object" || meta === null || Array.isArray(meta)) return null;
|
|
958
|
+
const { path, offset, lines, totalLines, lang } = meta;
|
|
959
|
+
if (typeof path !== "string" || typeof offset !== "number" || !Number.isInteger(offset) || offset < 1) return null;
|
|
960
|
+
if (typeof totalLines !== "number" || !Number.isInteger(totalLines) || totalLines < 0 || !Array.isArray(lines)) return null;
|
|
961
|
+
if (lang !== void 0 && typeof lang !== "string") return null;
|
|
962
|
+
const narrowed = [];
|
|
963
|
+
let previous = offset - 1;
|
|
964
|
+
for (const line of lines) {
|
|
965
|
+
if (typeof line !== "object" || line === null || Array.isArray(line)) return null;
|
|
966
|
+
const { number, text } = line;
|
|
967
|
+
if (typeof number !== "number" || !Number.isInteger(number) || number < 1 || number <= previous) return null;
|
|
968
|
+
if (number > totalLines || typeof text !== "string") return null;
|
|
969
|
+
previous = number;
|
|
970
|
+
narrowed.push({
|
|
971
|
+
number,
|
|
972
|
+
text
|
|
973
|
+
});
|
|
974
|
+
}
|
|
837
975
|
return {
|
|
838
|
-
|
|
839
|
-
lines,
|
|
840
|
-
totalLines
|
|
841
|
-
lang
|
|
976
|
+
path,
|
|
977
|
+
lines: narrowed,
|
|
978
|
+
totalLines,
|
|
979
|
+
...lang === void 0 ? {} : { lang }
|
|
842
980
|
};
|
|
843
981
|
}
|
|
844
982
|
function isValidFiles(files) {
|
|
@@ -850,39 +988,50 @@ function flattenContent(content) {
|
|
|
850
988
|
}
|
|
851
989
|
/** Search-card derivation, or null when this call is not a search card (mirrors ui-tool). */
|
|
852
990
|
function searchCardOf(block) {
|
|
853
|
-
if (!("kind" in block)) return null;
|
|
854
|
-
const
|
|
855
|
-
if (
|
|
991
|
+
if (block.parentCallId !== void 0 || !("kind" in block) || block.isError) return null;
|
|
992
|
+
const parsed = parsedArgsOf(block);
|
|
993
|
+
if (parsed === null || parsed.name !== "grep" && parsed.name !== "glob") return null;
|
|
994
|
+
const { pattern, path } = parsed.args;
|
|
995
|
+
if (typeof pattern !== "string") return null;
|
|
996
|
+
if (parsed.name === "grep" && pattern === "") return null;
|
|
997
|
+
if (parsed.name === "glob" && pattern.trim() === "") return null;
|
|
998
|
+
if (path !== void 0 && (typeof path !== "string" || path.trim() === "")) return null;
|
|
999
|
+
if (parsed.name === "grep") {
|
|
1000
|
+
const include = parsed.args.include;
|
|
1001
|
+
if (include !== void 0 && typeof include !== "string") return null;
|
|
1002
|
+
}
|
|
1003
|
+
if (typeof block.meta !== "object" || block.meta === null || Array.isArray(block.meta)) return null;
|
|
1004
|
+
const meta = block.meta;
|
|
1005
|
+
if (typeof meta.truncated !== "boolean") return null;
|
|
1006
|
+
if (typeof meta.total !== "number" || !Number.isInteger(meta.total) || meta.total < 0) return null;
|
|
856
1007
|
const common = {
|
|
857
|
-
truncated:
|
|
858
|
-
total:
|
|
1008
|
+
truncated: meta.truncated,
|
|
1009
|
+
total: meta.total
|
|
859
1010
|
};
|
|
860
|
-
const recovery =
|
|
861
|
-
if (
|
|
862
|
-
if (!isValidFiles(
|
|
1011
|
+
const recovery = meta.truncated ? flattenContent(block.content) : void 0;
|
|
1012
|
+
if (meta.shape === "matches") {
|
|
1013
|
+
if (!isValidFiles(meta.files)) return null;
|
|
863
1014
|
return {
|
|
864
|
-
title: result.title,
|
|
865
1015
|
recovery,
|
|
866
1016
|
card: {
|
|
867
1017
|
kind: "matches",
|
|
868
|
-
files:
|
|
1018
|
+
files: meta.files,
|
|
869
1019
|
...common
|
|
870
1020
|
}
|
|
871
1021
|
};
|
|
872
1022
|
}
|
|
873
|
-
if (
|
|
874
|
-
if (!Array.isArray(
|
|
1023
|
+
if (meta.shape !== "paths") return null;
|
|
1024
|
+
if (!Array.isArray(meta.paths) || !meta.paths.every((path$1) => typeof path$1 === "string")) return null;
|
|
875
1025
|
return {
|
|
876
|
-
title: result.title,
|
|
877
1026
|
recovery,
|
|
878
1027
|
card: {
|
|
879
1028
|
kind: "paths",
|
|
880
|
-
paths:
|
|
1029
|
+
paths: meta.paths,
|
|
881
1030
|
...common
|
|
882
1031
|
}
|
|
883
1032
|
};
|
|
884
1033
|
}
|
|
885
|
-
/** Narrow a
|
|
1034
|
+
/** Narrow a result metadata `diffs` to well-formed hunks (mirrors ui-tool). */
|
|
886
1035
|
function narrowDiffs(diffs) {
|
|
887
1036
|
if (!Array.isArray(diffs) || diffs.length === 0) return null;
|
|
888
1037
|
const out = [];
|
|
@@ -900,86 +1049,262 @@ function narrowDiffs(diffs) {
|
|
|
900
1049
|
}
|
|
901
1050
|
return out;
|
|
902
1051
|
}
|
|
1052
|
+
function intendedDiff(block) {
|
|
1053
|
+
const parsed = parsedArgsOf(block);
|
|
1054
|
+
if (parsed === null) return null;
|
|
1055
|
+
if (parsed.name === "str_replace_editor") {
|
|
1056
|
+
const { command, path: path$1, file_text: fileText, old_str: oldText$1, new_str: newText$1 } = parsed.args;
|
|
1057
|
+
if (typeof path$1 !== "string" || path$1.trim() === "") return null;
|
|
1058
|
+
if (command === "create") {
|
|
1059
|
+
if (fileText !== void 0 && typeof fileText !== "string") return null;
|
|
1060
|
+
return {
|
|
1061
|
+
tool: "str_replace_editor",
|
|
1062
|
+
diff: {
|
|
1063
|
+
path: path$1,
|
|
1064
|
+
oldText: null,
|
|
1065
|
+
newText: fileText ?? ""
|
|
1066
|
+
}
|
|
1067
|
+
};
|
|
1068
|
+
}
|
|
1069
|
+
if (command === "str_replace") {
|
|
1070
|
+
if (oldText$1 !== void 0 && typeof oldText$1 !== "string") return null;
|
|
1071
|
+
if (newText$1 !== void 0 && typeof newText$1 !== "string") return null;
|
|
1072
|
+
return {
|
|
1073
|
+
tool: "str_replace_editor",
|
|
1074
|
+
diff: {
|
|
1075
|
+
path: path$1,
|
|
1076
|
+
oldText: oldText$1 ?? null,
|
|
1077
|
+
newText: newText$1 ?? ""
|
|
1078
|
+
}
|
|
1079
|
+
};
|
|
1080
|
+
}
|
|
1081
|
+
return null;
|
|
1082
|
+
}
|
|
1083
|
+
const { file_path: path } = parsed.args;
|
|
1084
|
+
if (typeof path !== "string" || path.trim() === "") return null;
|
|
1085
|
+
if (parsed.name === "write") {
|
|
1086
|
+
const { content } = parsed.args;
|
|
1087
|
+
return typeof content === "string" ? {
|
|
1088
|
+
tool: "write",
|
|
1089
|
+
diff: {
|
|
1090
|
+
path,
|
|
1091
|
+
oldText: null,
|
|
1092
|
+
newText: content
|
|
1093
|
+
}
|
|
1094
|
+
} : null;
|
|
1095
|
+
}
|
|
1096
|
+
if (parsed.name !== "edit") return null;
|
|
1097
|
+
const { old_string: oldText, new_string: newText, replace_all: replaceAll } = parsed.args;
|
|
1098
|
+
if (typeof oldText !== "string" || typeof newText !== "string") return null;
|
|
1099
|
+
if (replaceAll !== void 0 && typeof replaceAll !== "boolean") return null;
|
|
1100
|
+
return {
|
|
1101
|
+
tool: "edit",
|
|
1102
|
+
diff: {
|
|
1103
|
+
path,
|
|
1104
|
+
oldText: oldText || null,
|
|
1105
|
+
newText
|
|
1106
|
+
}
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1109
|
+
function appliedDiffs(meta) {
|
|
1110
|
+
if (typeof meta !== "object" || meta === null || Array.isArray(meta)) return null;
|
|
1111
|
+
const diffs = meta.diffs;
|
|
1112
|
+
if (!Array.isArray(diffs)) return null;
|
|
1113
|
+
if (diffs.length === 0) return "empty";
|
|
1114
|
+
return narrowDiffs(diffs);
|
|
1115
|
+
}
|
|
903
1116
|
/** Diff-card derivation, or null when this call is not a diff card (mirrors ui-tool). */
|
|
904
1117
|
function diffCardOf(block) {
|
|
905
|
-
if (
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
1118
|
+
if (block.parentCallId !== void 0) return null;
|
|
1119
|
+
const intended = intendedDiff(block);
|
|
1120
|
+
if (intended === null) return null;
|
|
1121
|
+
if (!("kind" in block)) return { card: { diffs: [intended.diff] } };
|
|
1122
|
+
if (intended.tool === "str_replace_editor") return null;
|
|
1123
|
+
if (block.isError) return null;
|
|
1124
|
+
const applied = appliedDiffs(block.meta);
|
|
1125
|
+
if (applied === null || applied === "empty") return intended.tool === "write" ? { card: { diffs: [intended.diff] } } : null;
|
|
1126
|
+
return { card: { diffs: applied } };
|
|
1127
|
+
}
|
|
1128
|
+
function shellCallOf(name, args) {
|
|
1129
|
+
if (name !== "bash" && name !== "pwsh") return null;
|
|
1130
|
+
const { command, description, timeoutMs, workdir, run_in_background: background } = args;
|
|
1131
|
+
if (typeof command !== "string" || command.trim() === "") return null;
|
|
1132
|
+
if (timeoutMs !== void 0 && (typeof timeoutMs !== "number" || !Number.isFinite(timeoutMs) || timeoutMs <= 0)) return null;
|
|
1133
|
+
if (workdir !== void 0 && typeof workdir !== "string") return null;
|
|
1134
|
+
if (background !== void 0 && typeof background !== "boolean") return null;
|
|
1135
|
+
if (description === void 0) return {
|
|
1136
|
+
command,
|
|
1137
|
+
description: void 0,
|
|
1138
|
+
workdir: void 0,
|
|
1139
|
+
persistent: true,
|
|
1140
|
+
background: false
|
|
1141
|
+
};
|
|
1142
|
+
if (typeof description !== "string" || description.trim() === "") return null;
|
|
1143
|
+
return {
|
|
1144
|
+
command,
|
|
1145
|
+
description,
|
|
1146
|
+
workdir,
|
|
1147
|
+
persistent: false,
|
|
1148
|
+
background: background === true
|
|
1149
|
+
};
|
|
1150
|
+
}
|
|
1151
|
+
/**
|
|
1152
|
+
* Parse the result text's trailing exit-status marker (mirrors the shell
|
|
1153
|
+
* renderer's literal contract without importing that Host-only package).
|
|
1154
|
+
* @param text - rendered shell result text.
|
|
1155
|
+
* @returns output with a trailing exit-code or signal marker extracted.
|
|
1156
|
+
*/
|
|
1157
|
+
function parseExitStatus(text) {
|
|
1158
|
+
const signal = /\n\[killed by signal: ([^\]\n]+)\]$/.exec(text);
|
|
1159
|
+
if (signal?.[1] !== void 0) return {
|
|
1160
|
+
output: text.slice(0, signal.index),
|
|
1161
|
+
signal: signal[1]
|
|
1162
|
+
};
|
|
1163
|
+
const exit = /\n\[exit code: (\d+)\]$/.exec(text);
|
|
1164
|
+
if (exit?.[1] !== void 0) return {
|
|
1165
|
+
output: text.slice(0, exit.index),
|
|
1166
|
+
exitCode: Number(exit[1])
|
|
1167
|
+
};
|
|
1168
|
+
return {
|
|
1169
|
+
output: text,
|
|
1170
|
+
exitCode: 0
|
|
1171
|
+
};
|
|
1172
|
+
}
|
|
1173
|
+
/**
|
|
1174
|
+
* Collapse `.` and `..` segments so the prompt label names the directory the
|
|
1175
|
+
* command actually ran in (local mirror of ui-tool's terminal normalization).
|
|
1176
|
+
* @param path - a joined or absolute path, possibly carrying `.`/`..` segments.
|
|
1177
|
+
* @returns the same path with those segments resolved.
|
|
1178
|
+
*/
|
|
1179
|
+
function normalizeSegments(path) {
|
|
1180
|
+
if (!/(?:^|[/\\])\.\.?(?:[/\\]|$)/.test(path)) return path;
|
|
1181
|
+
const separator = path.includes("\\") && !path.includes("/") ? "\\" : "/";
|
|
1182
|
+
const rooted = /^[/\\]/.test(path);
|
|
1183
|
+
const drive = /^[A-Za-z]:/.exec(path)?.[0] ?? "";
|
|
1184
|
+
const body = collapse(path.slice(drive.length), rooted || drive !== "", separator);
|
|
1185
|
+
const leading = rooted ? separator : "";
|
|
1186
|
+
return drive === "" ? `${leading}${body}` : `${drive}${rooted ? leading : separator}${body}`;
|
|
1187
|
+
}
|
|
1188
|
+
function collapse(body, rooted, separator = "/") {
|
|
1189
|
+
const kept = [];
|
|
1190
|
+
for (const segment of body.split(/[/\\]/)) {
|
|
1191
|
+
if (segment === "" || segment === ".") continue;
|
|
1192
|
+
if (segment === "..") {
|
|
1193
|
+
if (kept.length > 0 && kept[kept.length - 1] !== "..") kept.pop();
|
|
1194
|
+
else if (!rooted) kept.push(segment);
|
|
1195
|
+
continue;
|
|
1196
|
+
}
|
|
1197
|
+
kept.push(segment);
|
|
909
1198
|
}
|
|
910
|
-
|
|
911
|
-
const diffs = result === null ? null : narrowDiffs(result.diffs);
|
|
912
|
-
return diffs === null ? null : { card: { diffs } };
|
|
1199
|
+
return kept.join(separator);
|
|
913
1200
|
}
|
|
914
1201
|
/**
|
|
915
|
-
* Resolve a
|
|
916
|
-
*
|
|
917
|
-
*
|
|
918
|
-
* @param
|
|
1202
|
+
* Resolve a shell call's workdir for display: an absolute path is used as-is,
|
|
1203
|
+
* a relative one joins under the session workspace, and an omitted one IS the
|
|
1204
|
+
* session workspace.
|
|
1205
|
+
* @param workdir - the raw call's workdir, if any.
|
|
919
1206
|
* @param sessionCwd - the session workspace root, if the caller knows it.
|
|
920
1207
|
* @returns the working directory for the prompt label, or undefined.
|
|
921
1208
|
*/
|
|
922
|
-
function resolveTerminalCwd(
|
|
923
|
-
if (
|
|
924
|
-
if (sessionCwd === void 0 || sessionCwd === "") return
|
|
925
|
-
return (
|
|
1209
|
+
function resolveTerminalCwd(workdir, sessionCwd) {
|
|
1210
|
+
if (workdir === void 0 || workdir === "") return sessionCwd;
|
|
1211
|
+
if (sessionCwd === void 0 || sessionCwd === "") return normalizeSegments(workdir);
|
|
1212
|
+
return normalizeSegments(resolveWorkspacePath(sessionCwd, workdir));
|
|
926
1213
|
}
|
|
927
1214
|
/** Terminal-card derivation, or null when this call is not a terminal card (mirrors ui-tool). */
|
|
928
1215
|
function terminalCardOf(block, sessionCwd) {
|
|
929
|
-
|
|
930
|
-
|
|
1216
|
+
if (block.parentCallId !== void 0) return null;
|
|
1217
|
+
const parsed = parsedArgsOf(block);
|
|
1218
|
+
if (parsed === null) return null;
|
|
1219
|
+
if (parsed.name !== "bash" && parsed.name !== "pwsh") return null;
|
|
1220
|
+
const call = shellCallOf(parsed.name, parsed.args);
|
|
1221
|
+
if (call === null || call.background) return null;
|
|
1222
|
+
const cwd = resolveTerminalCwd(call.workdir, sessionCwd);
|
|
1223
|
+
if (!("kind" in block)) return {
|
|
931
1224
|
description: call.description,
|
|
932
1225
|
card: {
|
|
933
|
-
command: call.
|
|
934
|
-
cwd
|
|
1226
|
+
command: call.command,
|
|
1227
|
+
cwd,
|
|
935
1228
|
output: void 0,
|
|
936
1229
|
exitCode: void 0,
|
|
937
1230
|
signal: void 0,
|
|
938
1231
|
running: true
|
|
939
1232
|
}
|
|
940
1233
|
};
|
|
941
|
-
|
|
942
|
-
|
|
1234
|
+
if (block.isError || call.persistent) return null;
|
|
1235
|
+
const output = singleResultText(block);
|
|
1236
|
+
if (output === void 0) return null;
|
|
1237
|
+
const status = parseExitStatus(output);
|
|
943
1238
|
return {
|
|
944
|
-
description: call
|
|
1239
|
+
description: call.description,
|
|
945
1240
|
card: {
|
|
946
|
-
command:
|
|
947
|
-
cwd
|
|
948
|
-
output:
|
|
949
|
-
exitCode:
|
|
950
|
-
signal:
|
|
1241
|
+
command: call.command,
|
|
1242
|
+
cwd,
|
|
1243
|
+
output: status.output,
|
|
1244
|
+
exitCode: status.exitCode,
|
|
1245
|
+
signal: status.signal,
|
|
951
1246
|
running: false
|
|
952
1247
|
}
|
|
953
1248
|
};
|
|
954
1249
|
}
|
|
955
1250
|
/** Web-card derivation, or null when this call is not a web card (mirrors ui-tool). */
|
|
956
1251
|
function webCardOf(block) {
|
|
957
|
-
if (!("kind" in block)) return null;
|
|
958
|
-
const
|
|
959
|
-
if (
|
|
960
|
-
if (
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
if (
|
|
1252
|
+
if (block.parentCallId !== void 0 || !("kind" in block) || block.isError) return null;
|
|
1253
|
+
const parsed = parsedArgsOf(block);
|
|
1254
|
+
if (parsed === null) return null;
|
|
1255
|
+
if (parsed.name === "web_search") {
|
|
1256
|
+
const { queries } = parsed.args;
|
|
1257
|
+
if (!Array.isArray(queries) || queries.length === 0) return null;
|
|
1258
|
+
if (!queries.every((query) => typeof query === "string" && query.trim() !== "")) return null;
|
|
1259
|
+
} else if (parsed.name === "web_fetch") {
|
|
1260
|
+
const { url } = parsed.args;
|
|
1261
|
+
if (typeof url !== "string" || url.trim() === "") return null;
|
|
1262
|
+
} else return null;
|
|
1263
|
+
if (typeof block.meta !== "object" || block.meta === null || Array.isArray(block.meta)) return null;
|
|
1264
|
+
const meta = block.meta;
|
|
1265
|
+
if (typeof meta.truncated !== "boolean") return null;
|
|
1266
|
+
if (parsed.name === "web_search") {
|
|
1267
|
+
const sources = webSources(meta.sources);
|
|
1268
|
+
if (sources === null || meta.answer !== void 0 && typeof meta.answer !== "string") return null;
|
|
1269
|
+
return {
|
|
1270
|
+
kind: "search",
|
|
1271
|
+
answer: meta.answer,
|
|
1272
|
+
sources,
|
|
1273
|
+
truncated: meta.truncated
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
1276
|
+
if (typeof meta.url !== "string") return null;
|
|
1277
|
+
if (typeof meta.statusCode !== "number" || !Number.isInteger(meta.statusCode)) return null;
|
|
1278
|
+
return {
|
|
972
1279
|
kind: "fetch",
|
|
973
|
-
url:
|
|
974
|
-
statusCode:
|
|
975
|
-
truncated:
|
|
1280
|
+
url: meta.url,
|
|
1281
|
+
statusCode: meta.statusCode,
|
|
1282
|
+
truncated: meta.truncated
|
|
976
1283
|
};
|
|
977
|
-
|
|
1284
|
+
}
|
|
1285
|
+
function webSources(value) {
|
|
1286
|
+
if (!Array.isArray(value)) return null;
|
|
1287
|
+
const sources = [];
|
|
1288
|
+
for (const source of value) {
|
|
1289
|
+
if (typeof source !== "object" || source === null) return null;
|
|
1290
|
+
const { url, title, snippet, publishedAt } = source;
|
|
1291
|
+
if (typeof url !== "string") return null;
|
|
1292
|
+
if (title !== void 0 && typeof title !== "string") return null;
|
|
1293
|
+
if (snippet !== void 0 && typeof snippet !== "string") return null;
|
|
1294
|
+
if (publishedAt !== void 0 && typeof publishedAt !== "string") return null;
|
|
1295
|
+
sources.push({
|
|
1296
|
+
url,
|
|
1297
|
+
...title === void 0 ? {} : { title },
|
|
1298
|
+
...snippet === void 0 ? {} : { snippet },
|
|
1299
|
+
...publishedAt === void 0 ? {} : { publishedAt }
|
|
1300
|
+
});
|
|
1301
|
+
}
|
|
1302
|
+
return sources;
|
|
978
1303
|
}
|
|
979
1304
|
|
|
980
1305
|
//#endregion
|
|
981
1306
|
//#region src/client/merge-run.ts
|
|
982
|
-
/** Tool-call node kind registered by ui-
|
|
1307
|
+
/** Tool-call node kind registered by ui-chat's built-in tool definition. */
|
|
983
1308
|
const TOOL_CALL_KIND = "tool-call";
|
|
984
1309
|
/** Extract a root call block from any chat node, when it is a tool-call node. */
|
|
985
1310
|
function toolRootOf(node) {
|
|
@@ -1004,7 +1329,10 @@ function stepIdOf(node) {
|
|
|
1004
1329
|
* Compute the merged group this call belongs to.
|
|
1005
1330
|
*
|
|
1006
1331
|
* 1. Locates this call's node in the chat order; null when it is not a chat
|
|
1007
|
-
* tool-call node (e.g. a read dispatched as a subcall).
|
|
1332
|
+
* tool-call node (e.g. a read dispatched as a subcall). The node key
|
|
1333
|
+
* format stays a ui-conversation internal, so the seat finds itself by
|
|
1334
|
+
* scanning the store for the tool-call node owning its call id instead of
|
|
1335
|
+
* recomputing the key.
|
|
1008
1336
|
* 2. Walks backward/forward to the maximal consecutive run containing it. A
|
|
1009
1337
|
* call continues the run when it is a grouped tool AND same-tool-same-run:
|
|
1010
1338
|
* the identical wire name, or a sibling of the same known variant family
|
|
@@ -1025,8 +1353,7 @@ function stepIdOf(node) {
|
|
|
1025
1353
|
* @returns the group partition, or null when the call is not a chat tool-call node.
|
|
1026
1354
|
*/
|
|
1027
1355
|
function readRun(order, nodes, myCallId, tools, groupBy, maxGroupSize) {
|
|
1028
|
-
const
|
|
1029
|
-
const myIndex = order.indexOf(myKey);
|
|
1356
|
+
const myIndex = myIndexOf(order, nodes, myCallId);
|
|
1030
1357
|
if (myIndex < 0) return null;
|
|
1031
1358
|
const myRoot = rootAtNode(order, nodes, myIndex);
|
|
1032
1359
|
if (myRoot === null) return null;
|
|
@@ -1061,6 +1388,17 @@ function readRun(order, nodes, myCallId, tools, groupBy, maxGroupSize) {
|
|
|
1061
1388
|
blocks
|
|
1062
1389
|
};
|
|
1063
1390
|
}
|
|
1391
|
+
/** Index in the chat order of the tool-call node owning `callId`; -1 when absent. */
|
|
1392
|
+
function myIndexOf(order, nodes, callId) {
|
|
1393
|
+
for (let index = 0; index < order.length; index++) {
|
|
1394
|
+
const key = order[index];
|
|
1395
|
+
if (key === void 0) continue;
|
|
1396
|
+
const node = nodes.get(key);
|
|
1397
|
+
if (node?.kind !== TOOL_CALL_KIND) continue;
|
|
1398
|
+
if (toolRootOf(node)?.callId === callId) return index;
|
|
1399
|
+
}
|
|
1400
|
+
return -1;
|
|
1401
|
+
}
|
|
1064
1402
|
function rootAtNode(order, nodes, index) {
|
|
1065
1403
|
const key = order[index];
|
|
1066
1404
|
const node = key === void 0 ? void 0 : nodes.get(key);
|
|
@@ -1137,29 +1475,100 @@ function terminalLabels(t) {
|
|
|
1137
1475
|
expand: (hidden) => t("terminal.expandRest", { n: hidden })
|
|
1138
1476
|
};
|
|
1139
1477
|
}
|
|
1478
|
+
/** ReadBlock display copy from the plugin's own dictionary. */
|
|
1479
|
+
function readLabels(t) {
|
|
1480
|
+
return {
|
|
1481
|
+
window: (shown, total) => t("read.window", {
|
|
1482
|
+
shown,
|
|
1483
|
+
total
|
|
1484
|
+
}),
|
|
1485
|
+
copy: t("copy"),
|
|
1486
|
+
copied: t("copied"),
|
|
1487
|
+
collapseAria: t("read.collapseAria"),
|
|
1488
|
+
expandAria: (count) => t("read.expandAria", { count }),
|
|
1489
|
+
collapse: t("collapse"),
|
|
1490
|
+
expand: (count) => t("read.expandRest", { count })
|
|
1491
|
+
};
|
|
1492
|
+
}
|
|
1493
|
+
/** SearchBlock display copy from the plugin's own dictionary. */
|
|
1494
|
+
function searchLabels(t) {
|
|
1495
|
+
return {
|
|
1496
|
+
pathsSummary: (shown, total, truncated) => t(truncated ? "search.paths.truncated" : "search.paths", {
|
|
1497
|
+
shown,
|
|
1498
|
+
total
|
|
1499
|
+
}),
|
|
1500
|
+
matchesSummary: (shown, total, files, truncated) => t(truncated ? "search.matches.truncated" : "search.matches", {
|
|
1501
|
+
shown,
|
|
1502
|
+
total,
|
|
1503
|
+
files
|
|
1504
|
+
}),
|
|
1505
|
+
copy: t("copy"),
|
|
1506
|
+
copied: t("copied"),
|
|
1507
|
+
noResults: t("search.noResults"),
|
|
1508
|
+
collapseAria: t("search.collapseAria"),
|
|
1509
|
+
expandAria: (count) => t("search.expandAria", { count }),
|
|
1510
|
+
collapse: t("collapse"),
|
|
1511
|
+
expand: (count) => t("search.expandRest", { count })
|
|
1512
|
+
};
|
|
1513
|
+
}
|
|
1514
|
+
/** DiffBlock display copy from the plugin's own dictionary. */
|
|
1515
|
+
function diffLabels(t) {
|
|
1516
|
+
return {
|
|
1517
|
+
copy: t("copy"),
|
|
1518
|
+
copied: t("copied"),
|
|
1519
|
+
collapseAria: t("diff.collapseAria"),
|
|
1520
|
+
expandAria: (count) => t("diff.expandAria", { count }),
|
|
1521
|
+
collapse: t("collapse"),
|
|
1522
|
+
expand: (count) => t("diff.expandRest", { count }),
|
|
1523
|
+
files: (count) => t("diff.files", { count })
|
|
1524
|
+
};
|
|
1525
|
+
}
|
|
1526
|
+
/** WebBlock display copy from the plugin's own dictionary. */
|
|
1527
|
+
function webLabels(t) {
|
|
1528
|
+
return {
|
|
1529
|
+
noResults: t("web.noResults"),
|
|
1530
|
+
sourcesTruncated: t("web.sourcesTruncated"),
|
|
1531
|
+
http: t("web.http"),
|
|
1532
|
+
contentTruncated: t("web.contentTruncated"),
|
|
1533
|
+
markdown: {
|
|
1534
|
+
code: {
|
|
1535
|
+
copyLabel: t("copy"),
|
|
1536
|
+
copiedLabel: t("copied")
|
|
1537
|
+
},
|
|
1538
|
+
footnotes: t("markdown.footnotes")
|
|
1539
|
+
}
|
|
1540
|
+
};
|
|
1541
|
+
}
|
|
1140
1542
|
/** One call's expanded-body card, mirroring the built-in ToolRow body. */
|
|
1141
|
-
function CardBody({ model, t }) {
|
|
1543
|
+
function CardBody({ model, home, t }) {
|
|
1142
1544
|
if (model.terminal !== null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_primitives.TerminalBlock, {
|
|
1143
1545
|
...model.terminal.card,
|
|
1546
|
+
home,
|
|
1144
1547
|
maxLines: Infinity,
|
|
1145
1548
|
labels: terminalLabels(t)
|
|
1146
1549
|
});
|
|
1147
1550
|
if (model.diff !== null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_primitives.DiffBlock, {
|
|
1148
1551
|
...model.diff.card,
|
|
1552
|
+
labels: diffLabels(t),
|
|
1149
1553
|
maxLines: CHAT_DIFF_MAX_LINES
|
|
1150
1554
|
});
|
|
1151
1555
|
if (model.read !== null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_primitives.ReadBlock, {
|
|
1152
1556
|
...model.read,
|
|
1557
|
+
labels: readLabels(t),
|
|
1153
1558
|
maxLines: CHAT_READ_MAX_LINES
|
|
1154
1559
|
});
|
|
1155
1560
|
if (model.search !== null) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_primitives.SearchBlock, {
|
|
1156
1561
|
...model.search.card,
|
|
1562
|
+
labels: searchLabels(t),
|
|
1157
1563
|
maxLines: CHAT_SEARCH_MAX_LINES
|
|
1158
1564
|
}), model.search.recovery !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1159
1565
|
className: "mtc-recovery",
|
|
1160
1566
|
children: model.search.recovery
|
|
1161
1567
|
})] });
|
|
1162
|
-
if (model.web !== null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_primitives.WebBlock, {
|
|
1568
|
+
if (model.web !== null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_primitives.WebBlock, {
|
|
1569
|
+
...model.web,
|
|
1570
|
+
labels: webLabels(t)
|
|
1571
|
+
});
|
|
1163
1572
|
const hasBody = model.body !== null;
|
|
1164
1573
|
const hasOutput = model.output !== null;
|
|
1165
1574
|
if (!hasBody && !hasOutput) return null;
|
|
@@ -1202,8 +1611,8 @@ function CardBody({ model, t }) {
|
|
|
1202
1611
|
* call is rendered as the first child row so every file path lands on a child
|
|
1203
1612
|
* row, never on the main row.
|
|
1204
1613
|
*/
|
|
1205
|
-
const RowCard = (0, react.memo)(function RowCard$1({ toolName, block, cwd, openFile, inspect, t, mergedCount, children }) {
|
|
1206
|
-
const model = callRowModel(toolName, block, cwd);
|
|
1614
|
+
const RowCard = (0, react.memo)(function RowCard$1({ toolName, block, cwd, home, openFile, inspect, t, mergedCount, children }) {
|
|
1615
|
+
const model = callRowModel(toolName, block, cwd, home);
|
|
1207
1616
|
const [expanded, setExpanded] = (0, react.useState)(false);
|
|
1208
1617
|
const hasChildren = mergedCount > 0;
|
|
1209
1618
|
const expandable = model.expandable || hasChildren;
|
|
@@ -1256,6 +1665,7 @@ const RowCard = (0, react.memo)(function RowCard$1({ toolName, block, cwd, openF
|
|
|
1256
1665
|
className: "mtc-card-body",
|
|
1257
1666
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(CardBody, {
|
|
1258
1667
|
model,
|
|
1668
|
+
home,
|
|
1259
1669
|
t
|
|
1260
1670
|
}), inspect !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1261
1671
|
type: "button",
|
|
@@ -1289,8 +1699,8 @@ const RowCard = (0, react.memo)(function RowCard$1({ toolName, block, cwd, openF
|
|
|
1289
1699
|
* renders as an open-file link (the sidebar preview) that stops propagation,
|
|
1290
1700
|
* exactly like the main row's summary link.
|
|
1291
1701
|
*/
|
|
1292
|
-
const ChildRow = (0, react.memo)(function ChildRow$1({ toolName, block, cwd, openFile, t }) {
|
|
1293
|
-
const model = callRowModel(toolName, block, cwd);
|
|
1702
|
+
const ChildRow = (0, react.memo)(function ChildRow$1({ toolName, block, cwd, home, openFile, t }) {
|
|
1703
|
+
const model = callRowModel(toolName, block, cwd, home);
|
|
1294
1704
|
const [open, setOpen] = (0, react.useState)(false);
|
|
1295
1705
|
const stateLabel = stateStatus(model.state, t);
|
|
1296
1706
|
const expandable = model.expandable;
|
|
@@ -1342,6 +1752,7 @@ const ChildRow = (0, react.memo)(function ChildRow$1({ toolName, block, cwd, ope
|
|
|
1342
1752
|
className: "mtc-child-body",
|
|
1343
1753
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CardBody, {
|
|
1344
1754
|
model,
|
|
1755
|
+
home,
|
|
1345
1756
|
t
|
|
1346
1757
|
})
|
|
1347
1758
|
})]
|
|
@@ -1359,8 +1770,8 @@ const ChildRow = (0, react.memo)(function ChildRow$1({ toolName, block, cwd, ope
|
|
|
1359
1770
|
* and indents the children so their dots and paths land on the main row's
|
|
1360
1771
|
* columns — no font/title constants to keep in sync.
|
|
1361
1772
|
*/
|
|
1362
|
-
function MergedToolRow({ callId, toolName, block, cwd, openFile, inspect, t, cfg,
|
|
1363
|
-
const run =
|
|
1773
|
+
function MergedToolRow({ callId, toolName, block, cwd, home, openFile, inspect, t, cfg, useChat }) {
|
|
1774
|
+
const run = useChat((snapshot) => readRun(snapshot.order, snapshot.nodes, callId, cfg.tools, cfg.groupBy, cfg.maxGroupSize));
|
|
1364
1775
|
const rootRef = (0, react.useRef)(null);
|
|
1365
1776
|
/** Main separator dot's left offset from the card root; null before first measure. */
|
|
1366
1777
|
const [sepLeft, setSepLeft] = (0, react.useState)(null);
|
|
@@ -1383,6 +1794,7 @@ function MergedToolRow({ callId, toolName, block, cwd, openFile, inspect, t, cfg
|
|
|
1383
1794
|
toolName,
|
|
1384
1795
|
block,
|
|
1385
1796
|
cwd,
|
|
1797
|
+
home,
|
|
1386
1798
|
openFile,
|
|
1387
1799
|
inspect,
|
|
1388
1800
|
t,
|
|
@@ -1399,6 +1811,7 @@ function MergedToolRow({ callId, toolName, block, cwd, openFile, inspect, t, cfg
|
|
|
1399
1811
|
toolName,
|
|
1400
1812
|
block: run.blocks[0] ?? block,
|
|
1401
1813
|
cwd,
|
|
1814
|
+
home,
|
|
1402
1815
|
openFile,
|
|
1403
1816
|
inspect,
|
|
1404
1817
|
t,
|
|
@@ -1407,6 +1820,7 @@ function MergedToolRow({ callId, toolName, block, cwd, openFile, inspect, t, cfg
|
|
|
1407
1820
|
toolName,
|
|
1408
1821
|
block: child,
|
|
1409
1822
|
cwd,
|
|
1823
|
+
home,
|
|
1410
1824
|
openFile,
|
|
1411
1825
|
t
|
|
1412
1826
|
}, child.callId))
|