Skip to content
This repository was archived by the owner on Jun 4, 2026. It is now read-only.

Commit bd52705

Browse files
authored
Merge pull request #4 from cardstack/copilot/sub-pr-3
Fix manual checkpoint creation to detect actual workspace changes
2 parents ae4865f + 17170b5 commit bd52705

2 files changed

Lines changed: 70 additions & 2 deletions

File tree

src/commands/history.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,9 @@ export async function historyCommand(
7474
manager.init();
7575
}
7676

77-
// Scan workspace to get current files for the checkpoint
78-
const changes = scanWorkspaceForChanges(workspaceDir);
77+
// Detect current changes to create an accurate checkpoint
78+
const changes = manager.detectCurrentChanges();
79+
7980
const checkpoint = manager.createCheckpoint('manual', changes, options.message);
8081

8182
if (checkpoint) {

src/lib/checkpoint-manager.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,73 @@ export class CheckpointManager {
149149
return files;
150150
}
151151

152+
/**
153+
* Detect current changes in the workspace by comparing with last checkpoint
154+
*/
155+
detectCurrentChanges(): CheckpointChange[] {
156+
if (!this.isInitialized()) {
157+
// If not initialized, all files are "added"
158+
const files = this.getWorkspaceFiles();
159+
return files.map(file => ({ file, status: 'added' as const }));
160+
}
161+
162+
// Sync files to history to get current state
163+
this.syncFilesToHistory();
164+
165+
// Get git status to see what changed
166+
const status = spawnSync('git', ['status', '--porcelain'], {
167+
cwd: this.gitDir,
168+
encoding: 'utf-8',
169+
});
170+
171+
const statusOutput = status.stdout.trim();
172+
if (!statusOutput) {
173+
return []; // No changes
174+
}
175+
176+
const changes: CheckpointChange[] = [];
177+
for (const line of statusOutput.split('\n')) {
178+
if (!line) continue;
179+
180+
const statusCode = line.substring(0, 2);
181+
let file = line.substring(3);
182+
183+
// Parse git status codes (two-character format)
184+
// ' M' or 'M ' = modified
185+
// 'A ' or 'AM' = added
186+
// 'D ' or ' D' = deleted
187+
// '??' = untracked (treat as added)
188+
// 'R ' = renamed (format: "R old -> new")
189+
// 'C ' = copied (treat similar to added)
190+
// 'UU' or 'AA' or other U combos = unmerged (treat as modified)
191+
// 'T ' = type changed (treat as modified)
192+
193+
// Handle renamed files - extract the new name
194+
if (statusCode.includes('R')) {
195+
const arrowIndex = file.indexOf(' -> ');
196+
if (arrowIndex !== -1) {
197+
const oldFile = file.substring(0, arrowIndex);
198+
const newFile = file.substring(arrowIndex + 4);
199+
// Record both the deletion of old and addition of new
200+
changes.push({ file: oldFile, status: 'deleted' });
201+
changes.push({ file: newFile, status: 'added' });
202+
continue;
203+
}
204+
}
205+
206+
// Classify changes based on status code
207+
if (statusCode.includes('D')) {
208+
changes.push({ file, status: 'deleted' });
209+
} else if (statusCode.includes('A') || statusCode.includes('C') || statusCode === '??') {
210+
changes.push({ file, status: 'added' });
211+
} else if (statusCode.includes('M') || statusCode.includes('U') || statusCode.includes('T')) {
212+
changes.push({ file, status: 'modified' });
213+
}
214+
}
215+
216+
return changes;
217+
}
218+
152219
/**
153220
* Create a checkpoint with the current state
154221
*/

0 commit comments

Comments
 (0)