@nitra/cursor 12.9.0 → 12.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-template/settings.template.json +1 -23
- package/CHANGELOG.md +12 -0
- package/bin/n-cursor.js +8 -43
- package/docs/stryker.config.md +0 -2
- package/lib/docs/llm.md +16 -21
- package/lib/docs/omlx.md +20 -25
- package/lib/llm.mjs +25 -7
- package/lib/omlx.mjs +10 -3
- package/package.json +1 -1
- package/rules/abie/docs/main.md +0 -2
- package/rules/abie/lib/docs/http-route.md +0 -2
- package/rules/abie/main.mdc +0 -22
- package/rules/adr/docs/main.md +0 -2
- package/rules/adr/js/docs/hooks.md +16 -26
- package/rules/adr/js/hooks.mjs +59 -0
- package/rules/adr/main.mdc +0 -9
- package/rules/bun/docs/main.md +0 -2
- package/rules/bun/main.mdc +1 -15
- package/rules/capacitor/docs/main.md +0 -2
- package/rules/capacitor/main.mdc +0 -6
- package/rules/changelog/docs/main.md +0 -2
- package/rules/changelog/js/agent-workflow.mdc +1 -1
- package/rules/changelog/js/consistency.mjs +57 -3
- package/rules/changelog/js/docs/consistency.md +26 -24
- package/rules/changelog/js/docs/index.md +2 -2
- package/rules/changelog/main.mdc +0 -5
- package/rules/ci4/docs/main.md +0 -2
- package/rules/ci4/main.mdc +0 -5
- package/rules/doc-files/docs/main.md +0 -2
- package/rules/doc-files/js/docs/docgen-crc.md +0 -2
- package/rules/doc-files/js/docs/docgen-extract.md +0 -2
- package/rules/doc-files/js/docs/docgen-files-batch.md +0 -2
- package/rules/doc-files/js/docs/docgen-gen.md +0 -2
- package/rules/doc-files/js/docs/docgen-judge-measure.md +0 -2
- package/rules/doc-files/js/docs/docgen-judge.md +0 -2
- package/rules/doc-files/js/docs/docgen-scan.md +0 -2
- package/rules/doc-files/js/docs/run-lint.md +0 -2
- package/rules/docker/docs/main.md +0 -2
- package/rules/docker/js/docs/lint.md +0 -2
- package/rules/docker/lib/docs/docker-hadolint.md +0 -2
- package/rules/docker/main.mdc +1 -21
- package/rules/efes/docs/main.md +0 -2
- package/rules/efes/main.mdc +0 -1
- package/rules/feedback/docs/main.md +0 -2
- package/rules/ga/docs/main.md +0 -2
- package/rules/ga/js/docs/index.md +0 -1
- package/rules/ga/main.mdc +1 -31
- package/rules/graphql/docs/main.md +0 -2
- package/rules/graphql/main.mdc +0 -5
- package/rules/hasura/docs/main.md +0 -2
- package/rules/hasura/js/docs/index.md +3 -3
- package/rules/hasura/js/docs/migrations.md +0 -2
- package/rules/hasura/main.mdc +1 -11
- package/rules/image-avif/docs/main.md +0 -2
- package/rules/image-avif/main.mdc +1 -9
- package/rules/image-compress/docs/main.md +0 -2
- package/rules/image-compress/js/docs/index.md +0 -1
- package/rules/image-compress/main.mdc +1 -9
- package/rules/js/docs/main.md +0 -2
- package/rules/js/js/dep-policy.mjs +8 -4
- package/rules/js/js/docs/check.md +0 -2
- package/rules/js/js/docs/dep-policy.md +10 -12
- package/rules/js/js/docs/index.md +5 -5
- package/rules/js/js/docs/tooling.md +0 -2
- package/rules/js/js/docs/utils_imports.md +0 -2
- package/rules/js/main.mdc +0 -31
- package/rules/js-bun-db/docs/main.md +0 -2
- package/rules/js-bun-db/js/docs/safety.md +18 -23
- package/rules/js-bun-db/js/safety.mjs +31 -3
- package/rules/js-bun-db/lib/bun-sql-scan.mjs +123 -0
- package/rules/js-bun-db/lib/docs/bun-sql-scan.md +37 -331
- package/rules/js-bun-db/main.mdc +1 -23
- package/rules/js-bun-redis/docs/main.md +0 -2
- package/rules/js-bun-redis/main.mdc +0 -5
- package/rules/js-mssql/docs/main.md +0 -2
- package/rules/js-mssql/main.mdc +0 -12
- package/rules/js-run/docs/main.md +0 -2
- package/rules/js-run/js/docs/runtime.md +15 -13
- package/rules/js-run/js/runtime.mjs +48 -4
- package/rules/js-run/main.mdc +0 -25
- package/rules/k8s/docs/main.md +0 -2
- package/rules/k8s/main.mdc +0 -45
- package/rules/nginx-default-tpl/docs/main.md +0 -2
- package/rules/nginx-default-tpl/main.mdc +0 -13
- package/rules/npm-module/docs/main.md +0 -2
- package/rules/npm-module/js/docs/header_doc_pointer.md +0 -2
- package/rules/npm-module/js/docs/rule_meta.md +0 -2
- package/rules/npm-module/js/docs/skill_meta.md +0 -2
- package/rules/npm-module/main.mdc +1 -15
- package/rules/php/docs/main.md +0 -2
- package/rules/php/js/docs/index.md +0 -1
- package/rules/php/main.mdc +1 -9
- package/rules/python/docs/main.md +0 -2
- package/rules/python/js/docs/index.md +0 -1
- package/rules/python/main.mdc +1 -13
- package/rules/python/policy/lint_python_yml/lint_python_yml.rego +9 -0
- package/rules/python/policy/pyproject_toml/pyproject_toml.rego +15 -1
- package/rules/rego/docs/main.md +0 -2
- package/rules/rego/js/docs/index.md +2 -2
- package/rules/rego/js/docs/tooling.md +0 -2
- package/rules/rego/js/tooling.mdc +14 -0
- package/rules/rego/main.mdc +0 -9
- package/rules/rego/policy/package_json/package_json.mdc +12 -0
- package/rules/release/docs/main.md +0 -2
- package/rules/release/main.mdc +2 -2
- package/rules/rust/docs/main.md +0 -2
- package/rules/rust/js/docs/index.md +0 -1
- package/rules/rust/main.mdc +1 -11
- package/rules/rust/policy/package_json/package_json.mdc +12 -0
- package/rules/security/docs/main.md +0 -2
- package/rules/security/js/docs/index.md +0 -1
- package/rules/security/main.mdc +0 -13
- package/rules/style/docs/main.md +0 -2
- package/rules/style/js/docs/index.md +2 -2
- package/rules/style/js/docs/tooling.md +0 -2
- package/rules/style/main.mdc +1 -23
- package/rules/tauri/docs/main.md +0 -2
- package/rules/tauri/main.mdc +1 -11
- package/rules/test/docs/main.md +0 -2
- package/rules/test/js/docs/no-console-store-restore.md +0 -2
- package/rules/test/js/docs/sandbox-aware-test.md +0 -2
- package/rules/test/js/docs/stryker_config.md +0 -2
- package/rules/test/js/docs/vitest-config-pool-forks.md +0 -2
- package/rules/test/main.mdc +1 -21
- package/rules/text/docs/main.md +0 -2
- package/rules/text/js/docs/cspell-fix.md +0 -2
- package/rules/text/js/docs/run-dotenv-linter.md +0 -2
- package/rules/text/js/docs/run-shellcheck.md +0 -2
- package/rules/text/js/docs/run-v8r.md +0 -2
- package/rules/text/main.mdc +0 -33
- package/rules/tool-surface/docs/main.md +0 -2
- package/rules/vue/docs/main.md +0 -2
- package/rules/vue/js/docs/packages.md +12 -17
- package/rules/vue/js/packages.mjs +41 -1
- package/rules/vue/main.mdc +0 -22
- package/rules/worktree/docs/main.md +0 -2
- package/scripts/docs/auto-rules.md +0 -2
- package/scripts/docs/auto-skills.md +0 -2
- package/scripts/docs/hook.md +13 -12
- package/scripts/docs/post-tool-use-check.md +0 -2
- package/scripts/docs/sync-claude-config.md +1 -3
- package/scripts/docs/sync-setup-bun-deps-action.md +0 -2
- package/scripts/hook.mjs +3 -4
- package/scripts/lib/docs/check-mdc-template-refs.md +0 -2
- package/scripts/lib/docs/index.md +35 -35
- package/scripts/lib/docs/inline-template-links.md +6 -8
- package/scripts/lib/docs/list-project-rules-mdc.md +0 -2
- package/scripts/lib/docs/list-rule-ids.md +0 -2
- package/scripts/lib/docs/mirror-parity.md +8 -10
- package/scripts/lib/docs/read-n-cursor-config-lite.md +0 -2
- package/scripts/lib/docs/rule-meta.md +0 -2
- package/scripts/lib/docs/run-lint.md +0 -2
- package/scripts/lib/docs/run-rule-cli.md +0 -2
- package/scripts/lib/docs/run-rule.md +0 -2
- package/scripts/lib/docs/run-standard-lint.md +0 -2
- package/scripts/lib/docs/run-standard-rule.md +0 -2
- package/scripts/lib/docs/skill-meta.md +0 -2
- package/scripts/lib/docs/timing-summary.md +0 -2
- package/scripts/lib/docs/worktree-notice.md +0 -2
- package/scripts/lib/fix/docs/analyze-escalation.md +0 -2
- package/scripts/lib/fix/docs/index.md +1 -0
- package/scripts/lib/fix/docs/llm-worker.md +18 -8
- package/scripts/lib/fix/docs/orchestrator.md +10 -16
- package/scripts/lib/fix/docs/run-conformance-check.md +0 -2
- package/scripts/lib/fix/docs/t0.md +0 -2
- package/scripts/lib/fix/docs/verbose-block.md +27 -0
- package/scripts/lib/fix/llm-worker.mjs +75 -22
- package/scripts/lib/fix/orchestrator.mjs +9 -3
- package/scripts/lib/fix/verbose-block.mjs +82 -0
- package/scripts/lib/inline-template-links.mjs +32 -22
- package/scripts/lib/mirror-parity.mjs +2 -2
- package/scripts/sync-claude-config.mjs +7 -4
- package/scripts/utils/docs/resolve-js-root.md +0 -2
- package/skills/doc-files/SKILL.md +9 -24
- package/skills/llm-patch/SKILL.md +4 -4
package/rules/style/main.mdc
CHANGED
|
@@ -5,26 +5,4 @@ globs: "**/*.{css,scss,vue}"
|
|
|
5
5
|
alwaysApply: false
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
Правило **style** для Vue-проєктів: Quasar як стильова система, SCSS-конвенції кольорів і відступів, фікси компонентів, stylelint через `@nitra/stylelint-config`.
|
|
9
|
-
|
|
10
|
-
[style-quasar](./js/quasar.mdc)
|
|
11
|
-
|
|
12
|
-
[style-colors](./js/colors.mdc)
|
|
13
|
-
|
|
14
|
-
[style-gap](./js/gap.mdc)
|
|
15
|
-
|
|
16
|
-
[style-quasar-fixes](./js/quasar-fixes.mdc)
|
|
17
|
-
|
|
18
|
-
[style-tooling](./js/tooling.mdc)
|
|
19
|
-
|
|
20
|
-
[style-admin-table](./js/admin-table.mdc)
|
|
21
|
-
|
|
22
|
-
## Швидкий gate через conftest (Rego)
|
|
23
|
-
|
|
24
|
-
[style-lint_style_yml](./policy/lint_style_yml/lint_style_yml.mdc)
|
|
25
|
-
|
|
26
|
-
[style-package_json](./policy/package_json/package_json.mdc)
|
|
27
|
-
|
|
28
|
-
[style-vscode_extensions](./policy/vscode_extensions/vscode_extensions.mdc)
|
|
29
|
-
|
|
30
|
-
[style-vscode_settings](./policy/vscode_settings/vscode_settings.mdc)
|
|
8
|
+
Правило **style** для Vue-проєктів: Quasar як стильова система, SCSS-конвенції кольорів і відступів, фікси компонентів, stylelint через `@nitra/stylelint-config`.
|
package/rules/tauri/docs/main.md
CHANGED
|
@@ -8,8 +8,6 @@ docgen:
|
|
|
8
8
|
score: 100
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## Огляд
|
|
12
|
-
|
|
13
11
|
Модуль обробляє JS-запити та взаємодіє з MDC для отримання даних. При запуску через публічну функцію `run` він оркеструє застосування правил, завантажуючи конфігурації з meta.json, застосовуючи білий список та надаючи підсумок. Модуль є read-only і не здійснює записів у ФС/БД.
|
|
14
12
|
|
|
15
13
|
## Поведінка
|
package/rules/tauri/main.mdc
CHANGED
|
@@ -5,14 +5,4 @@ alwaysApply: false
|
|
|
5
5
|
version: '1.5'
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
Правило встановлює канонічні вимоги для Tauri-проєктів: виявлення маркерів у монорепо, VS Code-розширення, налаштування mutation-testing для platform bridge та реалізацію Tool Surface поверх Tauri+Rust.
|
|
9
|
-
|
|
10
|
-
## Швидкий gate через conftest
|
|
11
|
-
|
|
12
|
-
[tauri-vscode_extensions](./policy/vscode_extensions/vscode_extensions.mdc)
|
|
13
|
-
|
|
14
|
-
[tauri-tooling](./js/tooling.mdc)
|
|
15
|
-
|
|
16
|
-
[tauri-cargo_mutants_config](./js/cargo_mutants_config.mdc)
|
|
17
|
-
|
|
18
|
-
[tauri-tool_surface](./js/tool_surface.mdc)
|
|
8
|
+
Правило встановлює канонічні вимоги для Tauri-проєктів: виявлення маркерів у монорепо, VS Code-розширення, налаштування mutation-testing для platform bridge та реалізацію Tool Surface поверх Tauri+Rust.
|
package/rules/test/docs/main.md
CHANGED
|
@@ -8,8 +8,6 @@ docgen:
|
|
|
8
8
|
score: 100
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## Огляд
|
|
12
|
-
|
|
13
11
|
Модуль виконує перевірку, обробляючи JS-запитання, політику та посилання на mdc. При запуску як окрема програма, він зчитує конфігурації з meta.json, застосовує білий список та підсумовує результати після застосування білого списку, визначаючи код виходу процесу. Функція run ініціює цей процес. Модуль є read-only і не пише у ФС/БД. Кешування відбувається у межах прогону.
|
|
14
12
|
|
|
15
13
|
## Поведінка
|
|
@@ -8,8 +8,6 @@ docgen:
|
|
|
8
8
|
score: 100
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## Огляд
|
|
12
|
-
|
|
13
11
|
Модуль сканує репозиторій для пошуку файлів, що відповідають шаблону `*.test.{mjs,js}`. Він перевіряє вміст кожного такого файлу на наявність прямих присвоєнь методів консолі. Публічна функція `check` виявляє такі присвоєння. (test.mdc)
|
|
14
12
|
|
|
15
13
|
## Поведінка
|
|
@@ -8,8 +8,6 @@ docgen:
|
|
|
8
8
|
score: 100
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## Огляд
|
|
12
|
-
|
|
13
11
|
Модуль сканує тестові файли, що відповідають шаблону `*.test.{mjs,js}` у вказаному корені репозиторію. Він перевіряє, чи файли, що містять глибоку навігацію (визначену як використання `import.meta.dirname` або `import.meta.url` з чотирма або більше рівнями `..`), захищені викликом `withTmpDir` або `test.skipIf` з посиланням на змінну середовища `env.STRYKER_MUTATOR_WORKER`. Перевірка фіксує порушення (test.mdc) у разі відсутності необхідної ізоляції для тестових файлів з глибокою навігацією.
|
|
14
12
|
|
|
15
13
|
## Поведінка
|
|
@@ -8,8 +8,6 @@ docgen:
|
|
|
8
8
|
score: 100
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## Огляд
|
|
12
|
-
|
|
13
11
|
Модуль перевіряє готовність JavaScript-проєктів до виконання тестів. Він збирає кореневі каталоги проєктів, використовуючи публічну функцію `check` для валідації. Перевірка гарантує наявність необхідних конфігураційних файлів, зокрема `mutation.json` та `package.json`, у кожному знайденому проєкті. Модуль свідомо пропускає каталоги `node_modules`. Він також додає відповідні артефакти тестів до `.gitignore` у коренях проєктів. (test.mdc)
|
|
14
12
|
|
|
15
13
|
## Поведінка
|
package/rules/test/main.mdc
CHANGED
|
@@ -7,22 +7,6 @@ alwaysApply: false
|
|
|
7
7
|
|
|
8
8
|
Правило **test** керує розміщенням тестових файлів, безпекою ізоляції тестів (заборона `process.chdir`, відносних шляхів у FS, ручного store/restore console), налаштуванням Vitest/Stryker baseline та конфігурацією cargo-mutants для Rust.
|
|
9
9
|
|
|
10
|
-
[test-location](./js/location.mdc)
|
|
11
|
-
|
|
12
|
-
[test-no-process-chdir](./js/no-process-chdir.mdc)
|
|
13
|
-
|
|
14
|
-
[test-no-relative-fs-path](./js/no-relative-fs-path.mdc)
|
|
15
|
-
|
|
16
|
-
[test-no-console-store-restore](./js/no-console-store-restore.mdc)
|
|
17
|
-
|
|
18
|
-
[test-sandbox-aware-test](./js/sandbox-aware-test.mdc)
|
|
19
|
-
|
|
20
|
-
[test-vitest-config-pool-forks](./js/vitest-config-pool-forks.mdc)
|
|
21
|
-
|
|
22
|
-
[test-stryker-config](./js/stryker_config.mdc)
|
|
23
|
-
|
|
24
|
-
[test-cargo-mutants-config](./js/cargo_mutants_config.mdc)
|
|
25
|
-
|
|
26
10
|
## Покриття + мутаційне тестування
|
|
27
11
|
|
|
28
12
|
Канонічна команда — `n-cursor coverage`: збирає метрики покриття (`vitest run --coverage`, `cargo llvm-cov` тощо) і мутаційного тестування (Stryker з vitest-runner + `coverageAnalysis: 'perTest'`, `cargo-mutants`) з усіх активних провайдерів у `.n-cursor.json#rules` і пише `COVERAGE.md` у корінь проєкту.
|
|
@@ -35,8 +19,4 @@ alwaysApply: false
|
|
|
35
19
|
|
|
36
20
|
### Multi-workspace iteration
|
|
37
21
|
|
|
38
|
-
У monorepo `n-cursor coverage` ітерує усі workspaces з власним `package.json` і агрегує метрики lcov + Stryker у єдиний `JS`-рядок `COVERAGE.md`. Workspace без тестів пропускається без помилки.
|
|
39
|
-
|
|
40
|
-
## Швидкий gate через conftest
|
|
41
|
-
|
|
42
|
-
[test-package_json](./policy/package_json/package_json.mdc)
|
|
22
|
+
У monorepo `n-cursor coverage` ітерує усі workspaces з власним `package.json` і агрегує метрики lcov + Stryker у єдиний `JS`-рядок `COVERAGE.md`. Workspace без тестів пропускається без помилки.
|
package/rules/text/docs/main.md
CHANGED
|
@@ -8,8 +8,6 @@ docgen:
|
|
|
8
8
|
score: 90
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## Огляд
|
|
12
|
-
|
|
13
11
|
Цей модуль є CLI-обгорткою над канонічним `lint-text` (text.mdc) та викликається через `n-cursor lint text` (оркестраторний адаптер `lint`). Він автоматично встановлює необхідні інструменти (`shellcheck`, `dotenv-linter`) через `ensureTool` (brew/scoop/GitHub Release per-platform) та перевіряє наявність `patch` (для авто-фіксу shellcheck). Функція `runLintTextCli` послідовно виконує: 1) перевірку правопису з `@nitra/cspell-dict` (`cspell .`); 2) авто-фікс та фінальну перевірку `.sh` файлів (`shellcheck`); 3) авто-фікс та фінальну перевірку `.env*` файлів (`dotenv-linter`); 4) авто-фікс Markdown-документів (`markdownlint-cli2 --fix "**\/*.md" "**\/*.mdc"`); 5) schema-валідацію JSON/YAML/TOML через `v8r`. При першому ненульовому коді з ланцюжка повертається код виходу, і наступні кроки не запускаються. Конфігурації, на які спирається код: meta.json.
|
|
14
12
|
|
|
15
13
|
## Поведінка
|
|
@@ -8,8 +8,6 @@ docgen:
|
|
|
8
8
|
score: 100
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## Огляд
|
|
12
|
-
|
|
13
11
|
Модуль інтегрує cspell у ланцюжку lint-text для класифікації невідомих слів згідно зі схемою docs/specs/2026-06-15-opportunistic-llm-fix-tier.md. Він виявляє невідомі слова, класифікує їх за допомогою LLM у межах omlx-класифікації. Валідні слова автоматично дописуються до `.cspell.json#words` (відповідно до конфігурацій .cspell.json та meta.json). Невалідні знахідки залишаються для ручного рев'ю. Процес є read-only (нуль мутацій), оскільки fix-режим не переписує файли, а лише класифікує знахідки. Після дописування словника виконується re-detect. Гейт-механізм гарантує, що cspell поверне ненульовий код, якщо нерозкласифіковані або потенційні одруки залишилися.
|
|
14
12
|
|
|
15
13
|
## Поведінка
|
|
@@ -8,8 +8,6 @@ docgen:
|
|
|
8
8
|
score: 100
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## Огляд
|
|
12
|
-
|
|
13
11
|
Модуль запускає `dotenv-linter` для валідації конфігураційних файлів `.env*` відповідно до стандартів (наприклад, `LowercaseKey`). Процес включає два етапи: спочатку автоматичне виправлення порушень за допомогою `dotenv-linter fix`, а потім фінальну перевірку за допомогою `dotenv-linter check`. Інструмент очікується у системному PATH і не включається у залежності проєкту. Він рекурсивно шукає файли, виключаючи `node_modules` та `.envrc`. Якщо `dotenv-linter` відсутній, виводиться інструкція щодо його встановлення (наприклад, `brew install dotenv-linter`) та повертається код помилки. Усі деталі роботи можна знайти за посиланням https://git.io/JLbXn.
|
|
14
12
|
|
|
15
13
|
## Поведінка
|
|
@@ -8,8 +8,6 @@ docgen:
|
|
|
8
8
|
score: 100
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## Огляд
|
|
12
|
-
|
|
13
11
|
Скрипт забезпечує відповідність shell-скриптів стандартам, виконуючи дві послідовні дії: спочатку застосовує автоматичні виправлення для проблем, виявлених `shellcheck` за допомогою формату виводу `diff` та команди `patch -p1` у корені проєкту; потім проводить фінальну перевірку всіх зібраних файлів. Скрипт збирає всі відстежувані shell-скрипти у робочому дереві, ігноруючи директорії `node_modules`. Якщо скриптів не знайдено, процес завершується з кодом 0. Якщо `shellcheck` або `patch` відсутні у PATH, скрипт завершується з кодом 1, надаючи підказки для їх встановлення. Після циклу автовиправлень будь-яке попередження чи помилка від `shellcheck` призводить до ненульового коду виходу.
|
|
14
12
|
|
|
15
13
|
## Поведінка
|
|
@@ -8,8 +8,6 @@ docgen:
|
|
|
8
8
|
score: 100
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## Огляд
|
|
12
|
-
|
|
13
11
|
Скрипт виконує єдиний виклик `v8r` для перевірки відповідності всіх файлів, які підтримує `v8r` (json, json5, yaml, yml, toml), визначеним контрактам. Це замінює необхідність у кількох окремих викликах `v8r`. Скрипт автоматично використовує каталог схем `@nitra/cursor`, який визначається у `v8r-catalog.json`. Якщо не надано додаткових аргументів, він шукає файли за типовими шаблонами у дереві проєкту. Механізм гарантує, що перевірка всіх розширень відбувається, навіть якщо один із глобів не знаходить файлів, оскільки він обходить проблему падіння `v8r` з кодом 98.
|
|
14
12
|
|
|
15
13
|
## Поведінка
|
package/rules/text/main.mdc
CHANGED
|
@@ -6,40 +6,7 @@ version: '1.30'
|
|
|
6
6
|
|
|
7
7
|
Правило охоплює весь текстовий стек проєкту: форматування (oxfmt), перевірку правопису (cspell), shell-скрипти (shellcheck), `.env`-файли (dotenv-linter), Markdown (markdownlint-cli2), JSON/YAML/TOML-схеми (v8r) та CI-workflow.
|
|
8
8
|
|
|
9
|
-
[text-vscode](./js/vscode.mdc)
|
|
10
|
-
|
|
11
|
-
[text-oxfmt](./js/oxfmt.mdc)
|
|
12
|
-
|
|
13
|
-
[text-forbidden-prettier](./js/forbidden-prettier.mdc)
|
|
14
|
-
|
|
15
|
-
[text-cspell](./js/cspell.mdc)
|
|
16
|
-
|
|
17
|
-
[text-markdownlint](./js/markdownlint.mdc)
|
|
18
|
-
|
|
19
|
-
[text-shellcheck](./js/shellcheck.mdc)
|
|
20
|
-
|
|
21
|
-
[text-dotenv-linter](./js/dotenv-linter.mdc)
|
|
22
|
-
|
|
23
|
-
[text-v8r](./js/v8r.mdc)
|
|
24
|
-
|
|
25
|
-
[text-package-json](./js/package-json.mdc)
|
|
26
|
-
|
|
27
|
-
[text-ci-lint-text](./js/ci-lint-text.mdc)
|
|
28
|
-
|
|
29
9
|
## Швидкий gate через conftest
|
|
30
10
|
|
|
31
11
|
Rego-пакети, що перевіряються через conftest (auto-discovered за `target.json` поряд із `.rego`):
|
|
32
12
|
|
|
33
|
-
[text-policy-cspell](./policy/cspell/cspell.mdc)
|
|
34
|
-
|
|
35
|
-
[text-policy-lint_text](./policy/lint_text/lint_text.mdc)
|
|
36
|
-
|
|
37
|
-
[text-policy-markdownlint](./policy/markdownlint/markdownlint.mdc)
|
|
38
|
-
|
|
39
|
-
[text-policy-oxfmtrc](./policy/oxfmtrc/oxfmtrc.mdc)
|
|
40
|
-
|
|
41
|
-
[text-policy-package_json](./policy/package_json/package_json.mdc)
|
|
42
|
-
|
|
43
|
-
[text-policy-vscode_extensions](./policy/vscode_extensions/vscode_extensions.mdc)
|
|
44
|
-
|
|
45
|
-
[text-policy-vscode_settings](./policy/vscode_settings/vscode_settings.mdc)
|
|
@@ -8,8 +8,6 @@ docgen:
|
|
|
8
8
|
score: 100
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## Огляд
|
|
12
|
-
|
|
13
11
|
Модуль виконує валідацію контенту, застосовуючи правила, визначені в конфігурації, що зчитується з meta.json. Він обробляє запити, пов'язані з JavaScript, та взаємодіє з MDC. При запуску як CLI, він ініціалізує та виконує повний цикл перевірки, надаючи фінальний звіт.
|
|
14
12
|
|
|
15
13
|
## Поведінка
|
package/rules/vue/docs/main.md
CHANGED
|
@@ -8,8 +8,6 @@ docgen:
|
|
|
8
8
|
score: 100
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## Огляд
|
|
12
|
-
|
|
13
11
|
Модуль виконує перевірку, застосовуючи політику та обробляючи логіку JavaScript. Він забезпечує повний запуск правила, завантажуючи конфігурації, такі як meta.json, застосовуючи білі списки та підбиваючи підсумки. При запуску як окрема утиліта командного рядка, виконується повний цикл перевірки через публічну функцію run. Модуль є Read-only і кешує дані у межах прогону.
|
|
14
12
|
|
|
15
13
|
## Поведінка
|
|
@@ -3,33 +3,28 @@ type: JS Module
|
|
|
3
3
|
title: packages.mjs
|
|
4
4
|
resource: npm/rules/vue/js/packages.mjs
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
7
|
-
|
|
6
|
+
crc: 8589151d
|
|
7
|
+
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
8
|
+
score: 100
|
|
8
9
|
---
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
Перевіряє, чи є пакет бібліотекою компонентів Vue шляхом перевірки `peerDependencies`.
|
|
11
|
+
## Огляд
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
Перевіряє залежності та конфігурацію vite.config одного Vue-пакета.
|
|
13
|
+
Модуль визначає, чи є пакет бібліотекою компонентів Vue, виходячи з даних у `package.json`, `jsconfig.json`, `package-lock.json`, `extensions.json`. Він також перевіряє відповідність усіх пакетів, що залежать від `vue`, критеріям, описаним у `vue.mdc`, і повертає код виходу.
|
|
15
14
|
|
|
16
15
|
## Поведінка
|
|
17
16
|
|
|
18
|
-
isVueComponentLibraryPkg
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
check
|
|
22
|
-
Перевіряє залежності та vite.config одного Vue-пакета
|
|
17
|
+
isVueComponentLibraryPkg визначає, чи є пакет бібліотекою компонентів Vue, перевіряючи наявність `vue` у `peerDependencies` його `package.json`.
|
|
18
|
+
check перевіряє відповідність проєкту правилам vue.mdc для всіх пакетів, що містять `vue` у `dependencies`, і повертає код виходу. При цьому ігноруються шляхи `.git` та `node_modules`.
|
|
23
19
|
|
|
24
20
|
## Публічний API
|
|
25
21
|
|
|
26
|
-
isVueComponentLibraryPkg —
|
|
27
|
-
passFn —
|
|
28
|
-
check — перевіряє, чи
|
|
22
|
+
isVueComponentLibraryPkg — визначає, чи є пакет бібліотекою компонентів Vue, щоб IDE коректно обробляла файли `.vue` та `vite-env.d.ts`.
|
|
23
|
+
passFn — підтверджує наявність файлу `jsconfig.json` у вказаній директорії.
|
|
24
|
+
check — перевіряє, чи відповідає проєкт вимогам vue.mdc, а саме: чи є `vue` у залежностях кореневого та всіх workspace-пакетів.
|
|
29
25
|
|
|
30
26
|
## Гарантії поведінки
|
|
31
27
|
|
|
32
|
-
- Read-only:
|
|
33
|
-
-
|
|
28
|
+
- Read-only: не виконує операцій запису (ФС/БД).
|
|
29
|
+
- Перехоплює помилки і не пропускає винятків назовні (fail-safe).
|
|
34
30
|
- Свідомо пропускає шляхи: `.git`, `node_modules`.
|
|
35
|
-
- Не звертається до мережі.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** @see ./docs/packages.md */
|
|
2
|
-
import { existsSync } from 'node:fs'
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
3
3
|
import { readFile } from 'node:fs/promises'
|
|
4
4
|
import { join, relative } from 'node:path'
|
|
5
5
|
|
|
@@ -500,6 +500,45 @@ async function checkVueVolarRecommendation(pass, fail, cwd) {
|
|
|
500
500
|
}
|
|
501
501
|
}
|
|
502
502
|
|
|
503
|
+
// Vitest-пакети мусять бути у кореневому devDependencies монорепо,
|
|
504
|
+
// бо npm-module правило забороняє devDeps у published Vue workspace.
|
|
505
|
+
const ROOT_VITEST_DEV_DEPS = ['vitest', '@vitest/coverage-v8', '@stryker-mutator/vitest-runner']
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* Перевіряє, що кореневий `package.json` монорепо містить vitest-залежності
|
|
509
|
+
* у `devDependencies`. Викликається тільки коли є Vue-пакети у воркспейсі.
|
|
510
|
+
* @param {string} cwd корінь репозиторію
|
|
511
|
+
* @param {(msg: string) => void} pass pass callback
|
|
512
|
+
* @param {(msg: string) => void} fail fail callback
|
|
513
|
+
* @returns {void}
|
|
514
|
+
*/
|
|
515
|
+
function checkRootVitestDevDeps(cwd, pass, fail) {
|
|
516
|
+
const rootPkgPath = join(cwd, 'package.json')
|
|
517
|
+
if (!existsSync(rootPkgPath)) {
|
|
518
|
+
fail('vue: кореневий package.json не знайдено — неможливо перевірити vitest devDependencies')
|
|
519
|
+
return
|
|
520
|
+
}
|
|
521
|
+
let rootPkg
|
|
522
|
+
try {
|
|
523
|
+
rootPkg = JSON.parse(readFileSync(rootPkgPath, 'utf8'))
|
|
524
|
+
} catch {
|
|
525
|
+
fail('vue: кореневий package.json не вдалося розпарсити — неможливо перевірити vitest devDependencies')
|
|
526
|
+
return
|
|
527
|
+
}
|
|
528
|
+
const devDeps =
|
|
529
|
+
rootPkg.devDependencies && typeof rootPkg.devDependencies === 'object' ? Object.keys(rootPkg.devDependencies) : []
|
|
530
|
+
const missing = ROOT_VITEST_DEV_DEPS.filter(p => !devDeps.includes(p))
|
|
531
|
+
if (missing.length === 0) {
|
|
532
|
+
pass(`vue: кореневий devDependencies містить ${ROOT_VITEST_DEV_DEPS.join(', ')} (vue.mdc testing)`)
|
|
533
|
+
} else {
|
|
534
|
+
for (const pkg of missing) {
|
|
535
|
+
fail(
|
|
536
|
+
`vue: кореневий devDependencies не містить '${pkg}' — перенеси з Vue workspace у корінь монорепо (vue.mdc testing)`
|
|
537
|
+
)
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
503
542
|
/**
|
|
504
543
|
* Перевіряє відповідність проєкту правилам vue.mdc (корінь і всі workspace-пакети з `vue` у dependencies).
|
|
505
544
|
* @param {string} [cwd] корінь репозиторію
|
|
@@ -519,6 +558,7 @@ export async function check(cwd = process.cwd()) {
|
|
|
519
558
|
}
|
|
520
559
|
|
|
521
560
|
await checkVueVolarRecommendation(pass, fail, cwd)
|
|
561
|
+
checkRootVitestDevDeps(cwd, pass, fail)
|
|
522
562
|
|
|
523
563
|
const ignorePaths = await loadCursorIgnorePaths(cwd)
|
|
524
564
|
for (const { rootDir, isComponentLibrary } of vueRoots) {
|
package/rules/vue/main.mdc
CHANGED
|
@@ -9,32 +9,10 @@ alwaysApply: false
|
|
|
9
9
|
|
|
10
10
|
Правило охоплює стандарти написання Vue 3 SFC з Composition API, конфігурацію Vite-проєкту, UI-бібліотеки, заборонені патерни та вимоги до тестування.
|
|
11
11
|
|
|
12
|
-
[vue-composition-api](./js/composition-api.mdc)
|
|
13
|
-
|
|
14
|
-
[vue-quasar-ui](./js/quasar-ui.mdc)
|
|
15
|
-
|
|
16
|
-
[vue-structure](./js/structure.mdc)
|
|
17
|
-
|
|
18
|
-
[vue-vite-config](./js/vite-config.mdc)
|
|
19
|
-
|
|
20
|
-
[vue-vite-env](./js/vite-env.mdc)
|
|
21
|
-
|
|
22
|
-
[vue-vue-imports](./js/vue-imports.mdc)
|
|
23
|
-
|
|
24
|
-
[vue-node-imports](./js/node-imports.mdc)
|
|
25
|
-
|
|
26
|
-
[vue-testing](./js/testing.mdc)
|
|
27
|
-
|
|
28
|
-
[vue-nheader-layout](./js/nheader-layout.mdc)
|
|
29
|
-
|
|
30
|
-
[vue-tfm-translations](./js/tfm-translations.mdc)
|
|
31
|
-
|
|
32
12
|
## Швидкий gate через conftest
|
|
33
13
|
|
|
34
14
|
Rego-перевірки (запускаються через `npx @nitra/cursor fix vue`):
|
|
35
15
|
|
|
36
|
-
[vue-package_json](./policy/package_json/package_json.mdc)
|
|
37
|
-
|
|
38
16
|
## Перевірка
|
|
39
17
|
|
|
40
18
|
`npx @nitra/cursor fix vue` — перевіряє залежності, `vite.config`, наявність **`src/vite-env.d.ts`** з `/// <reference types="vite/client" />` та **`jsconfig.json`** у корені Vue-пакета; обходить джерела Vue-пакета (`.vue`, `.ts`, `.js` тощо) на заборонені value-імпорти з модуля `vue` (дозволені лише type-only та side-effect `import 'vue'`) і додатково сканує `.vue` SFC на імпорти Node-нативних модулів (`node:*` префікс або bare-ім'я вбудованого модуля Node — `fs`, `path`, `timers/promises` тощо). Імпорти аналізуються через **oxc-parser** (`module.staticImports`); для `.vue` вміст `<script>` витягується з SFC, далі той самий парсер (логіка в `npm/rules/vue/js/packages/vue-forbidden-imports.mjs`).
|
|
@@ -8,8 +8,6 @@ docgen:
|
|
|
8
8
|
score: 100
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## Огляд
|
|
12
|
-
|
|
13
11
|
Модуль виконує перевірку, застосовуючи політики, визначені в meta.json. Він обробляє JS-запити та звертається до MDC-ресурсів. Модуль є Read-only, тобто не здійснює записів у файлову систему чи бази даних. При запуску як окрема утиліта командного рядка, він виконує правила, використовуючи публічну функцію run. Дані кешуються у межах одного прогону.
|
|
14
12
|
|
|
15
13
|
## Поведінка
|
|
@@ -8,8 +8,6 @@ docgen:
|
|
|
8
8
|
score: 90
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## Огляд
|
|
12
|
-
|
|
13
11
|
Автоматично визначає правила та скіли для конфігурації `.n-cursor.json`, скануючи мета-дані з `npm/rules/<id>/main.json` та аналізуючи структуру проєкту, зокрема `package.json`. Система виводить `AUTO_RULE_ORDER` (алфавітно) та `AUTO_RULE_DEPENDENCIES` для кожного правила. Для кожного правила обчислюється специфікація активації (`specMatches`), яка може бути безумовною (`always`), заснованою на шаблонах файлів (`glob`), або предикатною. Процес враховує винятки (`disable-rules`) та виконує транзитивне розгортання залежностей. Збираються контент-факти (GQL, bun-sql, hasura) для точного застосування правил. Також відбувається автоматичне виявлення скілів з `./auto-skills.mjs`, після чого всі виявлені правила та скіли зливаються у конфіг, враховуючи міграцію ID.
|
|
14
12
|
|
|
15
13
|
## Поведінка
|
|
@@ -8,8 +8,6 @@ docgen:
|
|
|
8
8
|
score: 100
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## Огляд
|
|
12
|
-
|
|
13
11
|
Визначає, які скіли мають автоматично активуватися, скануючи `npm/skills/` та аналізуючи `main.json` кожного скілу. Логіка активації базується на конфігурації скілу: скіл може активуватися завжди (`auto: "завжди"`), якщо всі перелічені правила виявлені (`auto: ["rule", …]`), або бути opt-in, якщо поле `auto` відсутнє у `main.json`. Це забезпечує, що визначення автоматичної активації скілів є детермінованим, оскільки `main.json` є джерелом правди. Результати сканування використовуються для встановлення `AUTO_SKILL_ORDER` та `AUTO_SKILL_RULE_DEPENDENCIES`, що впливає на роботу з `.n-cursor.json`.
|
|
14
12
|
|
|
15
13
|
## Поведінка
|
package/scripts/docs/hook.md
CHANGED
|
@@ -3,27 +3,28 @@ type: JS Module
|
|
|
3
3
|
title: hook.mjs
|
|
4
4
|
resource: npm/scripts/hook.mjs
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
7
|
-
model:
|
|
8
|
-
score:
|
|
6
|
+
crc: 602cd023
|
|
7
|
+
model: claude-sonnet-4-6
|
|
8
|
+
score: 100
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
Модуль є точкою входу для хуків Claude Code. Він зчитує контекст, отримуючи шлях до файлу з вхідного потоку або визначаючи його через Git. У режимі `--post-tool-use` шлях до файлу зчитується з JSON, що надходить у stdin. У режимі `--stop` визначається робоче дерево проти HEAD (`git diff HEAD` + untracked). Після зчитування контексту, він делегує виконання перевірки за допомогою `runLint`. Код виходу, отриманий від перевірки, перекодовується у відповідний протокол хука (1 $\rightarrow$ 2).
|
|
11
|
+
Точка входу для хуків Claude Code. У режимі `--post-tool-use` зчитує `file_path` зі stdin JSON (PostToolUse hook), запускає lint для цього файлу та перевіряє актуальність файлової документації (`doc-files`). У режимі `--stop` визначає змінені файли (`git diff HEAD` + untracked) і запускає lint по всьому робочому дереву. Повертає exit-код у hook-протоколі (ненуль → 2).
|
|
14
12
|
|
|
15
13
|
## Поведінка
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
`runHookCli` виконує відповідну логіку залежно від переданого режиму:
|
|
16
|
+
|
|
17
|
+
- **`--post-tool-use`**: читає stdin JSON → витягує `tool_input.file_path` → запускає `runLint` для цього файлу (read-only, усі per-file правила включно з `doc-files`) → повертає 2 при порушеннях.
|
|
18
|
+
- **`--stop`**: визначає всі змінені файли через `collectChangedFiles` → запускає `runLint` (read-only) → повертає 2 при порушеннях.
|
|
19
|
+
|
|
20
|
+
Якщо `file_path` відсутній у stdin або stdin порожній — завершується з кодом 0 (нема що перевіряти).
|
|
19
21
|
|
|
20
22
|
## Публічний API
|
|
21
23
|
|
|
22
|
-
extractFilePath — витягує
|
|
23
|
-
runHookCli —
|
|
24
|
+
- `extractFilePath(json)` — витягує `tool_input.file_path` зі stdin JSON Claude Code PostToolUse hook; повертає `null` якщо JSON відсутній або поле не знайдено.
|
|
25
|
+
- `runHookCli(argv)` — CLI-точка входу для `n-cursor hook`; повертає Promise<number> (0 — чисто, 1 — невідомий режим, 2 — є порушення).
|
|
24
26
|
|
|
25
27
|
## Гарантії поведінки
|
|
26
28
|
|
|
27
29
|
- Read-only: не виконує операцій запису (ФС/БД).
|
|
28
|
-
-
|
|
29
|
-
- За певних помилок повертає порожнє значення (напр. `null`) замість винятку.
|
|
30
|
+
- Не кидає винятків назовні: помилки stdin та parse-помилки повертають null/0.
|
|
@@ -8,8 +8,6 @@ docgen:
|
|
|
8
8
|
score: 100
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## Огляд
|
|
12
|
-
|
|
13
11
|
Цей модуль є PostToolUse hook, який виконує read-only детект конформності всіх активованих правил після кожного редагування файлу (`Edit` / `Write` / `MultiEdit`). Він отримує шлях до файлу з вхідного JSON. Якщо файл відсутній, модуль завершує роботу з кодом 0. Інакше, він запускає детект конформності по всіх правилах, не виконуючи жодних мутацій чи викликів LLM. Код виходу 1 інформує про наявність порушень конформності, хоча PostToolUse не блокує поточний обмін.
|
|
14
12
|
|
|
15
13
|
## Поведінка
|
|
@@ -3,13 +3,11 @@ type: JS Module
|
|
|
3
3
|
title: sync-claude-config.mjs
|
|
4
4
|
resource: npm/scripts/sync-claude-config.mjs
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
6
|
+
crc: 553933fa
|
|
7
7
|
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
8
8
|
score: 85
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## Огляд
|
|
12
|
-
|
|
13
11
|
Синхронізує конфігурацію Claude Code (`.claude/settings.json`, slash-команди з `commands/` темплейту, ADR Stop-hook) та Cursor hooks (`.cursor/hooks.json`) у поточний проєкт із темплейтів пакету `npm/.claude-template/`. Здійснює злиття конфігурацій: користувацькі поля зберігаються у `.claude/settings.json`, а дозволи (`permissions.allow`) зливаються через union. Керовані хуки, ідентифіковані командою-маркером `MANAGED_HOOK_COMMAND_MARKERS`, перезаписуються. Копіює ADR Stop-hook (`.claude/hooks/capture-decisions.sh`) та ADR normalize Stop-hook (`.claude/hooks/normalize-decisions.sh`) залежно від налаштувань у `.n-cursor.json`. Також зливає фрагмент `.gitignore` з канонічного шаблону, додаючи необхідні записи для ADR.
|
|
14
12
|
|
|
15
13
|
## Поведінка
|
|
@@ -8,8 +8,6 @@ docgen:
|
|
|
8
8
|
score: 100
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## Огляд
|
|
12
|
-
|
|
13
11
|
Копіює composite GitHub Action `setup-bun-deps` з каталогу `github-actions/setup-bun-deps/` у корені tarball пакету `@nitra/cursor` у цільовий репозиторій за шлях `.github/actions/setup-bun-deps/action.yml`. Це забезпечує можливість для workflow з правил `ga`, `js` або `text` викликати цей action для налаштування залежностей Bun одразу після виконання `actions/checkout@v6`.
|
|
14
12
|
|
|
15
13
|
## Поведінка
|
package/scripts/hook.mjs
CHANGED
|
@@ -58,15 +58,14 @@ export async function runHookCli(argv) {
|
|
|
58
58
|
return 1
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
let files
|
|
62
61
|
if (postToolUse) {
|
|
63
62
|
const fp = extractFilePath(await readStdin())
|
|
64
63
|
if (!fp) return 0
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
files = collectChangedFiles(cwd)
|
|
64
|
+
const code = await runLint({ files: [fp], readOnly: true, cwd })
|
|
65
|
+
return code !== 0 ? 2 : 0
|
|
68
66
|
}
|
|
69
67
|
|
|
68
|
+
const files = collectChangedFiles(cwd)
|
|
70
69
|
const code = await runLint({ files, readOnly: true, cwd })
|
|
71
70
|
return code !== 0 ? 2 : 0
|
|
72
71
|
}
|
|
@@ -8,8 +8,6 @@ docgen:
|
|
|
8
8
|
score: 100
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## Огляд
|
|
12
|
-
|
|
13
11
|
Визначає список файлів шаблонів, що знаходяться у каталогах `fix` та `policy`, які не є цільовими посиланнями у файлі `<id>.mdc` як markdown link targets. Це дозволяє ідентифікувати ресурси шаблонів, які не були згадані в контексті правила.
|
|
14
12
|
|
|
15
13
|
## Поведінка
|