Merge pull request #2565 from pikasTech/feat/v03-caserun-untracked-diff
Pipelines as Code CI / hwlab-nc01-v03-ci-poll- Success
Pipelines as Code CI / hwlab-nc01-v03-ci-poll- Success
feat: v0.3 CaseRun 收集未跟踪文件差异
This commit is contained in:
@@ -365,6 +365,7 @@ test("case run orchestrates agent prompt, diff capture, and compile evidence wit
|
||||
title: "D601-F103-V2 Keil compile-only CaseRun",
|
||||
hwpodSpec: "hwpod-spec.yaml",
|
||||
subject: { repoLocalPath: SUBJECT_REPO_LOCAL_PATH, commitId: SUBJECT_COMMIT_ID, subdir: "projects/01_baseline" },
|
||||
diffCollection: { ignore: [{ pattern: "build/**", reason: "generated output" }] },
|
||||
agentTask: { workspace: "subjectWorktree", prompt: "请通过 HWPOD 做一个很小的源码修改。", timeoutMs: 234000, pollIntervalMs: 10 },
|
||||
}, null, 2), "utf8");
|
||||
await writeFile(path.join(caseDir, "hwpod-spec.yaml"), hwpodSpecText(), "utf8");
|
||||
@@ -450,6 +451,12 @@ test("case run orchestrates agent prompt, diff capture, and compile evidence wit
|
||||
assert.equal(result.payload.agent.polls <= 3, true);
|
||||
assert.equal(result.payload.evidence.hwpod.source, "case-run-runner-post-agent-compile-check");
|
||||
assert.match(result.payload.agentDiff.statusShort, /projects\/01_baseline\/main\.c/u);
|
||||
assert.deepEqual(result.payload.agentDiff.diffCollection.untracked, { total: 2, included: 1, omitted: 1 });
|
||||
assert.equal(result.payload.agentDiff.diffCollection.included[0].path, "projects/01_baseline/new.c");
|
||||
assert.equal(result.payload.agentDiff.diffCollection.omitted[0].path, "projects/01_baseline/build/out.bin");
|
||||
assert.equal(result.payload.agentDiff.diffCollection.omitted[0].reason, "generated output");
|
||||
assert.match(await readFile(result.payload.agentDiff.diffPatchPath, "utf8"), /diff --git a\/projects\/01_baseline\/new\.c b\/projects\/01_baseline\/new\.c/u);
|
||||
assert.match(await readFile(result.payload.agentDiff.diffPatchPath, "utf8"), /build\/out\.bin rule=build\/\*\*/u);
|
||||
assert.equal(result.payload.build.autoEvaluation, false);
|
||||
assert.equal(result.payload.build.traceLookup.commands.trace, result.payload.traceLookup.commands.trace);
|
||||
assert.equal(result.payload.build.agentTraceHwpodCommandCount, 1);
|
||||
@@ -495,6 +502,7 @@ test("case run orchestrates agent prompt, diff capture, and compile evidence wit
|
||||
assert.equal(manifest.prompt.sha256, result.payload.evidence.agent.promptSha256);
|
||||
assert.equal(manifest.subject.commitId, SUBJECT_COMMIT_ID);
|
||||
assert.equal(manifest.diff.sha256, result.payload.evidence.agentDiff.diffPatchSha256);
|
||||
assert.deepEqual(manifest.diff.collection.untracked, { total: 2, included: 1, omitted: 1 });
|
||||
assert.equal(manifest.readableAgent.renderer, "tools/src/hwlab-cli/trace-renderer:traceDisplayRows");
|
||||
assert.equal(manifest.readableAgent.messagesPath, "agent-messages.json");
|
||||
assert.equal(manifest.readableAgent.tracePath, "agent-trace.md");
|
||||
@@ -941,8 +949,23 @@ function caseRunFlowFetch(requests: any[]) {
|
||||
resultPolls += 1;
|
||||
return new Response(JSON.stringify({ ok: true, status: resultPolls > 1 ? "completed" : "running", reply: { content: "done" } }), { status: 200, headers: { "content-type": "application/json" } });
|
||||
}
|
||||
if (body.ops?.[0]?.args?.command === "node") {
|
||||
return hwpodResponse([{ exitCode: 0, stdout: [
|
||||
JSON.stringify({ path: "projects/01_baseline/new.c", bytes: 21, sha256: "a".repeat(64) }),
|
||||
JSON.stringify({ path: "projects/01_baseline/build/out.bin", bytes: 4096, sha256: "b".repeat(64) })
|
||||
].join("\n") }]);
|
||||
}
|
||||
if (body.ops?.[0]?.args?.argv?.includes("ls-files")) {
|
||||
return hwpodResponse([{ exitCode: 0, stdout: "projects/01_baseline/new.c\nprojects/01_baseline/build/out.bin\n" }]);
|
||||
}
|
||||
if (body.ops?.[0]?.args?.argv?.includes("--no-index") && body.ops[0].args.argv.includes("--stat")) {
|
||||
return hwpodResponse([{ exitCode: 1, stdout: " projects/01_baseline/new.c | 1 +\n" }]);
|
||||
}
|
||||
if (body.ops?.[0]?.args?.argv?.includes("--no-index") && body.ops[0].args.argv.includes("--binary")) {
|
||||
return hwpodResponse([{ exitCode: 1, stdout: "diff --git a/dev/null b/projects/01_baseline/new.c\nnew file mode 100644\n--- a/dev/null\n+++ b/projects/01_baseline/new.c\n@@ -0,0 +1 @@\n+int added = 1;\n" }]);
|
||||
}
|
||||
if (body.ops?.[0]?.args?.argv?.includes("status") && body.ops?.length === 1) {
|
||||
return hwpodResponse([{ exitCode: 0, stdout: body.ops[0].args.argv.includes("--short") ? " M projects/01_baseline/main.c\n" : "" }]);
|
||||
return hwpodResponse([{ exitCode: 0, stdout: body.ops[0].args.argv.includes("--short") ? " M projects/01_baseline/main.c\n?? projects/01_baseline/new.c\n?? projects/01_baseline/build/out.bin\n" : "" }]);
|
||||
}
|
||||
if (body.ops?.[0]?.args?.argv?.includes("--stat")) {
|
||||
return hwpodResponse([{ exitCode: 0, stdout: " projects/01_baseline/main.c | 1 +\n" }]);
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
import { createHash } from "node:crypto";
|
||||
|
||||
type CommandResult = { stdout?: unknown } & Record<string, unknown>;
|
||||
|
||||
export type AgentDiffFileRecord = {
|
||||
path: string;
|
||||
source: "tracked" | "untracked";
|
||||
reason?: string;
|
||||
rule?: string;
|
||||
bytes?: number;
|
||||
sha256?: string;
|
||||
};
|
||||
|
||||
type DiffCollectionRule = { pattern: string; reason: string };
|
||||
|
||||
export type AgentDiffCollectionSummary = {
|
||||
contractVersion: "hwpod-case-run-diff-collection-v1";
|
||||
included: AgentDiffFileRecord[];
|
||||
omitted: AgentDiffFileRecord[];
|
||||
config: { include: DiffCollectionRule[]; ignore: DiffCollectionRule[] };
|
||||
tracked: { paths: string[]; diffStat: string; diffPatchSha256: string };
|
||||
untracked: { total: number; included: number; omitted: number };
|
||||
};
|
||||
|
||||
export async function collectAgentWorkspaceDiff(input: {
|
||||
definition: Record<string, unknown>;
|
||||
subjectSubdir: string;
|
||||
worktreePath: string;
|
||||
statusShort: string;
|
||||
trackedDiffStat: string;
|
||||
trackedPatchText: string;
|
||||
requestGit: (args: string[]) => Promise<CommandResult>;
|
||||
requestProcess: (command: string, args: string[]) => Promise<CommandResult>;
|
||||
}) {
|
||||
const config = diffCollectionConfig(input.definition);
|
||||
const roots = statusPaths(input.statusShort, "??");
|
||||
const requests: Array<{ label: string; result: CommandResult }> = [];
|
||||
const included: AgentDiffFileRecord[] = [];
|
||||
const omitted: AgentDiffFileRecord[] = [];
|
||||
|
||||
if (roots.length > 0) {
|
||||
const lsFiles = await input.requestGit(["ls-files", "--others", "--exclude-standard", "--", ...roots]);
|
||||
requests.push({ label: "untracked-ls-files", result: lsFiles });
|
||||
const paths = unique(text(lsFiles.stdout).split(/\r?\n/u).map(repoPath).filter(Boolean));
|
||||
const metadata = await fileMetadata(input, paths);
|
||||
requests.push(...metadata.requests);
|
||||
for (const filePath of paths) {
|
||||
const decision = classify(filePath, input.subjectSubdir, config);
|
||||
const record = compact({ path: filePath, source: "untracked" as const, reason: decision.reason, rule: decision.rule, ...metadata.records.get(filePath) });
|
||||
(decision.omit ? omitted : included).push(record);
|
||||
}
|
||||
}
|
||||
|
||||
const patches: string[] = [];
|
||||
const stats: string[] = [];
|
||||
for (const file of included) {
|
||||
const stat = await input.requestGit(["diff", "--no-index", "--stat", "--", "/dev/null", file.path]);
|
||||
const patch = await input.requestGit(["diff", "--no-index", "--binary", "--", "/dev/null", file.path]);
|
||||
requests.push({ label: `untracked-diff-stat:${file.path}`, result: stat }, { label: `untracked-diff-patch:${file.path}`, result: patch });
|
||||
stats.push(text(stat.stdout));
|
||||
patches.push(normalizeNewFilePatch(text(patch.stdout), file.path));
|
||||
}
|
||||
|
||||
const collection: AgentDiffCollectionSummary = {
|
||||
contractVersion: "hwpod-case-run-diff-collection-v1",
|
||||
included,
|
||||
omitted,
|
||||
config,
|
||||
tracked: { paths: patchPaths(input.trackedPatchText), diffStat: input.trackedDiffStat, diffPatchSha256: sha256(input.trackedPatchText) },
|
||||
untracked: { total: included.length + omitted.length, included: included.length, omitted: omitted.length }
|
||||
};
|
||||
return {
|
||||
patchText: joinPatch(input.trackedPatchText, patches.join("\n"), omitted),
|
||||
diffStat: joinStat(input.trackedDiffStat, stats.join("\n"), omitted),
|
||||
collection,
|
||||
requests
|
||||
};
|
||||
}
|
||||
|
||||
async function fileMetadata(input: Parameters<typeof collectAgentWorkspaceDiff>[0], paths: string[]) {
|
||||
const records = new Map<string, { bytes?: number; sha256?: string }>();
|
||||
if (paths.length === 0) return { records, requests: [] as Array<{ label: string; result: CommandResult }> };
|
||||
const script = [
|
||||
"const fs=require('fs');const path=require('path');const crypto=require('crypto');",
|
||||
"const root=String(process.argv[1]||'');const files=process.argv.slice(2);",
|
||||
"const abs=p=>/^[A-Za-z]:[\\\\/]/.test(p)||p.startsWith('/')||p.startsWith('\\\\\\\\');",
|
||||
"const full=p=>abs(p)?p:(root.includes('\\\\')?path.win32.join(root,p):path.join(root,p));",
|
||||
"for(const rel of files){try{const buf=fs.readFileSync(full(rel));console.log(JSON.stringify({path:rel,bytes:buf.length,sha256:crypto.createHash('sha256').update(buf).digest('hex')}));}catch(error){console.log(JSON.stringify({path:rel,error:String(error&&error.message||error)}));}}"
|
||||
].join("");
|
||||
const result = await input.requestProcess("node", ["-e", script, input.worktreePath, ...paths]);
|
||||
for (const line of text(result.stdout).split(/\r?\n/u)) {
|
||||
try {
|
||||
const value = JSON.parse(line);
|
||||
const filePath = repoPath(value.path);
|
||||
if (filePath) records.set(filePath, compact({ bytes: Number.isFinite(value.bytes) ? value.bytes : undefined, sha256: text(value.sha256) }));
|
||||
} catch {}
|
||||
}
|
||||
return { records, requests: [{ label: "untracked-file-metadata", result }] };
|
||||
}
|
||||
|
||||
function diffCollectionConfig(definition: Record<string, unknown>) {
|
||||
const raw = record(definition.diffCollection ?? definition.agentDiffCollection);
|
||||
return {
|
||||
include: rules(raw.include ?? raw.includes, "included by CaseRun diff collection rule"),
|
||||
ignore: rules(raw.ignore ?? raw.ignores ?? raw.omit ?? raw.omitted, "omitted by CaseRun diff collection rule")
|
||||
};
|
||||
}
|
||||
|
||||
function rules(value: unknown, defaultReason: string): DiffCollectionRule[] {
|
||||
if (Array.isArray(value)) return value.flatMap((item) => rules(item, defaultReason));
|
||||
if (typeof value === "string") return repoPath(value) ? [{ pattern: repoPath(value), reason: defaultReason }] : [];
|
||||
const raw = record(value);
|
||||
const pattern = text(raw.pattern ?? raw.path ?? raw.glob);
|
||||
if (pattern) return [{ pattern: repoPath(pattern), reason: text(raw.reason) || defaultReason }];
|
||||
return Object.entries(raw).flatMap(([key, item]) => repoPath(key) ? [{ pattern: repoPath(key), reason: typeof item === "string" ? item : text(record(item).reason) || defaultReason }] : []);
|
||||
}
|
||||
|
||||
function classify(filePath: string, subdir: string, config: { include: DiffCollectionRule[]; ignore: DiffCollectionRule[] }) {
|
||||
const candidates = unique([filePath, filePath.startsWith(`${repoPath(subdir)}/`) ? filePath.slice(repoPath(subdir).length + 1) : filePath]);
|
||||
const matches = (rule: DiffCollectionRule) => candidates.some((candidate) => globMatch(rule.pattern, candidate));
|
||||
const include = config.include.find(matches);
|
||||
const ignore = config.ignore.find(matches);
|
||||
if (ignore && !include) return { omit: true, reason: ignore.reason, rule: ignore.pattern };
|
||||
if (include) return { omit: false, reason: include.reason, rule: include.pattern };
|
||||
return { omit: false, reason: "included by default because untracked files are part of the agent diff", rule: "default-include-untracked" };
|
||||
}
|
||||
|
||||
function globMatch(patternInput: string, pathInput: string) {
|
||||
const pattern = repoPath(patternInput);
|
||||
const filePath = repoPath(pathInput);
|
||||
if (!pattern || !filePath) return false;
|
||||
if (!/[?*]/u.test(pattern)) return filePath === pattern || filePath.startsWith(`${pattern}/`);
|
||||
if (pattern.endsWith("/**") && filePath === pattern.slice(0, -3)) return true;
|
||||
let source = "";
|
||||
for (let index = 0; index < pattern.length; index += 1) {
|
||||
const char = pattern[index];
|
||||
if (char === "*") { source += pattern[index + 1] === "*" ? ".*" : "[^/]*"; if (pattern[index + 1] === "*") index += 1; }
|
||||
else if (char === "?") source += "[^/]";
|
||||
else source += char?.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
||||
}
|
||||
return new RegExp(`^${source}${pattern.endsWith("/") ? ".*" : ""}$`, "u").test(filePath);
|
||||
}
|
||||
|
||||
function statusPaths(status: string, marker: string) { return unique(status.split(/\r?\n/u).flatMap((line) => line.startsWith(`${marker} `) ? [repoPath(parseQuoted(line.slice(3)))] : []).filter(Boolean)); }
|
||||
function parseQuoted(value: string) { const raw = value.trim(); if (!raw.startsWith('"')) return raw; try { return JSON.parse(raw); } catch { return raw.replace(/^"|"$/gu, ""); } }
|
||||
function patchPaths(value: string) { return unique(text(value).split(/\r?\n/u).flatMap((line) => line.match(/^diff --git a\/(.*?) b\/(.*)$/u)?.[2] ?? []).map(repoPath)); }
|
||||
function normalizeNewFilePatch(value: string, filePath: string) { const rel = repoPath(filePath); return text(value).replace(/^diff --git a\/dev\/null b\/(.*?)$/mu, `diff --git a/${rel} b/${rel}`).replace(/^--- a\/dev\/null$/mu, "--- /dev/null").replace(/^\+\+\+ b\/(.*?)$/mu, `+++ b/${rel}`); }
|
||||
function joinPatch(tracked: string, untracked: string, omitted: AgentDiffFileRecord[]) { return [text(tracked), text(untracked), omitted.length ? ["# CaseRun diffCollection omitted files from patch body:", ...omitted.map((file) => `# - ${file.path} rule=${file.rule ?? ""} reason=${file.reason ?? ""} bytes=${file.bytes ?? ""} sha256=${file.sha256 ?? ""}`)].join("\n") : ""].filter(Boolean).join("\n"); }
|
||||
function joinStat(tracked: string, untracked: string, omitted: AgentDiffFileRecord[]) { return [text(tracked), text(untracked), omitted.length ? ["[omitted by CaseRun diffCollection]", ...omitted.map((file) => ` ${file.path} | omitted rule=${file.rule ?? ""} reason=${file.reason ?? ""} bytes=${file.bytes ?? ""} sha256=${file.sha256 ?? ""}`)].join("\n") : ""].filter(Boolean).join("\n"); }
|
||||
function sha256(value: string) { return createHash("sha256").update(value).digest("hex"); }
|
||||
function repoPath(value: unknown) { return text(value).replace(/\\/gu, "/").replace(/^\.\//u, "").replace(/^\/+|\/+$/gu, ""); }
|
||||
function text(value: unknown) { return typeof value === "string" ? value.trim() : value == null ? "" : String(value).trim(); }
|
||||
function record(value: unknown): Record<string, unknown> { return value && typeof value === "object" && !Array.isArray(value) ? value as Record<string, unknown> : {}; }
|
||||
function compact<T extends Record<string, unknown>>(value: T) { return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== undefined && item !== "")) as T; }
|
||||
function unique(values: string[]) { return [...new Set(values.filter(Boolean))]; }
|
||||
@@ -8,6 +8,7 @@ import { copyFile, mkdir, readFile, readdir, stat, writeFile } from "node:fs/pro
|
||||
import path from "node:path";
|
||||
|
||||
import { renderTraceRowsMarkdown, traceDisplayRows, traceNoiseEventCount, type TraceEventRow } from "./hwlab-cli/trace-renderer.ts";
|
||||
import { collectAgentWorkspaceDiff, type AgentDiffCollectionSummary } from "./hwlab-caserun-diff.ts";
|
||||
import { readHwpodSpec } from "./hwpod-harness-lib.ts";
|
||||
|
||||
const REMOVED_V02_API_URL = "http://74.48.78.17:19667";
|
||||
@@ -131,6 +132,7 @@ type AgentDiffStage = {
|
||||
diffStat: string;
|
||||
diffPatchPath: string;
|
||||
diffPatchSha256: string;
|
||||
diffCollection?: AgentDiffCollectionSummary;
|
||||
sourceRootStatusShort: string;
|
||||
sourceRootBaseline?: SourceRootSnapshot;
|
||||
sourceRootAfterPrepare?: SourceRootSnapshot;
|
||||
@@ -1047,16 +1049,27 @@ async function collectAgentDiff(context: CaseContext, run: PreparedCaseRun) {
|
||||
const status = await requestSubjectCommand(context, run, ["-C", run.subject.worktreePath, "status", "--short"]);
|
||||
const diffStat = await requestSubjectCommand(context, run, ["-C", run.subject.worktreePath, "diff", "--stat"]);
|
||||
const diffPatch = await requestSubjectCommand(context, run, ["-C", run.subject.worktreePath, "diff", "--binary"]);
|
||||
const collected = await collectAgentWorkspaceDiff({
|
||||
definition: run.definition,
|
||||
subjectSubdir: run.subject.subdir,
|
||||
worktreePath: run.subject.worktreePath,
|
||||
statusShort: text(status.stdout),
|
||||
trackedDiffStat: text(diffStat.stdout),
|
||||
trackedPatchText: text(diffPatch.stdout),
|
||||
requestGit: (args) => requestSubjectCommand(context, run, ["-C", run.subject.worktreePath, ...args]),
|
||||
requestProcess: (command, args) => requestSubjectProcess(context, run, command, args)
|
||||
});
|
||||
const sourceAfterAgent = await collectSourceRootSnapshot(context, run, "after-agent");
|
||||
const statusShort = text(status.stdout);
|
||||
const patchText = text(diffPatch.stdout);
|
||||
const patchText = collected.patchText;
|
||||
const diffPatchPath = path.join(run.runDir, "agent-diff.patch");
|
||||
await writeFile(diffPatchPath, patchText, "utf8");
|
||||
const diff: AgentDiffStage = {
|
||||
statusShort,
|
||||
diffStat: text(diffStat.stdout),
|
||||
diffStat: collected.diffStat,
|
||||
diffPatchPath,
|
||||
diffPatchSha256: sha256(patchText),
|
||||
diffCollection: collected.collection,
|
||||
sourceRootStatusShort: sourceAfterAgent.statusShort,
|
||||
sourceRootBaseline: run.subject.sourceRootBaseline,
|
||||
sourceRootAfterPrepare: run.subject.sourceRootAfterPrepare,
|
||||
@@ -1067,6 +1080,7 @@ async function collectAgentDiff(context: CaseContext, run: PreparedCaseRun) {
|
||||
requestSummary("status", status),
|
||||
requestSummary("diff-stat", diffStat),
|
||||
requestSummary("diff-patch", diffPatch),
|
||||
...collected.requests.map((request) => requestSummary(request.label, request.result)),
|
||||
{ label: "source-root-baseline", statusShort: run.subject.sourceRootBaseline?.statusShort ?? "", diffSha256: run.subject.sourceRootBaseline?.diffSha256 ?? "" },
|
||||
{ label: "source-root-after-prepare", statusShort: run.subject.sourceRootAfterPrepare?.statusShort ?? "", diffSha256: run.subject.sourceRootAfterPrepare?.diffSha256 ?? "" },
|
||||
{ label: "source-root-after-agent", statusShort: sourceAfterAgent.statusShort, diffSha256: sourceAfterAgent.diffSha256 }
|
||||
@@ -1076,6 +1090,26 @@ async function collectAgentDiff(context: CaseContext, run: PreparedCaseRun) {
|
||||
return { run: nextRun, diff };
|
||||
}
|
||||
|
||||
async function requestSubjectProcess(context: CaseContext, run: PreparedCaseRun, command: string, argv: string[]) {
|
||||
const document = await readHwpodSpec(run.specPath);
|
||||
const hwpodId = text(document.metadata.name) || text(document.metadata.uid) || run.caseId;
|
||||
const plan = {
|
||||
contractVersion: "hwpod-node-ops-v1",
|
||||
planId: `case_subject_cmd_${randomUUID()}`,
|
||||
hwpodId,
|
||||
nodeId: document.spec.nodeBinding.nodeId,
|
||||
intent: "cmd.run",
|
||||
source: { compiler: "hwlab-cli.case", specPath: run.specPath, specAuthority: "case-run-state" },
|
||||
ops: [{ opId: "op_01_subject_cmd", op: "cmd.run", args: { hwpodId, workspacePath: run.subject.repoLocalPath, command, argv } }]
|
||||
};
|
||||
const response = await context.fetchImpl(`${run.apiUrl}/v1/hwpod-node-ops`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(plan) });
|
||||
const textBody = await response.text();
|
||||
const body = parseJsonMaybe(textBody) ?? { raw: textBody };
|
||||
const result = firstHwpodOutput(body);
|
||||
const exitCode = numberOption(result?.exitCode) ?? (response.status >= 200 && response.status < 300 ? 0 : 1);
|
||||
return { ok: response.status >= 200 && response.status < 300 && exitCode === 0, httpStatus: response.status, exitCode, stdout: text(result?.stdout), stderr: text(result?.stderr), body: compactObject(body), command: [command, ...argv] };
|
||||
}
|
||||
|
||||
async function collectSourceRootSnapshot(context: CaseContext, run: PreparedCaseRun, label: string): Promise<SourceRootSnapshot> {
|
||||
const status = await requestSubjectCommand(context, run, ["status", "--short"]);
|
||||
const diffStat = await requestSubjectCommand(context, run, ["diff", "--stat"]);
|
||||
@@ -1430,6 +1464,7 @@ function diffSummary(diff: AgentDiffStage) {
|
||||
diffStat: diff.diffStat,
|
||||
diffPatchPath: diff.diffPatchPath,
|
||||
diffPatchSha256: diff.diffPatchSha256,
|
||||
diffCollection: diff.diffCollection,
|
||||
sourceRootStatusShort: diff.sourceRootStatusShort,
|
||||
sourceRootBaseline: diff.sourceRootBaseline,
|
||||
sourceRootAfterPrepare: diff.sourceRootAfterPrepare,
|
||||
@@ -2231,7 +2266,7 @@ async function writeReadableAgentArtifacts(caseRepoRunDir: string, run: Prepared
|
||||
noiseEventCount: traceNoiseEventCount(events),
|
||||
finalResponse,
|
||||
rows: rows.map(agentMessageRowForArchive),
|
||||
diff: clean({ path: "agent-diff.patch", sha256: evidence.agentDiff?.diffPatchSha256 ?? run.agentDiff?.diffPatchSha256, statusShort: evidence.agentDiff?.statusShort ?? run.agentDiff?.statusShort, diffStat: evidence.agentDiff?.diffStat ?? run.agentDiff?.diffStat, patchIncludedInTranscript: true })
|
||||
diff: clean({ path: "agent-diff.patch", sha256: evidence.agentDiff?.diffPatchSha256 ?? run.agentDiff?.diffPatchSha256, statusShort: evidence.agentDiff?.statusShort ?? run.agentDiff?.statusShort, diffStat: evidence.agentDiff?.diffStat ?? run.agentDiff?.diffStat, collection: evidence.agentDiff?.diffCollection ?? run.agentDiff?.diffCollection, patchIncludedInTranscript: true })
|
||||
});
|
||||
const transcript = renderAgentTranscript(run, evidence, messages, rows, diffPatch);
|
||||
await writeJson(path.join(caseRepoRunDir, messagesRel), messages);
|
||||
@@ -2520,6 +2555,7 @@ function caseRunArtifactManifest(context: CaseContext, run: PreparedCaseRun, evi
|
||||
sha256: evidence.agentDiff?.diffPatchSha256 ?? run.agentDiff?.diffPatchSha256,
|
||||
statusShort: evidence.agentDiff?.statusShort ?? run.agentDiff?.statusShort,
|
||||
diffStat: evidence.agentDiff?.diffStat ?? run.agentDiff?.diffStat,
|
||||
collection: evidence.agentDiff?.diffCollection ?? run.agentDiff?.diffCollection,
|
||||
sourceRootStatusShort: evidence.agentDiff?.sourceRootStatusShort ?? run.agentDiff?.sourceRootStatusShort,
|
||||
sourceRootChangedAfterPrepare: evidence.agentDiff?.sourceRootChangedAfterPrepare ?? run.agentDiff?.sourceRootChangedAfterPrepare,
|
||||
sourceRootChangedAfterAgent: evidence.agentDiff?.sourceRootChangedAfterAgent ?? run.agentDiff?.sourceRootChangedAfterAgent,
|
||||
|
||||
Reference in New Issue
Block a user