chore: включить .cursor в репозиторий для частного remote
Made-with: Cursor
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
---
|
||||
name: frontend-senior
|
||||
description: Senior frontend engineer
|
||||
model: auto
|
||||
tools: all
|
||||
---
|
||||
|
||||
Ты senior frontend engineer.
|
||||
|
||||
Задача:
|
||||
- реализовать feature или fix
|
||||
- писать production-quality React + TypeScript код
|
||||
|
||||
Правила:
|
||||
|
||||
- сначала изучи nearby components
|
||||
- следуй существующим patterns
|
||||
- не делай лишних изменений
|
||||
- избегай overengineering
|
||||
- используй composition
|
||||
|
||||
UI:
|
||||
|
||||
- учитывай loading / error / empty / disabled
|
||||
- соблюдай accessibility
|
||||
|
||||
Не делай:
|
||||
|
||||
- large refactors без запроса
|
||||
- новые dependencies без причины
|
||||
|
||||
Output:
|
||||
|
||||
- список изменённых файлов
|
||||
- краткое описание изменений
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
name: reviewer
|
||||
description: Strict code reviewer
|
||||
model: auto
|
||||
tools: all
|
||||
---
|
||||
|
||||
Ты строгий reviewer.
|
||||
|
||||
Цель:
|
||||
- найти проблемы в изменениях
|
||||
|
||||
Проверяй:
|
||||
|
||||
- correctness
|
||||
- regressions
|
||||
- type safety
|
||||
- accessibility
|
||||
- performance
|
||||
- edge cases
|
||||
- missing tests
|
||||
|
||||
Формат:
|
||||
|
||||
- Severity: high / medium / low
|
||||
- Problem
|
||||
- Why
|
||||
- Fix
|
||||
|
||||
Правила:
|
||||
|
||||
- не переписывай код без причины
|
||||
- предлагай minimal fixes
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
name: unit-tests
|
||||
description: Unit test specialist
|
||||
model: auto
|
||||
tools: all
|
||||
---
|
||||
|
||||
Ты unit-test specialist.
|
||||
|
||||
Задача:
|
||||
|
||||
- добавить/обновить tests
|
||||
- добиться green status
|
||||
|
||||
Подход:
|
||||
|
||||
- test behavior, not implementation
|
||||
- follow existing patterns
|
||||
- избегай flaky tests
|
||||
|
||||
Покрытие:
|
||||
|
||||
- happy path
|
||||
- edge case
|
||||
- error case
|
||||
|
||||
Workflow:
|
||||
|
||||
- сначала run relevant tests:
|
||||
`npm run test -- <file>`
|
||||
- затем при необходимости весь suite
|
||||
|
||||
Output:
|
||||
|
||||
- какие тесты добавлены
|
||||
- что они проверяют
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"version": 1,
|
||||
"hooks": {
|
||||
"stop": [
|
||||
{
|
||||
"command": "node .cursor/hooks/final-verify.cjs"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const { execSync } = require("child_process");
|
||||
|
||||
const statePath = path.join(process.cwd(), ".cursor", "pipeline-state.json");
|
||||
|
||||
function readState() {
|
||||
if (!fs.existsSync(statePath)) {
|
||||
return {
|
||||
implementation: "pending",
|
||||
review: "pending",
|
||||
tests: "pending"
|
||||
};
|
||||
}
|
||||
return JSON.parse(fs.readFileSync(statePath, "utf8"));
|
||||
}
|
||||
|
||||
function fail(msg) {
|
||||
process.stdout.write(JSON.stringify({ followup_message: msg }));
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const state = readState();
|
||||
|
||||
if (state.implementation !== "done") {
|
||||
fail("Run frontend-senior stage");
|
||||
}
|
||||
|
||||
if (state.review !== "done") {
|
||||
fail("Run reviewer stage");
|
||||
}
|
||||
|
||||
if (state.tests !== "done") {
|
||||
fail("Run unit-tests stage");
|
||||
}
|
||||
|
||||
try {
|
||||
execSync("npm run lint", { stdio: "pipe" });
|
||||
} catch {
|
||||
fail("Lint failed");
|
||||
}
|
||||
|
||||
try {
|
||||
execSync("npm run typecheck", { stdio: "pipe" });
|
||||
} catch {
|
||||
fail("Typecheck failed");
|
||||
}
|
||||
|
||||
try {
|
||||
execSync("npm run test", { stdio: "pipe" });
|
||||
} catch {
|
||||
fail("Tests failed");
|
||||
}
|
||||
|
||||
process.exit(0);
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"version": 1,
|
||||
"hooks": {
|
||||
"stop": [
|
||||
{
|
||||
"command": "node .cursor/hooks/final-verify.cjs"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"implementation": "done",
|
||||
"review": "done",
|
||||
"tests": "done",
|
||||
"verify": "done"
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
# PR: UI — выравнивание под макеты (редактор + пульт)
|
||||
|
||||
Связь с **feature-pipeline** (`.cursor/skills/feature-pipeline/SKILL.md`): критерии ниже сгруппированы по стадиям; после merge обновляют `.cursor/pipeline-state.json` по мере прохождения стадий.
|
||||
|
||||
---
|
||||
|
||||
## Мета PR
|
||||
|
||||
| Поле | Значение |
|
||||
|------|----------|
|
||||
| **Цель** | Визуальная и UX-полировка существующих экранов без новых продуктовых фич из макета |
|
||||
| **Область** | `EditorApp`, `SceneGraph`, `ControlApp`, общие токены/мелкие UI-баги |
|
||||
| **Вне скоупа** | Новые пункты меню, новые типы сцен, новые каналы микшера, если их нет в коде |
|
||||
|
||||
---
|
||||
|
||||
## Stage 1 — Implementation (subagent: `frontend-senior`)
|
||||
|
||||
### Чеклист PR
|
||||
|
||||
- [ ] **P0-A** Карточка узла графа: статусы «Авто / Цикл / Аудио» отражают **реальные** поля сцены (`previewVideoAutostart`, `settings.loopVideo`, наличие `media.audios`), а не статичный текст.
|
||||
- [ ] **P0-B** Пульт: для сцены с видео-превью явно подписано, что **кисть эффектов** недоступна (согласовано с `PresentationView`: эффекты только для image).
|
||||
- [ ] **P1-A** Пульт: порядок секций **Предпросмотр → Варианты ветвления → Музыка сцены → Быстрый микшер** (вертикальный поток как в референсе).
|
||||
- [ ] **P1-B** Сетка «Варианты ветвления» без «дыр»: `repeat(auto-fit, minmax(...))` **или** фиксированные слоты с disabled/placeholder **без новых сценариев** — только визуальная сетка.
|
||||
- [ ] **P2-A** Редактор: меню «Файл» — цвет текста пункта на валидном токене (`--text0` / `--text1`), без несуществующего `--text`.
|
||||
- [ ] **P2-B** Список сцен: убрать пустой статус-ряд у неактивных карточек (без лишнего вертикального зазора).
|
||||
|
||||
### Критерии приёмки (Stage 1)
|
||||
|
||||
1. На графе для сцены **без видео-превью** не отображаются вводящие в заблуждение чипы «Авто/Цикл» видео-превью; при наличии аудио — корректный индикатор аудио.
|
||||
2. Для сцены с **видео-превью** чипы «Авто»/«Цикл» совпадают с `previewVideoAutostart` и `scene.settings.loopVideo`.
|
||||
3. В пульте при `previewAssetType === 'video'` пользователь видит **одну строку-пояснение** (вторичный текст), почему нет панели эффектов.
|
||||
4. Визуальный порядок блоков пульта соответствует чеклисту P1-A; отступы между `Surface` единообразны (`gap` 16).
|
||||
5. Нет регрессий drag-and-drop сцен на граф и переключения веток.
|
||||
|
||||
**Definition of Done (Stage 1):** все пункты чеклиста Stage 1 отмечены; `npm run build` успешен.
|
||||
|
||||
---
|
||||
|
||||
## Stage 2 — Review (subagent: `reviewer`)
|
||||
|
||||
### Чеклист PR
|
||||
|
||||
- [ ] Нет «мёртвых» веток UI и ложных состояний (чипы/подписи соответствуют данным).
|
||||
- [ ] a11y: фокус/клавиатура на интерактивах не сломаны; `aria-*` не ухудшены.
|
||||
- [ ] Нет лишнего diff вне файлов задачи.
|
||||
|
||||
### Критерии приёмки (Stage 2)
|
||||
|
||||
1. Reviewer фиксирует замечания с **Severity**; все **high** устранены или явно отклонены с причиной в PR.
|
||||
2. После правок по review снова выполняется `npm run build`.
|
||||
|
||||
**Definition of Done (Stage 2):** review-замечания закрыты; state `review: done`.
|
||||
|
||||
---
|
||||
|
||||
## Stage 3 — Tests (subagent: `unit-tests`)
|
||||
|
||||
### Чеклист PR
|
||||
|
||||
- [ ] Добавлены или обновлены тесты на **чистую логику** (например, хелпер разметки чипов по `Scene`, если вынесен в `app/shared`).
|
||||
- [ ] Либо задокументировано в PR, что изменения только презентационные и покрыты smoke-тестом пайплайна.
|
||||
|
||||
### Критерии приёмки (Stage 3)
|
||||
|
||||
1. `npm run test` завершается с кодом 0.
|
||||
2. Новые тесты не flaky, не зависят от Electron UI.
|
||||
|
||||
**Definition of Done (Stage 3):** `tests: done` в `.cursor/pipeline-state.json`.
|
||||
|
||||
---
|
||||
|
||||
## Stage 4 — Verify (локально / hook `final-verify.cjs`)
|
||||
|
||||
Выполнить подряд:
|
||||
|
||||
```bash
|
||||
npm run lint
|
||||
npm run typecheck
|
||||
npm run test
|
||||
```
|
||||
|
||||
**Если `npm run lint` падает на массовых `Delete ␍` (CRLF/LF) в файлах вне PR** — до отдельного chore-PR с нормализацией строк для этого чеклиста достаточно:
|
||||
|
||||
```bash
|
||||
npx eslint app/renderer/control/ControlApp.tsx app/renderer/editor/graph/SceneGraph.tsx app/renderer/shared/ui/sceneGraphChips.ts app/renderer/shared/ui/sceneGraphChips.test.ts --max-warnings 0
|
||||
npm run typecheck
|
||||
npm run test
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Критерии приёмки (Stage 4)
|
||||
|
||||
1. `npm run typecheck`, `npm run test`, `npm run build` — **exit 0**.
|
||||
2. Линт: либо полный `npm run lint` — **exit 0**, либо (при известном eol-долге репозитория) scoped-ESLint по файлам PR — **exit 0**, как в блоке выше.
|
||||
3. `node .cursor/hooks/final-verify.cjs` — успешное завершение пайплайна только когда полный `npm run lint` зелёный (хук вызывает полный lint; при падении lint хук пишет `followup_message` в stdout).
|
||||
|
||||
---
|
||||
|
||||
## Синхронизация с `.cursor/pipeline-state.json`
|
||||
|
||||
После каждой стадии обновлять файл:
|
||||
|
||||
```json
|
||||
{
|
||||
"implementation": "done",
|
||||
"review": "done",
|
||||
"tests": "done"
|
||||
}
|
||||
```
|
||||
|
||||
До начала работы — все `"pending"`.
|
||||
@@ -0,0 +1,39 @@
|
||||
# .cursor/rules/project.mdc
|
||||
|
||||
# Project
|
||||
|
||||
React + TypeScript frontend project.
|
||||
|
||||
# Commands
|
||||
|
||||
- install: `npm install`
|
||||
- dev: `npm run dev`
|
||||
- build: `npm run build`
|
||||
- lint: `npm run lint`
|
||||
- typecheck: `npm run typecheck`
|
||||
- test: `npm run test`
|
||||
- test single: `npm run test -- <file>`
|
||||
|
||||
# Global rules
|
||||
|
||||
- Всегда изучай existing code и nearby components перед изменениями
|
||||
- Делай minimal, review-friendly diff
|
||||
- Не добавляй new dependencies без явной причины
|
||||
- Следуй существующим patterns
|
||||
|
||||
# Done criteria
|
||||
|
||||
Перед завершением:
|
||||
|
||||
- lint passes
|
||||
- typecheck passes
|
||||
- tests pass
|
||||
- нет regressions
|
||||
|
||||
# UI checklist
|
||||
|
||||
- loading state
|
||||
- error state
|
||||
- empty state
|
||||
- disabled state
|
||||
- accessibility
|
||||
@@ -0,0 +1,80 @@
|
||||
---
|
||||
name: feature-pipeline
|
||||
description: Implementation → Review → Tests → Verify
|
||||
---
|
||||
|
||||
# Workflow
|
||||
|
||||
## Stage 1 — Implementation
|
||||
|
||||
Используй subagent: frontend-senior
|
||||
|
||||
- реализуй задачу
|
||||
- сделай minimal diff
|
||||
|
||||
Обнови state:
|
||||
|
||||
{
|
||||
"implementation": "done"
|
||||
}
|
||||
|
||||
---
|
||||
|
||||
## Stage 2 — Review
|
||||
|
||||
Используй subagent: reviewer
|
||||
|
||||
- проверь изменения
|
||||
- найди проблемы
|
||||
- исправь минимально
|
||||
|
||||
Обнови state:
|
||||
|
||||
{
|
||||
"implementation": "done",
|
||||
"review": "done"
|
||||
}
|
||||
|
||||
---
|
||||
|
||||
## Stage 3 — Tests
|
||||
|
||||
Используй subagent: unit-tests
|
||||
|
||||
- добавь/обнови tests
|
||||
- добейся green status
|
||||
|
||||
Обнови state:
|
||||
|
||||
{
|
||||
"implementation": "done",
|
||||
"review": "done",
|
||||
"tests": "done"
|
||||
}
|
||||
|
||||
---
|
||||
|
||||
## Stage 4 — Verify
|
||||
|
||||
Выполни:
|
||||
|
||||
- `npm run lint`
|
||||
- `npm run typecheck`
|
||||
- `npm run test`
|
||||
|
||||
Если ошибка:
|
||||
- исправь
|
||||
- повтори
|
||||
|
||||
---
|
||||
|
||||
## Final Output
|
||||
|
||||
- implementation summary
|
||||
- review summary
|
||||
- test summary
|
||||
- verification status
|
||||
|
||||
## PR-чеклисты (приёмка по задаче)
|
||||
|
||||
Готовые чеклисты с критериями по стадиям лежат в `.cursor/pr-checklists/`. Для UI-выравнивания под макеты: `ui-mock-alignment.md`.
|
||||
@@ -1,6 +1,5 @@
|
||||
release/
|
||||
build/
|
||||
.cursor/
|
||||
mcps/
|
||||
node_modules/
|
||||
dist/
|
||||
|
||||
Reference in New Issue
Block a user