fix: close PI-090 review findings

This commit is contained in:
brother7 committed 2026-08-23 15:58:32 +08:00
1 parent 13ab383e53
commit 7e024093b1
11 files changed
+325 -66

No files matched your search

+51 -6
View File
@@ -1,14 +1,17 @@
// @vitest-environment node
import { execFile } from 'node:child_process';
import { mkdtemp, mkdir, rm, writeFile } from 'node:fs/promises';
import { mkdtemp, mkdir, rm, utimes, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import path from 'node:path';
import { promisify } from 'node:util';
import { afterEach, describe, expect, it } from 'vitest';
import type { AgentBrowserModule } from '../../electron/agent-browser';
import { CodingAttachmentStore } from '../../electron/coding-projects/attachment-store';
import { ConversationChangeTracker } from '../../electron/coding-projects/conversation-change-tracker';
import {
ConversationChangeTracker,
type ConversationGitAdapter,
} from '../../electron/coding-projects/conversation-change-tracker';
import {
buildProductCodingCommandCatalog,
listProductCodingSkills,
@@ -80,7 +83,7 @@ describe('PI-090 product tools', () => {
expect(settled?.files.some((file) => file.path === 'existing.txt')).toBe(false);
});
it('bounds untracked previews without hiding append-only changes beyond the preview', async () => {
it('bounds untracked reads and detects equal-length changes beyond the preview', async () => {
const root = await temporaryRoot('makelore-pi-bounded-preview-');
await initializeRepository(root);
const target = path.join(root, 'large.txt');
@@ -89,15 +92,57 @@ describe('PI-090 product tools', () => {
await tracker.beginRun({
conversationId: 'conversation-a', runId: 'run-a', projectPath: root,
});
await writeFile(target, `${'a'.repeat(9 * 1024)}tail`, 'utf8');
await tracker.markProjectRefresh('conversation-a', 'run-a');
const snapshot = await tracker.settleRun('conversation-a', 'run-a');
await writeFile(target, `${'a'.repeat((9 * 1024) - 1)}b`, 'utf8');
const changedAt = new Date(Date.now() + 5_000);
await utimes(target, changedAt, changedAt);
const snapshot = await tracker.recordTouchedPaths('conversation-a', 'run-a', ['large.txt']);
const file = snapshot?.files.find(({ path: filePath }) => filePath === 'large.txt');
expect(file).toMatchObject({ status: 'untracked', truncated: true });
expect(Buffer.byteLength(file?.preview ?? '', 'utf8')).toBeLessThanOrEqual(8 * 1024);
expect(JSON.stringify(snapshot)).not.toContain(root);
});
it('captures a dirty baseline without per-file Git diffs', async () => {
const root = await temporaryRoot('makelore-pi-dirty-baseline-');
const calls: string[][] = [];
const status = Array.from({ length: 100 }, (_, index) => (
`1 .M N... 100644 100644 100644 abc abc dirty-${index}.txt\0`
)).join('');
const adapter: ConversationGitAdapter = {
async run(_projectPath, args) {
calls.push([...args]);
if (args[0] === 'rev-parse' && args[1] === '--is-inside-work-tree') {
return { code: 0, stdout: 'true\n' };
}
if (args[0] === 'rev-parse') return { code: 0, stdout: `${'a'.repeat(40)}\n` };
if (args[0] === 'status') return { code: 0, stdout: status };
throw new Error(`Unexpected Git call: ${args.join(' ')}`);
},
};
const tracker = new ConversationChangeTracker(adapter);
expect((await tracker.beginRun({
conversationId: 'conversation-a', runId: 'run-a', projectPath: root,
})).git).toBe(true);
expect(calls).toHaveLength(3);
expect(calls.some(([command]) => command === 'diff')).toBe(false);
});
it('degrades to no-Git tracking when the Git executable is unavailable', async () => {
const root = await temporaryRoot('makelore-pi-git-unavailable-');
await writeFile(path.join(root, 'notes.txt'), 'local notes\n', 'utf8');
const tracker = new ConversationChangeTracker({
async run() {
throw Object.assign(new Error('spawn git ENOENT'), { code: 'ENOENT' });
},
});
expect((await tracker.beginRun({
conversationId: 'conversation-a', runId: 'run-a', projectPath: root,
})).git).toBe(false);
expect((await tracker.recordTouchedPaths(
'conversation-a', 'run-a', ['notes.txt'],
)).files).toEqual([expect.objectContaining({ path: 'notes.txt', preview: 'local notes\n' })]);
});
it('supports no-git projects and rejects paths outside the project', async () => {
const root = await temporaryRoot('makelore-pi-no-git-');
await writeFile(path.join(root, 'notes.txt'), 'local notes\n', 'utf8');