fix(cli-registry): merge-time fixes for the run-button accents (#463)

- mobile.css: gemini and antigravity run/gear rules get `!important` like
  pi/omp/grok/deepseek, so the gear half no longer keeps the skin accent
  while the body takes the mode colour (two-tone button on the default skin).
- test/skin-themes.test.ts: static guard that every run mode with a base
  `.btn-toolbar.btn-run.mode-<id>` rule also has a resting rule inside the
  `html:not([data-skin="og"])` block; ids are derived from the stylesheet.
- stock.ts: grok's accent comment names zinc-300 (border/badge colour);
  gemini's accent is #8ab4f8 to match its tab badge and run-mode dot, noted
  as the one exception to the border-colour method.
- types.ts: "(below)" -> "(above)".
- docs/cli-registry.md, CLAUDE.md: `accent` is now measured, not transcribed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer
2026-09-23 11:40:03 +02:00
parent 13e652e43f
commit 10f87428c3
6 changed files with 58 additions and 24 deletions
+29
View File
@@ -176,4 +176,33 @@ describe('Codeman light skins', () => {
expect(mobileStylesSource).toContain(':is(.header, .toolbar, .keyboard-accessory-bar)');
expect(mobileStylesSource).toContain(':is(.case-settings-popover-mobile, .mobile-case-picker-sheet)');
});
it('re-declares every run-mode colour inside the non-og skin block', () => {
// The skin block nests under `html:not([data-skin="og"])`, so its generic
// `.btn-toolbar.btn-run` outranks a base-sheet `.mode-<id>` pair. A mode with no
// resting rule of its own in there (a `:hover` alone does not count) renders as generic claude blue on the DEFAULT skin
// (gemini, antigravity and omp all shipped that way). Ids come from the sheet.
const css = stylesSource.replace(/\/\*[\s\S]*?\*\//g, '');
const opener = 'html:not([data-skin="og"]) {';
const start = css.indexOf(opener);
expect(start).toBeGreaterThan(-1);
let depth = 0;
let end = -1;
for (let i = start + opener.length - 1; i < css.length; i++) {
if (css[i] === '{') depth++;
else if (css[i] === '}' && --depth === 0) {
end = i;
break;
}
}
expect(end).toBeGreaterThan(start);
const nested = css.slice(start, end);
const base = css.slice(0, start) + css.slice(end);
const ids = (text: string) =>
new Set([...text.matchAll(/\.btn-toolbar\.btn-run\.mode-([\w-]+)(?![\w-]|:)/g)].map((m) => m[1]));
const baseIds = [...ids(base)];
expect(baseIds.length).toBeGreaterThanOrEqual(5);
const nestedIds = ids(nested);
expect(baseIds.filter((id) => !nestedIds.has(id))).toEqual([]);
});
});