@@ -16,6 +16,18 @@ import { t } from "../../i18n"
1616
1717const ROOMODES_FILENAME = ".roomodes"
1818
19+ /**
20+ * Creates a default .roomodes file content with proper structure
21+ */
22+ function createDefaultRoomodesContent ( ) : string {
23+ return yaml . stringify (
24+ {
25+ customModes : [ ] ,
26+ } ,
27+ { lineWidth : 0 } ,
28+ )
29+ }
30+
1931export class CustomModesManager {
2032 private static readonly cacheTTL = 10_000
2133
@@ -121,21 +133,30 @@ export class CustomModesManager {
121133 let cleanedContent = stripBom ( content )
122134 cleanedContent = this . cleanInvisibleCharacters ( cleanedContent )
123135
136+ // Handle empty or whitespace-only content
137+ if ( ! cleanedContent || cleanedContent . trim ( ) === "" ) {
138+ console . log ( `[CustomModesManager] Empty content detected in ${ filePath } ` )
139+ return { }
140+ }
141+
124142 try {
125- return yaml . parse ( cleanedContent )
143+ const parsed = yaml . parse ( cleanedContent )
144+ // Handle null result from YAML parser (empty document)
145+ return parsed === null ? { } : parsed
126146 } catch ( yamlError ) {
127147 // For .roomodes files, try JSON as fallback
128148 if ( filePath . endsWith ( ROOMODES_FILENAME ) ) {
129149 try {
130150 // Try parsing the original content as JSON (not the cleaned content)
131- return JSON . parse ( content )
151+ const jsonParsed = JSON . parse ( content )
152+ return jsonParsed === null ? { } : jsonParsed
132153 } catch ( jsonError ) {
133154 // JSON also failed, show the original YAML error
134155 const errorMsg = yamlError instanceof Error ? yamlError . message : String ( yamlError )
135156 console . error ( `[CustomModesManager] Failed to parse YAML from ${ filePath } :` , errorMsg )
136157
137158 const lineMatch = errorMsg . match ( / a t l i n e ( \d + ) / )
138- const line = lineMatch ? lineMatch [ 1 ] : "unknown "
159+ const line = lineMatch ? lineMatch [ 1 ] : "1 "
139160 vscode . window . showErrorMessage ( t ( "common:customModes.errors.yamlParseError" , { line } ) )
140161
141162 // Return empty object to prevent duplicate error handling
@@ -154,6 +175,20 @@ export class CustomModesManager {
154175 try {
155176 const content = await fs . readFile ( filePath , "utf-8" )
156177 const settings = this . parseYamlSafely ( content , filePath )
178+
179+ // Handle empty or null content gracefully
180+ if ( ! settings || ( typeof settings === "object" && Object . keys ( settings ) . length === 0 ) ) {
181+ // For .roomodes files, create a default structure if empty
182+ if ( filePath . endsWith ( ROOMODES_FILENAME ) ) {
183+ console . log (
184+ `[CustomModesManager] Empty .roomodes file detected, initializing with default structure` ,
185+ )
186+ // Initialize the file with proper structure
187+ await fs . writeFile ( filePath , createDefaultRoomodesContent ( ) , "utf-8" )
188+ }
189+ return [ ]
190+ }
191+
157192 const result = customModesSettingsSchema . safeParse ( settings )
158193
159194 if ( ! result . success ) {
@@ -166,6 +201,17 @@ export class CustomModesManager {
166201 . join ( "\n" )
167202
168203 vscode . window . showErrorMessage ( t ( "common:customModes.errors.schemaValidationError" , { issues } ) )
204+
205+ // Try to fix common issues automatically
206+ if (
207+ result . error . issues . some (
208+ ( issue ) => issue . path . includes ( "customModes" ) && issue . code === "invalid_type" ,
209+ )
210+ ) {
211+ console . log ( `[CustomModesManager] Attempting to fix malformed .roomodes file` )
212+ await fs . writeFile ( filePath , createDefaultRoomodesContent ( ) , "utf-8" )
213+ return [ ]
214+ }
169215 }
170216
171217 return [ ]
@@ -216,7 +262,7 @@ export class CustomModesManager {
216262 const fileExists = await fileExistsAtPath ( filePath )
217263
218264 if ( ! fileExists ) {
219- await this . queueWrite ( ( ) => fs . writeFile ( filePath , yaml . stringify ( { customModes : [ ] } , { lineWidth : 0 } ) ) )
265+ await this . queueWrite ( ( ) => fs . writeFile ( filePath , createDefaultRoomodesContent ( ) ) )
220266 }
221267
222268 return filePath
@@ -420,7 +466,7 @@ export class CustomModesManager {
420466 content = await fs . readFile ( filePath , "utf-8" )
421467 } catch ( error ) {
422468 // File might not exist yet.
423- content = yaml . stringify ( { customModes : [ ] } , { lineWidth : 0 } )
469+ content = createDefaultRoomodesContent ( )
424470 }
425471
426472 let settings
@@ -491,7 +537,7 @@ export class CustomModesManager {
491537 public async resetCustomModes ( ) : Promise < void > {
492538 try {
493539 const filePath = await this . getCustomModesFilePath ( )
494- await fs . writeFile ( filePath , yaml . stringify ( { customModes : [ ] } , { lineWidth : 0 } ) )
540+ await fs . writeFile ( filePath , createDefaultRoomodesContent ( ) )
495541 await this . context . globalState . update ( "customModes" , [ ] )
496542 this . clearCache ( )
497543 await this . onUpdate ( )
0 commit comments