From c623b32964f77529f2de7ad86f5193784cb5c803 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Sat, 30 May 2026 12:35:54 -0700 Subject: [PATCH] fix(gen-skill-docs): use function replacer so a $ in a description can't corrupt frontmatter (#1778) String.prototype.replace treats $&/$1/$` in the replacement as patterns. A future skill description containing $ (e.g. referencing $B/$D) would silently corrupt the generated frontmatter. Use a function replacer. Behavior-preserving for all current descriptions (regen produces no diff). Co-Authored-By: Claude Opus 4.8 (1M context) --- scripts/gen-skill-docs.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/gen-skill-docs.ts b/scripts/gen-skill-docs.ts index fb72e4bd9..f27d95613 100644 --- a/scripts/gen-skill-docs.ts +++ b/scripts/gen-skill-docs.ts @@ -424,7 +424,11 @@ export function applyCatalogTrim(content: string, skillName: string): { content: // parser reads as a nested mapping and rejects — #1778). toYamlInlineScalar // only quotes when needed, so descriptions without special chars stay plain. const newDesc = buildTrimmedDescription(parts); - const newFrontmatter = frontmatter.replace(descMatch[0], `description: ${toYamlInlineScalar(newDesc)}\n`); + // Function replacer (not a string) so a `$` in the description — e.g. a future + // skill referencing `$B`/`$D` — can't be interpreted as a `$&`/`$1` replacement + // pattern and silently corrupt the frontmatter. + const newDescLine = `description: ${toYamlInlineScalar(newDesc)}\n`; + const newFrontmatter = frontmatter.replace(descMatch[0], () => newDescLine); let newContent = '---\n' + newFrontmatter + content.slice(fmEnd); // Insert body section after frontmatter (after the closing ---\n and any