From d07edadafbf82f6f8803e3a8818e689c80ecee00 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 23 Aug 2026 23:11:14 +0000 Subject: [PATCH] Sync generated provider output --- .../scripts/detector/detect-antipatterns-browser.js | 8 ++++++++ .../skills/impeccable/scripts/detector/shared/color.mjs | 8 ++++++++ .../scripts/detector/detect-antipatterns-browser.js | 8 ++++++++ .../skills/impeccable/scripts/detector/shared/color.mjs | 8 ++++++++ .../scripts/detector/detect-antipatterns-browser.js | 8 ++++++++ .../skills/impeccable/scripts/detector/shared/color.mjs | 8 ++++++++ .../scripts/detector/detect-antipatterns-browser.js | 8 ++++++++ .../skills/impeccable/scripts/detector/shared/color.mjs | 8 ++++++++ .../scripts/detector/detect-antipatterns-browser.js | 8 ++++++++ .../skills/impeccable/scripts/detector/shared/color.mjs | 8 ++++++++ .../scripts/detector/detect-antipatterns-browser.js | 8 ++++++++ .grok/skills/impeccable/scripts/detector/shared/color.mjs | 8 ++++++++ .../scripts/detector/detect-antipatterns-browser.js | 8 ++++++++ .../skills/impeccable/scripts/detector/shared/color.mjs | 8 ++++++++ .../scripts/detector/detect-antipatterns-browser.js | 8 ++++++++ .kiro/skills/impeccable/scripts/detector/shared/color.mjs | 8 ++++++++ .../scripts/detector/detect-antipatterns-browser.js | 8 ++++++++ .../skills/impeccable/scripts/detector/shared/color.mjs | 8 ++++++++ .../scripts/detector/detect-antipatterns-browser.js | 8 ++++++++ .pi/skills/impeccable/scripts/detector/shared/color.mjs | 8 ++++++++ .../scripts/detector/detect-antipatterns-browser.js | 8 ++++++++ .../skills/impeccable/scripts/detector/shared/color.mjs | 8 ++++++++ .../scripts/detector/detect-antipatterns-browser.js | 8 ++++++++ .../skills/impeccable/scripts/detector/shared/color.mjs | 8 ++++++++ .../scripts/detector/detect-antipatterns-browser.js | 8 ++++++++ .../skills/impeccable/scripts/detector/shared/color.mjs | 8 ++++++++ .../scripts/detector/detect-antipatterns-browser.js | 8 ++++++++ .trae/skills/impeccable/scripts/detector/shared/color.mjs | 8 ++++++++ .../scripts/detector/detect-antipatterns-browser.js | 8 ++++++++ .vibe/skills/impeccable/scripts/detector/shared/color.mjs | 8 ++++++++ .../scripts/detector/detect-antipatterns-browser.js | 8 ++++++++ .../skills/impeccable/scripts/detector/shared/color.mjs | 8 ++++++++ 32 files changed, 256 insertions(+) diff --git a/.agents/skills/impeccable/scripts/detector/detect-antipatterns-browser.js b/.agents/skills/impeccable/scripts/detector/detect-antipatterns-browser.js index 8d5bce3f6..e3e5dc21c 100644 --- a/.agents/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +++ b/.agents/skills/impeccable/scripts/detector/detect-antipatterns-browser.js @@ -773,14 +773,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.agents/skills/impeccable/scripts/detector/shared/color.mjs b/.agents/skills/impeccable/scripts/detector/shared/color.mjs index d2524ce52..983e15330 100644 --- a/.agents/skills/impeccable/scripts/detector/shared/color.mjs +++ b/.agents/skills/impeccable/scripts/detector/shared/color.mjs @@ -103,14 +103,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.claude/skills/impeccable/scripts/detector/detect-antipatterns-browser.js b/.claude/skills/impeccable/scripts/detector/detect-antipatterns-browser.js index 8d5bce3f6..e3e5dc21c 100644 --- a/.claude/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +++ b/.claude/skills/impeccable/scripts/detector/detect-antipatterns-browser.js @@ -773,14 +773,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.claude/skills/impeccable/scripts/detector/shared/color.mjs b/.claude/skills/impeccable/scripts/detector/shared/color.mjs index d2524ce52..983e15330 100644 --- a/.claude/skills/impeccable/scripts/detector/shared/color.mjs +++ b/.claude/skills/impeccable/scripts/detector/shared/color.mjs @@ -103,14 +103,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.cursor/skills/impeccable/scripts/detector/detect-antipatterns-browser.js b/.cursor/skills/impeccable/scripts/detector/detect-antipatterns-browser.js index 8d5bce3f6..e3e5dc21c 100644 --- a/.cursor/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +++ b/.cursor/skills/impeccable/scripts/detector/detect-antipatterns-browser.js @@ -773,14 +773,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.cursor/skills/impeccable/scripts/detector/shared/color.mjs b/.cursor/skills/impeccable/scripts/detector/shared/color.mjs index d2524ce52..983e15330 100644 --- a/.cursor/skills/impeccable/scripts/detector/shared/color.mjs +++ b/.cursor/skills/impeccable/scripts/detector/shared/color.mjs @@ -103,14 +103,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.gemini/skills/impeccable/scripts/detector/detect-antipatterns-browser.js b/.gemini/skills/impeccable/scripts/detector/detect-antipatterns-browser.js index 8d5bce3f6..e3e5dc21c 100644 --- a/.gemini/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +++ b/.gemini/skills/impeccable/scripts/detector/detect-antipatterns-browser.js @@ -773,14 +773,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.gemini/skills/impeccable/scripts/detector/shared/color.mjs b/.gemini/skills/impeccable/scripts/detector/shared/color.mjs index d2524ce52..983e15330 100644 --- a/.gemini/skills/impeccable/scripts/detector/shared/color.mjs +++ b/.gemini/skills/impeccable/scripts/detector/shared/color.mjs @@ -103,14 +103,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.github/skills/impeccable/scripts/detector/detect-antipatterns-browser.js b/.github/skills/impeccable/scripts/detector/detect-antipatterns-browser.js index 8d5bce3f6..e3e5dc21c 100644 --- a/.github/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +++ b/.github/skills/impeccable/scripts/detector/detect-antipatterns-browser.js @@ -773,14 +773,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.github/skills/impeccable/scripts/detector/shared/color.mjs b/.github/skills/impeccable/scripts/detector/shared/color.mjs index d2524ce52..983e15330 100644 --- a/.github/skills/impeccable/scripts/detector/shared/color.mjs +++ b/.github/skills/impeccable/scripts/detector/shared/color.mjs @@ -103,14 +103,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.grok/skills/impeccable/scripts/detector/detect-antipatterns-browser.js b/.grok/skills/impeccable/scripts/detector/detect-antipatterns-browser.js index 8d5bce3f6..e3e5dc21c 100644 --- a/.grok/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +++ b/.grok/skills/impeccable/scripts/detector/detect-antipatterns-browser.js @@ -773,14 +773,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.grok/skills/impeccable/scripts/detector/shared/color.mjs b/.grok/skills/impeccable/scripts/detector/shared/color.mjs index d2524ce52..983e15330 100644 --- a/.grok/skills/impeccable/scripts/detector/shared/color.mjs +++ b/.grok/skills/impeccable/scripts/detector/shared/color.mjs @@ -103,14 +103,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.hermes/skills/impeccable/scripts/detector/detect-antipatterns-browser.js b/.hermes/skills/impeccable/scripts/detector/detect-antipatterns-browser.js index 8d5bce3f6..e3e5dc21c 100644 --- a/.hermes/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +++ b/.hermes/skills/impeccable/scripts/detector/detect-antipatterns-browser.js @@ -773,14 +773,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.hermes/skills/impeccable/scripts/detector/shared/color.mjs b/.hermes/skills/impeccable/scripts/detector/shared/color.mjs index d2524ce52..983e15330 100644 --- a/.hermes/skills/impeccable/scripts/detector/shared/color.mjs +++ b/.hermes/skills/impeccable/scripts/detector/shared/color.mjs @@ -103,14 +103,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.kiro/skills/impeccable/scripts/detector/detect-antipatterns-browser.js b/.kiro/skills/impeccable/scripts/detector/detect-antipatterns-browser.js index 8d5bce3f6..e3e5dc21c 100644 --- a/.kiro/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +++ b/.kiro/skills/impeccable/scripts/detector/detect-antipatterns-browser.js @@ -773,14 +773,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.kiro/skills/impeccable/scripts/detector/shared/color.mjs b/.kiro/skills/impeccable/scripts/detector/shared/color.mjs index d2524ce52..983e15330 100644 --- a/.kiro/skills/impeccable/scripts/detector/shared/color.mjs +++ b/.kiro/skills/impeccable/scripts/detector/shared/color.mjs @@ -103,14 +103,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.opencode/skills/impeccable/scripts/detector/detect-antipatterns-browser.js b/.opencode/skills/impeccable/scripts/detector/detect-antipatterns-browser.js index 8d5bce3f6..e3e5dc21c 100644 --- a/.opencode/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +++ b/.opencode/skills/impeccable/scripts/detector/detect-antipatterns-browser.js @@ -773,14 +773,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.opencode/skills/impeccable/scripts/detector/shared/color.mjs b/.opencode/skills/impeccable/scripts/detector/shared/color.mjs index d2524ce52..983e15330 100644 --- a/.opencode/skills/impeccable/scripts/detector/shared/color.mjs +++ b/.opencode/skills/impeccable/scripts/detector/shared/color.mjs @@ -103,14 +103,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.pi/skills/impeccable/scripts/detector/detect-antipatterns-browser.js b/.pi/skills/impeccable/scripts/detector/detect-antipatterns-browser.js index 8d5bce3f6..e3e5dc21c 100644 --- a/.pi/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +++ b/.pi/skills/impeccable/scripts/detector/detect-antipatterns-browser.js @@ -773,14 +773,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.pi/skills/impeccable/scripts/detector/shared/color.mjs b/.pi/skills/impeccable/scripts/detector/shared/color.mjs index d2524ce52..983e15330 100644 --- a/.pi/skills/impeccable/scripts/detector/shared/color.mjs +++ b/.pi/skills/impeccable/scripts/detector/shared/color.mjs @@ -103,14 +103,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.qoder/skills/impeccable/scripts/detector/detect-antipatterns-browser.js b/.qoder/skills/impeccable/scripts/detector/detect-antipatterns-browser.js index 8d5bce3f6..e3e5dc21c 100644 --- a/.qoder/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +++ b/.qoder/skills/impeccable/scripts/detector/detect-antipatterns-browser.js @@ -773,14 +773,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.qoder/skills/impeccable/scripts/detector/shared/color.mjs b/.qoder/skills/impeccable/scripts/detector/shared/color.mjs index d2524ce52..983e15330 100644 --- a/.qoder/skills/impeccable/scripts/detector/shared/color.mjs +++ b/.qoder/skills/impeccable/scripts/detector/shared/color.mjs @@ -103,14 +103,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.rovodev/skills/impeccable/scripts/detector/detect-antipatterns-browser.js b/.rovodev/skills/impeccable/scripts/detector/detect-antipatterns-browser.js index 8d5bce3f6..e3e5dc21c 100644 --- a/.rovodev/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +++ b/.rovodev/skills/impeccable/scripts/detector/detect-antipatterns-browser.js @@ -773,14 +773,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.rovodev/skills/impeccable/scripts/detector/shared/color.mjs b/.rovodev/skills/impeccable/scripts/detector/shared/color.mjs index d2524ce52..983e15330 100644 --- a/.rovodev/skills/impeccable/scripts/detector/shared/color.mjs +++ b/.rovodev/skills/impeccable/scripts/detector/shared/color.mjs @@ -103,14 +103,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.trae-cn/skills/impeccable/scripts/detector/detect-antipatterns-browser.js b/.trae-cn/skills/impeccable/scripts/detector/detect-antipatterns-browser.js index 8d5bce3f6..e3e5dc21c 100644 --- a/.trae-cn/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +++ b/.trae-cn/skills/impeccable/scripts/detector/detect-antipatterns-browser.js @@ -773,14 +773,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.trae-cn/skills/impeccable/scripts/detector/shared/color.mjs b/.trae-cn/skills/impeccable/scripts/detector/shared/color.mjs index d2524ce52..983e15330 100644 --- a/.trae-cn/skills/impeccable/scripts/detector/shared/color.mjs +++ b/.trae-cn/skills/impeccable/scripts/detector/shared/color.mjs @@ -103,14 +103,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.trae/skills/impeccable/scripts/detector/detect-antipatterns-browser.js b/.trae/skills/impeccable/scripts/detector/detect-antipatterns-browser.js index 8d5bce3f6..e3e5dc21c 100644 --- a/.trae/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +++ b/.trae/skills/impeccable/scripts/detector/detect-antipatterns-browser.js @@ -773,14 +773,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.trae/skills/impeccable/scripts/detector/shared/color.mjs b/.trae/skills/impeccable/scripts/detector/shared/color.mjs index d2524ce52..983e15330 100644 --- a/.trae/skills/impeccable/scripts/detector/shared/color.mjs +++ b/.trae/skills/impeccable/scripts/detector/shared/color.mjs @@ -103,14 +103,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.vibe/skills/impeccable/scripts/detector/detect-antipatterns-browser.js b/.vibe/skills/impeccable/scripts/detector/detect-antipatterns-browser.js index 8d5bce3f6..e3e5dc21c 100644 --- a/.vibe/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +++ b/.vibe/skills/impeccable/scripts/detector/detect-antipatterns-browser.js @@ -773,14 +773,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/.vibe/skills/impeccable/scripts/detector/shared/color.mjs b/.vibe/skills/impeccable/scripts/detector/shared/color.mjs index d2524ce52..983e15330 100644 --- a/.vibe/skills/impeccable/scripts/detector/shared/color.mjs +++ b/.vibe/skills/impeccable/scripts/detector/shared/color.mjs @@ -103,14 +103,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/plugin/skills/impeccable/scripts/detector/detect-antipatterns-browser.js b/plugin/skills/impeccable/scripts/detector/detect-antipatterns-browser.js index 8d5bce3f6..e3e5dc21c 100644 --- a/plugin/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +++ b/plugin/skills/impeccable/scripts/detector/detect-antipatterns-browser.js @@ -773,14 +773,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 }); diff --git a/plugin/skills/impeccable/scripts/detector/shared/color.mjs b/plugin/skills/impeccable/scripts/detector/shared/color.mjs index d2524ce52..983e15330 100644 --- a/plugin/skills/impeccable/scripts/detector/shared/color.mjs +++ b/plugin/skills/impeccable/scripts/detector/shared/color.mjs @@ -103,14 +103,22 @@ function extractColorFunctionTokens(value) { function parseGradientColors(bgImage) { if (!bgImage || !bgImage.includes('gradient')) return []; const colors = []; + const tokenSpans = []; + let from = 0; // Stops arrive in whatever syntax the author wrote and the browser kept. // A dark ground painted as `linear-gradient(oklch(...), oklch(...))` used // to read as a gradient with no stops at all. for (const token of extractColorFunctionTokens(bgImage)) { + const start = bgImage.indexOf(token, from); + if (start < 0) break; + tokenSpans.push({ start, end: start + token.length }); + from = start + token.length; const c = parseAnyColor(token); if (c) colors.push(c); } for (const m of bgImage.matchAll(/#([0-9a-f]{6}|[0-9a-f]{3})\b/gi)) { + // Nested hex inside color-mix is an ingredient, not a stop (issue #578). + if (tokenSpans.some(s => m.index >= s.start && m.index < s.end)) continue; const h = m[1]; if (h.length === 6) { colors.push({ r: parseInt(h.slice(0,2),16), g: parseInt(h.slice(2,4),16), b: parseInt(h.slice(4,6),16), a: 1 });