From e92bf2b774fc5d28175e35273677929228a50787 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 31 Aug 2026 20:32:06 +0000 Subject: [PATCH] Sync generated provider output --- .../impeccable/scripts/lib/design-parser.mjs | 48 +++++++------------ .../impeccable/scripts/lib/design-parser.mjs | 48 +++++++------------ .../impeccable/scripts/lib/design-parser.mjs | 48 +++++++------------ .../impeccable/scripts/lib/design-parser.mjs | 48 +++++++------------ .../impeccable/scripts/lib/design-parser.mjs | 48 +++++++------------ .../impeccable/scripts/lib/design-parser.mjs | 48 +++++++------------ .../impeccable/scripts/lib/design-parser.mjs | 48 +++++++------------ .../impeccable/scripts/lib/design-parser.mjs | 48 +++++++------------ .../impeccable/scripts/lib/design-parser.mjs | 48 +++++++------------ .../impeccable/scripts/lib/design-parser.mjs | 48 +++++++------------ .../impeccable/scripts/lib/design-parser.mjs | 48 +++++++------------ .../impeccable/scripts/lib/design-parser.mjs | 48 +++++++------------ .../impeccable/scripts/lib/design-parser.mjs | 48 +++++++------------ .../impeccable/scripts/lib/design-parser.mjs | 48 +++++++------------ .../impeccable/scripts/lib/design-parser.mjs | 48 +++++++------------ .../impeccable/scripts/lib/design-parser.mjs | 48 +++++++------------ 16 files changed, 288 insertions(+), 480 deletions(-) diff --git a/.agents/skills/impeccable/scripts/lib/design-parser.mjs b/.agents/skills/impeccable/scripts/lib/design-parser.mjs index cab191d69..6f240a51e 100644 --- a/.agents/skills/impeccable/scripts/lib/design-parser.mjs +++ b/.agents/skills/impeccable/scripts/lib/design-parser.mjs @@ -329,47 +329,37 @@ function stripBold(s) { function extractNamedRules(lines) { const rules = []; const seen = new Set(); + const addRule = (name, body, { allowDuplicate = false } = {}) => { + const key = name.toLowerCase(); + if (!allowDuplicate && seen.has(key)) return; + seen.add(key); + rules.push({ name, body }); + }; // Style A (Impeccable): "**The X Rule.** body body body" — can span lines. const joined = lines.join('\n'); - const inlineStart = /\*\*(The [^*]+?Rule)\.\*\*/g; - const inlineMatches = []; - let m; - while ((m = inlineStart.exec(joined)) !== null) { - inlineMatches.push({ name: m[1], start: m.index, end: inlineStart.lastIndex }); - } + const inlineMatches = [...joined.matchAll(/\*\*(The [^*]+?Rule)\.\*\*/g)]; for (let i = 0; i < inlineMatches.length; i++) { - const mm = inlineMatches[i]; - const bodyEnd = i + 1 < inlineMatches.length ? inlineMatches[i + 1].start : joined.length; + const match = inlineMatches[i]; + const bodyEnd = inlineMatches[i + 1]?.index ?? joined.length; const body = joined - .slice(mm.end, bodyEnd) + .slice(match.index + match[0].length, bodyEnd) .replace(/\n##[^\n]*$/s, '') .replace(/\n###[^\n]*$/s, '') .trim(); - const name = stripBold(mm.name).trim(); - seen.add(name.toLowerCase()); - rules.push({ name, body: stripBold(body) }); + // Preserve the inline format's historical behavior: repeated inline rules + // remain visible, while the later heading and bullet formats dedupe. + addRule(stripBold(match[1]).trim(), stripBold(body), { allowDuplicate: true }); } // Style B (Stitch): `### The "X" Rule` or `### The X Fallback`, body is the // bullets/paragraphs until the next heading. Accept Rule / Fallback / Principle. - for (let i = 0; i < lines.length; i++) { - const h3 = lines[i].match(/^###\s+(.+?)\s*$/); - if (!h3) continue; - const headerName = stripBold(h3[1]).replace(/["“”]/g, '').trim(); + for (const subsection of splitSubsections(lines).slice(1)) { + const headerName = stripBold(subsection.name).replace(/["“”]/g, '').trim(); if (!/^The\b.*\b(Rule|Fallback|Principle)\b/i.test(headerName)) continue; - if (seen.has(headerName.toLowerCase())) continue; - const bodyLines = []; - for (let j = i + 1; j < lines.length; j++) { - if (/^##\s|^###\s/.test(lines[j])) break; - bodyLines.push(lines[j]); - } - const body = stripBold(bodyLines.join('\n').replace(/\n+/g, ' ')).trim(); - if (body) { - seen.add(headerName.toLowerCase()); - rules.push({ name: headerName, body }); - } + const body = stripBold(subsection.lines.join('\n').replace(/\n+/g, ' ')).trim(); + if (body) addRule(headerName, body); } // Style C (Stitch bullet form): "* **The Layering Principle:** body" @@ -379,9 +369,7 @@ function extractNamedRules(lines) { if (!mm) continue; const nameRaw = mm[1].replace(/[.:]\s*$/, '').replace(/["“”]/g, '').trim(); if (!/^The\b.+\b(Rule|Fallback|Principle)$/i.test(nameRaw)) continue; - if (seen.has(nameRaw.toLowerCase())) continue; - seen.add(nameRaw.toLowerCase()); - rules.push({ name: nameRaw, body: stripBold(mm[2]).trim() }); + addRule(nameRaw, stripBold(mm[2]).trim()); } return rules; diff --git a/.claude/skills/impeccable/scripts/lib/design-parser.mjs b/.claude/skills/impeccable/scripts/lib/design-parser.mjs index cab191d69..6f240a51e 100644 --- a/.claude/skills/impeccable/scripts/lib/design-parser.mjs +++ b/.claude/skills/impeccable/scripts/lib/design-parser.mjs @@ -329,47 +329,37 @@ function stripBold(s) { function extractNamedRules(lines) { const rules = []; const seen = new Set(); + const addRule = (name, body, { allowDuplicate = false } = {}) => { + const key = name.toLowerCase(); + if (!allowDuplicate && seen.has(key)) return; + seen.add(key); + rules.push({ name, body }); + }; // Style A (Impeccable): "**The X Rule.** body body body" — can span lines. const joined = lines.join('\n'); - const inlineStart = /\*\*(The [^*]+?Rule)\.\*\*/g; - const inlineMatches = []; - let m; - while ((m = inlineStart.exec(joined)) !== null) { - inlineMatches.push({ name: m[1], start: m.index, end: inlineStart.lastIndex }); - } + const inlineMatches = [...joined.matchAll(/\*\*(The [^*]+?Rule)\.\*\*/g)]; for (let i = 0; i < inlineMatches.length; i++) { - const mm = inlineMatches[i]; - const bodyEnd = i + 1 < inlineMatches.length ? inlineMatches[i + 1].start : joined.length; + const match = inlineMatches[i]; + const bodyEnd = inlineMatches[i + 1]?.index ?? joined.length; const body = joined - .slice(mm.end, bodyEnd) + .slice(match.index + match[0].length, bodyEnd) .replace(/\n##[^\n]*$/s, '') .replace(/\n###[^\n]*$/s, '') .trim(); - const name = stripBold(mm.name).trim(); - seen.add(name.toLowerCase()); - rules.push({ name, body: stripBold(body) }); + // Preserve the inline format's historical behavior: repeated inline rules + // remain visible, while the later heading and bullet formats dedupe. + addRule(stripBold(match[1]).trim(), stripBold(body), { allowDuplicate: true }); } // Style B (Stitch): `### The "X" Rule` or `### The X Fallback`, body is the // bullets/paragraphs until the next heading. Accept Rule / Fallback / Principle. - for (let i = 0; i < lines.length; i++) { - const h3 = lines[i].match(/^###\s+(.+?)\s*$/); - if (!h3) continue; - const headerName = stripBold(h3[1]).replace(/["“”]/g, '').trim(); + for (const subsection of splitSubsections(lines).slice(1)) { + const headerName = stripBold(subsection.name).replace(/["“”]/g, '').trim(); if (!/^The\b.*\b(Rule|Fallback|Principle)\b/i.test(headerName)) continue; - if (seen.has(headerName.toLowerCase())) continue; - const bodyLines = []; - for (let j = i + 1; j < lines.length; j++) { - if (/^##\s|^###\s/.test(lines[j])) break; - bodyLines.push(lines[j]); - } - const body = stripBold(bodyLines.join('\n').replace(/\n+/g, ' ')).trim(); - if (body) { - seen.add(headerName.toLowerCase()); - rules.push({ name: headerName, body }); - } + const body = stripBold(subsection.lines.join('\n').replace(/\n+/g, ' ')).trim(); + if (body) addRule(headerName, body); } // Style C (Stitch bullet form): "* **The Layering Principle:** body" @@ -379,9 +369,7 @@ function extractNamedRules(lines) { if (!mm) continue; const nameRaw = mm[1].replace(/[.:]\s*$/, '').replace(/["“”]/g, '').trim(); if (!/^The\b.+\b(Rule|Fallback|Principle)$/i.test(nameRaw)) continue; - if (seen.has(nameRaw.toLowerCase())) continue; - seen.add(nameRaw.toLowerCase()); - rules.push({ name: nameRaw, body: stripBold(mm[2]).trim() }); + addRule(nameRaw, stripBold(mm[2]).trim()); } return rules; diff --git a/.cursor/skills/impeccable/scripts/lib/design-parser.mjs b/.cursor/skills/impeccable/scripts/lib/design-parser.mjs index cab191d69..6f240a51e 100644 --- a/.cursor/skills/impeccable/scripts/lib/design-parser.mjs +++ b/.cursor/skills/impeccable/scripts/lib/design-parser.mjs @@ -329,47 +329,37 @@ function stripBold(s) { function extractNamedRules(lines) { const rules = []; const seen = new Set(); + const addRule = (name, body, { allowDuplicate = false } = {}) => { + const key = name.toLowerCase(); + if (!allowDuplicate && seen.has(key)) return; + seen.add(key); + rules.push({ name, body }); + }; // Style A (Impeccable): "**The X Rule.** body body body" — can span lines. const joined = lines.join('\n'); - const inlineStart = /\*\*(The [^*]+?Rule)\.\*\*/g; - const inlineMatches = []; - let m; - while ((m = inlineStart.exec(joined)) !== null) { - inlineMatches.push({ name: m[1], start: m.index, end: inlineStart.lastIndex }); - } + const inlineMatches = [...joined.matchAll(/\*\*(The [^*]+?Rule)\.\*\*/g)]; for (let i = 0; i < inlineMatches.length; i++) { - const mm = inlineMatches[i]; - const bodyEnd = i + 1 < inlineMatches.length ? inlineMatches[i + 1].start : joined.length; + const match = inlineMatches[i]; + const bodyEnd = inlineMatches[i + 1]?.index ?? joined.length; const body = joined - .slice(mm.end, bodyEnd) + .slice(match.index + match[0].length, bodyEnd) .replace(/\n##[^\n]*$/s, '') .replace(/\n###[^\n]*$/s, '') .trim(); - const name = stripBold(mm.name).trim(); - seen.add(name.toLowerCase()); - rules.push({ name, body: stripBold(body) }); + // Preserve the inline format's historical behavior: repeated inline rules + // remain visible, while the later heading and bullet formats dedupe. + addRule(stripBold(match[1]).trim(), stripBold(body), { allowDuplicate: true }); } // Style B (Stitch): `### The "X" Rule` or `### The X Fallback`, body is the // bullets/paragraphs until the next heading. Accept Rule / Fallback / Principle. - for (let i = 0; i < lines.length; i++) { - const h3 = lines[i].match(/^###\s+(.+?)\s*$/); - if (!h3) continue; - const headerName = stripBold(h3[1]).replace(/["“”]/g, '').trim(); + for (const subsection of splitSubsections(lines).slice(1)) { + const headerName = stripBold(subsection.name).replace(/["“”]/g, '').trim(); if (!/^The\b.*\b(Rule|Fallback|Principle)\b/i.test(headerName)) continue; - if (seen.has(headerName.toLowerCase())) continue; - const bodyLines = []; - for (let j = i + 1; j < lines.length; j++) { - if (/^##\s|^###\s/.test(lines[j])) break; - bodyLines.push(lines[j]); - } - const body = stripBold(bodyLines.join('\n').replace(/\n+/g, ' ')).trim(); - if (body) { - seen.add(headerName.toLowerCase()); - rules.push({ name: headerName, body }); - } + const body = stripBold(subsection.lines.join('\n').replace(/\n+/g, ' ')).trim(); + if (body) addRule(headerName, body); } // Style C (Stitch bullet form): "* **The Layering Principle:** body" @@ -379,9 +369,7 @@ function extractNamedRules(lines) { if (!mm) continue; const nameRaw = mm[1].replace(/[.:]\s*$/, '').replace(/["“”]/g, '').trim(); if (!/^The\b.+\b(Rule|Fallback|Principle)$/i.test(nameRaw)) continue; - if (seen.has(nameRaw.toLowerCase())) continue; - seen.add(nameRaw.toLowerCase()); - rules.push({ name: nameRaw, body: stripBold(mm[2]).trim() }); + addRule(nameRaw, stripBold(mm[2]).trim()); } return rules; diff --git a/.gemini/skills/impeccable/scripts/lib/design-parser.mjs b/.gemini/skills/impeccable/scripts/lib/design-parser.mjs index cab191d69..6f240a51e 100644 --- a/.gemini/skills/impeccable/scripts/lib/design-parser.mjs +++ b/.gemini/skills/impeccable/scripts/lib/design-parser.mjs @@ -329,47 +329,37 @@ function stripBold(s) { function extractNamedRules(lines) { const rules = []; const seen = new Set(); + const addRule = (name, body, { allowDuplicate = false } = {}) => { + const key = name.toLowerCase(); + if (!allowDuplicate && seen.has(key)) return; + seen.add(key); + rules.push({ name, body }); + }; // Style A (Impeccable): "**The X Rule.** body body body" — can span lines. const joined = lines.join('\n'); - const inlineStart = /\*\*(The [^*]+?Rule)\.\*\*/g; - const inlineMatches = []; - let m; - while ((m = inlineStart.exec(joined)) !== null) { - inlineMatches.push({ name: m[1], start: m.index, end: inlineStart.lastIndex }); - } + const inlineMatches = [...joined.matchAll(/\*\*(The [^*]+?Rule)\.\*\*/g)]; for (let i = 0; i < inlineMatches.length; i++) { - const mm = inlineMatches[i]; - const bodyEnd = i + 1 < inlineMatches.length ? inlineMatches[i + 1].start : joined.length; + const match = inlineMatches[i]; + const bodyEnd = inlineMatches[i + 1]?.index ?? joined.length; const body = joined - .slice(mm.end, bodyEnd) + .slice(match.index + match[0].length, bodyEnd) .replace(/\n##[^\n]*$/s, '') .replace(/\n###[^\n]*$/s, '') .trim(); - const name = stripBold(mm.name).trim(); - seen.add(name.toLowerCase()); - rules.push({ name, body: stripBold(body) }); + // Preserve the inline format's historical behavior: repeated inline rules + // remain visible, while the later heading and bullet formats dedupe. + addRule(stripBold(match[1]).trim(), stripBold(body), { allowDuplicate: true }); } // Style B (Stitch): `### The "X" Rule` or `### The X Fallback`, body is the // bullets/paragraphs until the next heading. Accept Rule / Fallback / Principle. - for (let i = 0; i < lines.length; i++) { - const h3 = lines[i].match(/^###\s+(.+?)\s*$/); - if (!h3) continue; - const headerName = stripBold(h3[1]).replace(/["“”]/g, '').trim(); + for (const subsection of splitSubsections(lines).slice(1)) { + const headerName = stripBold(subsection.name).replace(/["“”]/g, '').trim(); if (!/^The\b.*\b(Rule|Fallback|Principle)\b/i.test(headerName)) continue; - if (seen.has(headerName.toLowerCase())) continue; - const bodyLines = []; - for (let j = i + 1; j < lines.length; j++) { - if (/^##\s|^###\s/.test(lines[j])) break; - bodyLines.push(lines[j]); - } - const body = stripBold(bodyLines.join('\n').replace(/\n+/g, ' ')).trim(); - if (body) { - seen.add(headerName.toLowerCase()); - rules.push({ name: headerName, body }); - } + const body = stripBold(subsection.lines.join('\n').replace(/\n+/g, ' ')).trim(); + if (body) addRule(headerName, body); } // Style C (Stitch bullet form): "* **The Layering Principle:** body" @@ -379,9 +369,7 @@ function extractNamedRules(lines) { if (!mm) continue; const nameRaw = mm[1].replace(/[.:]\s*$/, '').replace(/["“”]/g, '').trim(); if (!/^The\b.+\b(Rule|Fallback|Principle)$/i.test(nameRaw)) continue; - if (seen.has(nameRaw.toLowerCase())) continue; - seen.add(nameRaw.toLowerCase()); - rules.push({ name: nameRaw, body: stripBold(mm[2]).trim() }); + addRule(nameRaw, stripBold(mm[2]).trim()); } return rules; diff --git a/.github/skills/impeccable/scripts/lib/design-parser.mjs b/.github/skills/impeccable/scripts/lib/design-parser.mjs index cab191d69..6f240a51e 100644 --- a/.github/skills/impeccable/scripts/lib/design-parser.mjs +++ b/.github/skills/impeccable/scripts/lib/design-parser.mjs @@ -329,47 +329,37 @@ function stripBold(s) { function extractNamedRules(lines) { const rules = []; const seen = new Set(); + const addRule = (name, body, { allowDuplicate = false } = {}) => { + const key = name.toLowerCase(); + if (!allowDuplicate && seen.has(key)) return; + seen.add(key); + rules.push({ name, body }); + }; // Style A (Impeccable): "**The X Rule.** body body body" — can span lines. const joined = lines.join('\n'); - const inlineStart = /\*\*(The [^*]+?Rule)\.\*\*/g; - const inlineMatches = []; - let m; - while ((m = inlineStart.exec(joined)) !== null) { - inlineMatches.push({ name: m[1], start: m.index, end: inlineStart.lastIndex }); - } + const inlineMatches = [...joined.matchAll(/\*\*(The [^*]+?Rule)\.\*\*/g)]; for (let i = 0; i < inlineMatches.length; i++) { - const mm = inlineMatches[i]; - const bodyEnd = i + 1 < inlineMatches.length ? inlineMatches[i + 1].start : joined.length; + const match = inlineMatches[i]; + const bodyEnd = inlineMatches[i + 1]?.index ?? joined.length; const body = joined - .slice(mm.end, bodyEnd) + .slice(match.index + match[0].length, bodyEnd) .replace(/\n##[^\n]*$/s, '') .replace(/\n###[^\n]*$/s, '') .trim(); - const name = stripBold(mm.name).trim(); - seen.add(name.toLowerCase()); - rules.push({ name, body: stripBold(body) }); + // Preserve the inline format's historical behavior: repeated inline rules + // remain visible, while the later heading and bullet formats dedupe. + addRule(stripBold(match[1]).trim(), stripBold(body), { allowDuplicate: true }); } // Style B (Stitch): `### The "X" Rule` or `### The X Fallback`, body is the // bullets/paragraphs until the next heading. Accept Rule / Fallback / Principle. - for (let i = 0; i < lines.length; i++) { - const h3 = lines[i].match(/^###\s+(.+?)\s*$/); - if (!h3) continue; - const headerName = stripBold(h3[1]).replace(/["“”]/g, '').trim(); + for (const subsection of splitSubsections(lines).slice(1)) { + const headerName = stripBold(subsection.name).replace(/["“”]/g, '').trim(); if (!/^The\b.*\b(Rule|Fallback|Principle)\b/i.test(headerName)) continue; - if (seen.has(headerName.toLowerCase())) continue; - const bodyLines = []; - for (let j = i + 1; j < lines.length; j++) { - if (/^##\s|^###\s/.test(lines[j])) break; - bodyLines.push(lines[j]); - } - const body = stripBold(bodyLines.join('\n').replace(/\n+/g, ' ')).trim(); - if (body) { - seen.add(headerName.toLowerCase()); - rules.push({ name: headerName, body }); - } + const body = stripBold(subsection.lines.join('\n').replace(/\n+/g, ' ')).trim(); + if (body) addRule(headerName, body); } // Style C (Stitch bullet form): "* **The Layering Principle:** body" @@ -379,9 +369,7 @@ function extractNamedRules(lines) { if (!mm) continue; const nameRaw = mm[1].replace(/[.:]\s*$/, '').replace(/["“”]/g, '').trim(); if (!/^The\b.+\b(Rule|Fallback|Principle)$/i.test(nameRaw)) continue; - if (seen.has(nameRaw.toLowerCase())) continue; - seen.add(nameRaw.toLowerCase()); - rules.push({ name: nameRaw, body: stripBold(mm[2]).trim() }); + addRule(nameRaw, stripBold(mm[2]).trim()); } return rules; diff --git a/.grok/skills/impeccable/scripts/lib/design-parser.mjs b/.grok/skills/impeccable/scripts/lib/design-parser.mjs index cab191d69..6f240a51e 100644 --- a/.grok/skills/impeccable/scripts/lib/design-parser.mjs +++ b/.grok/skills/impeccable/scripts/lib/design-parser.mjs @@ -329,47 +329,37 @@ function stripBold(s) { function extractNamedRules(lines) { const rules = []; const seen = new Set(); + const addRule = (name, body, { allowDuplicate = false } = {}) => { + const key = name.toLowerCase(); + if (!allowDuplicate && seen.has(key)) return; + seen.add(key); + rules.push({ name, body }); + }; // Style A (Impeccable): "**The X Rule.** body body body" — can span lines. const joined = lines.join('\n'); - const inlineStart = /\*\*(The [^*]+?Rule)\.\*\*/g; - const inlineMatches = []; - let m; - while ((m = inlineStart.exec(joined)) !== null) { - inlineMatches.push({ name: m[1], start: m.index, end: inlineStart.lastIndex }); - } + const inlineMatches = [...joined.matchAll(/\*\*(The [^*]+?Rule)\.\*\*/g)]; for (let i = 0; i < inlineMatches.length; i++) { - const mm = inlineMatches[i]; - const bodyEnd = i + 1 < inlineMatches.length ? inlineMatches[i + 1].start : joined.length; + const match = inlineMatches[i]; + const bodyEnd = inlineMatches[i + 1]?.index ?? joined.length; const body = joined - .slice(mm.end, bodyEnd) + .slice(match.index + match[0].length, bodyEnd) .replace(/\n##[^\n]*$/s, '') .replace(/\n###[^\n]*$/s, '') .trim(); - const name = stripBold(mm.name).trim(); - seen.add(name.toLowerCase()); - rules.push({ name, body: stripBold(body) }); + // Preserve the inline format's historical behavior: repeated inline rules + // remain visible, while the later heading and bullet formats dedupe. + addRule(stripBold(match[1]).trim(), stripBold(body), { allowDuplicate: true }); } // Style B (Stitch): `### The "X" Rule` or `### The X Fallback`, body is the // bullets/paragraphs until the next heading. Accept Rule / Fallback / Principle. - for (let i = 0; i < lines.length; i++) { - const h3 = lines[i].match(/^###\s+(.+?)\s*$/); - if (!h3) continue; - const headerName = stripBold(h3[1]).replace(/["“”]/g, '').trim(); + for (const subsection of splitSubsections(lines).slice(1)) { + const headerName = stripBold(subsection.name).replace(/["“”]/g, '').trim(); if (!/^The\b.*\b(Rule|Fallback|Principle)\b/i.test(headerName)) continue; - if (seen.has(headerName.toLowerCase())) continue; - const bodyLines = []; - for (let j = i + 1; j < lines.length; j++) { - if (/^##\s|^###\s/.test(lines[j])) break; - bodyLines.push(lines[j]); - } - const body = stripBold(bodyLines.join('\n').replace(/\n+/g, ' ')).trim(); - if (body) { - seen.add(headerName.toLowerCase()); - rules.push({ name: headerName, body }); - } + const body = stripBold(subsection.lines.join('\n').replace(/\n+/g, ' ')).trim(); + if (body) addRule(headerName, body); } // Style C (Stitch bullet form): "* **The Layering Principle:** body" @@ -379,9 +369,7 @@ function extractNamedRules(lines) { if (!mm) continue; const nameRaw = mm[1].replace(/[.:]\s*$/, '').replace(/["“”]/g, '').trim(); if (!/^The\b.+\b(Rule|Fallback|Principle)$/i.test(nameRaw)) continue; - if (seen.has(nameRaw.toLowerCase())) continue; - seen.add(nameRaw.toLowerCase()); - rules.push({ name: nameRaw, body: stripBold(mm[2]).trim() }); + addRule(nameRaw, stripBold(mm[2]).trim()); } return rules; diff --git a/.hermes/skills/impeccable/scripts/lib/design-parser.mjs b/.hermes/skills/impeccable/scripts/lib/design-parser.mjs index cab191d69..6f240a51e 100644 --- a/.hermes/skills/impeccable/scripts/lib/design-parser.mjs +++ b/.hermes/skills/impeccable/scripts/lib/design-parser.mjs @@ -329,47 +329,37 @@ function stripBold(s) { function extractNamedRules(lines) { const rules = []; const seen = new Set(); + const addRule = (name, body, { allowDuplicate = false } = {}) => { + const key = name.toLowerCase(); + if (!allowDuplicate && seen.has(key)) return; + seen.add(key); + rules.push({ name, body }); + }; // Style A (Impeccable): "**The X Rule.** body body body" — can span lines. const joined = lines.join('\n'); - const inlineStart = /\*\*(The [^*]+?Rule)\.\*\*/g; - const inlineMatches = []; - let m; - while ((m = inlineStart.exec(joined)) !== null) { - inlineMatches.push({ name: m[1], start: m.index, end: inlineStart.lastIndex }); - } + const inlineMatches = [...joined.matchAll(/\*\*(The [^*]+?Rule)\.\*\*/g)]; for (let i = 0; i < inlineMatches.length; i++) { - const mm = inlineMatches[i]; - const bodyEnd = i + 1 < inlineMatches.length ? inlineMatches[i + 1].start : joined.length; + const match = inlineMatches[i]; + const bodyEnd = inlineMatches[i + 1]?.index ?? joined.length; const body = joined - .slice(mm.end, bodyEnd) + .slice(match.index + match[0].length, bodyEnd) .replace(/\n##[^\n]*$/s, '') .replace(/\n###[^\n]*$/s, '') .trim(); - const name = stripBold(mm.name).trim(); - seen.add(name.toLowerCase()); - rules.push({ name, body: stripBold(body) }); + // Preserve the inline format's historical behavior: repeated inline rules + // remain visible, while the later heading and bullet formats dedupe. + addRule(stripBold(match[1]).trim(), stripBold(body), { allowDuplicate: true }); } // Style B (Stitch): `### The "X" Rule` or `### The X Fallback`, body is the // bullets/paragraphs until the next heading. Accept Rule / Fallback / Principle. - for (let i = 0; i < lines.length; i++) { - const h3 = lines[i].match(/^###\s+(.+?)\s*$/); - if (!h3) continue; - const headerName = stripBold(h3[1]).replace(/["“”]/g, '').trim(); + for (const subsection of splitSubsections(lines).slice(1)) { + const headerName = stripBold(subsection.name).replace(/["“”]/g, '').trim(); if (!/^The\b.*\b(Rule|Fallback|Principle)\b/i.test(headerName)) continue; - if (seen.has(headerName.toLowerCase())) continue; - const bodyLines = []; - for (let j = i + 1; j < lines.length; j++) { - if (/^##\s|^###\s/.test(lines[j])) break; - bodyLines.push(lines[j]); - } - const body = stripBold(bodyLines.join('\n').replace(/\n+/g, ' ')).trim(); - if (body) { - seen.add(headerName.toLowerCase()); - rules.push({ name: headerName, body }); - } + const body = stripBold(subsection.lines.join('\n').replace(/\n+/g, ' ')).trim(); + if (body) addRule(headerName, body); } // Style C (Stitch bullet form): "* **The Layering Principle:** body" @@ -379,9 +369,7 @@ function extractNamedRules(lines) { if (!mm) continue; const nameRaw = mm[1].replace(/[.:]\s*$/, '').replace(/["“”]/g, '').trim(); if (!/^The\b.+\b(Rule|Fallback|Principle)$/i.test(nameRaw)) continue; - if (seen.has(nameRaw.toLowerCase())) continue; - seen.add(nameRaw.toLowerCase()); - rules.push({ name: nameRaw, body: stripBold(mm[2]).trim() }); + addRule(nameRaw, stripBold(mm[2]).trim()); } return rules; diff --git a/.kiro/skills/impeccable/scripts/lib/design-parser.mjs b/.kiro/skills/impeccable/scripts/lib/design-parser.mjs index cab191d69..6f240a51e 100644 --- a/.kiro/skills/impeccable/scripts/lib/design-parser.mjs +++ b/.kiro/skills/impeccable/scripts/lib/design-parser.mjs @@ -329,47 +329,37 @@ function stripBold(s) { function extractNamedRules(lines) { const rules = []; const seen = new Set(); + const addRule = (name, body, { allowDuplicate = false } = {}) => { + const key = name.toLowerCase(); + if (!allowDuplicate && seen.has(key)) return; + seen.add(key); + rules.push({ name, body }); + }; // Style A (Impeccable): "**The X Rule.** body body body" — can span lines. const joined = lines.join('\n'); - const inlineStart = /\*\*(The [^*]+?Rule)\.\*\*/g; - const inlineMatches = []; - let m; - while ((m = inlineStart.exec(joined)) !== null) { - inlineMatches.push({ name: m[1], start: m.index, end: inlineStart.lastIndex }); - } + const inlineMatches = [...joined.matchAll(/\*\*(The [^*]+?Rule)\.\*\*/g)]; for (let i = 0; i < inlineMatches.length; i++) { - const mm = inlineMatches[i]; - const bodyEnd = i + 1 < inlineMatches.length ? inlineMatches[i + 1].start : joined.length; + const match = inlineMatches[i]; + const bodyEnd = inlineMatches[i + 1]?.index ?? joined.length; const body = joined - .slice(mm.end, bodyEnd) + .slice(match.index + match[0].length, bodyEnd) .replace(/\n##[^\n]*$/s, '') .replace(/\n###[^\n]*$/s, '') .trim(); - const name = stripBold(mm.name).trim(); - seen.add(name.toLowerCase()); - rules.push({ name, body: stripBold(body) }); + // Preserve the inline format's historical behavior: repeated inline rules + // remain visible, while the later heading and bullet formats dedupe. + addRule(stripBold(match[1]).trim(), stripBold(body), { allowDuplicate: true }); } // Style B (Stitch): `### The "X" Rule` or `### The X Fallback`, body is the // bullets/paragraphs until the next heading. Accept Rule / Fallback / Principle. - for (let i = 0; i < lines.length; i++) { - const h3 = lines[i].match(/^###\s+(.+?)\s*$/); - if (!h3) continue; - const headerName = stripBold(h3[1]).replace(/["“”]/g, '').trim(); + for (const subsection of splitSubsections(lines).slice(1)) { + const headerName = stripBold(subsection.name).replace(/["“”]/g, '').trim(); if (!/^The\b.*\b(Rule|Fallback|Principle)\b/i.test(headerName)) continue; - if (seen.has(headerName.toLowerCase())) continue; - const bodyLines = []; - for (let j = i + 1; j < lines.length; j++) { - if (/^##\s|^###\s/.test(lines[j])) break; - bodyLines.push(lines[j]); - } - const body = stripBold(bodyLines.join('\n').replace(/\n+/g, ' ')).trim(); - if (body) { - seen.add(headerName.toLowerCase()); - rules.push({ name: headerName, body }); - } + const body = stripBold(subsection.lines.join('\n').replace(/\n+/g, ' ')).trim(); + if (body) addRule(headerName, body); } // Style C (Stitch bullet form): "* **The Layering Principle:** body" @@ -379,9 +369,7 @@ function extractNamedRules(lines) { if (!mm) continue; const nameRaw = mm[1].replace(/[.:]\s*$/, '').replace(/["“”]/g, '').trim(); if (!/^The\b.+\b(Rule|Fallback|Principle)$/i.test(nameRaw)) continue; - if (seen.has(nameRaw.toLowerCase())) continue; - seen.add(nameRaw.toLowerCase()); - rules.push({ name: nameRaw, body: stripBold(mm[2]).trim() }); + addRule(nameRaw, stripBold(mm[2]).trim()); } return rules; diff --git a/.opencode/skills/impeccable/scripts/lib/design-parser.mjs b/.opencode/skills/impeccable/scripts/lib/design-parser.mjs index cab191d69..6f240a51e 100644 --- a/.opencode/skills/impeccable/scripts/lib/design-parser.mjs +++ b/.opencode/skills/impeccable/scripts/lib/design-parser.mjs @@ -329,47 +329,37 @@ function stripBold(s) { function extractNamedRules(lines) { const rules = []; const seen = new Set(); + const addRule = (name, body, { allowDuplicate = false } = {}) => { + const key = name.toLowerCase(); + if (!allowDuplicate && seen.has(key)) return; + seen.add(key); + rules.push({ name, body }); + }; // Style A (Impeccable): "**The X Rule.** body body body" — can span lines. const joined = lines.join('\n'); - const inlineStart = /\*\*(The [^*]+?Rule)\.\*\*/g; - const inlineMatches = []; - let m; - while ((m = inlineStart.exec(joined)) !== null) { - inlineMatches.push({ name: m[1], start: m.index, end: inlineStart.lastIndex }); - } + const inlineMatches = [...joined.matchAll(/\*\*(The [^*]+?Rule)\.\*\*/g)]; for (let i = 0; i < inlineMatches.length; i++) { - const mm = inlineMatches[i]; - const bodyEnd = i + 1 < inlineMatches.length ? inlineMatches[i + 1].start : joined.length; + const match = inlineMatches[i]; + const bodyEnd = inlineMatches[i + 1]?.index ?? joined.length; const body = joined - .slice(mm.end, bodyEnd) + .slice(match.index + match[0].length, bodyEnd) .replace(/\n##[^\n]*$/s, '') .replace(/\n###[^\n]*$/s, '') .trim(); - const name = stripBold(mm.name).trim(); - seen.add(name.toLowerCase()); - rules.push({ name, body: stripBold(body) }); + // Preserve the inline format's historical behavior: repeated inline rules + // remain visible, while the later heading and bullet formats dedupe. + addRule(stripBold(match[1]).trim(), stripBold(body), { allowDuplicate: true }); } // Style B (Stitch): `### The "X" Rule` or `### The X Fallback`, body is the // bullets/paragraphs until the next heading. Accept Rule / Fallback / Principle. - for (let i = 0; i < lines.length; i++) { - const h3 = lines[i].match(/^###\s+(.+?)\s*$/); - if (!h3) continue; - const headerName = stripBold(h3[1]).replace(/["“”]/g, '').trim(); + for (const subsection of splitSubsections(lines).slice(1)) { + const headerName = stripBold(subsection.name).replace(/["“”]/g, '').trim(); if (!/^The\b.*\b(Rule|Fallback|Principle)\b/i.test(headerName)) continue; - if (seen.has(headerName.toLowerCase())) continue; - const bodyLines = []; - for (let j = i + 1; j < lines.length; j++) { - if (/^##\s|^###\s/.test(lines[j])) break; - bodyLines.push(lines[j]); - } - const body = stripBold(bodyLines.join('\n').replace(/\n+/g, ' ')).trim(); - if (body) { - seen.add(headerName.toLowerCase()); - rules.push({ name: headerName, body }); - } + const body = stripBold(subsection.lines.join('\n').replace(/\n+/g, ' ')).trim(); + if (body) addRule(headerName, body); } // Style C (Stitch bullet form): "* **The Layering Principle:** body" @@ -379,9 +369,7 @@ function extractNamedRules(lines) { if (!mm) continue; const nameRaw = mm[1].replace(/[.:]\s*$/, '').replace(/["“”]/g, '').trim(); if (!/^The\b.+\b(Rule|Fallback|Principle)$/i.test(nameRaw)) continue; - if (seen.has(nameRaw.toLowerCase())) continue; - seen.add(nameRaw.toLowerCase()); - rules.push({ name: nameRaw, body: stripBold(mm[2]).trim() }); + addRule(nameRaw, stripBold(mm[2]).trim()); } return rules; diff --git a/.pi/skills/impeccable/scripts/lib/design-parser.mjs b/.pi/skills/impeccable/scripts/lib/design-parser.mjs index cab191d69..6f240a51e 100644 --- a/.pi/skills/impeccable/scripts/lib/design-parser.mjs +++ b/.pi/skills/impeccable/scripts/lib/design-parser.mjs @@ -329,47 +329,37 @@ function stripBold(s) { function extractNamedRules(lines) { const rules = []; const seen = new Set(); + const addRule = (name, body, { allowDuplicate = false } = {}) => { + const key = name.toLowerCase(); + if (!allowDuplicate && seen.has(key)) return; + seen.add(key); + rules.push({ name, body }); + }; // Style A (Impeccable): "**The X Rule.** body body body" — can span lines. const joined = lines.join('\n'); - const inlineStart = /\*\*(The [^*]+?Rule)\.\*\*/g; - const inlineMatches = []; - let m; - while ((m = inlineStart.exec(joined)) !== null) { - inlineMatches.push({ name: m[1], start: m.index, end: inlineStart.lastIndex }); - } + const inlineMatches = [...joined.matchAll(/\*\*(The [^*]+?Rule)\.\*\*/g)]; for (let i = 0; i < inlineMatches.length; i++) { - const mm = inlineMatches[i]; - const bodyEnd = i + 1 < inlineMatches.length ? inlineMatches[i + 1].start : joined.length; + const match = inlineMatches[i]; + const bodyEnd = inlineMatches[i + 1]?.index ?? joined.length; const body = joined - .slice(mm.end, bodyEnd) + .slice(match.index + match[0].length, bodyEnd) .replace(/\n##[^\n]*$/s, '') .replace(/\n###[^\n]*$/s, '') .trim(); - const name = stripBold(mm.name).trim(); - seen.add(name.toLowerCase()); - rules.push({ name, body: stripBold(body) }); + // Preserve the inline format's historical behavior: repeated inline rules + // remain visible, while the later heading and bullet formats dedupe. + addRule(stripBold(match[1]).trim(), stripBold(body), { allowDuplicate: true }); } // Style B (Stitch): `### The "X" Rule` or `### The X Fallback`, body is the // bullets/paragraphs until the next heading. Accept Rule / Fallback / Principle. - for (let i = 0; i < lines.length; i++) { - const h3 = lines[i].match(/^###\s+(.+?)\s*$/); - if (!h3) continue; - const headerName = stripBold(h3[1]).replace(/["“”]/g, '').trim(); + for (const subsection of splitSubsections(lines).slice(1)) { + const headerName = stripBold(subsection.name).replace(/["“”]/g, '').trim(); if (!/^The\b.*\b(Rule|Fallback|Principle)\b/i.test(headerName)) continue; - if (seen.has(headerName.toLowerCase())) continue; - const bodyLines = []; - for (let j = i + 1; j < lines.length; j++) { - if (/^##\s|^###\s/.test(lines[j])) break; - bodyLines.push(lines[j]); - } - const body = stripBold(bodyLines.join('\n').replace(/\n+/g, ' ')).trim(); - if (body) { - seen.add(headerName.toLowerCase()); - rules.push({ name: headerName, body }); - } + const body = stripBold(subsection.lines.join('\n').replace(/\n+/g, ' ')).trim(); + if (body) addRule(headerName, body); } // Style C (Stitch bullet form): "* **The Layering Principle:** body" @@ -379,9 +369,7 @@ function extractNamedRules(lines) { if (!mm) continue; const nameRaw = mm[1].replace(/[.:]\s*$/, '').replace(/["“”]/g, '').trim(); if (!/^The\b.+\b(Rule|Fallback|Principle)$/i.test(nameRaw)) continue; - if (seen.has(nameRaw.toLowerCase())) continue; - seen.add(nameRaw.toLowerCase()); - rules.push({ name: nameRaw, body: stripBold(mm[2]).trim() }); + addRule(nameRaw, stripBold(mm[2]).trim()); } return rules; diff --git a/.qoder/skills/impeccable/scripts/lib/design-parser.mjs b/.qoder/skills/impeccable/scripts/lib/design-parser.mjs index cab191d69..6f240a51e 100644 --- a/.qoder/skills/impeccable/scripts/lib/design-parser.mjs +++ b/.qoder/skills/impeccable/scripts/lib/design-parser.mjs @@ -329,47 +329,37 @@ function stripBold(s) { function extractNamedRules(lines) { const rules = []; const seen = new Set(); + const addRule = (name, body, { allowDuplicate = false } = {}) => { + const key = name.toLowerCase(); + if (!allowDuplicate && seen.has(key)) return; + seen.add(key); + rules.push({ name, body }); + }; // Style A (Impeccable): "**The X Rule.** body body body" — can span lines. const joined = lines.join('\n'); - const inlineStart = /\*\*(The [^*]+?Rule)\.\*\*/g; - const inlineMatches = []; - let m; - while ((m = inlineStart.exec(joined)) !== null) { - inlineMatches.push({ name: m[1], start: m.index, end: inlineStart.lastIndex }); - } + const inlineMatches = [...joined.matchAll(/\*\*(The [^*]+?Rule)\.\*\*/g)]; for (let i = 0; i < inlineMatches.length; i++) { - const mm = inlineMatches[i]; - const bodyEnd = i + 1 < inlineMatches.length ? inlineMatches[i + 1].start : joined.length; + const match = inlineMatches[i]; + const bodyEnd = inlineMatches[i + 1]?.index ?? joined.length; const body = joined - .slice(mm.end, bodyEnd) + .slice(match.index + match[0].length, bodyEnd) .replace(/\n##[^\n]*$/s, '') .replace(/\n###[^\n]*$/s, '') .trim(); - const name = stripBold(mm.name).trim(); - seen.add(name.toLowerCase()); - rules.push({ name, body: stripBold(body) }); + // Preserve the inline format's historical behavior: repeated inline rules + // remain visible, while the later heading and bullet formats dedupe. + addRule(stripBold(match[1]).trim(), stripBold(body), { allowDuplicate: true }); } // Style B (Stitch): `### The "X" Rule` or `### The X Fallback`, body is the // bullets/paragraphs until the next heading. Accept Rule / Fallback / Principle. - for (let i = 0; i < lines.length; i++) { - const h3 = lines[i].match(/^###\s+(.+?)\s*$/); - if (!h3) continue; - const headerName = stripBold(h3[1]).replace(/["“”]/g, '').trim(); + for (const subsection of splitSubsections(lines).slice(1)) { + const headerName = stripBold(subsection.name).replace(/["“”]/g, '').trim(); if (!/^The\b.*\b(Rule|Fallback|Principle)\b/i.test(headerName)) continue; - if (seen.has(headerName.toLowerCase())) continue; - const bodyLines = []; - for (let j = i + 1; j < lines.length; j++) { - if (/^##\s|^###\s/.test(lines[j])) break; - bodyLines.push(lines[j]); - } - const body = stripBold(bodyLines.join('\n').replace(/\n+/g, ' ')).trim(); - if (body) { - seen.add(headerName.toLowerCase()); - rules.push({ name: headerName, body }); - } + const body = stripBold(subsection.lines.join('\n').replace(/\n+/g, ' ')).trim(); + if (body) addRule(headerName, body); } // Style C (Stitch bullet form): "* **The Layering Principle:** body" @@ -379,9 +369,7 @@ function extractNamedRules(lines) { if (!mm) continue; const nameRaw = mm[1].replace(/[.:]\s*$/, '').replace(/["“”]/g, '').trim(); if (!/^The\b.+\b(Rule|Fallback|Principle)$/i.test(nameRaw)) continue; - if (seen.has(nameRaw.toLowerCase())) continue; - seen.add(nameRaw.toLowerCase()); - rules.push({ name: nameRaw, body: stripBold(mm[2]).trim() }); + addRule(nameRaw, stripBold(mm[2]).trim()); } return rules; diff --git a/.rovodev/skills/impeccable/scripts/lib/design-parser.mjs b/.rovodev/skills/impeccable/scripts/lib/design-parser.mjs index cab191d69..6f240a51e 100644 --- a/.rovodev/skills/impeccable/scripts/lib/design-parser.mjs +++ b/.rovodev/skills/impeccable/scripts/lib/design-parser.mjs @@ -329,47 +329,37 @@ function stripBold(s) { function extractNamedRules(lines) { const rules = []; const seen = new Set(); + const addRule = (name, body, { allowDuplicate = false } = {}) => { + const key = name.toLowerCase(); + if (!allowDuplicate && seen.has(key)) return; + seen.add(key); + rules.push({ name, body }); + }; // Style A (Impeccable): "**The X Rule.** body body body" — can span lines. const joined = lines.join('\n'); - const inlineStart = /\*\*(The [^*]+?Rule)\.\*\*/g; - const inlineMatches = []; - let m; - while ((m = inlineStart.exec(joined)) !== null) { - inlineMatches.push({ name: m[1], start: m.index, end: inlineStart.lastIndex }); - } + const inlineMatches = [...joined.matchAll(/\*\*(The [^*]+?Rule)\.\*\*/g)]; for (let i = 0; i < inlineMatches.length; i++) { - const mm = inlineMatches[i]; - const bodyEnd = i + 1 < inlineMatches.length ? inlineMatches[i + 1].start : joined.length; + const match = inlineMatches[i]; + const bodyEnd = inlineMatches[i + 1]?.index ?? joined.length; const body = joined - .slice(mm.end, bodyEnd) + .slice(match.index + match[0].length, bodyEnd) .replace(/\n##[^\n]*$/s, '') .replace(/\n###[^\n]*$/s, '') .trim(); - const name = stripBold(mm.name).trim(); - seen.add(name.toLowerCase()); - rules.push({ name, body: stripBold(body) }); + // Preserve the inline format's historical behavior: repeated inline rules + // remain visible, while the later heading and bullet formats dedupe. + addRule(stripBold(match[1]).trim(), stripBold(body), { allowDuplicate: true }); } // Style B (Stitch): `### The "X" Rule` or `### The X Fallback`, body is the // bullets/paragraphs until the next heading. Accept Rule / Fallback / Principle. - for (let i = 0; i < lines.length; i++) { - const h3 = lines[i].match(/^###\s+(.+?)\s*$/); - if (!h3) continue; - const headerName = stripBold(h3[1]).replace(/["“”]/g, '').trim(); + for (const subsection of splitSubsections(lines).slice(1)) { + const headerName = stripBold(subsection.name).replace(/["“”]/g, '').trim(); if (!/^The\b.*\b(Rule|Fallback|Principle)\b/i.test(headerName)) continue; - if (seen.has(headerName.toLowerCase())) continue; - const bodyLines = []; - for (let j = i + 1; j < lines.length; j++) { - if (/^##\s|^###\s/.test(lines[j])) break; - bodyLines.push(lines[j]); - } - const body = stripBold(bodyLines.join('\n').replace(/\n+/g, ' ')).trim(); - if (body) { - seen.add(headerName.toLowerCase()); - rules.push({ name: headerName, body }); - } + const body = stripBold(subsection.lines.join('\n').replace(/\n+/g, ' ')).trim(); + if (body) addRule(headerName, body); } // Style C (Stitch bullet form): "* **The Layering Principle:** body" @@ -379,9 +369,7 @@ function extractNamedRules(lines) { if (!mm) continue; const nameRaw = mm[1].replace(/[.:]\s*$/, '').replace(/["“”]/g, '').trim(); if (!/^The\b.+\b(Rule|Fallback|Principle)$/i.test(nameRaw)) continue; - if (seen.has(nameRaw.toLowerCase())) continue; - seen.add(nameRaw.toLowerCase()); - rules.push({ name: nameRaw, body: stripBold(mm[2]).trim() }); + addRule(nameRaw, stripBold(mm[2]).trim()); } return rules; diff --git a/.trae-cn/skills/impeccable/scripts/lib/design-parser.mjs b/.trae-cn/skills/impeccable/scripts/lib/design-parser.mjs index cab191d69..6f240a51e 100644 --- a/.trae-cn/skills/impeccable/scripts/lib/design-parser.mjs +++ b/.trae-cn/skills/impeccable/scripts/lib/design-parser.mjs @@ -329,47 +329,37 @@ function stripBold(s) { function extractNamedRules(lines) { const rules = []; const seen = new Set(); + const addRule = (name, body, { allowDuplicate = false } = {}) => { + const key = name.toLowerCase(); + if (!allowDuplicate && seen.has(key)) return; + seen.add(key); + rules.push({ name, body }); + }; // Style A (Impeccable): "**The X Rule.** body body body" — can span lines. const joined = lines.join('\n'); - const inlineStart = /\*\*(The [^*]+?Rule)\.\*\*/g; - const inlineMatches = []; - let m; - while ((m = inlineStart.exec(joined)) !== null) { - inlineMatches.push({ name: m[1], start: m.index, end: inlineStart.lastIndex }); - } + const inlineMatches = [...joined.matchAll(/\*\*(The [^*]+?Rule)\.\*\*/g)]; for (let i = 0; i < inlineMatches.length; i++) { - const mm = inlineMatches[i]; - const bodyEnd = i + 1 < inlineMatches.length ? inlineMatches[i + 1].start : joined.length; + const match = inlineMatches[i]; + const bodyEnd = inlineMatches[i + 1]?.index ?? joined.length; const body = joined - .slice(mm.end, bodyEnd) + .slice(match.index + match[0].length, bodyEnd) .replace(/\n##[^\n]*$/s, '') .replace(/\n###[^\n]*$/s, '') .trim(); - const name = stripBold(mm.name).trim(); - seen.add(name.toLowerCase()); - rules.push({ name, body: stripBold(body) }); + // Preserve the inline format's historical behavior: repeated inline rules + // remain visible, while the later heading and bullet formats dedupe. + addRule(stripBold(match[1]).trim(), stripBold(body), { allowDuplicate: true }); } // Style B (Stitch): `### The "X" Rule` or `### The X Fallback`, body is the // bullets/paragraphs until the next heading. Accept Rule / Fallback / Principle. - for (let i = 0; i < lines.length; i++) { - const h3 = lines[i].match(/^###\s+(.+?)\s*$/); - if (!h3) continue; - const headerName = stripBold(h3[1]).replace(/["“”]/g, '').trim(); + for (const subsection of splitSubsections(lines).slice(1)) { + const headerName = stripBold(subsection.name).replace(/["“”]/g, '').trim(); if (!/^The\b.*\b(Rule|Fallback|Principle)\b/i.test(headerName)) continue; - if (seen.has(headerName.toLowerCase())) continue; - const bodyLines = []; - for (let j = i + 1; j < lines.length; j++) { - if (/^##\s|^###\s/.test(lines[j])) break; - bodyLines.push(lines[j]); - } - const body = stripBold(bodyLines.join('\n').replace(/\n+/g, ' ')).trim(); - if (body) { - seen.add(headerName.toLowerCase()); - rules.push({ name: headerName, body }); - } + const body = stripBold(subsection.lines.join('\n').replace(/\n+/g, ' ')).trim(); + if (body) addRule(headerName, body); } // Style C (Stitch bullet form): "* **The Layering Principle:** body" @@ -379,9 +369,7 @@ function extractNamedRules(lines) { if (!mm) continue; const nameRaw = mm[1].replace(/[.:]\s*$/, '').replace(/["“”]/g, '').trim(); if (!/^The\b.+\b(Rule|Fallback|Principle)$/i.test(nameRaw)) continue; - if (seen.has(nameRaw.toLowerCase())) continue; - seen.add(nameRaw.toLowerCase()); - rules.push({ name: nameRaw, body: stripBold(mm[2]).trim() }); + addRule(nameRaw, stripBold(mm[2]).trim()); } return rules; diff --git a/.trae/skills/impeccable/scripts/lib/design-parser.mjs b/.trae/skills/impeccable/scripts/lib/design-parser.mjs index cab191d69..6f240a51e 100644 --- a/.trae/skills/impeccable/scripts/lib/design-parser.mjs +++ b/.trae/skills/impeccable/scripts/lib/design-parser.mjs @@ -329,47 +329,37 @@ function stripBold(s) { function extractNamedRules(lines) { const rules = []; const seen = new Set(); + const addRule = (name, body, { allowDuplicate = false } = {}) => { + const key = name.toLowerCase(); + if (!allowDuplicate && seen.has(key)) return; + seen.add(key); + rules.push({ name, body }); + }; // Style A (Impeccable): "**The X Rule.** body body body" — can span lines. const joined = lines.join('\n'); - const inlineStart = /\*\*(The [^*]+?Rule)\.\*\*/g; - const inlineMatches = []; - let m; - while ((m = inlineStart.exec(joined)) !== null) { - inlineMatches.push({ name: m[1], start: m.index, end: inlineStart.lastIndex }); - } + const inlineMatches = [...joined.matchAll(/\*\*(The [^*]+?Rule)\.\*\*/g)]; for (let i = 0; i < inlineMatches.length; i++) { - const mm = inlineMatches[i]; - const bodyEnd = i + 1 < inlineMatches.length ? inlineMatches[i + 1].start : joined.length; + const match = inlineMatches[i]; + const bodyEnd = inlineMatches[i + 1]?.index ?? joined.length; const body = joined - .slice(mm.end, bodyEnd) + .slice(match.index + match[0].length, bodyEnd) .replace(/\n##[^\n]*$/s, '') .replace(/\n###[^\n]*$/s, '') .trim(); - const name = stripBold(mm.name).trim(); - seen.add(name.toLowerCase()); - rules.push({ name, body: stripBold(body) }); + // Preserve the inline format's historical behavior: repeated inline rules + // remain visible, while the later heading and bullet formats dedupe. + addRule(stripBold(match[1]).trim(), stripBold(body), { allowDuplicate: true }); } // Style B (Stitch): `### The "X" Rule` or `### The X Fallback`, body is the // bullets/paragraphs until the next heading. Accept Rule / Fallback / Principle. - for (let i = 0; i < lines.length; i++) { - const h3 = lines[i].match(/^###\s+(.+?)\s*$/); - if (!h3) continue; - const headerName = stripBold(h3[1]).replace(/["“”]/g, '').trim(); + for (const subsection of splitSubsections(lines).slice(1)) { + const headerName = stripBold(subsection.name).replace(/["“”]/g, '').trim(); if (!/^The\b.*\b(Rule|Fallback|Principle)\b/i.test(headerName)) continue; - if (seen.has(headerName.toLowerCase())) continue; - const bodyLines = []; - for (let j = i + 1; j < lines.length; j++) { - if (/^##\s|^###\s/.test(lines[j])) break; - bodyLines.push(lines[j]); - } - const body = stripBold(bodyLines.join('\n').replace(/\n+/g, ' ')).trim(); - if (body) { - seen.add(headerName.toLowerCase()); - rules.push({ name: headerName, body }); - } + const body = stripBold(subsection.lines.join('\n').replace(/\n+/g, ' ')).trim(); + if (body) addRule(headerName, body); } // Style C (Stitch bullet form): "* **The Layering Principle:** body" @@ -379,9 +369,7 @@ function extractNamedRules(lines) { if (!mm) continue; const nameRaw = mm[1].replace(/[.:]\s*$/, '').replace(/["“”]/g, '').trim(); if (!/^The\b.+\b(Rule|Fallback|Principle)$/i.test(nameRaw)) continue; - if (seen.has(nameRaw.toLowerCase())) continue; - seen.add(nameRaw.toLowerCase()); - rules.push({ name: nameRaw, body: stripBold(mm[2]).trim() }); + addRule(nameRaw, stripBold(mm[2]).trim()); } return rules; diff --git a/.vibe/skills/impeccable/scripts/lib/design-parser.mjs b/.vibe/skills/impeccable/scripts/lib/design-parser.mjs index cab191d69..6f240a51e 100644 --- a/.vibe/skills/impeccable/scripts/lib/design-parser.mjs +++ b/.vibe/skills/impeccable/scripts/lib/design-parser.mjs @@ -329,47 +329,37 @@ function stripBold(s) { function extractNamedRules(lines) { const rules = []; const seen = new Set(); + const addRule = (name, body, { allowDuplicate = false } = {}) => { + const key = name.toLowerCase(); + if (!allowDuplicate && seen.has(key)) return; + seen.add(key); + rules.push({ name, body }); + }; // Style A (Impeccable): "**The X Rule.** body body body" — can span lines. const joined = lines.join('\n'); - const inlineStart = /\*\*(The [^*]+?Rule)\.\*\*/g; - const inlineMatches = []; - let m; - while ((m = inlineStart.exec(joined)) !== null) { - inlineMatches.push({ name: m[1], start: m.index, end: inlineStart.lastIndex }); - } + const inlineMatches = [...joined.matchAll(/\*\*(The [^*]+?Rule)\.\*\*/g)]; for (let i = 0; i < inlineMatches.length; i++) { - const mm = inlineMatches[i]; - const bodyEnd = i + 1 < inlineMatches.length ? inlineMatches[i + 1].start : joined.length; + const match = inlineMatches[i]; + const bodyEnd = inlineMatches[i + 1]?.index ?? joined.length; const body = joined - .slice(mm.end, bodyEnd) + .slice(match.index + match[0].length, bodyEnd) .replace(/\n##[^\n]*$/s, '') .replace(/\n###[^\n]*$/s, '') .trim(); - const name = stripBold(mm.name).trim(); - seen.add(name.toLowerCase()); - rules.push({ name, body: stripBold(body) }); + // Preserve the inline format's historical behavior: repeated inline rules + // remain visible, while the later heading and bullet formats dedupe. + addRule(stripBold(match[1]).trim(), stripBold(body), { allowDuplicate: true }); } // Style B (Stitch): `### The "X" Rule` or `### The X Fallback`, body is the // bullets/paragraphs until the next heading. Accept Rule / Fallback / Principle. - for (let i = 0; i < lines.length; i++) { - const h3 = lines[i].match(/^###\s+(.+?)\s*$/); - if (!h3) continue; - const headerName = stripBold(h3[1]).replace(/["“”]/g, '').trim(); + for (const subsection of splitSubsections(lines).slice(1)) { + const headerName = stripBold(subsection.name).replace(/["“”]/g, '').trim(); if (!/^The\b.*\b(Rule|Fallback|Principle)\b/i.test(headerName)) continue; - if (seen.has(headerName.toLowerCase())) continue; - const bodyLines = []; - for (let j = i + 1; j < lines.length; j++) { - if (/^##\s|^###\s/.test(lines[j])) break; - bodyLines.push(lines[j]); - } - const body = stripBold(bodyLines.join('\n').replace(/\n+/g, ' ')).trim(); - if (body) { - seen.add(headerName.toLowerCase()); - rules.push({ name: headerName, body }); - } + const body = stripBold(subsection.lines.join('\n').replace(/\n+/g, ' ')).trim(); + if (body) addRule(headerName, body); } // Style C (Stitch bullet form): "* **The Layering Principle:** body" @@ -379,9 +369,7 @@ function extractNamedRules(lines) { if (!mm) continue; const nameRaw = mm[1].replace(/[.:]\s*$/, '').replace(/["“”]/g, '').trim(); if (!/^The\b.+\b(Rule|Fallback|Principle)$/i.test(nameRaw)) continue; - if (seen.has(nameRaw.toLowerCase())) continue; - seen.add(nameRaw.toLowerCase()); - rules.push({ name: nameRaw, body: stripBold(mm[2]).trim() }); + addRule(nameRaw, stripBold(mm[2]).trim()); } return rules; diff --git a/plugin/skills/impeccable/scripts/lib/design-parser.mjs b/plugin/skills/impeccable/scripts/lib/design-parser.mjs index cab191d69..6f240a51e 100644 --- a/plugin/skills/impeccable/scripts/lib/design-parser.mjs +++ b/plugin/skills/impeccable/scripts/lib/design-parser.mjs @@ -329,47 +329,37 @@ function stripBold(s) { function extractNamedRules(lines) { const rules = []; const seen = new Set(); + const addRule = (name, body, { allowDuplicate = false } = {}) => { + const key = name.toLowerCase(); + if (!allowDuplicate && seen.has(key)) return; + seen.add(key); + rules.push({ name, body }); + }; // Style A (Impeccable): "**The X Rule.** body body body" — can span lines. const joined = lines.join('\n'); - const inlineStart = /\*\*(The [^*]+?Rule)\.\*\*/g; - const inlineMatches = []; - let m; - while ((m = inlineStart.exec(joined)) !== null) { - inlineMatches.push({ name: m[1], start: m.index, end: inlineStart.lastIndex }); - } + const inlineMatches = [...joined.matchAll(/\*\*(The [^*]+?Rule)\.\*\*/g)]; for (let i = 0; i < inlineMatches.length; i++) { - const mm = inlineMatches[i]; - const bodyEnd = i + 1 < inlineMatches.length ? inlineMatches[i + 1].start : joined.length; + const match = inlineMatches[i]; + const bodyEnd = inlineMatches[i + 1]?.index ?? joined.length; const body = joined - .slice(mm.end, bodyEnd) + .slice(match.index + match[0].length, bodyEnd) .replace(/\n##[^\n]*$/s, '') .replace(/\n###[^\n]*$/s, '') .trim(); - const name = stripBold(mm.name).trim(); - seen.add(name.toLowerCase()); - rules.push({ name, body: stripBold(body) }); + // Preserve the inline format's historical behavior: repeated inline rules + // remain visible, while the later heading and bullet formats dedupe. + addRule(stripBold(match[1]).trim(), stripBold(body), { allowDuplicate: true }); } // Style B (Stitch): `### The "X" Rule` or `### The X Fallback`, body is the // bullets/paragraphs until the next heading. Accept Rule / Fallback / Principle. - for (let i = 0; i < lines.length; i++) { - const h3 = lines[i].match(/^###\s+(.+?)\s*$/); - if (!h3) continue; - const headerName = stripBold(h3[1]).replace(/["“”]/g, '').trim(); + for (const subsection of splitSubsections(lines).slice(1)) { + const headerName = stripBold(subsection.name).replace(/["“”]/g, '').trim(); if (!/^The\b.*\b(Rule|Fallback|Principle)\b/i.test(headerName)) continue; - if (seen.has(headerName.toLowerCase())) continue; - const bodyLines = []; - for (let j = i + 1; j < lines.length; j++) { - if (/^##\s|^###\s/.test(lines[j])) break; - bodyLines.push(lines[j]); - } - const body = stripBold(bodyLines.join('\n').replace(/\n+/g, ' ')).trim(); - if (body) { - seen.add(headerName.toLowerCase()); - rules.push({ name: headerName, body }); - } + const body = stripBold(subsection.lines.join('\n').replace(/\n+/g, ' ')).trim(); + if (body) addRule(headerName, body); } // Style C (Stitch bullet form): "* **The Layering Principle:** body" @@ -379,9 +369,7 @@ function extractNamedRules(lines) { if (!mm) continue; const nameRaw = mm[1].replace(/[.:]\s*$/, '').replace(/["“”]/g, '').trim(); if (!/^The\b.+\b(Rule|Fallback|Principle)$/i.test(nameRaw)) continue; - if (seen.has(nameRaw.toLowerCase())) continue; - seen.add(nameRaw.toLowerCase()); - rules.push({ name: nameRaw, body: stripBold(mm[2]).trim() }); + addRule(nameRaw, stripBold(mm[2]).trim()); } return rules;