源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { buildAgentTurnSummaryPatchDiff } from "./agentTurnSummaryPatchDiff";
|
||||
import { isAgentUnifiedDiffText } from "./agentUnifiedDiffValidation";
|
||||
|
||||
describe("buildAgentTurnSummaryPatchDiff", () => {
|
||||
it("wraps cwd-relative hunk diffs with git headers", () => {
|
||||
const diff = buildAgentTurnSummaryPatchDiff({
|
||||
cwd: "/workspace/project",
|
||||
toolCallId: "call-1",
|
||||
changes: [
|
||||
{
|
||||
path: "/workspace/project/src/app.ts",
|
||||
changeType: "modified",
|
||||
unifiedDiff: "@@ -1 +1 @@\n-old\n+new"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
expect(diff).toBe(
|
||||
"diff --git a/src/app.ts b/src/app.ts\n--- a/src/app.ts\n+++ b/src/app.ts\n@@ -1 +1 @@\n-old\n+new\n"
|
||||
);
|
||||
});
|
||||
|
||||
it("generates add-file diffs from created content", () => {
|
||||
const diff = buildAgentTurnSummaryPatchDiff({
|
||||
cwd: "/workspace/project",
|
||||
toolCallId: "call-1",
|
||||
changes: [
|
||||
{
|
||||
path: "/workspace/project/src/new.ts",
|
||||
changeType: "created",
|
||||
content: "export const ready = true;\n"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
expect(diff).toBe(
|
||||
"diff --git a/src/new.ts b/src/new.ts\nnew file mode 100644\n--- /dev/null\n+++ b/src/new.ts\n@@ -0,0 +1,1 @@\n+export const ready = true;\n"
|
||||
);
|
||||
});
|
||||
|
||||
it("makes Windows absolute paths relative to the patch cwd", () => {
|
||||
const diff = buildAgentTurnSummaryPatchDiff({
|
||||
cwd: "C:\\Users\\17940\\Documents\\tutti\\test_git",
|
||||
toolCallId: "call-1",
|
||||
changes: [
|
||||
{
|
||||
path: "C:/Users/17940/Documents/tutti/test_git/today.txt",
|
||||
changeType: "created",
|
||||
content: "2026-08-12\n"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
expect(diff).toBe(
|
||||
"diff --git a/today.txt b/today.txt\nnew file mode 100644\n--- /dev/null\n+++ b/today.txt\n@@ -0,0 +1,1 @@\n+2026-08-12\n"
|
||||
);
|
||||
});
|
||||
|
||||
it("rebases Windows paths in complete unified diffs case-insensitively", () => {
|
||||
const absolutePath = "C:/Users/17940/Documents/tutti/test_git/today.txt";
|
||||
const diff = buildAgentTurnSummaryPatchDiff({
|
||||
cwd: "c:/users/17940/documents/tutti/test_git",
|
||||
toolCallId: "call-1",
|
||||
changes: [
|
||||
{
|
||||
path: absolutePath,
|
||||
changeType: "modified",
|
||||
unifiedDiff: [
|
||||
`diff --git a/${absolutePath} b/${absolutePath}`,
|
||||
`--- a/${absolutePath}`,
|
||||
`+++ b/${absolutePath}`,
|
||||
"@@ -1,2 +1,2 @@",
|
||||
"--- old option",
|
||||
"+++ new option",
|
||||
"-old",
|
||||
"+new"
|
||||
].join("\n")
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
expect(diff).toBe(
|
||||
"diff --git a/today.txt b/today.txt\n--- a/today.txt\n+++ b/today.txt\n@@ -1,2 +1,2 @@\n--- old option\n+++ new option\n-old\n+new\n"
|
||||
);
|
||||
});
|
||||
|
||||
it("builds a valid zero-old-count patch for the reported Kimi empty-file edit", () => {
|
||||
const content =
|
||||
"这是一个示例文本文件。\n\n当前时间:2026-08-20\n用途:测试文件创建\n\n你可以随时修改或删除此文件。";
|
||||
const diff = buildAgentTurnSummaryPatchDiff({
|
||||
cwd: "C:/Users/17940/Documents/tutti/test_git",
|
||||
toolCallId: "kimi-create-note",
|
||||
changes: [
|
||||
{
|
||||
path: "C:/Users/17940/Documents/tutti/test_git/note.txt",
|
||||
changeType: "modified",
|
||||
oldString: "",
|
||||
newString: content
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
expect(new TextEncoder().encode(content)).toHaveLength(132);
|
||||
expect(new TextEncoder().encode(diff)).toHaveLength(218);
|
||||
expect(diff).toContain("@@ -0,0 +1,6 @@");
|
||||
expect(isAgentUnifiedDiffText(diff)).toBe(true);
|
||||
});
|
||||
|
||||
it("normalizes CRLF while preserving a valid zero-new-count patch", () => {
|
||||
const diff = buildAgentTurnSummaryPatchDiff({
|
||||
cwd: "/workspace/project",
|
||||
toolCallId: "clear-file",
|
||||
changes: [
|
||||
{
|
||||
path: "/workspace/project/note.txt",
|
||||
changeType: "modified",
|
||||
oldString: "first\r\nsecond\r\n",
|
||||
newString: ""
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
expect(diff).toContain("@@ -1,2 +0,0 @@");
|
||||
expect(diff).not.toContain("\r");
|
||||
expect(isAgentUnifiedDiffText(diff)).toBe(true);
|
||||
});
|
||||
|
||||
it("fails closed for binary content without an executable binary diff", () => {
|
||||
const diff = buildAgentTurnSummaryPatchDiff({
|
||||
cwd: "/workspace/project",
|
||||
toolCallId: "binary-write",
|
||||
changes: [
|
||||
{
|
||||
path: "/workspace/project/image.bin",
|
||||
changeType: "modified",
|
||||
oldString: "old\0bytes",
|
||||
newString: "new\0bytes"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
expect(diff).toBe("");
|
||||
});
|
||||
|
||||
it.each([
|
||||
["created", "0000000..e69de29"],
|
||||
["deleted", "e69de29..0000000"]
|
||||
] as const)("builds an exact %s empty-file patch", (changeType, index) => {
|
||||
const diff = buildAgentTurnSummaryPatchDiff({
|
||||
cwd: "/workspace/project",
|
||||
toolCallId: `empty-${changeType}`,
|
||||
changes: [
|
||||
{
|
||||
path: "/workspace/project/empty.txt",
|
||||
changeType,
|
||||
...(changeType === "created"
|
||||
? { newString: "", content: "" }
|
||||
: { oldString: "", content: "" })
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
expect(diff).toContain(`index ${index}`);
|
||||
expect(diff).not.toContain("@@");
|
||||
});
|
||||
it.each([
|
||||
{ oldString: "before\n", newString: undefined },
|
||||
{ oldString: undefined, newString: "after\n" }
|
||||
])(
|
||||
"does not invent a modified-file patch from one-sided content",
|
||||
(change) => {
|
||||
const diff = buildAgentTurnSummaryPatchDiff({
|
||||
cwd: "/workspace/project",
|
||||
toolCallId: "call-1",
|
||||
changes: [
|
||||
{
|
||||
path: "/workspace/project/src/app.ts",
|
||||
changeType: "modified",
|
||||
...change
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
expect(diff).toBe("");
|
||||
}
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user