En
Написать
‹ Назад

ui-repair

Починкаopen source

Линтер говорит, что в коде сырой button и цвет #8B5CF6. ui-repair заменяет сырой button, этот цвет и самодельный modal на компоненты системы и показывает, какие проверки раньше не проходили, а теперь проходят. На примере счёт по десяти проверкам идёт с 50 до 100. Это не вызов модели и не прогон ds-eval.

Зачем

Найти нарушение мало. Команде нужен патч: сырой <button> становится Button, захардкоженный #8B5CF6 становится токеном, самодельный modal становится Dialog. ui-repair делает эту замену по правилам и показывает, какие проверки раньше не проходили, а теперь проходят.

Агент должен отдавать такой же патч. В этом примере правила каждый раз дают один и тот же патч, чтобы пример можно было повторить без ключа.

Правила

Каждое правило смотрит на текст примера и на tokens.css рядом. На Acme --color-accent равен #8B5CF6, --space-3 равен 12px.

НаходитПишет
hex, если значение совпало с токеномvar(--color-accent)
padding: 13var(--space-3)
<div className="modal"><Dialog>
сырой <button><Button> и импорт из @ds
кнопка, внутри которой только ×aria-label="Close"

Импорт добавляется одной строкой, если в файле ещё нет from "@ds": import { Button, Dialog } from "@ds";

Запуск

python3 ui-repair/ui_repair.py scan ui-repair/fixtures
python3 ui-repair/ui_repair.py fix ui-repair/fixtures --out ui-repair/examples

scan печатает список и ничего не пишет. fix кладёт Settings.jsx в ui-repair/examples и печатает счёт до и после. На примере scan находит:

6 issues
  raw <button>
  hardcoded hex color
  hand-rolled modal
  padding 13 is off the space scale
  icon button without an accessible name
  no design-system import

До

Файл ui-repair/fixtures/Settings.jsx. Фиолетовый фон числом, отступ 13, Save сырым тегом, модалка из div и крестик без имени.

export function Settings() {
  const open = () => {};
  return (
    <section>
      <h1>Settings</h1>
      <div style={{ background: "#8B5CF6", padding: 13 }}>
        <button onClick={open}>Save</button>
        <div className="modal">
          <h2>Delete account</h2>
          <button>×</button>
        </div>
      </div>
    </section>
  );
}

После

Тот же файл после fix. Это результат правил, не ответ модели.

import { Button, Dialog } from "@ds";
export function Settings() {
  const open = () => {};
  return (
    <section>
      <h1>Settings</h1>
      <div style={{ background: "var(--color-accent)", padding: "var(--space-3)" }}>
        <Button onClick={open}>Save</Button>
        <Dialog>
          <h2>Delete account</h2>
          <Button aria-label="Close">×</Button>
        </Dialog>
      </div>
    </section>
  );
}

Проверки

Десять проверок, равный вес. До починки счёт 50: пять структурных проверок уже проходили, пять проверок системы не проходили. После — 100.

ПроверкаДоПосле
экспортирует компонентдада
обрабатывает кликдада
нет dangerouslySetInnerHTMLдада
есть заголовокдада
нет !importantдада
импортирует дизайн-системунетда
нет сырого buttonнетда
нет цвета, прописанного вручнуюнетда
Dialog, а не div.modalнетда
нет отступа, прописанного вручнуюнетда

Это не балл ds-eval и не результат Claude. Следующий шаг — прогнать патч в ds-eval: сборка, axe, Playwright. Здесь виден только ремонт по правилам и то, какие проверки он закрыл.

Связь с остальными инструментами

ds-context говорит, какие компоненты и токены существуют. ui-repair правит файл по этому списку. ds-eval проверяет, стал ли экран рабочим, а не только формально чистым.

Предел

Правила знают этот пример: конкретный hex, padding 13, класс modal, крестик. Чтобы автоматически переписывать произвольный React-проект, поверх замен нужны разбор AST, проверка типов TypeScript, сборка и прогон поведения в Playwright. Здесь нет диффа, скриншота и живого агента: рост счёта 50 → 100 показывает работу правил на контролируемой фикстуре, а не готовый продакшен-кодмод.

Есть задача?

Напишите мне. Вместе разберёмся, с чего начать.