fix(task-change-ledger): normalize fixture paths on Windows

This commit is contained in:
777genius 2026-04-21 18:19:29 +03:00
parent 728603d788
commit e0d32d59ff
2 changed files with 53 additions and 4 deletions

View file

@ -943,8 +943,9 @@ export class TaskChangeLedgerReader {
private mapV2SummaryFile(file: LedgerSummaryFileV2, projectPath?: string): FileChangeSummary {
const displayPath = file.displayPath ?? file.filePath;
const filePath = this.normalizeLedgerFilePath(file.filePath);
return {
filePath: file.filePath,
filePath,
relativePath: this.relativePath(displayPath, projectPath, file.relativePath),
snippets: [],
linesAdded: file.linesAdded,
@ -1001,7 +1002,7 @@ export class TaskChangeLedgerReader {
startTimestamp: scope.startTimestamp,
endTimestamp: scope.endTimestamp,
toolUseIds: scope.toolUseIds,
filePaths: files.map((file) => file.filePath),
filePaths: files.map((file) => this.normalizeLedgerFilePath(file.filePath)),
confidence: scope.confidence,
...(scope.primaryActorKey ? { primaryActorKey: scope.primaryActorKey } : {}),
...(scope.primaryAgentId ? { primaryAgentId: scope.primaryAgentId } : {}),
@ -1049,9 +1050,10 @@ export class TaskChangeLedgerReader {
beforeContent: string | null,
afterContent: string | null
): SnippetDiff {
const filePath = this.normalizeLedgerFilePath(event.filePath);
return {
toolUseId: event.toolUseId,
filePath: event.filePath,
filePath,
toolName: this.mapToolName(event.source),
type: this.mapSnippetType(event),
oldString: event.oldString ?? beforeContent ?? '',
@ -1371,7 +1373,18 @@ export class TaskChangeLedgerReader {
return null;
}
return `${normalizedAnchor.slice(0, normalizedAnchor.length - normalizedAnchorRelation.length)}${targetRelationPath.replace(/\\/g, '/')}`;
return this.normalizeLedgerFilePath(
`${normalizedAnchor.slice(0, normalizedAnchor.length - normalizedAnchorRelation.length)}${targetRelationPath.replace(/\\/g, '/')}`
);
}
private normalizeLedgerFilePath(filePath: string): string {
const slashPath = filePath.replace(/\\/g, '/');
const isWindowsAbsolute = /^[A-Za-z]:\//.test(slashPath) || slashPath.startsWith('//');
if (path.isAbsolute(filePath) || isWindowsAbsolute) {
return path.normalize(filePath);
}
return slashPath;
}
private relativePath(

View file

@ -61,6 +61,41 @@ async function rewriteProjectRootTokens(rootDir: string, token: string, projectD
}
}
function shouldNormalizeLfFixtureFile(filePath: string): boolean {
const normalizedPath = filePath.replace(/\\/g, '/');
return (
/\.(json|jsonl|md|txt|ts|tsx|js|jsx)$/.test(normalizedPath) ||
normalizedPath.includes('/.board-task-changes/blobs/sha256/')
);
}
function looksBinary(buffer: Buffer): boolean {
for (const byte of buffer) {
if (byte === 0) return true;
if (byte < 9 || (byte > 13 && byte < 32)) return true;
}
return false;
}
async function normalizeFixtureTextLineEndings(rootDir: string): Promise<void> {
const entries = await fs.readdir(rootDir, { withFileTypes: true });
for (const entry of entries) {
const entryPath = path.join(rootDir, entry.name);
if (entry.isDirectory()) {
await normalizeFixtureTextLineEndings(entryPath);
continue;
}
if (!shouldNormalizeLfFixtureFile(entryPath)) {
continue;
}
const raw = await fs.readFile(entryPath);
if (!raw.includes(13) || looksBinary(raw)) {
continue;
}
await fs.writeFile(entryPath, raw.toString('utf8').replace(/\r\n?/g, '\n'), 'utf8');
}
}
export async function materializeTaskChangeLedgerFixture(
fixtureName: string
): Promise<MaterializedTaskChangeLedgerFixture> {
@ -76,6 +111,7 @@ export async function materializeTaskChangeLedgerFixture(
const token = manifest.projectRootToken ?? DEFAULT_PROJECT_ROOT_TOKEN;
await rewriteProjectRootTokens(rootDir, token, projectDir);
await normalizeFixtureTextLineEndings(rootDir);
return {
rootDir,