@nitra/cursor 1.29.5 → 1.32.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/CHANGELOG.md CHANGED
@@ -4,6 +4,46 @@
4
4
 
5
5
  Формат — [Keep a Changelog](https://keepachangelog.com/uk/1.1.0/), нумерація — [SemVer](https://semver.org/lang/uk/).
6
6
 
7
+ ## [1.32.0] - 2026-05-30
8
+
9
+ ### Added
10
+
11
+ - **`rules/ci4/js/marksman_config.mjs`** + **`rules/ci4/js/data/marksman_config/marksman.baseline.toml`** — новий JS-концерн `marksman_config` за зразком `test.stryker_config`: при `npx @nitra/cursor fix ci4` копіює canonical `.marksman.toml` baseline у корінь cwd, якщо файлу ще немає. Idempotent через паттерн `ensureBaselineFile` (existsSync → pass+skip vs copyFile → pass+create) — ручні правки користувача між прогонами зберігаються, повторний прогон не перетирає. Baseline містить три ключові опції: `[core] markdown.glfm = true` (GLFM-фічі portable subset — alerts/таблиці/todo), `[completion] wiki.style = "file-stem"` (ADR slug == ім'я файла; стабільний ідентифікатор у AUTOGEN `sources`/manifest/валідаторі — заголовок міняється, посилання не ламається), `[code_action] toc.enable = true` (Insert/Update TOC code action для довгих arc42-сторінок). Дефолти marksman (`title-slug-ref` + вимкнений GLFM) ламали б частину задокументованої навігації. Розміщення в `cwd` (корені репо) робить весь монорепо одним marksman-workspace — README.md і docs/ перехресно навігуються. Тести: `+4` сценарії у `rules/ci4/js/tests/marksman_config.test.mjs` через `withTmpDir` (порожній cwd → файл створюється; idempotency — кастомний контент не перетирається; валідні TOML-секції `[core]`/`[completion]`/`[code_action]`; exit 0 у обох сценаріях). 4/4 PASS через `bunx vitest run rules/ci4/js/tests/marksman_config.test.mjs`.
12
+
13
+ ### Changed
14
+
15
+ - **`rules/ci4/ci4.mdc`** (`version` 3.1 → 3.2) — у секцію «Viewer/editor: Zed + marksman LSP» додано параграф про авто-створення `.marksman.toml` правилом ci4 з посиланням на canonical baseline і поясненням кожної з трьох ключових опцій (glfm/wiki.style/toc.enable). У frontmatter `description` додано пункт про `.marksman.toml`. Дзеркало `.cursor/rules/n-ci4.mdc` синхронізується наступним прогоном `npx @nitra/cursor`.
16
+
17
+ ## [1.31.0] - 2026-05-30
18
+
19
+ ### Added
20
+
21
+ - **`rules/ci4/policy/vscode_extensions/`** — нова policy за зразком text/style-lint/rego/ga/js-lint/graphql/nginx-default-tpl/rust/tauri: `vscode_extensions.rego` (deny якщо рекомендація з template-snippet відсутня в `.vscode/extensions.json`) + `vscode_extensions_test.rego` (5 сценаріїв: canonical, missing marksman, empty recommendations, extra recommendations пропускаються, drift-test що канон керується через `data.template`) + `template/extensions.json.snippet.json` (`{"recommendations": ["arr.marksman"]}`) + `target.json` (single `.vscode/extensions.json`). Призначення — контрибʼютори, що працюють у VSCode/Cursor замість Zed, отримують той самий шар marksman-навігації (cmd+click по `[link](file.md)`/`[[wiki-link]]`, find-references, refactor-перейменування заголовків) через офіційне розширення marksman LSP. Дзеркальна правка у репо: `.vscode/extensions.json` отримав `arr.marksman` у `recommendations`. Тести: 5/5 PASS через `opa test npm/rules/ci4/policy/vscode_extensions/`.
22
+
23
+ ### Changed
24
+
25
+ - **`rules/ci4/ci4.mdc`** (`version` 3.0 → 3.1) — у секцію «Viewer/editor: Zed + marksman LSP» додано підсекцію **«VSCode-альтернатива»** з канонічним JSON-блоком `.vscode/extensions.json` (`recommendations: ["arr.marksman"]`) і посиланням на snippet-файл policy (за стилем `text.mdc`); також згадка про marksman-сумісні редактори (Neovim, Helix, Emacs). У frontmatter `description` додано пункт про VSCode-розширення. Дзеркало `.cursor/rules/n-ci4.mdc` синхронізується наступним прогоном `npx @nitra/cursor`.
26
+
27
+ ### Fixed
28
+
29
+ - **`vitest.config.js`** — git-залежні тести (`rules/changelog/check.test.mjs`, `rules/ga/workflows.test.mjs`) масово таймаутили локально (`23 failed | 13 passed`, 187s; усі фейли — `Test timed out in 5000ms`, не assertion), хоча в CI зелені. Першопричина: глобальний `~/.gitconfig` тестової машини має `trace2.eventtarget=af_unix:stream:~/.git-ai/.../trace2.sock` (tooling `git-ai`), який успадковується tmp-репо в тестах → кожна git-команда під'єднується до Unix-сокета даемона; коли даемон деградований, запис у сокет блокується (~1s/команда не на CPU), а під `pool: 'forks'` десятки паралельних git-операцій × латентність > 5000ms `testTimeout`. Фікс: `env: { GIT_TRACE2_EVENT: '0' }` прибирає trace2-залежність із гарячого шляху тестового git (root-cause), плюс `testTimeout: 20000` як defence-in-depth проти будь-якої залишкової локальної I/O-латентності. Після фіксу `bun run vitest run rules/changelog/` → `36 passed` за ~7s (відтворювано); повний suite — `1248 passed | 2 skipped`. CI не зачеплено (там немає trace2-таргета).
30
+
31
+ ## [1.30.1] - 2026-05-29
32
+
33
+ ### Added
34
+
35
+ - **`rules/test/coverage/tests/coverage.test.mjs`** — три нові тести `/n-coverage-fix`-ітерації, що вбивають усі чотири вцілілі мутанти на `rules/test/coverage/coverage.mjs`. (1) `opts.fix=false → fixSurvivedMutants НЕ викликається` і (2) `opts.fix=true → fixSurvivedMutants викликається` фіксують умовну гілку `if (opts.fix)` (L189) через лог `'✓ Всі мутанти вбиті — доповнення тестів не потрібне'`, який друкує `fixSurvivedMutants` для порожнього `survived[]`. (3) `source 2-ї стрілки містить fix:false` перевіряє джерело захопленої callback-стрілки 2-го `withLock` через `Function.prototype.toString()`: токени `fix` і `false` мають бути присутні, а `fix: true` — заборонений; це поведінково невловимо (`{}` і `{ fix: false }` дають однаковий falsy `opts.fix`), тому інваріант на рівні джерела.
36
+
37
+ ### Fixed
38
+
39
+ - **`CHANGELOG.md`** — заголовок секції `[1.30.0]` піднято з `#` на `##` (Keep a Changelog vN.M.M вимагає H2 для версій). Чек `npm-module.mdc` зчитував h1 як «без версії», знаходив `[1.29.5]` першою і скаржився на розбіжність із `package.json#version "1.30.0"`.
40
+
41
+ ## [1.30.0] - 2026-05-29
42
+
43
+ ### Changed
44
+
45
+ - **`rules/ci4/ci4.mdc`** (`version` 2.1 → 3.0) — viewer-story повністю переписано під **Zed + marksman LSP без site-generator-а**. MkDocs Material і pymdownx-розширення (`!!! note`, `??? engineer`, `=== "tab"`, кастомні audience-CSS) прибрані як рекомендація: їх не рендерить вбудований MD-preview Zed, що ламає принцип «відкрив файл = бачу фінальний вигляд». Collapsible-блоки для змішаної аудиторії — через нативний HTML5 `<details>` / `<summary>`, що рендериться скрізь (Zed preview, GitHub, будь-який майбутній збирач) без розширень парсера. Введено **portable-only subset**: CommonMark + GFM + Mermaid у fenced code + KaTeX + `<details>`; заборонені VitePress containers (`::: tip`), MDX/Astro-компоненти, Hugo shortcodes, AsciiDoc-вкраплення, RST-директиви. Конвенція маркера у `<summary>`: перше слово — аудиторія з фіксованого словника (`Engineer:`/`Ops:`/`Security:`/`Manager:`) → детермінований regex для валідатора. Валідатор отримав чотири нові перевірки: жоден `Engineer:`/`Ops:`/`Security:` блок у manager-only проекціях; кожен `<details>` має оточуючі порожні рядки (інакше `<summary>` рендериться як plain HTML); у `docs/` немає заборонених framework-specific конструкцій; inter-doc посилання працюють для marksman LSP (відносні шляхи або wiki-links). Промпт-скелет LLM-проекцій оновлено — генератор видає `<details>`, не `???`, і дотримується списку заборонених синтаксисів. Subset **forward-compatible**: будь-який збирач (MkDocs, VitePress, Antora) підключається пізніше без переписування контенту. Дзеркало `.cursor/rules/n-ci4.mdc` синхронізується наступним прогоном `npx @nitra/cursor`.
46
+
7
47
  ## [1.29.5] - 2026-05-29
8
48
 
9
49
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nitra/cursor",
3
- "version": "1.29.5",
3
+ "version": "1.32.0",
4
4
  "description": "CLI для завантаження cursor-правил (префікс n-) у локальний репозиторій",
5
5
  "keywords": [
6
6
  "cli",
package/rules/ci4/ci4.mdc CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- description: Архітектурна документація продукту — Markdown як джерело істини; рекомендований стек arc42 + Diátaxis + ADR (MADR v4, формат описаний у правилі `adr`) + C4 як набір нотацій; гібридна модель manual + autogen-зон, що регенеруються з accepted ADR; MkDocs Material як viewer з collapsible engineer-блоками для змішаної аудиторії
2
+ description: Архітектурна документація продукту — Markdown як джерело істини; рекомендований стек arc42 + Diátaxis + ADR (MADR v4, формат описаний у правилі `adr`) + C4 як набір нотацій; гібридна модель manual + autogen-зон, що регенеруються з accepted ADR; Zed + marksman LSP як viewer без site-generator-а, portable subset (CommonMark + GFM + Mermaid + KaTeX), collapsible engineer-блоки через нативний `<details>`; рекомендоване VSCode-розширення `arr.marksman` для контрибʼюторів поза Zed; `.marksman.toml` авто-створюється у корені проєкту з canonical baseline
3
3
  alwaysApply: true
4
- version: '2.1'
4
+ version: '3.2'
5
5
  ---
6
6
 
7
7
  Архітектурна документація проєкту живе у Markdown поряд із кодом. Це не довідник «для людей із порталу архітектора» — це **джерело істини**, з якого LLM-агент і людина читають намір системи перед будь-якою зміною коду. Тому правила нижче — не оформлення, а робочий процес: який стек використовуємо, як зберігаємо рішення, як автоматично перегенеровуємо проекції з ADR і як рендеримо для змішаної аудиторії (менеджери + інженери + ops).
@@ -47,7 +47,7 @@ RAG витягує **фрагменти**, не цілі документи. Т
47
47
 
48
48
  Доповнюємо **під domain**:
49
49
 
50
- - **DDD Context Maps** — коли є >1 bounded context (типово для multi-agent: agents, orchestration, memory, tooling). Одна Mermaid-діаграма в `explanation/architecture.md`, ховається під `??? engineer`.
50
+ - **DDD Context Maps** — коли є >1 bounded context (типово для multi-agent: agents, orchestration, memory, tooling). Одна Mermaid-діаграма в `explanation/architecture.md`, ховається під `<details><summary><strong>Engineer:</strong> Context Map</summary>`.
51
51
  - **EventModeling** — для event-driven систем (агентські pipeline, CQRS, Event Sourcing). Структура: trigger → command → event → read model. Читається менеджером як наратив, інженером — як креслення.
52
52
  - **Business Capability Map** — верхньорівневий manager-overview. Autogen через семантичну класифікацію accepted ADR за тематикою.
53
53
  - **Wardley Map** — стратегічний артефакт для board/інвесторів. Manual, не autogen. Квартальне оновлення. Живе в `explanation/strategy.md`.
@@ -108,7 +108,7 @@ docs/
108
108
 
109
109
  ## Гібрид manual + autogen
110
110
 
111
- Реальні проєкти мають legacy docs, написані до появи ADR. Розв'язок — **зони** через HTML-коментарі (виживають у Markdown, не рендеряться у MkDocs):
111
+ Реальні проєкти мають legacy docs, написані до появи ADR. Розв'язок — **зони** через HTML-коментарі (виживають у Markdown, не рендеряться у жодному MD viewer — ні в Zed built-in preview, ні на GitHub, ні в будь-якому майбутньому site-generator-і):
112
112
 
113
113
  ```markdown
114
114
  # User Service
@@ -191,61 +191,80 @@ User Service відповідає за автентифікацію та про
191
191
  - **Incremental**: LLM отримує поточний doc + новий ADR (або `## Update`) — видає diff. Дешевше, але дрейф накопичується.
192
192
  - **Компроміс**: incremental + періодичний full rebuild (раз на місяць або після N нових ADR).
193
193
 
194
- ## MkDocs Material: collapsible engineer-блоки
194
+ ## Viewer/editor: Zed + marksman LSP
195
195
 
196
- Менеджер читає прозу зверху, інженер клікає `??? engineer` і провалюється глибше. Один документ дві аудиторії без дублювання.
196
+ Окремого site-generator-а **немає** каталог `docs/` сам є інтерфейсом читання. Інженер відкриває `.md`-файл у Zed і одразу бачить рендер через built-in preview (`cmd+shift+m`). Між сторінками рухається через **`marksman`** LSP: `cmd+click` по `[link](file.md)` і `[[wiki-link]]`, автокомпліт заголовків, find-references, refactor-перейменування заголовків з оновленням посилань у всьому `docs/`.
197
197
 
198
- `mkdocs.yml`:
198
+ `~/.config/zed/settings.json`:
199
199
 
200
- ```yaml
201
- theme:
202
- name: material
203
- features:
204
- - content.code.copy
205
- - navigation.tabs
200
+ ```json
201
+ {
202
+ "languages": {
203
+ "Markdown": {
204
+ "language_servers": ["marksman"],
205
+ "soft_wrap": "editor_width"
206
+ }
207
+ }
208
+ }
209
+ ```
210
+
211
+ **`.marksman.toml`** у корені проєкту авто-створюється правилом ci4 при першому `npx @nitra/cursor fix ci4` із canonical baseline ([data/marksman_config/marksman.baseline.toml](./js/data/marksman_config/marksman.baseline.toml)). Ключові опції — `markdown.glfm = true` (потрібен для GFM-alerts/таблиць/todo з portable subset), `[completion] wiki.style = "file-stem"` (ADR slug == ім'я файла, стабільний ідентифікатор у AUTOGEN `sources`/manifest/валідаторі — заголовок змінюється, посилання не ламається), `[code_action] toc.enable = true` (TOC code action для довгих arc42-сторінок). Без явного конфіга marksman використовує `title-slug-ref` і вимкнений GLFM — частина задокументованої навігації працювала б інакше. Ручні правки конфіга не перетираються — `ensureBaselineFile` ідемпотентний.
206
212
 
207
- markdown_extensions:
208
- - admonition
209
- - pymdownx.details
210
- - pymdownx.superfences
211
- - pymdownx.tabbed: { alternate_style: true }
212
- - attr_list
213
+ **VSCode-альтернатива.** Контрибʼютори, що працюють у VSCode/Cursor замість Zed, отримують той самий шар навігації через офіційне розширення marksman LSP. Канонічний запис у `.vscode/extensions.json`:
213
214
 
214
- extra_css:
215
- - stylesheets/audience.css
215
+ ```json title=".vscode/extensions.json"
216
+ {
217
+ "recommendations": ["arr.marksman"]
218
+ }
216
219
  ```
217
220
 
218
- Синтаксис у документах:
221
+ Канон `recommendations` (substring requirement): [extensions.json.snippet.json](./policy/vscode_extensions/template/extensions.json.snippet.json). Інші marksman-сумісні редактори (Neovim, Helix, Emacs) налаштовують `marksman` як LSP-сервер за документацією свого редактора — поведінка ідентична (cmd+click по `[link](file.md)`/`[[wiki-link]]`, find-references, refactor-перейменування).
222
+
223
+ **Portable-only синтаксис.** Усе, що пишемо в `docs/`, обмежене **CommonMark + GFM + Mermaid у fenced code (` ```mermaid `) + KaTeX (`$...$`) + нативний HTML5 `<details>`**. Заборонено:
224
+
225
+ - pymdownx admonitions (`!!! note`, `??? engineer`, `=== "tab"`)
226
+ - VitePress containers (`::: tip`, `::: details`)
227
+ - MDX/Astro-компоненти (`<MyComponent />`)
228
+ - Hugo shortcodes (`{{< youtube id >}}`)
229
+ - AsciiDoc-вкраплення, RST-директиви
230
+
231
+ Усе вище не рендериться у Zed built-in preview і ламає головний принцип: **«відкрив файл = побачив фінальний вигляд»**. Обмеження **forward-compatible**: portable subset рендериться у GitHub, MkDocs, VitePress, Antora — підключення збирача в майбутньому не потребує переписування контенту.
232
+
233
+ ## Collapsible-блоки для змішаної аудиторії
234
+
235
+ Менеджер читає прозу зверху, інженер розгортає деталі. Реалізація — нативний HTML5 `<details>` / `<summary>`, що рендериться **скрізь**: Zed preview, GitHub, будь-який майбутній збирач. Жодних розширень парсера не треба.
219
236
 
220
237
  ```markdown
221
238
  User Service автентифікує користувачів і керує профілями.
222
239
  Підтримуємо OIDC-логін та email/password.
223
240
 
224
- ??? engineer "Технічна реалізація автентифікації"
225
- OIDC-сервер на Fastify з PKCE flow [oidc-pkce-flow].
226
- Refresh-токени з rotation, TTL 30 днів, Redis storage.
241
+ <details>
242
+ <summary><strong>Engineer:</strong> Технічна реалізація автентифікації</summary>
243
+
244
+ OIDC-сервер на Fastify з PKCE flow [oidc-pkce-flow].
245
+ Refresh-токени з rotation, TTL 30 днів, Redis storage.
246
+
247
+ </details>
227
248
 
228
249
  Профілі зберігаються в основній БД, кешуються в Redis на 5 хв.
229
250
 
230
- ??? ops "Деталі кешу та інвалідації"
231
- Cache key: `user:profile:{userId}:v2`.
232
- Інвалідація — NATS подія `user.profile.updated` [user-profile-events].
251
+ <details>
252
+ <summary><strong>Ops:</strong> Деталі кешу та інвалідації</summary>
253
+
254
+ Cache key: `user:profile:{userId}:v2`.
255
+ Інвалідація — NATS подія `user.profile.updated` [user-profile-events].
256
+
257
+ </details>
233
258
  ```
234
259
 
235
- `???` = згорнуто за замовчуванням, `???+` = розгорнуто.
260
+ **Конвенція маркера у `<summary>`:** перше слово аудиторія з фіксованого словника (`Engineer:`, `Ops:`, `Security:`, `Manager:`), далі — описова назва. Це дає валідатору детермінований regex для перевірок типу «жоден `Engineer:`-блок не з'являється в manager-only проекціях».
236
261
 
237
- Кастомні audience-styles у `docs/stylesheets/audience.css`:
262
+ **Технічні нюанси `<details>`:**
238
263
 
239
- ```css
240
- .md-typeset details.engineer > summary {
241
- background-color: rgba(84, 110, 122, 0.1);
242
- border-color: #546e7a;
243
- }
244
- .md-typeset details.ops > summary {
245
- background-color: rgba(255, 152, 0, 0.1);
246
- border-color: #ff9800;
247
- }
248
- ```
264
+ - порожній рядок до `<details>` і після `<summary>` обов'язковий — інакше Markdown-парсер не активує блочний рендер усередині
265
+ - за замовчуванням блок згорнутий; `<details open>` розгорнутий
266
+ - візуальна типізація аудиторій робиться **через текст `<summary>`**, не через CSS — у Zed preview кастомні стилі недоступні
267
+ - `<details>` ≠ HTML-обгортка з правила «жодних `<div>`/`<span>`»: це **семантичний** HTML5-елемент, а не презентаційний; його token-cost мізерний
249
268
 
250
269
  ## Промпт для LLM-проекцій
251
270
 
@@ -259,21 +278,35 @@ User Service автентифікує користувачів і керує п
259
278
  як пов'язано з іншими частинами продукту. Без технологій, версій, коду.
260
279
 
261
280
  2. Технічні деталі — тільки всередині блоків:
262
- ??? engineer "Описова назва блоку"
263
- Код, конфіги, версії, посилання на ADR.
281
+ <details>
282
+ <summary><strong>Engineer:</strong> Описова назва блоку</summary>
283
+
284
+ Код, конфіги, версії, посилання на ADR.
285
+
286
+ </details>
264
287
 
265
288
  3. Operational деталі:
266
- ??? ops "Що моніторити та як реагувати"
289
+ <details>
290
+ <summary><strong>Ops:</strong> Що моніторити та як реагувати</summary>
291
+
292
+ Метрики, алерти, runbook-кроки.
293
+
294
+ </details>
267
295
 
268
296
  Правила:
269
- - Якщо прибрати всі ??? блоки, текст лишається зв'язним менеджерським документом.
270
- - Кожен факт з ADR маркуй [<slug>] всередині engineer-блоку slug це ім'я clean ADR
297
+ - Якщо прибрати всі <details>-блоки, текст лишається зв'язним менеджерським документом.
298
+ - Перше слово у <summary> — аудиторія з фіксованого словника
299
+ (Engineer:/Ops:/Security:/Manager:), далі — описова назва
300
+ (наприклад «<strong>Engineer:</strong> Чому Percona, а не MariaDB»).
301
+ - Порожній рядок до і після вмісту <details> обов'язковий.
302
+ - Кожен факт з ADR маркуй [<slug>] всередині <details>-блоку — slug це ім'я clean ADR
271
303
  без розширення (наприклад `[ланцюжок-запуску-abie]`).
272
- - Назви блоків — описові («Чому Percona, а не MariaDB»).
273
304
  - НЕ виходь за межі <!-- AUTOGEN:start --> ... <!-- AUTOGEN:end -->.
274
305
  - ADR без рядка `**Status:** Accepted` ігноруй.
275
306
  - Якщо в ADR є `## Update YYYY-MM-DD` секції — враховуй найсвіжіший стан рішення,
276
307
  старі формулювання вважай застарілими.
308
+ - Заборонені framework-specific synaxes: !!! note, ??? engineer, ::: tip,
309
+ MDX-компоненти, Hugo shortcodes — тільки CommonMark + GFM + Mermaid + <details>.
277
310
  ```
278
311
 
279
312
  ## Типові поломки LLM і захист
@@ -293,7 +326,10 @@ User Service автентифікує користувачів і керує п
293
326
  - Усі `[<slug>]` посилання вказують на існуючі файли `docs/adr/<slug>.md` із рядком `**Status:** Accepted`
294
327
  - Усі `AUTOGEN:start` мають парний `AUTOGEN:end` з тим самим `id`
295
328
  - Hash у `manifest.json` відповідає фактичному контенту зон
296
- - Жоден `??? engineer` блок не з'являється в manager-only проекціях
329
+ - Жоден `<details>`-блок з `<summary>` що починається на `Engineer:` / `Ops:` / `Security:` не з'являється в manager-only проекціях
330
+ - Кожен `<details>` має оточуючі порожні рядки (інакше `<summary>`-вміст рендериться як plain HTML, не collapsible)
331
+ - У `docs/` немає заборонених framework-specific конструкцій: `!!! note`, `??? `, `::: tip`, `::: details`, MDX-теги `<[A-Z][a-zA-Z]*`, Hugo shortcodes `{{< `
332
+ - Усі inter-doc посилання працюють для `marksman` LSP (відносні шляхи `[text](./other.md)` або `[[wiki-link]]`, не absolute URLs усередині `docs/`)
297
333
  - Якщо в зоні згадано компонент — він є в `docs/glossary.md`
298
334
  - ADR без `**Status:** Accepted` не потрапили у проекцію
299
335
 
@@ -317,7 +353,7 @@ ADR (`docs/adr/<slug>.md`) — джерело правди для autogen-про
317
353
 
318
354
  ## Зв'язок із документацією
319
355
 
320
- Архітектурні артефакти — частина **користувацької документації**, а не закритий артефакт для команди. Контекстна діаграма (C4 рівень 1) і контейнерна (рівень 2) живуть там, де читач шукає вступ у проєкт — у `explanation/architecture.md`, не у відокремленій теці «for-architects». MkDocs Material рендерить це з collapsible-блоками, тому менеджер бачить прозу, інженер провалюється в деталі.
356
+ Архітектурні артефакти — частина **користувацької документації**, а не закритий артефакт для команди. Контекстна діаграма (C4 рівень 1) і контейнерна (рівень 2) живуть там, де читач шукає вступ у проєкт — у `explanation/architecture.md`, не у відокремленій теці «for-architects». Нативний `<details>`-блок дає collapsible-вигляд у будь-якому MD-viewer (Zed built-in preview, GitHub web UI, потенційний майбутній site-generator) без залежності від конкретного фреймворку — менеджер бачить прозу, інженер розгортає деталі.
321
357
 
322
358
  ## Зв'язок із `.cursor/rules`
323
359
 
@@ -330,8 +366,11 @@ ADR (`docs/adr/<slug>.md`) — джерело правди для autogen-про
330
366
  - **Claude Code** як runner — slash-команда `/regen-docs` або post-commit hook на зміни `docs/adr/**`
331
367
  - **capture-decisions.sh** + **normalize-decisions.sh** — Stop-hooks створення ADR (керує правило `adr`)
332
368
  - **gray-matter** на Bun — лише для парсингу draft frontmatter; clean ADR парситься regexp по `**Status:**` / `**Date:**`
333
- - **MkDocs + Material** як viewer
334
- - **Mermaid** для C4-діаграм, EventModeling, Context Maps у проекціях
369
+ - **Zed** як viewer/editor — built-in MD preview (`cmd+shift+m`) рендерить кожен файл без site-generator-а; `<details>` для collapsible-блоків
370
+ - **marksman** LSP як шар навігації `cmd+click` по `[text](file.md)`/`[[wiki-link]]`, find-references, refactor-перейменування заголовків
371
+ - **Mermaid** для C4-діаграм, EventModeling, Context Maps — рендериться у Zed preview напряму з ` ```mermaid ` fenced code, без розширень
372
+ - **KaTeX** (опційно) — інлайн-математика `$...$` для метрик/формул; рендериться у Zed preview
373
+ - Site-generator (MkDocs Material / VitePress / Antora) — **не використовується**; portable subset гарантує, що його можна підключити пізніше без переписування контенту
335
374
 
336
375
  ## Query mode як бонус
337
376
 
@@ -0,0 +1,27 @@
1
+ # Workspace-маркер marksman LSP. У корені репо робить весь монорепо одним
2
+ # marksman-workspace — README.md і docs/ перехресно навігуються через
3
+ # [text](file.md) і [[wiki-link]]. Файли .mdc не індексуються — marksman
4
+ # дивиться лише на розширення нижче.
5
+ #
6
+ # Створюється правилом ci4 (npx @nitra/cursor fix ci4) із canonical baseline.
7
+ # Ручні правки не перетираються: повторні прогони ідемпотентні (no-op).
8
+
9
+ [core]
10
+ markdown.file_extensions = ["md", "markdown"]
11
+
12
+ # GitHub-Flavored Markdown (таблиці, todo, alerts, math) — наш portable subset.
13
+ markdown.glfm = true
14
+
15
+ [completion]
16
+ # Стиль резолву [[wiki-link]]:
17
+ # "file-stem" → [[oidc-pkce-flow]] резолвиться у docs/adr/oidc-pkce-flow.md
18
+ # "title-slug-ref" → резолв за slugified H1 заголовком
19
+ # Беремо file-stem: ADR-slug == ім'я файла, стабільний ідентифікатор у
20
+ # AUTOGEN sources, manifest, валідаторі. Заголовок може мінятися — посилання
21
+ # не ламається.
22
+ wiki.style = "file-stem"
23
+
24
+ [code_action]
25
+ # Code action "Insert/Update TOC" — корисно для довгих arc42-сторінок
26
+ # (architecture.md з 12 розділами).
27
+ toc.enable = true
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Концерн `marksman_config` правила ci4 (ci4.mdc): копіює canonical
3
+ * `.marksman.toml` baseline у корінь cwd, якщо файлу ще немає.
4
+ *
5
+ * Marksman LSP читає `.marksman.toml` для визначення workspace-роота,
6
+ * GLFM-флага (GitHub-Flavored Markdown), стилю wiki-links і code actions.
7
+ * Дефолти marksman не вмикають GLFM і використовують `title-slug-ref` —
8
+ * але portable subset з ci4.mdc вимагає GLFM (alerts/таблиці/todo) +
9
+ * `file-stem` (ADR slug == ім'я файла). Без явного конфіга частина
10
+ * marksman-функцій працює інакше, ніж задокументовано у правилі.
11
+ *
12
+ * Idempotent: якщо `.marksman.toml` вже існує (навіть з кастомним вмістом)
13
+ * — не перетирається, тільки рапортується факт існування. Ручні правки
14
+ * користувача зберігаються між прогонами.
15
+ *
16
+ * Файл скопійовано в `cwd`, бо marksman визначає workspace-root за
17
+ * розташуванням свого `.marksman.toml`. У корені репо марксман бачить
18
+ * і docs/, і README.md усіх workspaces одним workspace-ом.
19
+ */
20
+ import { existsSync } from 'node:fs'
21
+ import { copyFile } from 'node:fs/promises'
22
+ import { dirname, join, relative } from 'node:path'
23
+ import { fileURLToPath } from 'node:url'
24
+
25
+ import { createCheckReporter } from '../../../scripts/lib/check-reporter.mjs'
26
+
27
+ const HERE = dirname(fileURLToPath(import.meta.url))
28
+ const MARKSMAN_BASELINE_PATH = join(HERE, 'data', 'marksman_config', 'marksman.baseline.toml')
29
+ const MARKSMAN_TARGET_FILENAME = '.marksman.toml'
30
+
31
+ /**
32
+ * @param {string} [cwd] корінь проєкту (default: `process.cwd()` — CLI-сумісність)
33
+ * @returns {Promise<number>} 0 — OK (створено або вже існує), 1 — baseline-файл пакета зламаний
34
+ */
35
+ export async function check(cwd = process.cwd()) {
36
+ const reporter = createCheckReporter()
37
+
38
+ if (!existsSync(MARKSMAN_BASELINE_PATH)) {
39
+ reporter.fail(`canonical baseline не знайдено (${MARKSMAN_BASELINE_PATH}) — перевстанови @nitra/cursor`)
40
+ return reporter.getExitCode()
41
+ }
42
+
43
+ const target = join(cwd, MARKSMAN_TARGET_FILENAME)
44
+ if (existsSync(target)) {
45
+ reporter.pass(`${MARKSMAN_TARGET_FILENAME} існує (${relative(cwd, target)})`)
46
+ return reporter.getExitCode()
47
+ }
48
+
49
+ await copyFile(MARKSMAN_BASELINE_PATH, target)
50
+ reporter.pass(`${MARKSMAN_TARGET_FILENAME} створено з canonical baseline (${relative(cwd, target)}) (ci4.mdc)`)
51
+ return reporter.getExitCode()
52
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": ".vscode/extensions.json" }
4
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "recommendations": ["arr.marksman"]
3
+ }
@@ -0,0 +1,12 @@
1
+ # Перевірка `.vscode/extensions.json` для ci4 (ci4.mdc).
2
+ #
3
+ # Канон надходить через --data: { "template": { "snippet": ... } }
4
+ package ci4.vscode_extensions
5
+
6
+ import rego.v1
7
+
8
+ deny contains msg if {
9
+ some rec in data.template.snippet.recommendations
10
+ not rec in {r | some r in object.get(input, "recommendations", [])}
11
+ msg := sprintf(".vscode/extensions.json: recommendations має містити %q (ci4.mdc)", [rec])
12
+ }