Skip to content

Commit d490029

Browse files
Permissions issue when initializing checkpoints (RooCodeInc#2354)
* initial * More error handling and git option * Cleanup and tweaks * one small change * Update src/integrations/checkpoints/CheckpointUtils.ts Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> --------- Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
1 parent a936a7d commit d490029

File tree

4 files changed

+35
-10
lines changed

4 files changed

+35
-10
lines changed

.changeset/yellow-moose-bathe.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"claude-dev": patch
3+
---
4+
5+
Added permissions checks, error handling, and git options to deal with cases where the entire workspace or specific files within it cannot be accessed. These issues were preventing checkpoints from working correctly, or causing checkpoints to hang.

src/integrations/checkpoints/CheckpointGitOperations.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,11 @@ export class GitOperations {
9090
const lfsPatterns = await getLfsPatterns(cwd)
9191
await writeExcludesFile(gitPath, lfsPatterns)
9292

93-
await this.addCheckpointFiles(git)
93+
const addFilesResult = await this.addCheckpointFiles(git)
94+
if (!addFilesResult.success) {
95+
console.error("Failed to add at least one file(s) to checkpoints shadow git")
96+
throw new Error("Failed to add at least one file(s) to checkpoints shadow git")
97+
}
9498

9599
// Initial commit only on first repo creation
96100
await git.commit("initial commit", { "--allow-empty": null })
@@ -142,6 +146,7 @@ export class GitOperations {
142146
ignore: [".git"], // Ignore root level .git
143147
dot: true,
144148
markDirectories: false,
149+
suppressErrors: true,
145150
})
146151

147152
// For each nested .git directory, rename it based on operation
@@ -190,18 +195,18 @@ export class GitOperations {
190195
await this.renameNestedGitRepos(true)
191196
console.info("Starting checkpoint add operation...")
192197

198+
// Attempt to add all files. Any files with permissions errors will not be added,
199+
// but the process will proceed and add the rest (--ignore-errors).
193200
try {
194-
await git.add(".")
201+
await git.add([".", "--ignore-errors"])
195202
const durationMs = Math.round(performance.now() - startTime)
196203
console.debug(`Checkpoint add operation completed in ${durationMs}ms`)
197204
return { success: true }
198205
} catch (error) {
199-
console.error("Checkpoint add operation failed:", error)
200-
throw error
206+
return { success: false }
201207
}
202208
} catch (error) {
203-
console.error("Failed to add files to checkpoint", error)
204-
throw error
209+
return { success: false }
205210
} finally {
206211
await this.renameNestedGitRepos(false)
207212
}

src/integrations/checkpoints/CheckpointTracker.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,10 @@ class CheckpointTracker {
165165

166166
console.info(`Using shadow git at: ${gitPath}`)
167167

168-
await this.gitOperations.addCheckpointFiles(git)
168+
const addFilesResult = await this.gitOperations.addCheckpointFiles(git)
169+
if (!addFilesResult.success) {
170+
console.error("Failed to add at least one file(s) to checkpoints shadow git")
171+
}
169172

170173
const commitMessage = "checkpoint-" + this.cwdHash + "-" + this.taskId
171174

src/integrations/checkpoints/CheckpointUtils.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { mkdir } from "fs/promises"
1+
import { mkdir, access, constants } from "fs/promises"
22
import * as path from "path"
33
import * as vscode from "vscode"
44
import os from "os"
@@ -31,7 +31,9 @@ export async function getShadowGitPath(globalStoragePath: string, taskId: string
3131
/**
3232
* Gets the current working directory from the VS Code workspace.
3333
* Validates that checkpoints are not being used in protected directories
34-
* like home, Desktop, Documents, or Downloads.
34+
* like home, Desktop, Documents, or Downloads. Checks to confirm that the workspace
35+
* is accessible and that we will not encounter breaking permissions issues when
36+
* creating checkpoints.
3537
*
3638
* Protected directories:
3739
* - User's home directory
@@ -40,13 +42,23 @@ export async function getShadowGitPath(globalStoragePath: string, taskId: string
4042
* - Downloads
4143
*
4244
* @returns Promise<string> The absolute path to the current working directory
43-
* @throws Error if no workspace is detected or if in a protected directory
45+
* @throws Error if no workspace is detected, if in a protected directory, or if no read access
4446
*/
4547
export async function getWorkingDirectory(): Promise<string> {
4648
const cwd = vscode.workspace.workspaceFolders?.map((folder) => folder.uri.fsPath).at(0)
4749
if (!cwd) {
4850
throw new Error("No workspace detected. Please open Cline in a workspace to use checkpoints.")
4951
}
52+
53+
// Check if directory exists and we have read permissions
54+
try {
55+
await access(cwd, constants.R_OK)
56+
} catch (error) {
57+
throw new Error(
58+
`Cannot access workspace directory. Please ensure VS Code has permission to access your workspace. Error: ${error instanceof Error ? error.message : String(error)}`,
59+
)
60+
}
61+
5062
const homedir = os.homedir()
5163
const desktopPath = path.join(homedir, "Desktop")
5264
const documentsPath = path.join(homedir, "Documents")

0 commit comments

Comments
 (0)