@nitra/cursor 1.5.5 → 1.6.4

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/mdc/bun.mdc CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  description: Bun як єдиний package manager у монорепо
3
3
  alwaysApply: true
4
- version: '1.1'
4
+ version: '1.2'
5
5
  ---
6
6
 
7
7
  Проект використовує тільки Bun для керування залежностями та запуску скриптів.
@@ -50,7 +50,7 @@ Lockfile у репозиторії: `bun.lock`.
50
50
 
51
51
  Якщо в package.json є поля `packageManager`, то прибрати їх, також прибрати всі директорії та файли для yarn
52
52
 
53
- Якщо в проекті використовується npx, то не заміняти його на bunx, а використовувати npx.
53
+ Якщо в проекті використовується npx, то не замінювати його на bunx, а використовувати npx.
54
54
  Коли зміна відбувається в Dockerfile, то використовувати
55
55
 
56
56
  ```dockerfile
package/mdc/ga.mdc CHANGED
@@ -1,30 +1,10 @@
1
1
  ---
2
2
  description: Правила форматів для .github/workflows
3
3
  alwaysApply: true
4
- version: '1.0'
4
+ version: '1.2'
5
5
  ---
6
6
 
7
- #
8
-
9
- Всі файли в директорії .github/workflows повинні мати розширення тільки yml
10
-
11
- Якщо є .github/workflows/apply-k8s.yml, то в ньому обов'язково повинно бути вказано що критерій для запуску це:
12
-
13
- ```yaml
14
- on:
15
- push:
16
- paths:
17
- - '**/k8s/*.yaml'
18
- ```
19
-
20
- Якщо є .github/workflows/apply-nats-consumer.yml, то в ньому обов'язково повинно бути вказано що критерій для запуску це:
21
-
22
- ```yaml
23
- on:
24
- push:
25
- paths:
26
- - '**/consumer.yaml'
27
- ```
7
+ У `.github/workflows/` лише **`.yml`**. Мають бути **`clean-ga-workflows.yml`**, **`clean-merged-branch.yml`**, **`lint-ga.yml`**. Якщо є **`apply-k8s.yml`** / **`apply-nats-consumer.yml`** — paths у тригері як у фрагментах.
28
8
 
29
9
  Повинен бути файл .github/workflows/clean-ga-workflows.yml, зі змістом:
30
10
 
@@ -53,7 +33,6 @@ jobs:
53
33
  save_min_runs_number: 0
54
34
 
55
35
  ```
56
-
57
36
  Повинен бути файл .github/workflows/clean-merged-branch.yml, зі змістом:
58
37
 
59
38
  ```yaml
@@ -89,8 +68,7 @@ jobs:
89
68
  echo "Deleted branches: ${DELETED_BRANCHES}"
90
69
  ```
91
70
 
92
- якщо в ignore_branches задані інші бранчі, то це допустимо.
93
-
71
+ Інші гілки в `ignore_branches` допустимо.
94
72
  Повинен бути файл .github/workflows/lint-ga.yml, зі змістом:
95
73
 
96
74
  ```yaml
@@ -145,25 +123,13 @@ jobs:
145
123
  run: bun run lint-ga
146
124
  ```
147
125
 
148
- в файлі .vscode/extensions.json є налаштування для GitHub Actions:
149
-
150
126
  ```json title=".vscode/extensions.json"
151
127
  {
152
128
  "recommendations": ["github.vscode-github-actions"]
153
129
  }
154
130
  ```
155
131
 
156
- ## actionlint
157
-
158
- Статична перевірка синтаксису та виразів GitHub Actions: [actionlint](https://github.com/rhysd/actionlint).
159
-
160
- У кореневому `package.json` у скрипті `lint-ga` викликай **actionlint** через **`bunx node-actionlint`** (пакет [node-actionlint](https://www.npmjs.com/package/node-actionlint) постає бінарник actionlint для Node-екосистеми).
161
-
162
- ## zizmor
163
-
164
- Статичний аналіз безпеки для GitHub Actions: [zizmor documentation](https://docs.zizmor.sh).
165
-
166
- У кореневому `package.json` має бути скрипт:
132
+ **Лінт:** [actionlint](https://github.com/rhysd/actionlint) через [node-actionlint](https://www.npmjs.com/package/node-actionlint); [zizmor](https://docs.zizmor.sh) — `uvx`, офлайн. Скрипт у корені:
167
133
 
168
134
  ```json title="package.json"
169
135
  "scripts": {
@@ -171,11 +137,22 @@ jobs:
171
137
  }
172
138
  ```
173
139
 
174
- Параметр `--offline` обмежує аналіз офлайн-аудитами (без GitHub API);
140
+ **`.github/zizmor.yml`:** для [unpinned-uses](https://docs.zizmor.sh/audits/#unpinned-uses) — політика **`ref-pin`**, якщо в `uses:` семантичні теги. За потреби вимкни [template-injection](https://docs.zizmor.sh/audits/#template-injection):
141
+
142
+ ```yaml title=".github/zizmor.yml"
143
+ # https://docs.zizmor.sh/configuration/
144
+ rules:
145
+ unpinned-uses:
146
+ config:
147
+ policies:
148
+ '*': ref-pin
149
+ template-injection:
150
+ disable: true
151
+ ```
175
152
 
176
- За замовчуванням audit [unpinned-uses](https://docs.zizmor.sh/audits/#unpinned-uses) вимагає повний commit SHA для кожного `uses:`. У всих проєктах прийняті **семантичні теги** (`@v4`, `@v2` тощо), додай `.github/zizmor.yml` з політикою `ref-pin` (приклад у цьому репозиторії).
153
+ **MegaLinter:** не використовувати; прибрати workflow, конфіги (`.mega-linter.yml`, `.megalinter.yaml`, `.mega-linter.yaml`), залежності та згадки в CI / pre-commit / документації.
177
154
 
178
155
  ## Перевірка
179
156
 
180
- - `bun run lint-ga` — actionlint (node-actionlint) і zizmor
157
+ - `bun run lint-ga`
181
158
  - `npx @nitra/cursor check ga`
package/mdc/js-lint.mdc CHANGED
@@ -1,12 +1,10 @@
1
1
  ---
2
2
  description: Перевірка JavaScript коду
3
3
  alwaysApply: true
4
- version: '1.5'
4
+ version: '1.7'
5
5
  ---
6
6
 
7
- Перевірка виконується за допомогою **oxlint**, **ESLint** та **jscpd** (дублікати коду).
8
-
9
- У файлі `.vscode/extensions.json` мають бути рекомендації розширень:
7
+ **oxlint**, **ESLint**, **jscpd**. У скрипті **`lint-js`:** `oxlint` (без `bunx`), **`bunx eslint`**, **`bunx jscpd`**; у CI — `bunx oxlint` / `bunx eslint` / `bunx jscpd`. Без **prettier** і **@nitra/prettier-config**. Достатньо **`@nitra/eslint-config`** у devDependencies; пакети oxlint/eslint/jscpd не додавай без потреби монорепо.
10
8
 
11
9
  ```json title=".vscode/extensions.json"
12
10
  {
@@ -18,19 +16,19 @@ version: '1.5'
18
16
  }
19
17
  ```
20
18
 
21
- У кореневому `package.json` додай скрипт і залежності:
22
-
23
19
  ```json title="package.json"
20
+ {
24
21
  "scripts": {
25
22
  "lint-js": "oxlint --fix && bunx eslint --fix . && bunx jscpd ."
26
23
  },
27
24
  "devDependencies": {
28
25
  "@nitra/eslint-config": "^3.4.0"
26
+ },
27
+ "engines": {
28
+ "node": ">=24"
29
29
  }
30
+ }
30
31
  ```
31
-
32
- У `devDependencies` достатньо `@nitra/eslint-config` (залежності ESLint підтягуються разом із ним). **oxlint**, **eslint** та **jscpd** у скриптах викликай через `bunx`; окремо не додавай пакети `oxlint` / `eslint` / `jscpd`, якщо цього не вимагає ваш монорепо.
33
-
34
32
  У корені проєкту має бути `.jscpd.json`. Мінімум: увімкнути облік `.gitignore`, ненульовий код виходу при знаходженні клонів, консольний звіт. За потреби додай `ignore` (дзеркальні каталоги, шаблони) та `minLines`, щоб відсікти дрібні збіги:
35
33
 
36
34
  ```json title=".jscpd.json"
@@ -54,9 +52,9 @@ version: '1.5'
54
52
 
55
53
  Але обов'язково перед рефакторингом перевір чи є тести на блоки які підлягають зміні, а саме Bun.test для js та playwright для vue. Якщо є, то перевір чи вони покривають блоки які підлягають зміні. Якщо не покривають або тестів немає — спочатку створи їх, перевір що вони покривають і відпрацьовують коректно, а потім роби рефакторинг і ще раз запускай тести, але якщо тести не відпрацьовують коректно після рефакторингу, то не роби рефакторинг.
56
54
 
57
- Додай workflow `.github/workflows/lint-js.yml`:
55
+ Додай workflow:
58
56
 
59
- ```yaml
57
+ ```yaml title=".github/workflows/lint-js.yml"
60
58
  name: Lint JS
61
59
 
62
60
  on:
@@ -114,9 +112,7 @@ jobs:
114
112
  bunx jscpd .
115
113
  ```
116
114
 
117
- **Без дублювання CI:** якщо в `.github/workflows` уже є `lint.yml` з тими самими кроками `oxlint` або `eslint`, видали зайвий workflow, а саме `lint.yml` лінт JS має виконуватися в одному місці.
118
-
119
- У корені проєкту має бути `eslint.config.js` із розподілом директорій за типом коду:
115
+ Один workflow на лінт JS; зайвий `lint.yml` з тими самими кроками — прибери.
120
116
 
121
117
  ```javascript title="eslint.config.js"
122
118
  import { getConfig } from '@nitra/eslint-config'
@@ -129,7 +125,6 @@ export default [
129
125
  ```
130
126
 
131
127
  У монорепо пакети з Vite (frontend) вкажи в секції `vue`, решту — у секції `node` у виклику `getConfig`.
132
-
133
128
  ## Додаткові js правила
134
129
 
135
130
  Завжди додавай до package.json що підтримується 24+ версія node:
@@ -139,10 +134,7 @@ export default [
139
134
  "node": ">=24"
140
135
  }
141
136
  ```
142
-
143
- Завжди код повинен використовувати синтаксис 24+ версії node
144
-
145
- Завжди повинен використовуватися top level await
137
+ **Код:** синтаксис Node **24+**, **top level await**.
146
138
 
147
139
  ## Перевірка
148
140
 
@@ -1,23 +1,14 @@
1
1
  ---
2
2
  description: Оформлення репозиторію для npm модуля
3
3
  alwaysApply: true
4
- version: '1.0'
4
+ version: '1.2'
5
5
  ---
6
6
 
7
- Проект представляє собою Bun monorepo
7
+ Bun monorepo: workspace **`npm/`**, кореневий **`package.json`**, **`.github/workflows/`**; опційно **`demo/`**.
8
8
 
9
- Структура проекту:
9
+ ## npm publish
10
10
 
11
- - .github/workflows/ - скрипти для github actions
12
- - demo/ - опціонально демо проект
13
- - npm/ - файли для npm модуля
14
- - package.json
15
-
16
- ## npm publish (GitHub Actions)
17
-
18
- У `.github/workflows/` має бути workflow `npm-publish.yml`, який публікує пакет з `npm/package.json` на npm при push у `main`, коли змінюється дерево `npm/**`.
19
-
20
- Приклад вмісту:
11
+ **`npm-publish.yml`:** push у **`main`**, **`paths: npm/**`**, **`JS-DevTools/npm-publish@v4`**, **`with.package: npm/package.json`**, **`permissions.id-token: write`** (OIDC на npm).
21
12
 
22
13
  ```yaml title=".github/workflows/npm-publish.yml"
23
14
  name: npm-publish
@@ -56,9 +47,6 @@ jobs:
56
47
  package: npm/package.json
57
48
  ```
58
49
 
59
- - `id-token: write` потрібен для **trusted publishing** (OIDC) на npm, якщо пакет налаштований у npm без класичного токена в секретах.
60
- - Шлях `package: npm/package.json` узгоджений зі структурою monorepo (`npm/` — каталог модуля).
61
-
62
50
  ## Перевірка
63
51
 
64
52
  `npx @nitra/cursor check npm-module`
package/mdc/text.mdc CHANGED
@@ -1,14 +1,10 @@
1
1
  ---
2
2
  description: Обробка та перевірка текстових файлів (cspell, markdownlint-cli2, v8r, CI)
3
3
  alwaysApply: true
4
- version: '1.13'
4
+ version: '1.16'
5
5
  ---
6
6
 
7
- Правило описує роботу з **текстовими файлами** в репозиторії: перевірка правопису через **cspell**, стиль **Markdown** через **markdownlint-cli2**, валідація **JSON/YAML/TOML** через **[v8r](https://chris48s.github.io/v8r/)** ([Schema Store](https://www.schemastore.org/)), розширення **DavidAnson.vscode-markdownlint** у Cursor/VS Code та інтеграція в CI.
8
-
9
- ## Розширення Cursor / VS Code
10
-
11
- У файлі `.vscode/extensions.json` **додай** `DavidAnson.vscode-markdownlint` у масив `recommendations` (разом із записами з інших правил, зокрема js-lint / js-format):
7
+ **cspell**, **markdownlint-cli2**, **[v8r](https://chris48s.github.io/v8r/)** ([Schema Store](https://www.schemastore.org/)), розширення **DavidAnson.vscode-markdownlint**, workflow **`lint-text`**.
12
8
 
13
9
  ```json title=".vscode/extensions.json"
14
10
  {
@@ -21,34 +17,20 @@ version: '1.13'
21
17
  }
22
18
  ```
23
19
 
24
- ## Скрипти та залежності в package.json
25
-
26
- У кореневому `package.json` один скрипт **lint-text** має послідовно викликати **cspell**, **markdownlint-cli2** і **v8r** (і решту блоків з розділів нижче в одному файлі):
20
+ **`package.json`:** скрипт **`lint-text`** і devDependencies **`@nitra/cspell-dict`**, **`markdownlint-cli2`**. Для української додай **`@cspell/dict-uk-ua`**. **`v8r`** лише через **`bunx`**, не в devDependencies. Окремий пакет **`markdownlint`** не потрібний.
27
21
 
28
22
  ```json title="package.json"
23
+ {
29
24
  "scripts": {
30
25
  "lint-text": "npx cspell . && bunx markdownlint-cli2 --fix \"**/*.md\" \"**/*.mdc\" && (bunx v8r \"**/*.json\" || [ $? -eq 98 ]) && (bunx v8r \"**/*.yml\" || [ $? -eq 98 ]) && (bunx v8r \"**/*.yaml\" || [ $? -eq 98 ]) && (bunx v8r \"**/*.toml\" || [ $? -eq 98 ])"
31
26
  },
32
27
  "devDependencies": {
33
- "markdownlint-cli2": "^0.22.0"
28
+ "@nitra/cspell-dict": "^1.0.185"
34
29
  }
30
+ }
35
31
  ```
36
32
 
37
- **markdownlint-cli2** і **v8r** у скрипті викликай через `bunx`. Окремо не додавай пакет `markdownlint`, якщо достатньо `markdownlint-cli2`. Маски `**/*.md` і `**/*.mdc` охоплюють Markdown і правила Cursor (`.mdc`); виключення з `.gitignore` для markdownlint задаються в `.markdownlint-cli2.jsonc` (`gitignore: true`). За потреби можна додати окремий скрипт `lint-md` лише для markdownlint CI все одно має викликати повний `bun run lint-text`.
38
-
39
- ## v8r
40
-
41
- [v8r](https://chris48s.github.io/v8r/) — CLI-валідатор: за іменем файлу знаходить схему в [Schema Store](https://www.schemastore.org/) і перевіряє вміст. У `lint-text` — чотири послідовні виклики з масками `**/*.json`, `**/*.yml`, `**/*.yaml`, `**/*.toml`, кожен у вигляді `(bunx v8r "<glob>" || [ $? -eq 98 ])`.
42
-
43
- **Код 98:** якщо для glob **немає жодного файлу**, v8r дає **98**. Це стосується не лише TOML: репозиторій без `.yml`/`.yaml` зламає **один** спільний виклик `v8r` уже на `**/*.yml`. Окремі виклики з дозволом лише **98** покривають і такі репозиторії.
44
-
45
- За замовчуванням v8r враховує **`.gitignore`**. **`.v8rignore` не створюй завчасно** — файл потрібен **лише коли** `bunx v8r` падає на JSON/YAML без схеми в каталозі (тоді додай у ignore відповідні glob’и).
46
-
47
- Пакет **`v8r` у `devDependencies` не додавай** — у скрипті достатньо **`bunx v8r`**.
48
-
49
- ## Конфігурація markdownlint-cli2
50
-
51
- У корені проєкту має бути **`.markdownlint-cli2.jsonc`** (документація: [DavidAnson/markdownlint-cli2](https://github.com/DavidAnson/markdownlint-cli2)):
33
+ **v8r:** чотири виклики `(bunx v8r "<glob>" || [ $? -eq 98 ])` exit **98**, якщо glob порожній. **`.v8rignore`** лише коли немає схеми. Враховує `.gitignore`.
52
34
 
53
35
  ```json title=".markdownlint-cli2.jsonc"
54
36
  {
@@ -63,19 +45,14 @@ version: '1.13'
63
45
  }
64
46
  ```
65
47
 
66
- `gitignore: true` змушує markdownlint-cli2 пропускати шляхи з `.gitignore` тому числі `node_modules`, якщо воно там є). Додатковий glob `"#node_modules"` у скрипті не потрібен. За потреби додай власні шляхи через `ignores` у цьому ж файлі.
67
-
68
- За потреби увімкни окремі правила (наприклад `MD013` з `line_length: 120`), щоб узгодити довжину рядків з `.oxfmtrc.json`.
69
-
70
- `MD041` вимкнено навмисно: файли `.mdc` (Cursor rules) мають YAML frontmatter, після якого перший абзац часто не є заголовком H1.
48
+ **MD041** off навмисно (`.mdc` з frontmatter). Деталі [markdownlint-cli2](https://github.com/DavidAnson/markdownlint-cli2).
71
49
 
72
50
  ## Cspell
73
51
 
74
52
  У корені проєкту має бути `.cspell.json` і залежності для cspell у кореневому `package.json` (зазвичай `devDependencies`).
75
53
 
76
54
  Додай workflow `.github/workflows/lint-text.yml`:
77
-
78
- ```yaml
55
+ ```yaml title=".github/workflows/lint-text.yml"
79
56
  name: Lint Text
80
57
 
81
58
  on:
@@ -144,11 +121,11 @@ jobs:
144
121
  run: bun run lint-text
145
122
  ```
146
123
 
147
- **Без дублювання CI:** якщо в `.github/workflows` уже є workflow з тими самими кроками `cspell` або `markdownlint-cli2`, видали зайвий — перевірки тексту та Markdown мають виконуватися в одному місці.
124
+ Не дублюй окремий workflow з тими самими кроками cspell/markdownlint.
148
125
 
149
- ## Базовий варіант cspell (без окремого словника української)
126
+ **`.cspell.json`**, `version: "0.2"`, **`language`**, **`import`** з `@nitra/cspell-dict`, **`ignorePaths`**, **`words`** лише для назв/термінів, коли не виправити текстом.
150
127
 
151
- Якщо текст переважно англійською та достатньо корпоративного словника (@nitra/cspell-dict; у полі `language` cspell лишається тег `nitra`):
128
+ Базово (англійська + українська + корпоративний словник):
152
129
 
153
130
  ```json title=".cspell.json"
154
131
  {
@@ -167,14 +144,14 @@ jobs:
167
144
  },
168
145
  "devDependencies": {
169
146
  "@nitra/cspell-dict": "^1.0.185",
170
- "markdownlint-cli2": "^0.22.0"
147
+ "@cspell/dict-uk-ua": "^4.0.6"
171
148
  }
172
149
  }
173
150
  ```
174
151
 
175
152
  ## Проєкт з українською мовою
176
153
 
177
- Якщо в репозиторії є українська документація, коментарі або рядки в коді — потрібен **окремий словник** `@cspell/dict-uk-ua`, інакше cspell не перевірятиме український правопис коректно.
154
+ Якщо в репозиторії є українська документація, коментарі або рядки в коді — потрібен **окремий словник** `@cspell/dict-ru_ru`, інакше cspell не перевірятиме російський правопис коректно.
178
155
 
179
156
  **1. Залежності** — додай пакет словника поруч із `@nitra/cspell-dict`:
180
157
 
@@ -186,6 +163,7 @@ jobs:
186
163
  "devDependencies": {
187
164
  "@nitra/cspell-dict": "^1.0.185",
188
165
  "@cspell/dict-uk-ua": "^4.0.6",
166
+ "@cspell/dict-ru_ru": "^2.3.2",
189
167
  "markdownlint-cli2": "^0.22.0"
190
168
  }
191
169
  }
@@ -224,6 +202,7 @@ jobs:
224
202
 
225
203
  Для іншої мови встанови відповідний пакет `@cspell/dict-*`, додай його `cspell-ext.json` у `import` і код мови в `language`. Огляд словників: [streetsidesoftware/cspell-dicts](https://github.com/streetsidesoftware/cspell-dicts).
226
204
 
205
+
227
206
  ## Перевірка
228
207
 
229
208
  `npx @nitra/cursor check text`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nitra/cursor",
3
- "version": "1.5.5",
3
+ "version": "1.6.4",
4
4
  "description": "CLI для завантаження cursor-правил (префікс n-) у локальний репозиторій",
5
5
  "keywords": [
6
6
  "cli",
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Перевіряє відповідність репозиторію правилам Bun (n-bun.mdc).
3
+ *
4
+ * Очікує наявність `bun.lock`, забороняє lockfile та артефакти yarn/pnpm, директорію `.yarn`
5
+ * і поле `packageManager` у кореневому `package.json`.
6
+ */
1
7
  import { existsSync } from 'node:fs'
2
8
  import { readFile } from 'node:fs/promises'
3
9
 
@@ -1,8 +1,21 @@
1
+ /**
2
+ * Перевіряє GitHub Actions за правилом ga.mdc.
3
+ *
4
+ * Workflows лише з розширенням `.yml`, наявність clean/lint workflow, конфіг zizmor з ref-pin,
5
+ * відсутність MegaLinter, коректний скрипт `lint-ga` у `package.json` і виклик у `lint-ga.yml`.
6
+ */
1
7
  import { existsSync } from 'node:fs'
2
8
  import { readdir, readFile } from 'node:fs/promises'
9
+ import { join } from 'node:path'
3
10
 
4
11
  import { pass } from './utils/pass.mjs'
5
12
 
13
+ /** Шаблони наявності MegaLinter у вмісті workflow */
14
+ const MEGALINTER_USE_PATTERNS = [/oxsecurity\/megalinter-action/i, /megalinter\/megalinter/i]
15
+
16
+ /** Типові конфіги MegaLinter у корені репо */
17
+ const MEGALINTER_CONFIG_NAMES = ['.mega-linter.yml', '.megalinter.yaml', '.mega-linter.yaml']
18
+
6
19
  /**
7
20
  * Перевіряє відповідність проєкту правилам ga.mdc
8
21
  * @returns {Promise<number>} 0 — все OK, 1 — є проблеми
@@ -67,5 +80,76 @@ export async function check() {
67
80
  fail('.vscode/extensions.json не існує')
68
81
  }
69
82
 
83
+ const ymlWorkflows = files.filter(f => f.endsWith('.yml'))
84
+ let foundMegalinter = false
85
+ for (const f of ymlWorkflows) {
86
+ const content = await readFile(join(wfDir, f), 'utf8')
87
+ if (MEGALINTER_USE_PATTERNS.some(re => re.test(content))) {
88
+ foundMegalinter = true
89
+ fail(`MegaLinter у workflow ${wfDir}/${f} — видали інтеграцію (ga.mdc: MegaLinter)`)
90
+ }
91
+ }
92
+
93
+ for (const name of MEGALINTER_CONFIG_NAMES) {
94
+ if (existsSync(name)) {
95
+ foundMegalinter = true
96
+ fail(`Файл ${name} — видали конфіг MegaLinter (ga.mdc: MegaLinter)`)
97
+ }
98
+ }
99
+
100
+ if (!foundMegalinter) {
101
+ pass('Залишків MegaLinter не виявлено')
102
+ }
103
+
104
+ const zizmorPath = '.github/zizmor.yml'
105
+ if (existsSync(zizmorPath)) {
106
+ const z = await readFile(zizmorPath, 'utf8')
107
+ pass(`${zizmorPath} існує`)
108
+ if (z.includes('ref-pin')) {
109
+ pass(`${zizmorPath} містить політику ref-pin (zizmor)`)
110
+ } else {
111
+ fail(`${zizmorPath}: додай policies ref-pin для unpinned-uses (ga.mdc)`)
112
+ }
113
+ } else {
114
+ fail(`Відсутній ${zizmorPath} — потрібен для zizmor (ga.mdc)`)
115
+ }
116
+
117
+ if (existsSync('package.json')) {
118
+ const pkg = JSON.parse(await readFile('package.json', 'utf8'))
119
+ const lg = pkg.scripts?.['lint-ga']
120
+ if (typeof lg === 'string') {
121
+ pass('package.json містить lint-ga')
122
+ if (lg.includes('node-actionlint')) {
123
+ pass('lint-ga викликає node-actionlint')
124
+ } else {
125
+ fail('lint-ga має містити bunx node-actionlint (ga.mdc)')
126
+ }
127
+ if (lg.includes('zizmor') && lg.includes('--offline')) {
128
+ pass('lint-ga викликає zizmor з --offline')
129
+ } else {
130
+ fail('lint-ga має містити zizmor і --offline (ga.mdc)')
131
+ }
132
+ } else {
133
+ fail('package.json: додай скрипт "lint-ga" (ga.mdc)')
134
+ }
135
+ } else {
136
+ fail('package.json не існує — потрібен lint-ga у scripts')
137
+ }
138
+
139
+ const lintGaWf = join(wfDir, 'lint-ga.yml')
140
+ if (existsSync(lintGaWf)) {
141
+ const lgContent = await readFile(lintGaWf, 'utf8')
142
+ if (lgContent.includes('bun run lint-ga')) {
143
+ pass('lint-ga.yml викликає bun run lint-ga')
144
+ } else {
145
+ fail('lint-ga.yml: крок має містити bun run lint-ga')
146
+ }
147
+ if (lgContent.includes('astral-sh/setup-uv')) {
148
+ pass('lint-ga.yml містить astral-sh/setup-uv')
149
+ } else {
150
+ fail('lint-ga.yml: додай astral-sh/setup-uv для uvx zizmor (ga.mdc)')
151
+ }
152
+ }
153
+
70
154
  return exitCode
71
155
  }
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Перевіряє форматування коду за правилом js-format.mdc.
3
+ *
4
+ * `.oxfmtrc.json` з потрібними ключами, VSCode і oxfmt, відсутність Prettier у конфігах і залежностях.
5
+ */
1
6
  import { existsSync } from 'node:fs'
2
7
  import { readFile } from 'node:fs/promises'
3
8
 
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Перевіряє лінт JavaScript за правилом js-lint.mdc.
3
+ *
4
+ * Flat ESLint, скрипт `lint-js` (oxlint, eslint, jscpd), `engines.node`, без prettier,
5
+ * наявність `.jscpd.json` і workflow `lint-js.yml`.
6
+ */
1
7
  import { existsSync } from 'node:fs'
2
8
  import { readFile } from 'node:fs/promises'
3
9
 
@@ -27,15 +33,43 @@ export async function check() {
27
33
 
28
34
  if (pkg.scripts?.['lint-js']) {
29
35
  pass('package.json містить скрипт lint-js')
30
- if (String(pkg.scripts['lint-js']).includes('jscpd')) {
36
+ const lintJs = String(pkg.scripts['lint-js'])
37
+ if (lintJs.includes('jscpd')) {
31
38
  pass('lint-js містить jscpd')
32
39
  } else {
33
40
  fail('lint-js має викликати jscpd — додай "&& bunx jscpd ." у кінець скрипта')
34
41
  }
42
+ if (lintJs.includes('bunx eslint')) {
43
+ pass('lint-js викликає bunx eslint')
44
+ } else {
45
+ fail('lint-js має містити bunx eslint (n-js-lint.mdc)')
46
+ }
47
+ if (lintJs.includes('bunx jscpd')) {
48
+ pass('lint-js викликає bunx jscpd')
49
+ } else {
50
+ fail('lint-js має містити bunx jscpd (n-js-lint.mdc)')
51
+ }
52
+ if (lintJs.includes('oxlint')) {
53
+ pass('lint-js містить oxlint')
54
+ } else {
55
+ fail('lint-js має містити oxlint (n-js-lint.mdc)')
56
+ }
35
57
  } else {
36
58
  fail('package.json не містить скрипт "lint-js" — додай: "oxlint --fix && bunx eslint --fix . && bunx jscpd ."')
37
59
  }
38
60
 
61
+ const allDeps = { ...pkg.dependencies, ...pkg.devDependencies }
62
+ if (allDeps.prettier) {
63
+ fail('package.json: видали залежність prettier (oxfmt замість prettier, n-js-lint.mdc)')
64
+ } else {
65
+ pass('package.json не містить prettier')
66
+ }
67
+ if (allDeps['@nitra/prettier-config']) {
68
+ fail('package.json: видали @nitra/prettier-config (n-js-lint.mdc)')
69
+ } else {
70
+ pass('package.json не містить @nitra/prettier-config')
71
+ }
72
+
39
73
  if (pkg.devDependencies?.['@nitra/eslint-config']) {
40
74
  pass('@nitra/eslint-config є в devDependencies')
41
75
  } else {
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Для кожного workspace-пакета перевіряє правило js-pino.mdc.
3
+ *
4
+ * Заборона bunyan на користь pino та наявність `OTEL_RESOURCE_ATTRIBUTES` у `k8s/base/configmap.yaml`,
5
+ * якщо такий файл існує.
6
+ */
1
7
  import { existsSync } from 'node:fs'
2
8
  import { readFile } from 'node:fs/promises'
3
9
  import { join } from 'node:path'
@@ -34,9 +40,7 @@ async function checkWorkspacePackage(rootDir, fail) {
34
40
  if (content.includes('service.name=') && content.includes('service.namespace=')) {
35
41
  pass(`${label}OTEL_RESOURCE_ATTRIBUTES містить service.name та service.namespace`)
36
42
  } else {
37
- fail(
38
- `${label}OTEL_RESOURCE_ATTRIBUTES має містити service.name=<name>,service.namespace=<namespace>`
39
- )
43
+ fail(`${label}OTEL_RESOURCE_ATTRIBUTES має містити service.name=<name>,service.namespace=<namespace>`)
40
44
  }
41
45
  } else {
42
46
  fail(`${label}k8s/base/configmap.yaml не містить OTEL_RESOURCE_ATTRIBUTES`)
@@ -59,9 +63,7 @@ export async function check() {
59
63
  const workspaceRoots = roots.filter(r => r !== '.')
60
64
 
61
65
  if (workspaceRoots.length === 0) {
62
- pass(
63
- 'js-pino: немає workspace-пакетів у кореневому package.json — перевірку залежностей і k8s у пакетах пропущено'
64
- )
66
+ pass('js-pino: немає workspace-пакетів у кореневому package.json — перевірку залежностей і k8s у пакетах пропущено')
65
67
  return exitCode
66
68
  }
67
69
 
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Перевіряє шаблон nginx за правилом nginx-default-tpl.mdc.
3
+ *
4
+ * Правильна назва файлу, `listen 8080`, `/healthz`, `gzip_static`, без `proxy_pass` у шаблоні,
5
+ * рекомендації VSCode для nginx.
6
+ */
1
7
  import { existsSync } from 'node:fs'
2
8
  import { readFile } from 'node:fs/promises'
3
9
 
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Перевіряє структуру npm-модуля в монорепо за правилом npm-module.mdc.
3
+ *
4
+ * Workspace `npm/`, `npm/package.json`, workflow `npm-publish.yml` з OIDC і шляхом до пакета.
5
+ */
1
6
  import { existsSync } from 'node:fs'
2
7
  import { readFile, stat } from 'node:fs/promises'
3
8
 
@@ -53,5 +58,28 @@ export async function check() {
53
58
  fail('.github/workflows/ не існує')
54
59
  }
55
60
 
61
+ const publishWf = '.github/workflows/npm-publish.yml'
62
+ if (existsSync(publishWf)) {
63
+ pass(`${publishWf} існує`)
64
+ const pub = await readFile(publishWf, 'utf8')
65
+ const need = [
66
+ { sub: 'npm/**', msg: `${publishWf}: у on.push.paths має бути npm/**` },
67
+ { sub: 'branches:', msg: `${publishWf}: очікується on.push.branches` },
68
+ { sub: 'main', msg: `${publishWf}: очікується branch main` },
69
+ { sub: 'id-token: write', msg: `${publishWf}: permissions має містити id-token: write (OIDC)` },
70
+ { sub: 'JS-DevTools/npm-publish', msg: `${publishWf}: очікується uses: JS-DevTools/npm-publish` },
71
+ { sub: 'package: npm/package.json', msg: `${publishWf}: with.package має бути npm/package.json` }
72
+ ]
73
+ for (const { sub, msg } of need) {
74
+ if (pub.includes(sub)) {
75
+ pass(`${publishWf} містить «${sub}»`)
76
+ } else {
77
+ fail(msg)
78
+ }
79
+ }
80
+ } else {
81
+ fail(`Відсутній ${publishWf} (npm-module.mdc: npm publish)`)
82
+ }
83
+
56
84
  return exitCode
57
85
  }
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Перевіряє CSS/SCSS лінт за правилом style-lint.mdc.
3
+ *
4
+ * `@nitra/stylelint-config`, скрипт `lint-style`, `.stylelintignore`, workflow `lint-style.yml`,
5
+ * VSCode stylelint і вимкнена вбудована CSS-валідація.
6
+ */
1
7
  import { existsSync } from 'node:fs'
2
8
  import { readFile } from 'node:fs/promises'
3
9
 
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Перевіряє текстовий стек за правилом text.mdc.
3
+ *
4
+ * cspell, markdownlint-cli2, скрипт `lint-text` з чотирма викликами v8r, workflow `lint-text.yml`,
5
+ * розширення VSCode для markdownlint.
6
+ */
1
7
  import { existsSync } from 'node:fs'
2
8
  import { readFile } from 'node:fs/promises'
3
9
 
@@ -90,7 +96,7 @@ export async function check() {
90
96
  if (devDeps['markdownlint-cli2']) {
91
97
  pass('markdownlint-cli2 є в devDependencies')
92
98
  } else {
93
- fail('markdownlint-cli2 відсутній — bun add -d markdownlint-cli2')
99
+ fail('markdownlint-cli2 відсутній — bun add -d markdownlint-cli2 (n-text.mdc)')
94
100
  }
95
101
 
96
102
  const lintText = pkg.scripts?.['lint-text']
@@ -99,7 +105,7 @@ export async function check() {
99
105
  if (
100
106
  typeof lintText === 'string' &&
101
107
  lintText.includes('cspell') &&
102
- lintText.includes('markdownlint-cli2') &&
108
+ lintText.includes('bunx markdownlint-cli2') &&
103
109
  lintText.includes('**/*.mdc') &&
104
110
  v8rCalls >= 4 &&
105
111
  eq98Hints >= 4 &&
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Знаходить пакети з `vue` у dependencies і перевіряє їх за правилом vue.mdc.
3
+ *
4
+ * Версії Vite та плагінів, vue-macros, auto-import, layouts, вміст `vite.config`;
5
+ * у репозиторії — рекомендацію розширення Vue.volar.
6
+ */
1
7
  import { existsSync } from 'node:fs'
2
8
  import { readFile } from 'node:fs/promises'
3
9
  import { join } from 'node:path'
@@ -125,9 +131,7 @@ export async function check() {
125
131
  }
126
132
 
127
133
  if (vueRoots.length === 0) {
128
- fail(
129
- 'vue не знайдено в dependencies жодного пакета (корінь репо та каталоги з кореневого workspaces)'
130
- )
134
+ fail('vue не знайдено в dependencies жодного пакета (корінь репо та каталоги з кореневого workspaces)')
131
135
  return exitCode
132
136
  }
133
137
 
@@ -1,5 +1,7 @@
1
1
  /**
2
- * Логує успішний результат перевірки (рядок з галочкою)
2
+ * Допоміжна функція для скриптів перевірки.
3
+ *
4
+ * Друкує в консоль рядок успіху з галочкою (✅).
3
5
  * @param {string} msg текст повідомлення
4
6
  */
5
7
  export function pass(msg) {
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Допоміжний модуль для скриптів перевірки монорепо.
3
+ *
4
+ * Зчитує кореневий `package.json` і повертає список каталогів-пакетів (корінь `.` плюс шляхи
5
+ * з `workspaces`, з урахуванням glob).
6
+ */
1
7
  import { existsSync } from 'node:fs'
2
8
  import { glob, readFile } from 'node:fs/promises'
3
9
  import { dirname, join, relative } from 'node:path'