@@ -65,6 +65,38 @@ function sleep(ms) {
6565 return new Promise ( resolve => setTimeout ( resolve , ms ) ) ;
6666}
6767
68+ /**
69+ * Builds targeted context for a JSON.parse error so logs can point at the likely key.
70+ *
71+ * @param {string } jsonText
72+ * @param {string } parseErrorMessage
73+ * @returns {{line: number, column: number, lineText: string, key: string | null} | null }
74+ */
75+ function getJSONParseErrorContext ( jsonText , parseErrorMessage ) {
76+ const posMatch = parseErrorMessage . match ( / p o s i t i o n \s + ( \d + ) / i) ;
77+ if ( ! posMatch ) {
78+ return null ;
79+ }
80+
81+ const pos = Number ( posMatch [ 1 ] ) ;
82+ if ( ! Number . isFinite ( pos ) || pos < 0 ) {
83+ return null ;
84+ }
85+
86+ const safePos = Math . min ( pos , Math . max ( 0 , jsonText . length - 1 ) ) ;
87+ const before = jsonText . slice ( 0 , safePos ) ;
88+ const line = before . split ( "\n" ) . length ;
89+ const lineStart = before . lastIndexOf ( "\n" ) + 1 ;
90+ const lineEnd = jsonText . indexOf ( "\n" , safePos ) ;
91+ const resolvedLineEnd = lineEnd === - 1 ? jsonText . length : lineEnd ;
92+ const lineText = jsonText . slice ( lineStart , resolvedLineEnd ) ;
93+ const column = safePos - lineStart + 1 ;
94+ const keyMatch = lineText . match ( / " ( [ ^ " ] + ) " \s * : / ) ;
95+ const key = keyMatch ? keyMatch [ 1 ] : null ;
96+
97+ return { line, column, lineText, key } ;
98+ }
99+
68100/**
69101 * Normalizes GH_AW_OTLP_IF_MISSING to a supported mode.
70102 * @param {string | undefined } value
@@ -367,7 +399,16 @@ async function main() {
367399 core . error ( "ERROR: Configuration is not valid JSON" ) ;
368400 core . error ( "" ) ;
369401 core . error ( "JSON validation error:" ) ;
370- core . error ( /** @type {Error } */ err . message ) ;
402+ const parseMessage = /** @type {Error } */ err . message ;
403+ core . error ( parseMessage ) ;
404+ const parseContext = getJSONParseErrorContext ( mcpConfig , parseMessage ) ;
405+ if ( parseContext ) {
406+ core . error ( `Likely offending location: line ${ parseContext . line } , column ${ parseContext . column } ` ) ;
407+ if ( parseContext . key ) {
408+ core . error ( `Likely offending key: ${ parseContext . key } ` ) ;
409+ }
410+ core . error ( `Context line: ${ parseContext . lineText } ` ) ;
411+ }
371412 core . error ( "" ) ;
372413 core . error ( "Configuration content:" ) ;
373414 const lines = mcpConfig . split ( "\n" ) ;
@@ -909,5 +950,6 @@ module.exports = {
909950 getOTLPIfMissingMode,
910951 hasNonEmptyOTLPHeaders,
911952 isOTLPIfMissingIgnore,
953+ getJSONParseErrorContext,
912954 resolveCopilotConfigPaths,
913955} ;
0 commit comments