@@ -73,12 +73,95 @@ export class CustomModesManager {
7373 return exists ? roomodesPath : undefined
7474 }
7575
76+ /**
77+ * Strip BOM (Byte Order Mark) from the beginning of a string
78+ */
79+ private stripBOM ( content : string ) : string {
80+ // Common BOMs: UTF-8, UTF-16 BE, UTF-16 LE
81+ const boms = [
82+ "\uFEFF" , // UTF-8 BOM
83+ "\uFFFE" , // UTF-16 LE BOM (reversed)
84+ ]
85+
86+ let result = content
87+ for ( const bom of boms ) {
88+ if ( result . startsWith ( bom ) ) {
89+ result = result . slice ( bom . length )
90+ }
91+ }
92+
93+ return result
94+ }
95+
96+ /**
97+ * Clean invisible and problematic characters from YAML content
98+ */
99+ private cleanInvisibleCharacters ( content : string ) : string {
100+ // Replace non-breaking spaces with regular spaces
101+ let cleaned = content . replace ( / \u00A0 / g, " " )
102+
103+ // Replace other invisible characters that can cause issues
104+ // Zero-width space, zero-width non-joiner, zero-width joiner
105+ cleaned = cleaned . replace ( / [ \u200B \u200C \u200D ] / g, "" )
106+
107+ // Replace various dash characters with standard hyphen
108+ cleaned = cleaned . replace ( / [ \u2010 - \u2015 \u2212 ] / g, "-" )
109+
110+ // Replace various quote characters with standard quotes
111+ cleaned = cleaned . replace ( / [ \u2018 \u2019 ] / g, "'" )
112+ cleaned = cleaned . replace ( / [ \u201C \u201D ] / g, '"' )
113+
114+ return cleaned
115+ }
116+
117+ /**
118+ * Parse YAML content with enhanced error handling and preprocessing
119+ */
120+ private parseYamlSafely ( content : string , filePath : string ) : any {
121+ // Clean the content
122+ let cleanedContent = this . stripBOM ( content )
123+ cleanedContent = this . cleanInvisibleCharacters ( cleanedContent )
124+
125+ try {
126+ return yaml . parse ( cleanedContent )
127+ } catch ( error ) {
128+ const errorMsg = error instanceof Error ? error . message : String ( error )
129+ console . error ( `[CustomModesManager] Failed to parse YAML from ${ filePath } :` , errorMsg )
130+
131+ // Show user-friendly error message for .roomodes files
132+ if ( filePath . endsWith ( ROOMODES_FILENAME ) ) {
133+ const lineMatch = errorMsg . match ( / a t l i n e ( \d + ) / )
134+ const line = lineMatch ? lineMatch [ 1 ] : "unknown"
135+ vscode . window . showErrorMessage (
136+ `Invalid YAML in .roomodes file at line ${ line } . Please check for:\n` +
137+ `• Proper indentation (use spaces, not tabs)\n` +
138+ `• Matching quotes and brackets\n` +
139+ `• Valid YAML syntax` ,
140+ )
141+ }
142+
143+ throw error
144+ }
145+ }
146+
76147 private async loadModesFromFile ( filePath : string ) : Promise < ModeConfig [ ] > {
77148 try {
78149 const content = await fs . readFile ( filePath , "utf-8" )
79- const settings = yaml . parse ( content )
150+ const settings = this . parseYamlSafely ( content , filePath )
80151 const result = customModesSettingsSchema . safeParse ( settings )
152+
81153 if ( ! result . success ) {
154+ console . error ( `[CustomModesManager] Schema validation failed for ${ filePath } :` , result . error )
155+
156+ // Show user-friendly error for .roomodes files
157+ if ( filePath . endsWith ( ROOMODES_FILENAME ) ) {
158+ const issues = result . error . issues
159+ . map ( ( issue ) => `• ${ issue . path . join ( "." ) } : ${ issue . message } ` )
160+ . join ( "\n" )
161+
162+ vscode . window . showErrorMessage ( `Invalid custom modes format in .roomodes:\n${ issues } ` )
163+ }
164+
82165 return [ ]
83166 }
84167
@@ -153,7 +236,7 @@ export class CustomModesManager {
153236 let config : any
154237
155238 try {
156- config = yaml . parse ( content )
239+ config = this . parseYamlSafely ( content , settingsPath )
157240 } catch ( error ) {
158241 console . error ( error )
159242 vscode . window . showErrorMessage ( errorMessage )
@@ -335,9 +418,9 @@ export class CustomModesManager {
335418 let settings
336419
337420 try {
338- settings = yaml . parse ( content )
421+ settings = this . parseYamlSafely ( content , filePath )
339422 } catch ( error ) {
340- console . error ( `[CustomModesManager] Failed to parse YAML from ${ filePath } :` , error )
423+ // Error already logged in parseYamlSafely
341424 settings = { customModes : [ ] }
342425 }
343426
0 commit comments