Skip to content

Commit 546e1a1

Browse files
committed
Delete or modify source attribution
1 parent 8ed4a26 commit 546e1a1

25 files changed

Lines changed: 77 additions & 844 deletions

packages/codingcode/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
"./client/direct-clients": "./src/client/direct/index.ts",
3737
"./checkpoint/checkpoint-service": "./src/checkpoint/checkpoint-service.ts",
3838
"./checkpoint/shadow-git": "./src/checkpoint/shadow-git.ts",
39-
"./checkpoint/ledger": "./src/checkpoint/ledger.ts",
4039
"./checkpoint/bootstrap": "./src/checkpoint/bootstrap.ts",
4140
"./subagent/registry": "./src/subagent/registry.ts",
4241
"./subagent/loader": "./src/subagent/loader.ts",

packages/codingcode/src/agent/agent.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ export async function* runReActLoop(
306306

307307
// Check abort signal
308308
if (opts.abortSignal?.aborted) {
309+
checkpoint.snapshotFinal(projectPath, state.sessionId, state.currentTurnId);
309310
yield { _tag: 'Error', error: new AgentError('AGENT_ABORTED', 'cancelled') };
310311
await Effect.runPromise(
311312
hooks.emit('agent.turn.end', {
@@ -557,6 +558,7 @@ export async function* runReActLoop(
557558

558559
// If abort fired during tool execution, terminate immediately
559560
if (opts.abortSignal?.aborted) {
561+
checkpoint.snapshotFinal(projectPath, state.sessionId, state.currentTurnId);
560562
yield { _tag: 'Error', error: new AgentError('AGENT_ABORTED', 'cancelled') };
561563
await Effect.runPromise(
562564
hooks.emit('agent.turn.end', {

packages/codingcode/src/checkpoint/checkpoint-service.ts

Lines changed: 33 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
11
import { Effect } from 'effect';
22
import { createHash } from 'crypto';
33
import { readFileSync } from 'fs';
4-
import { resolve, dirname } from 'path';
4+
import { resolve } from 'path';
55
import { ShadowGit } from './shadow-git.js';
66
import { ProjectLock } from './project-lock.js';
77
import { normalizePath } from '../core/path.js';
8-
import { Ledger } from './ledger.js';
9-
import { registerCheckpointHooks } from './hook-recorder.js';
10-
import { HookService } from '../hooks/registry.js';
118
import { shortSid, commitMsg } from './commit-naming.js';
129
import { readRestoreEntry, writeRestoreEntry } from './restore-store.js';
13-
import { classifyDiff, parseDiffStats } from './classification.js';
1410
import {
1511
getCompletedTurnsFor,
1612
getTurnRestorePlan,
1713
getRollbackToTurnPlan,
18-
type RestorePlan,
1914
} from './restore-planning.js';
2015
import { emptyRollbackResult, executeRollback } from './rollback-engine.js';
2116

@@ -25,7 +20,6 @@ export interface CheckpointDiff {
2520
turnId: number;
2621
files: Array<{
2722
path: string;
28-
source: 'agent' | 'unknown';
2923
status: string;
3024
diff: string;
3125
insertions: number;
@@ -58,12 +52,7 @@ export interface RollbackPreviewDiff {
5852
export interface CodeRestoreEntry {
5953
id: string;
6054
sessionId: string;
61-
action:
62-
| 'checkpoint-file'
63-
| 'checkpoint-files'
64-
| 'checkpoint-agent'
65-
| 'checkpoint-all'
66-
| 'rollback-to-turn';
55+
action: 'checkpoint-file' | 'checkpoint-files' | 'rollback-to-turn';
6756
throughTurnId: number;
6857
affectedTurns: number[];
6958
selectedFiles: string[];
@@ -97,12 +86,8 @@ export function hashWorkspaceFile(projectPath: string, file: string): string | n
9786

9887
export class CheckpointService extends Effect.Service<CheckpointService>()('Checkpoint', {
9988
effect: Effect.gen(function* () {
100-
const hooks = yield* HookService;
101-
registerCheckpointHooks(hooks);
102-
10389
const shadowGitByProject = new Map<string, ShadowGit>();
10490
const lockByProject = new Map<string, ProjectLock>();
105-
const ledgerByProject = new Map<string, { ledger: Ledger; gitDir: string }>();
10691

10792
function ensure(projectPath: string): ShadowGit {
10893
const normalized = normalizePath(projectPath);
@@ -125,15 +110,20 @@ export class CheckpointService extends Effect.Service<CheckpointService>()('Chec
125110
return lock;
126111
}
127112

128-
function ledger(sg: ShadowGit): Ledger {
129-
const key = sg.gitDir;
130-
let entry = ledgerByProject.get(key);
131-
if (!entry || entry.gitDir !== key) {
132-
const l = new Ledger(dirname(sg.gitDir));
133-
entry = { ledger: l, gitDir: key };
134-
ledgerByProject.set(key, entry);
113+
function repairIncompleteTurn(sg: ShadowGit, sessionId: string): void {
114+
const completed = getCompletedTurnsFor(sg, sessionId);
115+
const candidate = completed.length > 0 ? completed[completed.length - 1]! + 1 : 1;
116+
const baseline = sg.findCommitByMessage(commitMsg(sessionId, candidate, 'baseline'));
117+
if (!baseline) return;
118+
const final = sg.findCommitByMessage(commitMsg(sessionId, candidate, 'final'));
119+
if (final) return;
120+
const lock = lockFor(sg.projectPath);
121+
lock.lock();
122+
try {
123+
sg.commit(commitMsg(sessionId, candidate, 'final'));
124+
} finally {
125+
lock.unlock();
135126
}
136-
return entry.ledger;
137127
}
138128

139129
return {
@@ -146,6 +136,7 @@ export class CheckpointService extends Effect.Service<CheckpointService>()('Chec
146136
title?: string
147137
): void => {
148138
const sg = ensure(projectPath);
139+
repairIncompleteTurn(sg, sessionId);
149140
if (sg.isTooLargeForSnapshot()) return;
150141
const lock = lockFor(projectPath);
151142
const msg = title
@@ -171,22 +162,11 @@ export class CheckpointService extends Effect.Service<CheckpointService>()('Chec
171162
}
172163
},
173164

174-
// ---- Classification ----
175-
176-
classifyChanges: (
177-
projectPath: string,
178-
sessionId: string,
179-
turnId: number
180-
): { agentModified: string[]; unknownSource: string[] } | null => {
181-
const sg = ensure(projectPath);
182-
const l = ledger(sg);
183-
return classifyDiff(projectPath, sessionId, turnId, sg, l);
184-
},
185-
186165
// ---- Query ----
187166

188167
getCompletedTurns: (projectPath: string, sessionId: string): number[] => {
189168
const sg = ensure(projectPath);
169+
repairIncompleteTurn(sg, sessionId);
190170
return getCompletedTurnsFor(sg, sessionId);
191171
},
192172

@@ -196,18 +176,16 @@ export class CheckpointService extends Effect.Service<CheckpointService>()('Chec
196176
): Array<{
197177
turnId: number;
198178
title: string;
199-
agentModified: string[];
200-
unknownSource: string[];
179+
files: string[];
201180
}> => {
202181
const sg = ensure(projectPath);
203-
const l = ledger(sg);
182+
repairIncompleteTurn(sg, sessionId);
204183
const prefix = `turn-${shortSid(sessionId)}-`;
205184
const completedTurns = getCompletedTurnsFor(sg, sessionId);
206185
const result: Array<{
207186
turnId: number;
208187
title: string;
209-
agentModified: string[];
210-
unknownSource: string[];
188+
files: string[];
211189
}> = [];
212190

213191
for (const i of completedTurns) {
@@ -221,18 +199,9 @@ export class CheckpointService extends Effect.Service<CheckpointService>()('Chec
221199
const title = fullMsg.includes(' ') ? fullMsg.split(' ').slice(1).join(' ') : '';
222200

223201
const allChanges = sg.diffFiles(bCommit, fCommit);
224-
const rawAllFiles = allChanges.map((c) => normalizePath(resolve(projectPath, c.file)));
225-
const allFiles = [...new Set(rawAllFiles)];
226-
const agentFiles = new Set(
227-
l.getAgentFiles(i, sessionId).map((p) => normalizePath(p).toLowerCase())
228-
);
202+
const files = [...new Set(allChanges.map((c) => normalizePath(resolve(projectPath, c.file))))];
229203

230-
result.push({
231-
turnId: i,
232-
title,
233-
agentModified: allFiles.filter((f) => agentFiles.has(f.toLowerCase())),
234-
unknownSource: allFiles.filter((f) => !agentFiles.has(f.toLowerCase())),
235-
});
204+
result.push({ turnId: i, title, files });
236205
}
237206
return result;
238207
},
@@ -243,6 +212,7 @@ export class CheckpointService extends Effect.Service<CheckpointService>()('Chec
243212
turnId?: number
244213
): CheckpointDiff => {
245214
const sg = ensure(projectPath);
215+
repairIncompleteTurn(sg, sessionId);
246216
const completedTurns = getCompletedTurnsFor(sg, sessionId);
247217
const latestTurnId =
248218
turnId ?? (completedTurns.length > 0 ? completedTurns[completedTurns.length - 1]! : 0);
@@ -257,29 +227,28 @@ export class CheckpointService extends Effect.Service<CheckpointService>()('Chec
257227
const allChanges = sg.diffFiles(baseline, final);
258228
const rawAllFiles = allChanges.map((c) => normalizePath(resolve(projectPath, c.file)));
259229
const allFiles = [...new Set(rawAllFiles)];
260-
const agentFiles = new Set(
261-
ledger(sg)
262-
.getAgentFiles(latestTurnId, sessionId)
263-
.map((p) => normalizePath(p).toLowerCase())
264-
);
265230

266231
const files = allFiles.map((f) => {
267232
const relPath = toGitPath(projectPath, f);
268233
const diffResult = sg.git('diff', baseline, final, '--', relPath);
269234
const rawPath = normalizePath(resolve(projectPath, relPath));
270-
const stats = parseDiffStats(diffResult.stdout);
235+
let insertions = 0;
236+
let deletions = 0;
237+
for (const line of diffResult.stdout.split('\n')) {
238+
if (line.startsWith('+') && !line.startsWith('+++')) insertions++;
239+
else if (line.startsWith('-') && !line.startsWith('---')) deletions++;
240+
}
271241
return {
272242
path: f,
273-
source: (agentFiles.has(f.toLowerCase()) ? 'agent' : 'unknown') as 'agent' | 'unknown',
274243
status:
275244
allChanges.find(
276245
(c) =>
277246
normalizePath(resolve(projectPath, c.file)).toLowerCase() ===
278247
rawPath.toLowerCase()
279248
)?.status ?? 'M',
280249
diff: diffResult.stdout,
281-
insertions: stats.insertions,
282-
deletions: stats.deletions,
250+
insertions,
251+
deletions,
283252
};
284253
});
285254

@@ -297,7 +266,7 @@ export class CheckpointService extends Effect.Service<CheckpointService>()('Chec
297266
const sg = ensure(projectPath);
298267
const plan = getTurnRestorePlan(sg, sessionId, turnId);
299268
if (!plan) {
300-
return emptyRollbackResult(turnId, turnId);
269+
return emptyRollbackResult(turnId);
301270
}
302271
return executeRollback(sessionId, plan, [file], 'checkpoint-file', sg, lockFor(projectPath));
303272
},
@@ -310,53 +279,10 @@ export class CheckpointService extends Effect.Service<CheckpointService>()('Chec
310279
): CodeRollbackResult => {
311280
const sg = ensure(projectPath);
312281
const plan = getTurnRestorePlan(sg, sessionId, turnId);
313-
if (!plan) {
314-
return emptyRollbackResult(turnId, turnId);
315-
}
316-
return executeRollback(sessionId, plan, files, 'checkpoint-files', sg, lockFor(projectPath));
317-
},
318-
319-
revertCheckpointAgentFiles: (
320-
projectPath: string,
321-
sessionId: string,
322-
turnId: number
323-
): CodeRollbackResult => {
324-
const sg = ensure(projectPath);
325-
const l = ledger(sg);
326-
const changes = classifyDiff(projectPath, sessionId, turnId, sg, l);
327-
if (!changes) {
328-
return emptyRollbackResult(turnId);
329-
}
330-
if (changes.agentModified.length === 0) {
331-
return emptyRollbackResult(turnId);
332-
}
333-
const plan = getTurnRestorePlan(sg, sessionId, turnId);
334-
if (!plan) {
335-
return emptyRollbackResult(turnId);
336-
}
337-
return executeRollback(sessionId, plan, changes.agentModified, 'checkpoint-agent', sg, lockFor(projectPath));
338-
},
339-
340-
revertCheckpointAllFiles: (
341-
projectPath: string,
342-
sessionId: string,
343-
turnId: number
344-
): CodeRollbackResult => {
345-
const sg = ensure(projectPath);
346-
const l = ledger(sg);
347-
const changes = classifyDiff(projectPath, sessionId, turnId, sg, l);
348-
if (!changes) {
349-
return emptyRollbackResult(turnId);
350-
}
351-
const all = [...changes.agentModified, ...changes.unknownSource];
352-
if (all.length === 0) {
353-
return emptyRollbackResult(turnId);
354-
}
355-
const plan = getTurnRestorePlan(sg, sessionId, turnId);
356282
if (!plan) {
357283
return emptyRollbackResult(turnId);
358284
}
359-
return executeRollback(sessionId, plan, all, 'checkpoint-all', sg, lockFor(projectPath));
285+
return executeRollback(sessionId, plan, files, 'checkpoint-files', sg, lockFor(projectPath));
360286
},
361287

362288
// ---- Rollback ----

packages/codingcode/src/checkpoint/classification.ts

Lines changed: 0 additions & 39 deletions
This file was deleted.

0 commit comments

Comments
 (0)