From eba2db6fe7106c270dc852cc81819b1eec65bd75 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 18 May 2026 06:00:26 +0000 Subject: [PATCH 1/6] Update submission workflow insertion logic Agent-Logs-Url: https://github.com/webprofusion/OpenAudio/sessions/7e52c2b7-7fa1-4363-8530-1618aab4d3de Co-authored-by: webprofusion-chrisc <2445502+webprofusion-chrisc@users.noreply.github.com> --- .github/workflows/process-submission.yml | 134 ++++++++++++++++++----- 1 file changed, 105 insertions(+), 29 deletions(-) diff --git a/.github/workflows/process-submission.yml b/.github/workflows/process-submission.yml index f9d117e..2db9d29 100644 --- a/.github/workflows/process-submission.yml +++ b/.github/workflows/process-submission.yml @@ -230,30 +230,115 @@ jobs: node << 'EOF' const fs = require('fs'); const path = require('path'); - const {createRequire} = require('module'); - - let prettier; - - try { - const requireFromGenerator = createRequire( - path.join(process.cwd(), 'generator/package.json') - ); - prettier = requireFromGenerator('prettier'); - } catch (error) { - console.error( - 'Unable to load Prettier from generator dependencies. Ensure generator/npm ci has completed successfully.' - ); - console.error(error); - process.exit(1); - } const main = async () => { const entry = JSON.parse(process.env.ENTRY); const targetFile = process.env.TARGET_FILE; + const eol = '\n'; + + const collectTopLevelObjectRanges = source => { + const ranges = []; + let depth = 0; + let inString = false; + let isEscaped = false; + let objectStart = -1; + + for (let index = 0; index < source.length; index += 1) { + const character = source[index]; + + if (inString) { + if (isEscaped) { + isEscaped = false; + continue; + } + + if (character === '\\') { + isEscaped = true; + continue; + } + + if (character === '"') { + inString = false; + } + + continue; + } + + if (character === '"') { + inString = true; + continue; + } + + if (character === '[' || character === '{') { + if (character === '{' && depth === 1) { + objectStart = index; + } + + depth += 1; + continue; + } + + if (character === ']' || character === '}') { + if (character === '}' && depth === 2 && objectStart !== -1) { + ranges.push({ + start: objectStart, + end: index + 1, + }); + objectStart = -1; + } + + depth -= 1; + } + } + + return ranges; + }; + + const inferItemIndent = (source, ranges) => { + if (ranges.length === 0) { + return ' '; + } + + const firstItemStart = ranges[0].start; + const lineStart = source.lastIndexOf(eol, firstItemStart - 1); + const indent = source.slice(lineStart + 1, firstItemStart); + return /^[ \t]*$/.test(indent) ? indent : ' '; + }; + + const formatEntry = (value, indent) => + JSON.stringify(value, null, 2) + .split('\n') + .map(line => `${indent}${line}`) + .join(eol); + + const insertEntryIntoArraySource = (source, value, insertIndex) => { + const ranges = collectTopLevelObjectRanges(source); + const indent = inferItemIndent(source, ranges); + const formattedEntry = formatEntry(value, indent); + + if (ranges.length === 0) { + const openBracketIndex = source.indexOf('['); + const closeBracketIndex = source.lastIndexOf(']'); + return `${source.slice(0, openBracketIndex + 1)}${eol}${formattedEntry}${eol}${source.slice(closeBracketIndex)}`; + } + + if (ranges.length !== data.length) { + throw new Error(`Top-level JSON item range count (${ranges.length}) does not match parsed entry count (${data.length}).`); + } + + if (insertIndex === data.length - 1) { + const previousItemRange = ranges.at(-1); + return `${source.slice(0, previousItemRange.end)},${eol}${formattedEntry}${source.slice(previousItemRange.end)}`; + } + + const nextItemRange = ranges[insertIndex]; + return `${source.slice(0, nextItemRange.start)}${formattedEntry},${eol}${source.slice(nextItemRange.start)}`; + }; // Read existing data const filePath = path.join(process.cwd(), targetFile); - const data = JSON.parse(fs.readFileSync(filePath, 'utf8')); + const source = fs.readFileSync(filePath, 'utf8'); + const data = JSON.parse(source); // Find insertion index (alphabetical by name, case-insensitive) const insertIndex = data.findIndex(item => @@ -267,19 +352,10 @@ jobs: data.splice(insertIndex, 0, entry); } - // Write back with repository formatting to avoid noisy diffs - let formattedData; - - try { - formattedData = await prettier.format(JSON.stringify(data), { - filepath: filePath, - }); - } catch (error) { - console.error(`Failed to format updated JSON for ${targetFile}.`); - throw error; - } + const normalizedInsertIndex = insertIndex === -1 ? data.length - 1 : insertIndex; + const updatedSource = insertEntryIntoArraySource(source, entry, normalizedInsertIndex); - fs.writeFileSync(filePath, formattedData); + fs.writeFileSync(filePath, updatedSource); console.log(`Inserted "${entry.name}" into ${targetFile}`); }; From 7996aade3a2e571239414b80ec1817396834dd53 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 18 May 2026 06:01:18 +0000 Subject: [PATCH 2/6] Fix submission insertion index handling Agent-Logs-Url: https://github.com/webprofusion/OpenAudio/sessions/7e52c2b7-7fa1-4363-8530-1618aab4d3de Co-authored-by: webprofusion-chrisc <2445502+webprofusion-chrisc@users.noreply.github.com> --- .github/workflows/process-submission.yml | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/.github/workflows/process-submission.yml b/.github/workflows/process-submission.yml index 2db9d29..3e7d6df 100644 --- a/.github/workflows/process-submission.yml +++ b/.github/workflows/process-submission.yml @@ -326,7 +326,7 @@ jobs: throw new Error(`Top-level JSON item range count (${ranges.length}) does not match parsed entry count (${data.length}).`); } - if (insertIndex === data.length - 1) { + if (insertIndex === data.length) { const previousItemRange = ranges.at(-1); return `${source.slice(0, previousItemRange.end)},${eol}${formattedEntry}${source.slice(previousItemRange.end)}`; } @@ -345,14 +345,7 @@ jobs: item.name.toLowerCase() > entry.name.toLowerCase() ); - // Insert at correct position - if (insertIndex === -1) { - data.push(entry); - } else { - data.splice(insertIndex, 0, entry); - } - - const normalizedInsertIndex = insertIndex === -1 ? data.length - 1 : insertIndex; + const normalizedInsertIndex = insertIndex === -1 ? data.length : insertIndex; const updatedSource = insertEntryIntoArraySource(source, entry, normalizedInsertIndex); fs.writeFileSync(filePath, updatedSource); From 474b72ef6595bdbb2645a045c1a81c4f0b031cd3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 18 May 2026 06:02:33 +0000 Subject: [PATCH 3/6] Pass item count into submission inserter Agent-Logs-Url: https://github.com/webprofusion/OpenAudio/sessions/7e52c2b7-7fa1-4363-8530-1618aab4d3de Co-authored-by: webprofusion-chrisc <2445502+webprofusion-chrisc@users.noreply.github.com> --- .github/workflows/process-submission.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/process-submission.yml b/.github/workflows/process-submission.yml index 3e7d6df..4fb6f77 100644 --- a/.github/workflows/process-submission.yml +++ b/.github/workflows/process-submission.yml @@ -311,7 +311,7 @@ jobs: .map(line => `${indent}${line}`) .join(eol); - const insertEntryIntoArraySource = (source, value, insertIndex) => { + const insertEntryIntoArraySource = (source, value, insertIndex, itemCount) => { const ranges = collectTopLevelObjectRanges(source); const indent = inferItemIndent(source, ranges); const formattedEntry = formatEntry(value, indent); @@ -322,11 +322,11 @@ jobs: return `${source.slice(0, openBracketIndex + 1)}${eol}${formattedEntry}${eol}${source.slice(closeBracketIndex)}`; } - if (ranges.length !== data.length) { - throw new Error(`Top-level JSON item range count (${ranges.length}) does not match parsed entry count (${data.length}).`); + if (ranges.length !== itemCount) { + throw new Error(`Top-level JSON item range count (${ranges.length}) does not match parsed entry count (${itemCount}).`); } - if (insertIndex === data.length) { + if (insertIndex === itemCount) { const previousItemRange = ranges.at(-1); return `${source.slice(0, previousItemRange.end)},${eol}${formattedEntry}${source.slice(previousItemRange.end)}`; } @@ -346,7 +346,7 @@ jobs: ); const normalizedInsertIndex = insertIndex === -1 ? data.length : insertIndex; - const updatedSource = insertEntryIntoArraySource(source, entry, normalizedInsertIndex); + const updatedSource = insertEntryIntoArraySource(source, entry, normalizedInsertIndex, data.length); fs.writeFileSync(filePath, updatedSource); From 319af6015833a503cf08367693056fc0f50e5943 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 18 May 2026 06:03:37 +0000 Subject: [PATCH 4/6] Refine submission inserter diagnostics Agent-Logs-Url: https://github.com/webprofusion/OpenAudio/sessions/7e52c2b7-7fa1-4363-8530-1618aab4d3de Co-authored-by: webprofusion-chrisc <2445502+webprofusion-chrisc@users.noreply.github.com> --- .github/workflows/process-submission.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/process-submission.yml b/.github/workflows/process-submission.yml index 4fb6f77..69d65f6 100644 --- a/.github/workflows/process-submission.yml +++ b/.github/workflows/process-submission.yml @@ -235,7 +235,9 @@ jobs: const entry = JSON.parse(process.env.ENTRY); const targetFile = process.env.TARGET_FILE; const eol = '\n'; + const defaultIndent = ' '; + // Track top-level object ranges so the new entry can be spliced into the source without reformatting existing items. const collectTopLevelObjectRanges = source => { const ranges = []; let depth = 0; @@ -296,13 +298,13 @@ jobs: const inferItemIndent = (source, ranges) => { if (ranges.length === 0) { - return ' '; + return defaultIndent; } const firstItemStart = ranges[0].start; const lineStart = source.lastIndexOf(eol, firstItemStart - 1); const indent = source.slice(lineStart + 1, firstItemStart); - return /^[ \t]*$/.test(indent) ? indent : ' '; + return /^[ \t]*$/.test(indent) ? indent : defaultIndent; }; const formatEntry = (value, indent) => @@ -311,6 +313,7 @@ jobs: .map(line => `${indent}${line}`) .join(eol); + // Insert the formatted entry at the computed top-level position while preserving all untouched source text. const insertEntryIntoArraySource = (source, value, insertIndex, itemCount) => { const ranges = collectTopLevelObjectRanges(source); const indent = inferItemIndent(source, ranges); @@ -323,7 +326,7 @@ jobs: } if (ranges.length !== itemCount) { - throw new Error(`Top-level JSON item range count (${ranges.length}) does not match parsed entry count (${itemCount}).`); + throw new Error(`Top-level JSON item range count (${ranges.length}) does not match parsed entry count (${itemCount}). This may indicate malformed JSON or unexpected file content in ${targetFile}.`); } if (insertIndex === itemCount) { From 0839527d0ac345b43370eac06efa163470ad801c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 18 May 2026 06:04:26 +0000 Subject: [PATCH 5/6] Tidy submission range parser names Agent-Logs-Url: https://github.com/webprofusion/OpenAudio/sessions/7e52c2b7-7fa1-4363-8530-1618aab4d3de Co-authored-by: webprofusion-chrisc <2445502+webprofusion-chrisc@users.noreply.github.com> --- .github/workflows/process-submission.yml | 34 ++++++++++++------------ 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/workflows/process-submission.yml b/.github/workflows/process-submission.yml index 69d65f6..fb92ba0 100644 --- a/.github/workflows/process-submission.yml +++ b/.github/workflows/process-submission.yml @@ -243,10 +243,10 @@ jobs: let depth = 0; let inString = false; let isEscaped = false; - let objectStart = -1; + let objectStartIndex = -1; - for (let index = 0; index < source.length; index += 1) { - const character = source[index]; + for (let charIndex = 0; charIndex < source.length; charIndex += 1) { + const char = source[charIndex]; if (inString) { if (isEscaped) { @@ -254,39 +254,39 @@ jobs: continue; } - if (character === '\\') { + if (char === '\\') { isEscaped = true; continue; } - if (character === '"') { + if (char === '"') { inString = false; } continue; } - if (character === '"') { + if (char === '"') { inString = true; continue; } - if (character === '[' || character === '{') { - if (character === '{' && depth === 1) { - objectStart = index; + if (char === '[' || char === '{') { + if (char === '{' && depth === 1) { + objectStartIndex = charIndex; } depth += 1; continue; } - if (character === ']' || character === '}') { - if (character === '}' && depth === 2 && objectStart !== -1) { + if (char === ']' || char === '}') { + if (char === '}' && depth === 2 && objectStartIndex !== -1) { ranges.push({ - start: objectStart, - end: index + 1, + start: objectStartIndex, + end: charIndex + 1, }); - objectStart = -1; + objectStartIndex = -1; } depth -= 1; @@ -314,7 +314,7 @@ jobs: .join(eol); // Insert the formatted entry at the computed top-level position while preserving all untouched source text. - const insertEntryIntoArraySource = (source, value, insertIndex, itemCount) => { + const insertEntryIntoArraySource = (source, value, insertIndex, itemCount, fileName) => { const ranges = collectTopLevelObjectRanges(source); const indent = inferItemIndent(source, ranges); const formattedEntry = formatEntry(value, indent); @@ -326,7 +326,7 @@ jobs: } if (ranges.length !== itemCount) { - throw new Error(`Top-level JSON item range count (${ranges.length}) does not match parsed entry count (${itemCount}). This may indicate malformed JSON or unexpected file content in ${targetFile}.`); + throw new Error(`Top-level JSON item range count (${ranges.length}) does not match parsed entry count (${itemCount}). This may indicate malformed JSON or unexpected file content in ${fileName}.`); } if (insertIndex === itemCount) { @@ -349,7 +349,7 @@ jobs: ); const normalizedInsertIndex = insertIndex === -1 ? data.length : insertIndex; - const updatedSource = insertEntryIntoArraySource(source, entry, normalizedInsertIndex, data.length); + const updatedSource = insertEntryIntoArraySource(source, entry, normalizedInsertIndex, data.length, targetFile); fs.writeFileSync(filePath, updatedSource); From 1dac20ab649253f394e052611c96564c047dd7d8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 18 May 2026 06:05:13 +0000 Subject: [PATCH 6/6] Guard submission indent detection Agent-Logs-Url: https://github.com/webprofusion/OpenAudio/sessions/7e52c2b7-7fa1-4363-8530-1618aab4d3de Co-authored-by: webprofusion-chrisc <2445502+webprofusion-chrisc@users.noreply.github.com> --- .github/workflows/process-submission.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/process-submission.yml b/.github/workflows/process-submission.yml index fb92ba0..5734b48 100644 --- a/.github/workflows/process-submission.yml +++ b/.github/workflows/process-submission.yml @@ -303,7 +303,9 @@ jobs: const firstItemStart = ranges[0].start; const lineStart = source.lastIndexOf(eol, firstItemStart - 1); - const indent = source.slice(lineStart + 1, firstItemStart); + const indent = lineStart === -1 + ? '' + : source.slice(lineStart + 1, firstItemStart); return /^[ \t]*$/.test(indent) ? indent : defaultIndent; };