@nitra/cursor 5.3.3 → 5.4.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.
Files changed (157) hide show
  1. package/.claude-template/settings.template.json +2 -2
  2. package/.pi-template/extensions/n-cursor-adr/docs/index.md +13 -24
  3. package/CHANGELOG.md +17 -0
  4. package/bin/n-cursor.js +43 -22
  5. package/lib/docs/llm.md +23 -12
  6. package/lib/docs/models.md +29 -18
  7. package/lib/docs/omlx-trace.md +51 -0
  8. package/lib/docs/omlx.md +31 -15
  9. package/lib/omlx.mjs +2 -5
  10. package/package.json +1 -1
  11. package/rules/abie/docs/fix.md +17 -11
  12. package/rules/adr/docs/fix.md +25 -140
  13. package/rules/bun/docs/fix.md +18 -151
  14. package/rules/capacitor/docs/fix.md +16 -13
  15. package/rules/capacitor/js/docs/platforms.md +31 -43
  16. package/rules/changelog/docs/fix.md +25 -169
  17. package/rules/ci4/docs/fix.md +11 -14
  18. package/rules/doc-files/doc-files.mdc +60 -0
  19. package/rules/doc-files/docs/fix.md +31 -0
  20. package/rules/doc-files/fix.mjs +19 -0
  21. package/{skills → rules}/doc-files/js/docgen-extract.mjs +42 -19
  22. package/{skills → rules}/doc-files/js/docgen-ignore.mjs +2 -1
  23. package/{skills → rules}/doc-files/js/docgen-scan.mjs +9 -1
  24. package/{skills → rules}/doc-files/js/docs/docgen-crc.md +1 -1
  25. package/rules/doc-files/js/docs/docgen-extract-anchors.md +45 -0
  26. package/rules/doc-files/js/docs/docgen-extract.md +39 -0
  27. package/rules/doc-files/js/docs/docgen-files-batch.md +35 -0
  28. package/rules/doc-files/js/docs/docgen-gen.md +46 -0
  29. package/rules/doc-files/js/docs/docgen-ignore.md +37 -0
  30. package/rules/doc-files/js/docs/docgen-prompts.md +39 -0
  31. package/rules/doc-files/js/docs/docgen-scan.md +54 -0
  32. package/rules/doc-files/js/docs/lint.md +36 -0
  33. package/rules/doc-files/js/docs/units-js.md +31 -0
  34. package/rules/doc-files/js/docs/units-rs.md +35 -0
  35. package/rules/doc-files/js/docs/units.md +30 -0
  36. package/rules/doc-files/js/lint.mjs +96 -0
  37. package/{skills → rules}/doc-files/js/units-rs.mjs +37 -17
  38. package/rules/doc-files/lint/docs/lint.md +37 -0
  39. package/rules/doc-files/lint/lint.mjs +105 -0
  40. package/rules/doc-files/meta.json +1 -0
  41. package/rules/docker/docs/fix.md +21 -161
  42. package/rules/efes/docs/fix.md +23 -194
  43. package/rules/feedback/docs/fix.md +10 -8
  44. package/rules/ga/docs/fix.md +10 -5
  45. package/rules/graphql/docs/fix.md +23 -119
  46. package/rules/hasura/docs/fix.md +19 -5
  47. package/rules/hasura/js/docs/internal_urls.md +34 -307
  48. package/rules/image-avif/docs/fix.md +16 -127
  49. package/rules/image-compress/docs/fix.md +20 -141
  50. package/rules/image-compress/js/docs/package_setup.md +22 -182
  51. package/rules/js-bun-db/docs/fix.md +23 -139
  52. package/rules/js-bun-db/js/docs/safety.md +33 -221
  53. package/rules/js-bun-redis/docs/fix.md +25 -114
  54. package/rules/js-bun-redis/js/docs/imports.md +18 -166
  55. package/rules/js-lint/docs/fix.md +30 -108
  56. package/rules/js-lint/js/docs/lint-findings.md +37 -17
  57. package/rules/js-lint/js/docs/lint.md +22 -238
  58. package/rules/js-lint/js/docs/tooling.md +34 -331
  59. package/rules/js-lint-ci/docs/fix.md +16 -149
  60. package/rules/js-lint-ci/js/docs/lint.md +16 -136
  61. package/rules/js-mssql/docs/fix.md +18 -123
  62. package/rules/js-mssql/js/docs/deps.md +28 -251
  63. package/rules/js-run/docs/fix.md +23 -138
  64. package/rules/js-run/js/docs/runtime.md +24 -378
  65. package/rules/k8s/docs/fix.md +18 -123
  66. package/rules/nginx-default-tpl/docs/fix.md +22 -118
  67. package/rules/nginx-default-tpl/js/docs/template.md +38 -360
  68. package/rules/npm-module/docs/fix.md +27 -89
  69. package/rules/npm-module/js/docs/header_doc_pointer.md +15 -15
  70. package/rules/npm-module/js/docs/package_structure.md +36 -258
  71. package/rules/npm-module/js/docs/rule_meta.md +25 -127
  72. package/rules/npm-module/js/docs/skill_meta.md +18 -180
  73. package/rules/php/docs/fix.md +21 -98
  74. package/rules/php/js/docs/tooling.md +20 -143
  75. package/rules/python/docs/fix.md +25 -157
  76. package/rules/python/js/docs/applies.md +20 -98
  77. package/rules/python/js/docs/tooling.md +27 -144
  78. package/rules/rego/docs/fix.md +24 -112
  79. package/rules/rego/js/docs/applies.md +20 -164
  80. package/rules/rego/js/docs/lint.md +15 -110
  81. package/rules/release/docs/fix.md +16 -114
  82. package/rules/rust/docs/fix.md +24 -119
  83. package/rules/rust/js/docs/applies.md +20 -129
  84. package/rules/security/docs/fix.md +21 -78
  85. package/rules/security/js/docs/sample_secret.md +23 -182
  86. package/rules/security/js/docs/trufflehog.md +19 -128
  87. package/rules/style-lint/docs/fix.md +16 -150
  88. package/rules/style-lint/js/docs/lint.md +21 -172
  89. package/rules/style-lint/js/docs/tooling.md +19 -184
  90. package/rules/tauri/docs/fix.md +26 -152
  91. package/rules/tauri/js/docs/cargo_mutants_config.md +21 -159
  92. package/rules/tauri/js/docs/tooling.md +20 -217
  93. package/rules/test/docs/fix.md +19 -127
  94. package/rules/test/js/data/stryker_config/docs/stryker.config.baseline.md +15 -127
  95. package/rules/test/js/data/stryker_config/docs/stryker.config.vue.baseline.md +17 -153
  96. package/rules/test/js/docs/cargo_mutants_config.md +24 -164
  97. package/rules/test/js/docs/location.md +24 -126
  98. package/rules/test/js/docs/no-process-chdir.md +20 -151
  99. package/rules/test/js/docs/no-relative-fs-path.md +24 -261
  100. package/rules/test/js/docs/stryker_config.md +48 -148
  101. package/rules/test/js/docs/vitest-config-pool-forks.md +21 -164
  102. package/rules/text/docs/fix.md +25 -113
  103. package/rules/text/js/docs/forbidden-prettier.md +21 -132
  104. package/rules/text/js/docs/formatting.md +60 -251
  105. package/rules/text/js/docs/lint.md +17 -114
  106. package/rules/vue/docs/fix.md +25 -118
  107. package/rules/vue/js/docs/packages.md +25 -323
  108. package/rules/worktree/docs/fix.md +31 -150
  109. package/scripts/coverage-classify/docs/index.md +23 -209
  110. package/scripts/coverage-classify/docs/verdict-schema.md +14 -159
  111. package/scripts/dispatcher/docs/trace.md +35 -0
  112. package/scripts/docs/auto-rules.md +37 -361
  113. package/scripts/docs/lint-cli.md +12 -13
  114. package/scripts/docs/post-tool-use-fix.md +16 -15
  115. package/scripts/docs/skills-cli.md +26 -23
  116. package/scripts/docs/sync-claude-config.md +94 -34
  117. package/scripts/docs/worktree-cli.md +11 -34
  118. package/scripts/lib/docs/assert-project-root.md +14 -16
  119. package/scripts/lib/docs/changed-files.md +24 -139
  120. package/scripts/lib/docs/discover-check-rules-from-cursor.md +14 -146
  121. package/scripts/lib/docs/rule-predicates.md +20 -17
  122. package/scripts/lib/docs/run-rule-cli.md +14 -18
  123. package/scripts/lib/docs/run-rule.md +13 -20
  124. package/scripts/lib/docs/run-standard-rule.md +12 -15
  125. package/scripts/lib/docs/sync-gitignore-worktree.md +15 -18
  126. package/scripts/lib/rule-predicates.mjs +1 -1
  127. package/scripts/sync-claude-config.mjs +4 -1
  128. package/scripts/utils/docs/with-lock.md +19 -12
  129. package/scripts/utils/with-lock.mjs +4 -2
  130. package/skills/doc-aggregate/SKILL.md +2 -2
  131. package/skills/doc-aggregate/js/docgen-ignore.mjs +6 -6
  132. package/skills/doc-aggregate/js/docs/docgen-ignore.md +1 -1
  133. package/skills/doc-aggregate/js/docs/docgen-scan.md +78 -0
  134. package/skills/doc-files/.changes/260612-0012.md +5 -0
  135. package/skills/doc-files/.changes/260612-0031.md +5 -0
  136. package/skills/doc-files/.changes/260612-0036.md +5 -0
  137. package/skills/doc-files/.changes/260612-0114.md +5 -0
  138. package/skills/doc-files/SKILL.md +6 -6
  139. package/skills/fix/js/docs/llm-worker.md +17 -15
  140. package/skills/fix/js/docs/orchestrator.md +30 -23
  141. package/skills/fix/js/docs/t0.md +26 -16
  142. package/skills/start-check/js/docs/check.md +26 -22
  143. package/skills/taze/js/docs/diff.md +44 -20
  144. package/skills/doc-files/js/docs/docgen-extract-anchors.md +0 -27
  145. package/skills/doc-files/js/docs/docgen-extract.md +0 -29
  146. package/skills/doc-files/js/docs/docgen-files-batch.md +0 -25
  147. package/skills/doc-files/js/docs/docgen-gen.md +0 -30
  148. package/skills/doc-files/js/docs/docgen-prompts.md +0 -32
  149. package/skills/doc-files/js/docs/docgen-scan.md +0 -25
  150. package/skills/doc-files/js/docs/units-rs.md +0 -35
  151. /package/{skills → rules}/doc-files/js/docgen-crc.mjs +0 -0
  152. /package/{skills → rules}/doc-files/js/docgen-extract-anchors.mjs +0 -0
  153. /package/{skills → rules}/doc-files/js/docgen-files-batch.mjs +0 -0
  154. /package/{skills → rules}/doc-files/js/docgen-gen.mjs +0 -0
  155. /package/{skills → rules}/doc-files/js/docgen-prompts.mjs +0 -0
  156. /package/{skills → rules}/doc-files/js/units-js.mjs +0 -0
  157. /package/{skills → rules}/doc-files/js/units.mjs +0 -0
@@ -0,0 +1,35 @@
1
+ ---
2
+ docgen:
3
+ source: npm/rules/doc-files/js/docgen-files-batch.mjs
4
+ crc: 5c9b8d72
5
+ score: 95
6
+ ---
7
+
8
+ # docgen-files-batch.mjs
9
+
10
+ ## Огляд
11
+
12
+ runDocFilesGenCli
13
+ Запускає генерацію документації для застарілих або відсутніх файлів.
14
+
15
+ runDocFilesStampCli
16
+ Перештампує frontmatter джерело та CRC у наявних документах без виклику LLM.
17
+
18
+ ## Поведінка
19
+
20
+ runDocFilesGenCli
21
+ Запускає генерацію документації для застарілих/відсутніх док.
22
+
23
+ runDocFilesStampCli
24
+ Перештампує frontmatter source+crc у наявних доках без виклику LLM.
25
+
26
+ ## Публічний API
27
+
28
+ - runDocFilesGenCli — згенерувати документацію для застарілих/відсутніх док.
29
+ - runDocFilesStampCli — детерміновано (пере)штампувати frontmatter `source`+`crc` у наявних доках без виклику LLM. Для міграції док, які ще не мають CRC. Поля якості (`score`/`issues`) зберігаються з наявного frontmatter.
30
+
31
+ ## Гарантії поведінки
32
+
33
+ - Перехоплює помилки і не пропускає винятків назовні (fail-safe).
34
+ - За невдачі повертає значення помилки (`false`/`null`/`Err`) замість генерування винятку чи паніки.
35
+ - Не звертається до мережі.
@@ -0,0 +1,46 @@
1
+ ---
2
+ docgen:
3
+ source: npm/rules/doc-files/js/docgen-gen.mjs
4
+ crc: e2af04d6
5
+ score: 100
6
+ ---
7
+
8
+ # docgen-gen.mjs
9
+
10
+ ## Огляд
11
+
12
+ Огляд
13
+ Публічні функції виконують операції з текстом та оцінками. Вони включають виділення коду, вставлення інформації та генерацію документів на основі визначених параметрів.
14
+
15
+ ## Поведінка
16
+
17
+ splitProtected
18
+ Вибирає та видаляє код-фенс-обгортку з секції
19
+
20
+ insertProtected
21
+ Вставляє захищений блок Призначення після заголовка Огляд
22
+
23
+ scoreDoc
24
+ Перевіряє вихід проти фактів і повертає оцінку та список проблем
25
+
26
+ DEFAULT_LOCAL_MODEL
27
+ Повертає дефолтну модель для роботи
28
+
29
+ generateDoc
30
+ Генерує документ з детермінованою оцінкою та метаданими
31
+
32
+ ## Публічний API
33
+
34
+ splitProtected — Відокремлює захищену секцію `## Призначення` (Варіант B). Межа — наступний `## ` і `###` не обриває блок. (abie.mdc)
35
+ insertProtected — Вставляє захищений блок `## Призначення` одразу після H1 (фіксована позиція). (abie.mdc)
36
+ scoreDoc — Stage 2.5 — Детермінований скоринг (0 токенів): перевіряє вихід проти фактів. (abie.mdc)
37
+ DEFAULT_LOCAL_MODEL — Дефолтна модель: N_CURSOR_DOCGEN_MODEL → resolveModel → omlx напряму. Останній fallback гарантує локальний виклик без змін середовища (через pi CLI той самий локальний виклик виміряно повільніший на ~46%). (abie.mdc)
38
+ generateDoc — Головний API: файл → md-дока з det-оцінкою. (abie.mdc)
39
+
40
+ ## Гарантії поведінки
41
+
42
+ - Read-only: файл не виконує операцій запису у файлову систему.
43
+ - Перехоплює помилки і не пропускає винятків назовні (fail-safe).
44
+ - За невдачі повертає значення помилки (`false`/`null`/`Err`) замість генерування винятку чи паніки.
45
+ - Кешує результати в межах одного прогону.
46
+ - Не звертається до мережі.
@@ -0,0 +1,37 @@
1
+ ---
2
+ docgen:
3
+ source: npm/rules/doc-files/js/docgen-ignore.mjs
4
+ crc: c17cd785
5
+ score: 100
6
+ ---
7
+
8
+ # docgen-ignore.mjs
9
+
10
+ ## Огляд
11
+
12
+ DOCGEN_IGNORE_GLOBS
13
+ Список шляхів, які docgen повинен ігнорувати.
14
+
15
+ isDocgenIgnored
16
+ Перевіряє, чи шлях знаходиться у списку ігнорованих шляхів.
17
+
18
+ ## Поведінка
19
+
20
+ DOCGEN_IGNORE_GLOBS
21
+ Базовий список glob-ів для docgen ignore
22
+
23
+ isDocgenIgnored
24
+ Перевіряє, чи шлях має бути пропущений docgen
25
+
26
+ ## Публічний API
27
+
28
+ DOCGEN_IGNORE_GLOBS — Список glob-ів для ігнорування у `docgen`.
29
+ isDocgenIgnored — Визначає, чи шлях повинен бути пропущений `docgen`. Для `kind = 'dir'` працює і на підкаталоги, наприклад, `**\\/demo/**` спрацьовує на `demo/x` під час рекурсивного обходу.
30
+
31
+ ## Гарантії поведінки
32
+
33
+ - Read-only: файл не виконує операцій запису у файлову систему.
34
+ - За невдачі повертає значення помилки (`false`/`null`/`Err`) замість генерування винятку чи паніки.
35
+ - Кешує результати в межах одного прогону.
36
+ - Свідомо пропускає шляхи: `.git`, `node_modules`.
37
+ - Не звертається до мережі.
@@ -0,0 +1,39 @@
1
+ ---
2
+ docgen:
3
+ source: npm/rules/doc-files/js/docgen-prompts.mjs
4
+ crc: 72ac304f
5
+ score: 100
6
+ ---
7
+
8
+ # docgen-prompts.mjs
9
+
10
+ ## Огляд
11
+
12
+ Файл надає інструкції для створення лаконічної поведінкової документації українською мовою. Він містить інструменти для формування, перевірки та виправлення тексту документації, а також для визначення гарантій щодо роботи файлу
13
+
14
+ ## Поведінка
15
+
16
+ Поведінка:
17
+ - STYLE: Надає інструкцію для генерації лаконічної поведінкової документації українською мовою.
18
+ - sectionMessages: Генерує секційні промпти для різних частин документації.
19
+ - overviewMessages: Формує текст для узагальнення ролі та призначення файлу.
20
+ - criticMessages: Створює запити для перевірки чорновиків документації на наявність дефектів.
21
+ - refineMessages: Переписує та виправляє чорновки документації відповідно до критики.
22
+ - guaranteesFromMarkers: Формує список гарантій щодо поведінки файлу на основі маркерів.
23
+ - oneShotMessages: Створює універсальний запит для генерації повної документації.
24
+
25
+ ## Публічний API
26
+
27
+ STYLE — Формулює стиль файлу.
28
+ sectionMessages — Збирає повідомлення з мінімальним контекстом для кожної секції.
29
+ overviewMessages — Надає узагальнення поведінки файлу.
30
+ criticMessages — Виявляє дефекти в чорнетці секції.
31
+ refineMessages — Виправляє чорнетку, усуваючи виявлені дефекти.
32
+ guaranteesFromMarkers — Створює детермінований шаблон гарантій поведінки з фактів.
33
+
34
+ ## Гарантії поведінки
35
+
36
+ - Read-only: файл не виконує операцій запису у файлову систему.
37
+ - За невдачі повертає значення помилки (`false`/`null`/`Err`) замість генерування винятку чи паніки.
38
+ - Кешує результати в межах одного прогону.
39
+ - Не звертається до мережі.
@@ -0,0 +1,54 @@
1
+ ---
2
+ docgen:
3
+ source: npm/rules/doc-files/js/docgen-scan.mjs
4
+ crc: 46f11827
5
+ score: 100
6
+ ---
7
+
8
+ # docgen-scan.mjs
9
+
10
+ ## Огляд
11
+
12
+ isSourceFile перевіряє, чи є файл кодовим джерелом.
13
+ docPathForSource обчислює шлях md-документа для кодового файлу.
14
+ isDocCandidate перевіряє, чи підлягає файл документуванню.
15
+ describeFile описує кодовий файл, включаючи шлях доки та стан застарілості.
16
+ scanForDocFiles рекурсивно обходить дерево, повертаючи кандидати з інформацією про старілість.
17
+ resolveRoot парсить аргументи, щоб визначити абсолютний корінь.
18
+ runDocFilesScanCli сканує дерево і друкує JSON-масив усіх кодових файлів зі станом застарілості.
19
+ runDocFilesCheckCli детектує застарілість для хук'ів, гейтів або інших режимів, повертаючи код виходу.
20
+
21
+ ## Поведінка
22
+
23
+ isSourceFile Обчислює, чи є файл кодовим джерелом.
24
+ docPathForSource Обчислює шлях md-документа для кодового файлу.
25
+ isDocCandidate Перевіряє, чи підлягає файл документуванню.
26
+ describeFile Описує кодовий файл, включаючи шлях доки та стан застарілості.
27
+ scanForDocFiles Рекурсивно обходить дерево, повертаючи кандидати з інформацією про старілість.
28
+ resolveRoot Парсить аргументи, щоб визначити абсолютний корінь.
29
+ runDocFilesScanCli Сканує дерево і друкує JSON-масив усіх кодових файлів зі станом застарілості.
30
+ runDocFilesCheckCli Детектує застарілість для хук'ів, гейтів або інших режимів, повертаючи код виходу.
31
+
32
+ ## Публічний API
33
+
34
+ isSourceFile — перевіряє, чи є файл коду для документування.
35
+ docPathForSource — обчислює шлях до документа для кодового файлу, розміщуючи його в теці `docs/` поруч із джерелом. Якщо шлях відносний, документ також відносний; якщо абсолютний, документ залишається абсолютним.
36
+ isDocCandidate — визначає, чи підлягає кодовий файл документуванню: має правильне розширення, не є тестом, не знаходиться в ігнорованому списку, і не є кореневим системним документуванням.
37
+ describeFile — надає опис кодового файлу: шлях до джерела, шлях до документа та стан застарілості за CRC.
38
+ scanForDocFiles — рекурсивно переглядає дерево від заданого кореня і повертає кодові файли разом зі станом застарілості.
39
+ resolveRoot — парсить аргумент `--root <dir>` з командного рядка; за замовчуванням використовує поточну робочу директорію.
40
+ runDocFilesScanCli — сканує дерево і виводить JSON-масив усіх кодових файлів із зазначенням їхнього стану застарілості.
41
+ runDocFilesCheckCli — виконує перевірку застарілості для хуків та командного рядка через інструмент `doc-files check`.
42
+ Режими — це способи виконання:
43
+ --hook — бере шлях до файлу з вводу JSON і перевіряє один файл.
44
+ --git — перевіряє різницю в Git (`git diff --name-only HEAD`) з урахуванням порогу `--max` (за замовчуванням 50); якщо застарілості більше, не блокує (виходить з кодом 0 з попередженням).
45
+ --degraded — генерує інформаційний звіт про документи, які мають оцінку нижче встановленого порогу (виходить з кодом 0).
46
+ <paths…> — використовується для визначення явних шляхів до джерел.
47
+ Exit 2 — повертається, якщо знайдено застарілі дані; повертається 0, якщо дані свіжі або пройдено перевищення порогу.
48
+
49
+ ## Гарантії поведінки
50
+
51
+ - Read-only: файл не виконує операцій запису у файлову систему.
52
+ - Перехоплює помилки і не пропускає винятків назовні (fail-safe).
53
+ - За невдачі повертає значення помилки (`false`/`null`/`Err`) замість генерування винятку чи паніки.
54
+ - Не звертається до мережі.
@@ -0,0 +1,36 @@
1
+ ---
2
+ docgen:
3
+ source: npm/rules/doc-files/js/lint.mjs
4
+ crc: f25a3bbe
5
+ score: 100
6
+ ---
7
+
8
+ # lint.mjs
9
+
10
+ ## Огляд
11
+
12
+ Адаптер правила doc-files до агрегатора `n-cursor lint`. Дає агрегатору відповідь на одне
13
+ питання: чи має кожен дотичний кодовий файл актуальну файлову документацію поряд із собою.
14
+
15
+ ## Поведінка
16
+
17
+ У quick-фазі отримує список змінених файлів і зводить його до набору джерел для перевірки в
18
+ **обидва** боки: змінене джерело перевіряється проти своєї доки, а змінена або видалена дока
19
+ (`<dir>/docs/<stem>.md`) повертається до відповідного джерела з тим самим іменем у каталозі над
20
+ `docs/`. У ci-фазі (списку немає) обходить усе дерево.
21
+
22
+ Порушенням вважається відсутня дока (`missing`) або розбіжність контрольної суми джерела з тією,
23
+ що записана у frontmatter доки (`crc-mismatch`). Документ із низькою якістю, але свіжою сумою —
24
+ не порушення.
25
+
26
+ ## Публічний API
27
+
28
+ `lint` — перевіряє документацію для переданого набору змінених файлів (або всього репозиторію,
29
+ якщо набір не задано); повертає код виходу `1`, якщо є застарілі чи відсутні доки, інакше `0`.
30
+ Список проблемних файлів друкується у stderr із підказкою регенерувати.
31
+
32
+ ## Гарантії поведінки
33
+
34
+ - Детермінованість: жодного виклику мовної моделі, рішення лише за контрольною сумою.
35
+ - Реверс-мапінг доки до джерела перебирає лише кодові розширення і повертає наявний файл-кандидат.
36
+ - Порожній набір змінених файлів дає код `0` без обходу дерева.
@@ -0,0 +1,31 @@
1
+ ---
2
+ docgen:
3
+ source: npm/rules/doc-files/js/units-js.mjs
4
+ crc: 58b898cc
5
+ score: 100
6
+ ---
7
+
8
+ # units-js.mjs
9
+
10
+ ## Огляд
11
+
12
+ Файл парсить програму, ітеруючи по її елементах для збору юнітів. Для кожної декларації визначається опис. Для функцій та класів збираються виклики інших юнітів через ребра викликів.
13
+
14
+ ## Поведінка
15
+
16
+ 1. Парсинг програми.
17
+ 2. Ітерація по тілу програми.
18
+ 3. Збір юнітів.
19
+ 4. Для кожної декларації визначається опис.
20
+ 5. Для функцій та класів збираються виклики інших юнітів.
21
+ 6. Вибираються виклики інших юнітів з ребрами викликів.
22
+
23
+ ## Публічний API
24
+
25
+ extractUnitsJs — Юніт-шар для js/mjs/ts: top-level функції/класи/const-функції з тілом, JSDoc, прапором експорту і ребрами call-graph (виклики ІНШИХ юнітів у тілі).
26
+
27
+ ## Гарантії поведінки
28
+
29
+ - Read-only: файл не виконує операцій запису у файлову систему.
30
+ - За невдачі повертає значення помилки (`false`/`null`/`Err`) замість генерування винятку чи паніки.
31
+ - Не звертається до мережі.
@@ -0,0 +1,35 @@
1
+ ---
2
+ docgen:
3
+ source: npm/rules/doc-files/js/units-rs.mjs
4
+ crc: 114e9a0b
5
+ score: 100
6
+ ---
7
+
8
+ # units-rs.mjs
9
+
10
+ ## Огляд
11
+
12
+ Файл аналізує структуру коду для вилучення інформації про юніти. Процес включає сканування рядків, ітерацію для визначення глибини блоків та позиції закриваючих лапок. Обробляються рядкові літерали для визначення межі блоків та підраховуються глибини блоків для визначення видимості. Обробляються декларації для визначення публічності. Витягується тіло функцій, структур, перерахувань або трейтів. Визначається експонування функцій через атрибути. Збирається документація перед декларацією. Формується об'єкт юніту з назвою, типом, публічністю, ім'я impl та діапазон. Визначається область видимості тіла за допомогою пошуку закриваючої фігу. Збираються виклики інших юнітів у тілі функції.
13
+
14
+ ## Поведінка
15
+
16
+ 1. Скан файлу по рядках.
17
+ 2. Ітерація по рядках для визначення глибини блоків.
18
+ 3. Обробка рядкових літералів для визначення позиції закриваючого лапки.
19
+ 4. Підрахунок глибини блоків для визначення видимості.
20
+ 5. Обробка декларацій для визначення публічності.
21
+ 6. Витягнення тіла функції, структури, перерахування або трейта.
22
+ 7. Визначення експонування функції через атрибути.
23
+ 8. Збір документації перед декларацією.
24
+ 9. Формування об'єкта юніту з назвою, типом, публічністю, ім'ям impl та діапазоном.
25
+ 10. Визначення області видимості тіла за допомогою пошуку закриваючої фігу.
26
+ 11. Збір викликів інших юнітів у тілі функції.
27
+
28
+ ## Публічний API
29
+
30
+ extractUnitsRs — Визначає top-level і impl-методи через підрахунок дужок по рядках. Обмеження: рядкові літерали з `{`/`}` всередині `{}` можуть дати хибну глибину.
31
+
32
+ ## Гарантії поведінки
33
+
34
+ - Read-only: файл не виконує операцій запису у файлову систему.
35
+ - Не звертається до мережі.
@@ -0,0 +1,30 @@
1
+ ---
2
+ docgen:
3
+ source: npm/rules/doc-files/js/units.mjs
4
+ crc: af91bd0d
5
+ score: 100
6
+ ---
7
+
8
+ # units.mjs
9
+
10
+ ## Огляд
11
+
12
+ Файл витягує одиниці з вмісту файлу залежно від розширення шляху. Якщо розширення належить до набору JS_EXT, використовується extractUnitsJs. Якщо розширення дорівнює 'rs', використовується extractUnitsRs. В інших випадках функція повертає null.
13
+
14
+ ## Поведінка
15
+
16
+ 1. extractUnits приймає вміст файлу та шлях файлу.
17
+ 2. Перевіряє розширення шляху.
18
+ 3. Якщо розширення знаходиться у наборі JS_EXT, викликає extractUnitsJs.
19
+ 4. Якщо розширення дорівнює 'rs', викликає extractUnitsRs.
20
+ 5. У інших випадках повертає null.
21
+
22
+ ## Публічний API
23
+
24
+ extractUnits — Визначає тип парсингу залежно від розширення файлу: js/mjs/ts використовує oxc AST, rs використовує regex+brace-counting, vue/py повертає null (повний шлях).
25
+
26
+ ## Гарантії поведінки
27
+
28
+ - Read-only: файл не виконує операцій запису у файлову систему.
29
+ - За невдачі повертає значення помилки (`false`/`null`/`Err`) замість генерування винятку чи паніки.
30
+ - Не звертається до мережі.
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Адаптер агрегатора `n-cursor lint` для правила doc-files.
3
+ *
4
+ * Quick-фаза отримує список змінених файлів і мапить їх у пари в **обидва** боки:
5
+ * - змінене **джерело** (`.js/.mjs/.ts/.vue/.py/.rs`) → перевірка його доки `<dir>/docs/<stem>.md`;
6
+ * - змінена/видалена **дока** (`<dir>/docs/<stem>.md`) → перевірка відповідного джерела
7
+ * (той самий stem у каталозі над текою `docs`).
8
+ * Ci-фаза (files === undefined) проганяє повний скан дерева.
9
+ *
10
+ * Порушення — `missing` ∪ `crc-mismatch` (детермінований CRC-детект, 0 LLM-токенів);
11
+ * degraded не блокує. Exit 1 — є stale; 0 — все свіже (конвенція агрегатора).
12
+ */
13
+ import { join, dirname, basename, extname } from 'node:path'
14
+ import { existsSync, readdirSync } from 'node:fs'
15
+
16
+ import { describeFile, isDocCandidate, isSourceFile, scanForDocFiles } from './docgen-scan.mjs'
17
+
18
+ /** Дока живе у `<dir>/docs/<stem>.md`; повертає `<dir>/<stem>` для реверс-мапінгу. */
19
+ const DOC_MD_RE = /(?:^|\/)docs\/[^/]+\.md$/u
20
+
21
+ /**
22
+ * Реверс-мапінг доки → джерело: для `<dir>/docs/<stem>.md` шукає у `<dir>` файл
23
+ * `<stem>.<ext>` із кодовим розширенням, що існує і є кандидатом на доку.
24
+ * @param {string} cwd корінь репо
25
+ * @param {string} docRel posix-шлях доки від кореня
26
+ * @returns {string|null} posix-шлях джерела або null
27
+ */
28
+ function sourceForDoc(cwd, docRel) {
29
+ const docsDir = dirname(docRel) // `<dir>/docs`
30
+ const srcDir = dirname(docsDir) // `<dir>`
31
+ const stem = basename(docRel, '.md')
32
+ let entries
33
+ try {
34
+ entries = readdirSync(join(cwd, srcDir), { withFileTypes: true })
35
+ } catch {
36
+ return null
37
+ }
38
+ for (const e of entries) {
39
+ if (!e.isFile() || !isSourceFile(e.name)) continue
40
+ if (basename(e.name, extname(e.name)) !== stem) continue
41
+ const rel = srcDir === '.' ? e.name : `${srcDir}/${e.name}`
42
+ if (isDocCandidate(cwd, rel)) return rel
43
+ }
44
+ return null
45
+ }
46
+
47
+ /**
48
+ * Зводить список змінених файлів у множину джерел-кандидатів для перевірки доки.
49
+ * @param {string[]} files змінені шляхи (posix або нативні)
50
+ * @param {string} cwd корінь репо
51
+ * @returns {string[]} унікальні posix-шляхи джерел
52
+ */
53
+ function sourcesFromChanged(files, cwd) {
54
+ const out = new Set()
55
+ for (const raw of files) {
56
+ const rel = raw.split('\\').join('/')
57
+ if (DOC_MD_RE.test(rel)) {
58
+ const src = sourceForDoc(cwd, rel)
59
+ if (src) out.add(src)
60
+ } else if (isDocCandidate(cwd, rel) && existsSync(join(cwd, rel))) {
61
+ out.add(rel)
62
+ }
63
+ }
64
+ return [...out]
65
+ }
66
+
67
+ /**
68
+ * Друкує список stale і повертає exit-код.
69
+ * @param {Array<{sourcePath:string, reason:string|null}>} stale застарілі описи
70
+ * @returns {number} 1 — є stale; 0 — немає
71
+ */
72
+ function reportStale(stale) {
73
+ if (stale.length === 0) return 0
74
+ const list = stale.map(f => ` - ${f.sourcePath} (${f.reason})`).join('\n')
75
+ process.stderr.write(
76
+ `✗ doc-files: документація застаріла/відсутня для ${stale.length} файл(ів):\n${list}\n→ перегенеруй: npx @nitra/cursor fix-doc-files\n`
77
+ )
78
+ return 1
79
+ }
80
+
81
+ /**
82
+ * Крок агрегатора lint для doc-files.
83
+ * @param {string[] | undefined} files quick: лише ці файли; undefined: весь репозиторій
84
+ * @param {string} [cwd] корінь репо
85
+ * @returns {Promise<number>} 0 — OK, 1 — є застарілі доки
86
+ */
87
+ export function lint(files, cwd = process.cwd()) {
88
+ if (files === undefined) {
89
+ const stale = scanForDocFiles(cwd).filter(f => f.stale)
90
+ return Promise.resolve(reportStale(stale))
91
+ }
92
+ const sources = sourcesFromChanged(files, cwd)
93
+ if (sources.length === 0) return Promise.resolve(0)
94
+ const stale = sources.map(src => describeFile(cwd, src)).filter(f => f.stale)
95
+ return Promise.resolve(reportStale(stale))
96
+ }
@@ -9,7 +9,10 @@
9
9
  function skipString(src, i) {
10
10
  i++ // відкриваючий "
11
11
  while (i < src.length) {
12
- if (src[i] === '\\') { i += 2; continue }
12
+ if (src[i] === '\\') {
13
+ i += 2
14
+ continue
15
+ }
13
16
  if (src[i] === '"') return i + 1
14
17
  i++
15
18
  }
@@ -38,8 +41,15 @@ function findClosingBrace(src, start) {
38
41
  i = end === -1 ? src.length : end + 2
39
42
  continue
40
43
  }
41
- if (ch === '"') { i = skipString(src, i); continue }
42
- if (ch === '{') { depth++; i++; continue }
44
+ if (ch === '"') {
45
+ i = skipString(src, i)
46
+ continue
47
+ }
48
+ if (ch === '{') {
49
+ depth++
50
+ i++
51
+ continue
52
+ }
43
53
  if (ch === '}') {
44
54
  depth--
45
55
  if (depth === 0) return i
@@ -73,12 +83,17 @@ function docBefore(lines, lineIdx) {
73
83
  return doc.join(' ').trim()
74
84
  }
75
85
 
76
- // Pub-items: pub fn / pub struct / pub enum / pub trait / pub type
86
+ // Pub-items матчаться у два кроки по trim-нутому рядку (прості регекспи без
87
+ // бектрекінгу): спершу опційний pub(...)-префікс, потім сама декларація.
77
88
  // Також ловить fn без pub (для localSymbols і impl-методів)
78
- const ITEM_RE = /^[ \t]*(pub(?:\([^)]*\))?\s+)?(?:async\s+)?(?:unsafe\s+)?(fn|struct|enum|trait|type)\s+(\w+)/
89
+ const PUB_PREFIX_RE = /^pub(?:\([^)]*\))?\s+/
90
+ const ITEM_DECL_RE = /^(?:async\s+)?(?:unsafe\s+)?(fn|struct|enum|trait|type)\s+(\w+)/
79
91
 
80
- // impl Type { або impl<T> Trait for Type {
81
- const IMPL_RE = /^[ \t]*(?:pub\s+)?impl(?:<[^>]*>)?\s+(?:(?:\w[\w:<>, ]*\s+for\s+))?(\w+)/
92
+ // impl Type { або impl<T> Trait for Type { — теж двокроково: голова `impl<...>`,
93
+ // далі тип після `for` (trait-impl) або перше слово (inherent impl)
94
+ const IMPL_HEAD_RE = /^impl(?:<[^>]*>)?\s+/
95
+ const IMPL_FOR_TYPE_RE = /\bfor\s+(\w+)/
96
+ const TYPE_NAME_RE = /^(\w+)/
82
97
 
83
98
  // Підозрілі exposure-атрибути, що роблять непуб-fn фактично публічними
84
99
  const EXPOSURE_ATTR_RE = /#\[(?:tauri::command|wasm_bindgen|uniffi::export|pyo3::pyfunction|napi)/
@@ -93,7 +108,7 @@ const CALL_RE = /\b([a-z_]\w*)\s*\(/g
93
108
  * хибну глибину (рідкісно в реальному Rust-коді з rustfmt).
94
109
  * @param {string} src вміст файлу
95
110
  * @param {string} [_relPath] резервний (не використовується)
96
- * @returns {Array<{name:string, kind:string, exported:boolean, implName:string|null, span:{start:number,end:number}, body:string, calls:string[], doc:string}>|null}
111
+ * @returns {Array<{name:string, kind:string, exported:boolean, implName:string|null, span:{start:number,end:number}, body:string, calls:string[], doc:string}>|null} юніти файлу (fn та impl-методи) або `null`, якщо юнітів не знайдено
97
112
  */
98
113
  export function extractUnitsRs(src, _relPath) {
99
114
  const lines = src.split('\n')
@@ -129,7 +144,7 @@ export function extractUnitsRs(src, _relPath) {
129
144
  }
130
145
 
131
146
  // Закриті impl-блоки прибираємо зі стека
132
- while (implStack.length > 0 && implStack[implStack.length - 1].openDepth > depth) {
147
+ while (implStack.length > 0 && implStack.at(-1).openDepth > depth) {
133
148
  implStack.pop()
134
149
  }
135
150
 
@@ -140,22 +155,27 @@ export function extractUnitsRs(src, _relPath) {
140
155
  nextFnExposed = true
141
156
  }
142
157
 
158
+ const trimmed = line.trimStart()
159
+
143
160
  // Impl-декларація (зазвичай глибина 0, але може бути в mod)
144
161
  if (depthAtStart <= 1) {
145
- const implM = line.match(IMPL_RE)
146
- if (implM && line.includes('{')) {
147
- implStack.push({ typeName: implM[1], openDepth: depth })
162
+ const headM = trimmed.match(IMPL_HEAD_RE)
163
+ if (headM && line.includes('{')) {
164
+ const rest = trimmed.slice(headM[0].length)
165
+ const typeM = rest.match(IMPL_FOR_TYPE_RE) ?? rest.match(TYPE_NAME_RE)
166
+ if (typeM) implStack.push({ typeName: typeM[1], openDepth: depth })
148
167
  }
149
168
  }
150
169
 
151
170
  // Елементи на глибині 0 (top-level) і 1 (всередині impl)
152
171
  if (depthAtStart <= 1) {
153
- const m = line.match(ITEM_RE)
172
+ const pubM = trimmed.match(PUB_PREFIX_RE)
173
+ const m = (pubM ? trimmed.slice(pubM[0].length) : trimmed).match(ITEM_DECL_RE)
154
174
  if (m) {
155
- const isPub = Boolean(m[1]) || (m[2] === 'fn' && nextFnExposed)
156
- if (m[2] === 'fn') nextFnExposed = false
157
- const kind = m[2]
158
- const name = m[3]
175
+ const isPub = Boolean(pubM) || (m[1] === 'fn' && nextFnExposed)
176
+ if (m[1] === 'fn') nextFnExposed = false
177
+ const kind = m[1]
178
+ const name = m[2]
159
179
  const doc = docBefore(lines, li)
160
180
 
161
181
  // Витягуємо тіло через findClosingBrace для fn/struct/enum/trait
@@ -0,0 +1,37 @@
1
+ ---
2
+ docgen:
3
+ source: npm/rules/doc-files/lint/lint.mjs
4
+ crc: a30dd81f
5
+ score: 100
6
+ ---
7
+
8
+ # lint.mjs
9
+
10
+ ## Огляд
11
+
12
+ CLI-команда `lint-doc-files` — детермінований детектор застарілості файлових док. Працює без
13
+ мовної моделі скрізь: локально, в hook'ах і в CI.
14
+
15
+ ## Поведінка
16
+
17
+ Без прапорців або з переліком шляхів робить повний чи точковий детект і повертає код `1`, якщо є
18
+ застарілі/відсутні доки. `--missing-only` звужує до самих відсутніх. `--json` друкує машинний
19
+ лістинг усіх кандидатів зі станом і завершується кодом `0`. Режими `--hook`, `--git` і
20
+ `--degraded` делегуються детектору hook-протоколу (PostToolUse за одним файлом зі stdin, Stop-гейт
21
+ за зміненими у задачі джерелами з порогом, інформаційний звіт про доки нижчої якості).
22
+
23
+ Повний прогін серіалізується спільним локом під ключем, виведеним зі шляху каталогу, тож паралельні
24
+ запуски не накладаються; hook-форми навмисно виконуються без локу заради завжди-свіжого вердикту.
25
+
26
+ ## Публічний API
27
+
28
+ `runLintDocFilesCli` — точка входу команди: маршрутизує між делегатом hook-протоколу, JSON-лістингом
29
+ і повним/точковим детектом; повертає код виходу.
30
+ `runLintDocFilesSteps` — сама робота повного чи точкового детекту, придатна для прямого виклику з
31
+ тестів без локу; повертає `1` за наявності застарілих док, інакше `0`.
32
+
33
+ ## Гарантії поведінки
34
+
35
+ - Неіснуючий корінь дає зрозумілу помилку і код `1`.
36
+ - Повний прогін — код `1` (конвенція `lint-*`); hook/git — код `2` (blocking feedback для Claude Code).
37
+ - Жодних викликів мовної моделі.