Compare commits

...
Author SHA1 Message Date
celestial-vault 247954ee1a update error wording 2025-09-09 14:54:12 -07:00
celestial-vault 21af5db39f don't write empty array if old taskHistory is corrupted, just abort migration 2025-09-09 14:50:38 -07:00
celestial-vault 5345ea185d change error wording 2025-09-09 14:47:44 -07:00
celestial-vault f0ff944633 Validate task history file format and heal invalid data
- Parse JSON once and rely on outer catch
- If content is not an array, log and rewrite with []
- Skip migration only when the new file has a non-empty array
- Prevent silent skips and normalize corrupt task history files
2025-09-09 14:45:46 -07:00
celestial-vault 15b5671824 rework taskHistory migration to check for existing taskHistory in new location and only migrate if empty or non-existant 2025-09-09 14:33:04 -07:00
celestial-vault 8aa18c078f Merge branch 'main' into taskHistory-migration-improvements 2025-09-09 10:57:38 -07:00
celestial-vault dd05ec1723 Improve error handling and user feedback for initialization failures
- Add user-facing error message when StateManager initialization fails
- Change console.log to console.error for malformed task history migration
2025-09-08 16:50:56 -05:00
celestial-vault 555e819fb0 add further safety checks to the migration 2025-09-05 13:45:51 -05:00
3 changed files with 61 additions and 26 deletions
+4
View File
@@ -70,6 +70,10 @@ export class Controller {
"[Controller] CRITICAL: Failed to initialize StateManager - extension may not function properly:",
error,
)
HostProvider.window.showMessage({
type: ShowMessageType.ERROR,
message: "Failed to initialize Cline's application state. Please restart the extension.",
})
})
// Set up persistence error recovery
+5 -3
View File
@@ -202,10 +202,12 @@ export async function readTaskHistoryFromState(context: vscode.ExtensionContext)
const filePath = await getTaskHistoryStateFilePath(context)
if (await fileExistsAtPath(filePath)) {
const contents = await fs.readFile(filePath, "utf8")
if (contents.trim() === "") {
return []
try {
return JSON.parse(contents)
} catch (error) {
console.error("[Disk] Failed to parse task history, it is malformed:", error)
throw error
}
return JSON.parse(contents)
}
return []
} catch (error) {
+52 -23
View File
@@ -2,7 +2,13 @@ import fs from "fs/promises"
import path from "path"
import * as vscode from "vscode"
import { HistoryItem } from "@/shared/HistoryItem"
import { ensureRulesDirectoryExists, readTaskHistoryFromState, writeTaskHistoryToState } from "./disk"
import { fileExistsAtPath } from "@/utils/fs"
import {
ensureRulesDirectoryExists,
getTaskHistoryStateFilePath,
readTaskHistoryFromState,
writeTaskHistoryToState,
} from "./disk"
import { StateManager } from "./StateManager"
export async function migrateWorkspaceToGlobalStorage(context: vscode.ExtensionContext) {
@@ -69,37 +75,60 @@ export async function migrateWorkspaceToGlobalStorage(context: vscode.ExtensionC
export async function migrateTaskHistoryToFile(context: vscode.ExtensionContext) {
try {
// Get data from old location
const vscodeGlobalStateTaskHistory = context.globalState.get<HistoryItem[] | undefined>("taskHistory")
// Check if the taskHistory is already in the new location.
// If it exists and is a valid, non-empty array, we skip the migration.
const taskHistoryFilePath = await getTaskHistoryStateFilePath(context)
// Normalize old location data to array (empty array if undefined/null/not-array)
const oldLocationData = Array.isArray(vscodeGlobalStateTaskHistory) ? vscodeGlobalStateTaskHistory : []
if (await fileExistsAtPath(taskHistoryFilePath)) {
try {
const contents = await fs.readFile(taskHistoryFilePath, "utf8")
const newTaskHistory = JSON.parse(contents)
if (!Array.isArray(newTaskHistory)) {
console.error(
"[Storage Migration] Task history in the new location is not an array, rewriting with an empty array.",
)
await writeTaskHistoryToState(context, [])
}
if (newTaskHistory.length > 0) {
console.log("[Storage Migration] Task history already in new location, skipping migration")
return
}
} catch (error) {
console.error("[Disk] Failed to read task history:", error)
return
}
}
// Early return if no migration needed
if (oldLocationData.length === 0) {
console.log("[Storage Migration] No task history to migrate")
// If we have reached this point, then the taskHistory.json file does not exist or it is an empty array.
// We will get the taskHistory from the old location in the vs code global state and write it to the new location.
const oldLocationTaskHistory = context.globalState.get<HistoryItem[] | undefined>("taskHistory") || []
// We make sure that the old location taskHistory is an array. If it's not, then it's malformed, so we just write an empty array to the new taskHistory storage location.
if (!Array.isArray(oldLocationTaskHistory)) {
console.error("[Storage Migration] Task history in the vs code global state is not an array, skipping migration")
return
}
let finalData: HistoryItem[]
let migrationAction: string
// We write the taskHistory from the vs code global state to the new storage location in the json file.
await writeTaskHistoryToState(context, oldLocationTaskHistory)
const newLocationData = await readTaskHistoryFromState(context)
if (newLocationData.length === 0) {
// Move old data to new location
finalData = oldLocationData
migrationAction = "Migrated task history from old location to new location"
} else {
// Merge old data (more recent) with new data
finalData = [...newLocationData, ...oldLocationData]
migrationAction = "Merged task history from old and new locations"
// confirm that the data has been successfully written to the file by reading it back
const successfullyWrittenData = await readTaskHistoryFromState(context)
if (!Array.isArray(successfullyWrittenData)) {
console.error("[Storage Migration] Task history in the new location is not an array, aborting migration.")
return
}
// Perform migration operations sequentially - only clear old data if write succeeds
await writeTaskHistoryToState(context, finalData)
void context.globalState.update("taskHistory", undefined)
if (successfullyWrittenData.length !== oldLocationTaskHistory.length) {
console.error("[Storage Migration] Task history has not been successfully written to the file")
return
}
console.log(`[Storage Migration] ${migrationAction}`)
console.log(
`[Storage Migration] Migrated task history from old location to new location. ${successfullyWrittenData.length} items written.`,
)
} catch (error) {
console.error("[Storage Migration] Failed to migrate task history to file:", error)
}