@nitra/cursor 12.6.1 → 12.7.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 (266) hide show
  1. package/.claude-template/settings.template.json +1 -1
  2. package/CHANGELOG.md +10 -0
  3. package/bin/docs/n-cursor.md +4 -20
  4. package/bin/n-cursor.js +7 -53
  5. package/docs/stryker.config.md +20 -28
  6. package/package.json +1 -1
  7. package/rules/abie/docs/index.md +1 -0
  8. package/rules/abie/docs/main.md +29 -0
  9. package/rules/abie/{fix.mjs → main.mjs} +5 -3
  10. package/rules/adr/docs/index.md +1 -0
  11. package/rules/adr/docs/main.md +29 -0
  12. package/rules/adr/{fix.mjs → main.mjs} +5 -3
  13. package/rules/bun/docs/index.md +1 -0
  14. package/rules/bun/docs/main.md +30 -0
  15. package/rules/bun/js/docs/layout.md +11 -36
  16. package/rules/bun/{fix.mjs → main.mjs} +5 -3
  17. package/rules/capacitor/docs/index.md +1 -0
  18. package/rules/capacitor/docs/main.md +29 -0
  19. package/rules/capacitor/{fix.mjs → main.mjs} +5 -3
  20. package/rules/changelog/docs/index.md +1 -0
  21. package/rules/changelog/docs/main.md +27 -0
  22. package/rules/changelog/main.mjs +20 -0
  23. package/rules/ci4/docs/index.md +1 -0
  24. package/rules/ci4/docs/main.md +30 -0
  25. package/rules/ci4/main.mjs +20 -0
  26. package/rules/doc-files/docs/index.md +1 -0
  27. package/rules/doc-files/docs/main.md +31 -0
  28. package/rules/doc-files/js/docgen-files-batch.mjs +47 -3
  29. package/rules/doc-files/js/docgen-scan.mjs +89 -9
  30. package/rules/doc-files/js/docs/docgen-files-batch.md +15 -15
  31. package/rules/doc-files/js/docs/docgen-scan.md +34 -34
  32. package/rules/doc-files/js/docs/index.md +1 -0
  33. package/rules/doc-files/js/docs/run-lint.md +27 -0
  34. package/rules/doc-files/{lint/lint.mjs → js/run-lint.mjs} +23 -9
  35. package/rules/doc-files/{js/lint.mjs → main.mjs} +60 -10
  36. package/rules/docker/docs/index.md +1 -0
  37. package/rules/docker/docs/main.md +28 -0
  38. package/rules/docker/js/docs/lint.md +26 -54
  39. package/rules/docker/js/lint.mjs +11 -0
  40. package/rules/docker/lib/docker-hadolint.mjs +1 -1
  41. package/rules/docker/lib/docs/docker-hadolint.md +16 -173
  42. package/rules/docker/main.mjs +20 -0
  43. package/rules/efes/docs/index.md +1 -0
  44. package/rules/efes/docs/main.md +29 -0
  45. package/rules/efes/main.mjs +20 -0
  46. package/rules/feedback/docs/index.md +1 -0
  47. package/rules/feedback/docs/main.md +30 -0
  48. package/rules/feedback/main.mjs +20 -0
  49. package/rules/ga/docs/index.md +1 -0
  50. package/rules/ga/docs/main.md +29 -0
  51. package/rules/ga/{lint/lint.mjs → main.mjs} +36 -10
  52. package/rules/graphql/docs/index.md +1 -0
  53. package/rules/graphql/docs/main.md +36 -0
  54. package/rules/graphql/main.mjs +20 -0
  55. package/rules/hasura/docs/index.md +1 -0
  56. package/rules/hasura/docs/main.md +30 -0
  57. package/rules/hasura/main.mjs +20 -0
  58. package/rules/image-avif/docs/index.md +1 -0
  59. package/rules/image-avif/docs/main.md +30 -0
  60. package/rules/image-avif/js/docs/avif_generation.md +20 -233
  61. package/rules/image-avif/main.mjs +20 -0
  62. package/rules/image-compress/docs/index.md +1 -0
  63. package/rules/image-compress/docs/main.md +29 -0
  64. package/rules/image-compress/js/docs/package_setup.md +12 -11
  65. package/rules/image-compress/{js/lint.mjs → main.mjs} +21 -5
  66. package/rules/js-bun-db/docs/index.md +1 -0
  67. package/rules/js-bun-db/docs/main.md +30 -0
  68. package/rules/js-bun-db/main.mjs +20 -0
  69. package/rules/js-bun-redis/docs/index.md +1 -0
  70. package/rules/js-bun-redis/docs/main.md +29 -0
  71. package/rules/js-bun-redis/main.mjs +20 -0
  72. package/rules/js-lint/docs/index.md +1 -0
  73. package/rules/js-lint/docs/main.md +29 -0
  74. package/rules/js-lint/js/check.mjs +268 -0
  75. package/rules/js-lint/js/docs/check.md +39 -0
  76. package/rules/js-lint/js/docs/index.md +1 -1
  77. package/rules/js-lint/js/docs/tooling.md +12 -32
  78. package/rules/js-lint/js/tooling.mjs +1 -265
  79. package/rules/js-lint/{js/lint.mjs → main.mjs} +19 -2
  80. package/rules/js-lint-ci/docs/index.md +1 -0
  81. package/rules/js-lint-ci/docs/main.md +27 -0
  82. package/rules/js-lint-ci/main.mjs +33 -0
  83. package/rules/js-mssql/docs/index.md +1 -0
  84. package/rules/js-mssql/docs/main.md +30 -0
  85. package/rules/js-mssql/main.mjs +20 -0
  86. package/rules/js-run/docs/index.md +1 -0
  87. package/rules/js-run/docs/main.md +30 -0
  88. package/rules/js-run/main.mjs +20 -0
  89. package/rules/k8s/docs/index.md +1 -0
  90. package/rules/k8s/docs/main.md +40 -0
  91. package/rules/k8s/js/docs/index.md +12 -0
  92. package/rules/k8s/{lint/lint.mjs → main.mjs} +32 -10
  93. package/rules/nginx-default-tpl/docs/index.md +1 -0
  94. package/rules/nginx-default-tpl/docs/main.md +30 -0
  95. package/rules/nginx-default-tpl/main.mjs +20 -0
  96. package/rules/npm-module/docs/index.md +1 -0
  97. package/rules/npm-module/docs/main.md +29 -0
  98. package/rules/npm-module/js/docs/rule_meta.md +17 -16
  99. package/rules/npm-module/js/rule_meta.mjs +13 -3
  100. package/rules/npm-module/main.mjs +20 -0
  101. package/rules/php/docs/index.md +1 -0
  102. package/rules/php/docs/main.md +33 -0
  103. package/rules/php/js/docs/tooling.md +10 -10
  104. package/rules/php/{lint/lint.mjs → main.mjs} +32 -6
  105. package/rules/python/docs/index.md +1 -0
  106. package/rules/python/docs/main.md +31 -0
  107. package/rules/python/js/docs/tooling.md +17 -17
  108. package/rules/python/{lint/lint.mjs → main.mjs} +29 -5
  109. package/rules/rego/docs/index.md +1 -0
  110. package/rules/rego/docs/main.md +37 -0
  111. package/rules/rego/{lint/lint.mjs → main.mjs} +27 -5
  112. package/rules/release/docs/index.md +1 -0
  113. package/rules/release/docs/main.md +29 -0
  114. package/rules/release/docs/release.md +0 -3
  115. package/rules/release/release.mdc +10 -0
  116. package/rules/rust/docs/index.md +1 -0
  117. package/rules/rust/docs/main.md +27 -0
  118. package/rules/rust/{js/lint.mjs → main.mjs} +20 -3
  119. package/rules/security/docs/index.md +1 -0
  120. package/rules/security/docs/main.md +28 -0
  121. package/rules/security/main.mjs +45 -0
  122. package/rules/style-lint/docs/index.md +1 -0
  123. package/rules/style-lint/docs/main.md +29 -0
  124. package/rules/style-lint/{js/lint.mjs → main.mjs} +19 -1
  125. package/rules/tauri/docs/index.md +1 -0
  126. package/rules/tauri/docs/main.md +29 -0
  127. package/rules/tauri/main.mjs +20 -0
  128. package/rules/test/docs/index.md +1 -0
  129. package/rules/test/docs/main.md +30 -0
  130. package/rules/test/main.mjs +20 -0
  131. package/rules/text/docs/index.md +1 -0
  132. package/rules/text/docs/main.md +29 -0
  133. package/rules/text/js/docs/cspell-fix.md +30 -0
  134. package/rules/text/js/docs/formatting.md +12 -45
  135. package/rules/text/js/docs/index.md +4 -0
  136. package/rules/text/js/docs/run-dotenv-linter.md +31 -0
  137. package/rules/text/js/docs/run-shellcheck.md +28 -0
  138. package/rules/text/js/docs/run-v8r.md +29 -0
  139. package/rules/text/{lint/lint.mjs → main.mjs} +38 -9
  140. package/rules/tool-surface/docs/index.md +1 -0
  141. package/rules/tool-surface/docs/main.md +29 -0
  142. package/rules/tool-surface/main.mjs +20 -0
  143. package/rules/vue/docs/index.md +1 -0
  144. package/rules/vue/docs/main.md +29 -0
  145. package/rules/vue/main.mjs +20 -0
  146. package/rules/worktree/docs/index.md +1 -0
  147. package/rules/worktree/docs/main.md +28 -0
  148. package/rules/worktree/main.mjs +20 -0
  149. package/scripts/docs/index.md +1 -0
  150. package/scripts/docs/post-tool-use-check.md +29 -0
  151. package/scripts/docs/sync-claude-config.md +64 -92
  152. package/scripts/lib/adr/docs/normalize-cli.md +0 -3
  153. package/scripts/lib/adr/docs/normalize-pipeline.md +0 -3
  154. package/scripts/lib/docs/gha-workflow.md +25 -317
  155. package/scripts/lib/docs/index.md +1 -0
  156. package/scripts/lib/docs/list-project-rules-mdc.md +5 -4
  157. package/scripts/lib/docs/list-rule-ids.md +15 -148
  158. package/scripts/lib/docs/read-n-cursor-config-lite.md +12 -16
  159. package/scripts/lib/docs/run-lint-step.md +13 -13
  160. package/scripts/lib/docs/run-lint.md +30 -0
  161. package/scripts/lib/docs/run-rule-cli.md +14 -10
  162. package/scripts/lib/docs/run-standard-lint.md +27 -10
  163. package/scripts/lib/docs/run-standard-rule.md +12 -11
  164. package/scripts/lib/docs/timing-summary.md +11 -12
  165. package/scripts/lib/docs/worktree-notice.md +0 -3
  166. package/scripts/lib/fix/docs/index.md +1 -0
  167. package/scripts/lib/fix/docs/orchestrator.md +23 -18
  168. package/scripts/lib/fix/docs/run-conformance-check.md +32 -0
  169. package/scripts/lib/fix/docs/t0.md +10 -9
  170. package/scripts/lib/fix/orchestrator.mjs +5 -5
  171. package/scripts/lib/fix/{run-fix-check.mjs → run-conformance-check.mjs} +13 -13
  172. package/scripts/lib/fix/t0.mjs +3 -3
  173. package/scripts/lib/list-project-rules-mdc.mjs +1 -1
  174. package/scripts/lib/list-rule-ids.mjs +12 -3
  175. package/scripts/lib/read-n-cursor-config-lite.mjs +2 -2
  176. package/{rules/lint/js/orchestrate.mjs → scripts/lib/run-lint.mjs} +42 -20
  177. package/scripts/lib/run-rule-cli.mjs +4 -4
  178. package/scripts/lib/run-standard-lint.mjs +19 -6
  179. package/scripts/lib/run-standard-rule.mjs +4 -4
  180. package/scripts/lib/timing-summary.mjs +1 -1
  181. package/scripts/{post-tool-use-fix.mjs → post-tool-use-check.mjs} +9 -9
  182. package/scripts/sync-claude-config.mjs +2 -2
  183. package/rules/changelog/fix.mjs +0 -18
  184. package/rules/ci4/fix.mjs +0 -18
  185. package/rules/doc-files/fix.mjs +0 -19
  186. package/rules/doc-files/js/docs/lint.md +0 -34
  187. package/rules/doc-files/lint/docs/index.md +0 -11
  188. package/rules/doc-files/lint/docs/lint.md +0 -35
  189. package/rules/docker/fix.mjs +0 -18
  190. package/rules/docker/lint/docs/index.md +0 -11
  191. package/rules/docker/lint/docs/lint.md +0 -200
  192. package/rules/docker/lint/lint.mjs +0 -95
  193. package/rules/efes/fix.mjs +0 -18
  194. package/rules/feedback/fix.mjs +0 -18
  195. package/rules/ga/fix.mjs +0 -18
  196. package/rules/ga/js/docs/lint.md +0 -20
  197. package/rules/ga/js/lint.mjs +0 -12
  198. package/rules/ga/lint/docs/index.md +0 -11
  199. package/rules/ga/lint/docs/lint.md +0 -31
  200. package/rules/graphql/fix.mjs +0 -18
  201. package/rules/hasura/fix.mjs +0 -18
  202. package/rules/image-avif/fix.mjs +0 -18
  203. package/rules/image-compress/fix.mjs +0 -18
  204. package/rules/image-compress/js/docs/lint.md +0 -24
  205. package/rules/js-bun-db/fix.mjs +0 -18
  206. package/rules/js-bun-redis/fix.mjs +0 -18
  207. package/rules/js-lint/fix.mjs +0 -18
  208. package/rules/js-lint/js/docs/lint.md +0 -32
  209. package/rules/js-lint-ci/fix.mjs +0 -18
  210. package/rules/js-lint-ci/js/docs/lint.md +0 -22
  211. package/rules/js-lint-ci/js/lint.mjs +0 -15
  212. package/rules/js-mssql/fix.mjs +0 -18
  213. package/rules/js-run/fix.mjs +0 -18
  214. package/rules/k8s/fix.mjs +0 -18
  215. package/rules/k8s/js/lint.mjs +0 -14
  216. package/rules/k8s/lint/docs/index.md +0 -11
  217. package/rules/k8s/lint/docs/lint.md +0 -413
  218. package/rules/lint/docs/fix.md +0 -25
  219. package/rules/lint/docs/index.md +0 -11
  220. package/rules/lint/fix.mjs +0 -18
  221. package/rules/lint/js/docs/index.md +0 -11
  222. package/rules/lint/js/docs/orchestrate.md +0 -31
  223. package/rules/lint/meta.json +0 -1
  224. package/rules/nginx-default-tpl/fix.mjs +0 -18
  225. package/rules/npm-module/fix.mjs +0 -18
  226. package/rules/php/fix.mjs +0 -18
  227. package/rules/php/js/docs/lint.md +0 -20
  228. package/rules/php/js/lint.mjs +0 -15
  229. package/rules/php/lint/docs/index.md +0 -11
  230. package/rules/php/lint/docs/lint.md +0 -219
  231. package/rules/python/fix.mjs +0 -18
  232. package/rules/python/js/docs/lint.md +0 -21
  233. package/rules/python/js/lint.mjs +0 -14
  234. package/rules/python/lint/docs/index.md +0 -11
  235. package/rules/python/lint/docs/lint.md +0 -29
  236. package/rules/rego/fix.mjs +0 -18
  237. package/rules/rego/js/docs/lint.md +0 -21
  238. package/rules/rego/js/lint.mjs +0 -12
  239. package/rules/rego/lint/docs/index.md +0 -11
  240. package/rules/rego/lint/docs/lint.md +0 -208
  241. package/rules/rust/fix.mjs +0 -18
  242. package/rules/rust/js/docs/lint.md +0 -21
  243. package/rules/security/fix.mjs +0 -18
  244. package/rules/security/js/docs/lint.md +0 -175
  245. package/rules/security/js/lint.mjs +0 -26
  246. package/rules/style-lint/fix.mjs +0 -18
  247. package/rules/style-lint/js/docs/lint.md +0 -31
  248. package/rules/tauri/fix.mjs +0 -18
  249. package/rules/test/fix.mjs +0 -18
  250. package/rules/text/fix.mjs +0 -18
  251. package/rules/text/js/docs/lint.md +0 -23
  252. package/rules/text/js/lint.mjs +0 -15
  253. package/rules/text/lint/docs/cspell-fix.md +0 -32
  254. package/rules/text/lint/docs/index.md +0 -15
  255. package/rules/text/lint/docs/lint.md +0 -36
  256. package/rules/text/lint/docs/run-dotenv-linter.md +0 -161
  257. package/rules/text/lint/docs/run-shellcheck.md +0 -216
  258. package/rules/text/lint/docs/run-v8r.md +0 -201
  259. package/rules/tool-surface/fix.mjs +0 -18
  260. package/rules/vue/fix.mjs +0 -18
  261. package/rules/worktree/fix.mjs +0 -18
  262. /package/rules/release/{fix.mjs → main.mjs} +0 -0
  263. /package/rules/text/{lint → js}/cspell-fix.mjs +0 -0
  264. /package/rules/text/{lint → js}/run-dotenv-linter.mjs +0 -0
  265. /package/rules/text/{lint → js}/run-shellcheck.mjs +0 -0
  266. /package/rules/text/{lint → js}/run-v8r.mjs +0 -0
@@ -1,12 +1,12 @@
1
1
  /**
2
- * Light read-only `.n-cursor.json` reader для standalone `fix.mjs` invocation.
2
+ * Light read-only `.n-cursor.json` reader для standalone `check.mjs` invocation.
3
3
  *
4
4
  * НЕ робить auto-rules detection, merge, schema sync — це справа повного `readConfig` у CLI.
5
5
  * Тут лише: прочитати файл (якщо є), повернути `{ rules: string[], disableRules: string[] }`.
6
6
  *
7
7
  * Спостереження whitelist:
8
8
  * - якщо `.n-cursor.json` НЕМАЄ → правило вважається enabled (поведінка "open by default"),
9
- * щоб `bun rules/<id>/fix.mjs` з будь-якої тимчасової директорії працювало для debug.
9
+ * щоб `bun rules/<id>/check.mjs` з будь-якої тимчасової директорії працювало для debug.
10
10
  * - якщо файл є з `rules:[…]`, але правила там немає → правило не enabled.
11
11
  * - якщо правило в `disable-rules` → не enabled, навіть якщо у `rules:[…]`.
12
12
  */
@@ -1,19 +1,40 @@
1
- /** @see ./docs/orchestrate.md */
1
+ /** @see ./docs/run-lint.md */
2
2
  import { existsSync, readdirSync } from 'node:fs'
3
3
  import { dirname, join } from 'node:path'
4
4
  import { fileURLToPath } from 'node:url'
5
5
  import { cwd as processCwd } from 'node:process'
6
6
  import { spawnSync } from 'node:child_process'
7
7
 
8
- import { parseRuleLintSpec, readRuleMetaRaw } from '../../../scripts/lib/rule-meta.mjs'
9
- import { collectChangedFilesSince, resolveChangedBase } from '../../../scripts/lib/changed-files.mjs'
10
- import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
11
- import { isRuleEnabled, readNCursorConfigLite } from '../../../scripts/lib/read-n-cursor-config-lite.mjs'
8
+ import { parseRuleLintSpec, readRuleMetaRaw } from './rule-meta.mjs'
9
+ import { collectChangedFilesSince, resolveChangedBase } from './changed-files.mjs'
10
+ import { resolveCmd } from '../utils/resolve-cmd.mjs'
11
+ import { isRuleEnabled, readNCursorConfigLite } from './read-n-cursor-config-lite.mjs'
12
12
 
13
- // Цей файл: npm/rules/lint/js/orchestrate.mjs → PACKAGE_ROOT = npm (чотири dirname угору).
14
- const PACKAGE_ROOT = dirname(dirname(dirname(dirname(fileURLToPath(import.meta.url)))))
13
+ // Цей файл: npm/scripts/lib/run-lint.mjs → PACKAGE_ROOT = npm (два dirname угору).
14
+ const PACKAGE_ROOT = dirname(dirname(fileURLToPath(import.meta.url)))
15
15
  const RULES_DIR = join(PACKAGE_ROOT, 'rules')
16
16
 
17
+ /**
18
+ * Чи має правило лінт-поверхню — `meta.json#lint` задано (`per-file`/`full`).
19
+ * Канонічний сигнал (ADR 2026-06-21): gate за meta, не за наявністю файлу.
20
+ * @param {Record<string, unknown> | undefined} raw meta-обʼєкт правила
21
+ * @returns {boolean} true — правило лінтить
22
+ */
23
+ function hasLintSurface(raw) {
24
+ return parseRuleLintSpec(raw?.lint) !== null
25
+ }
26
+
27
+ /**
28
+ * Резолвить лінт-entrypoint правила: `main.mjs` з експортом `lint` (канон, ADR 2026-06-21).
29
+ * @param {string} rulesDir каталог rules
30
+ * @param {string} id rule-id
31
+ * @returns {string | null} шлях до `main.mjs`, або null якщо файлу нема
32
+ */
33
+ function resolveLintEntrypoint(rulesDir, id) {
34
+ const main = join(rulesDir, id, 'main.mjs')
35
+ return existsSync(main) ? main : null
36
+ }
37
+
17
38
  /**
18
39
  * Конформність-фаза lint (whole-repo: config/file/workflow conformance — те, що раніше робив `fix`).
19
40
  * Per-file декомпозиції немає, тож виконується лише у `--full`.
@@ -27,11 +48,11 @@ const RULES_DIR = join(PACKAGE_ROOT, 'rules')
27
48
  */
28
49
  async function runConformance(cwd, readOnly, log, filter = []) {
29
50
  if (!readOnly) {
30
- const { runOrchestratorCli } = await import('../../../scripts/lib/fix/orchestrator.mjs')
51
+ const { runOrchestratorCli } = await import('./fix/orchestrator.mjs')
31
52
  return runOrchestratorCli(filter, cwd)
32
53
  }
33
- const { runFixCheck } = await import('../../../scripts/lib/fix/run-fix-check.mjs')
34
- const { rules } = await runFixCheck(filter, cwd)
54
+ const { runConformanceCheck } = await import('./fix/run-conformance-check.mjs')
55
+ const { rules } = await runConformanceCheck(filter, cwd)
35
56
  const failed = rules.filter(x => !x.ok)
36
57
  if (failed.length === 0) return 0
37
58
  log(`❌ lint: конформність — ${failed.length} порушень: ${failed.map(x => x.ruleId).join(', ')}\n`)
@@ -97,9 +118,9 @@ async function runPerFileRules(ids, ctx) {
97
118
  const { rulesDir, changed, cwd, readOnly, metaById, log } = ctx
98
119
  let worst = 0
99
120
  for (const id of ids) {
100
- const lintPath = join(rulesDir, id, 'js', 'lint.mjs')
101
- if (!existsSync(lintPath)) {
102
- log(`⚠️ lint: правило ${id} має lint-фазу, але немає js/lint.mjs — пропускаю.\n`)
121
+ const lintPath = resolveLintEntrypoint(rulesDir, id)
122
+ if (!lintPath) {
123
+ log(`⚠️ lint: правило ${id} має lint-фазу (meta.lint), але немає main.mjs — пропускаю.\n`)
103
124
  continue
104
125
  }
105
126
  // lintPath = join(rulesDir, id, …) — суто package-internal (rulesDir пакета + id зі
@@ -128,7 +149,7 @@ async function runPerFileRules(ids, ctx) {
128
149
  */
129
150
  async function runFullConformancePhase(cwd, readOnly, log) {
130
151
  const { escalationLogSize, maybeAnalyzeEscalation, reportRunStats } = await import(
131
- '../../../scripts/lib/fix/analyze-escalation.mjs'
152
+ './fix/analyze-escalation.mjs'
132
153
  )
133
154
  const escOffset = readOnly ? 0 : escalationLogSize()
134
155
  const conformanceCode = await runConformance(cwd, readOnly, log)
@@ -160,11 +181,12 @@ function runFormat(cwd, log) {
160
181
  }
161
182
 
162
183
  /**
163
- * Scoped-режим (`lint <rule…>`): повний прогін НАЗВАНИХ правил — їх лінтер (`js/lint.mjs`,
164
- * whole-repo) для тих, що його мають, + конформність для всіх названих. Дзеркалить `--full`,
165
- * але звужено до правил, тож `lint ga` standalone `lint-ga`. Конформність-only правила
166
- * (напр. `changelog` із hk) не мають `js/lint.mjs` проганяється лише їх конформність
167
- * (зворотна сумісність із колишнім `fix <rule>`). oxfmt у scoped НЕ запускається — це
184
+ * Scoped-режим (`lint <rule…>`): повний прогін НАЗВАНИХ правил — їх лінтер (entrypoint
185
+ * `main.mjs::lint`, whole-repo) для тих, що мають лінт-поверхню
186
+ * (`meta.json#lint`), + конформність для всіх названих. Дзеркалить `--full`, але звужено
187
+ * до правил, тож `lint ga` standalone `lint-ga`. Конформність-only правила (напр.
188
+ * `changelog` із hk) без `meta.lint` проганяється лише їх конформність (зворотна
189
+ * сумісність із колишнім `fix <rule>`). oxfmt у scoped НЕ запускається — це
168
190
  * таргетований прогін правил, а не глобальне форматування.
169
191
  * @param {string[]} rules id названих правил
170
192
  * @param {{ cwd: string, readOnly: boolean, rulesDir: string, conformance: boolean, log: (s: string) => void }} ctx контекст (`conformance` — чи запускати конформність; false для юніт-тестів із кастомним rulesDir, де реальний пакет недоступний)
@@ -173,7 +195,7 @@ function runFormat(cwd, log) {
173
195
  async function runScopedRules(rules, ctx) {
174
196
  const { cwd, readOnly, rulesDir, conformance, log } = ctx
175
197
  const metaById = readAllMeta(rulesDir)
176
- const linterIds = rules.filter(id => existsSync(join(rulesDir, id, 'js', 'lint.mjs')))
198
+ const linterIds = rules.filter(id => hasLintSurface(metaById[id]))
177
199
  let worst = 0
178
200
  if (linterIds.length > 0) {
179
201
  const perFile = await runPerFileRules(linterIds, { rulesDir, changed: undefined, cwd, readOnly, metaById, log })
@@ -1,10 +1,10 @@
1
1
  /**
2
- * Standalone CLI runner для одного правила. Викликається з `rules/<id>/fix.mjs`
3
- * у блоці `if (import.meta.main)` — це робить `bun rules/<id>/fix.mjs` повним
2
+ * Standalone CLI runner для одного правила. Викликається з `rules/<id>/check.mjs`
3
+ * у блоці `if (import.meta.main)` — це робить `bun rules/<id>/check.mjs` повним
4
4
  * еквівалентом `npx \@nitra/cursor fix <id>`: друкує summary, повертає aggregated exit-code.
5
5
  *
6
6
  * **Без whitelist-гейту.** Гейтинг активних правил — єдине джерело: `resolveCheckRuleIds`
7
- * (`scripts/lib/fix/run-fix-check.mjs`) за `.n-cursor.json`. Прямий `bun rules/<id>/fix.mjs` —
7
+ * (`scripts/lib/fix/run-conformance-check.mjs`) за `.n-cursor.json`. Прямий `bun rules/<id>/check.mjs` —
8
8
  * свідомий запуск саме цього правила (debug / override), тож виконується беззастережно;
9
9
  * усі автоматичні шляхи (lint-конформність, orchestrator, t0, hook) уже спавнять лише активні.
10
10
  *
@@ -15,7 +15,7 @@ import { basename } from 'node:path'
15
15
  import { runStandardRule } from './run-standard-rule.mjs'
16
16
  import { getOrCreateWalkCache } from '../utils/walk-cache.mjs'
17
17
 
18
- // Re-export для зворотної сумісності: уся `rules/<id>/fix.mjs` уже імпортує `isRunAsCli`
18
+ // Re-export для зворотної сумісності: уся `rules/<id>/check.mjs` уже імпортує `isRunAsCli`
19
19
  // саме звідси. Канонічна реалізація — у `scripts/cli-entry.mjs`. Caller передає
20
20
  // `import.meta.url`: `if (isRunAsCli(import.meta.url)) …`.
21
21
  export { isRunAsCli } from '../cli-entry.mjs'
@@ -7,29 +7,42 @@
7
7
  * патчилися в кожному `rules/<rule>/lint/lint.mjs`.
8
8
  *
9
9
  * Зараз робить рівно одне: серіалізує + дедуплікує запуски через `withLock('lint-<ruleId>')`.
10
- * `ruleId` виводиться зі шляху: `import.meta.dirname` у `rules/<id>/lint/lint.mjs` → `<id>`.
10
+ * `ruleId` виводиться зі шляху незалежно від глибини виклику: `rules/<id>` (з `main.mjs`),
11
+ * `rules/<id>/js` або `rules/<id>/lint` → `<id>` (сегмент одразу після `rules/`).
11
12
  *
12
13
  * Інтеграція з боку правила:
13
14
  *
14
15
  * ```js
15
- * import { runStandardLint } from '../../../scripts/lib/run-standard-lint.mjs'
16
+ * import { runStandardLint } from '../../scripts/lib/run-standard-lint.mjs'
16
17
  *
17
18
  * async function runLintFooSteps() { ... }
18
19
  *
19
- * export const runLintFooCli = () => runStandardLint(import.meta.dirname, runLintFooSteps)
20
+ * export function lint(_files) { return runStandardLint(import.meta.dirname, runLintFooSteps) }
20
21
  * ```
21
22
  */
22
- import { basename, dirname } from 'node:path'
23
+ import { basename } from 'node:path'
23
24
 
24
25
  import { withLock } from '../utils/with-lock.mjs'
25
26
 
26
27
  /**
27
- * @param {string} lintDir абсолютний шлях до `rules/<id>/lint/` (передавай `import.meta.dirname`)
28
+ * Виводить `<id>` зі шляху каталогу правила незалежно від глибини: сегмент одразу після
29
+ * останнього `rules/`. Fallback — `basename(dir)`, якщо `rules/` у шляху немає.
30
+ * @param {string} dir абсолютний шлях каталогу (`rules/<id>`, `rules/<id>/js`, …)
31
+ * @returns {string} rule-id
32
+ */
33
+ function ruleIdFromDir(dir) {
34
+ const parts = dir.split(/[/\\]/u)
35
+ const i = parts.lastIndexOf('rules')
36
+ return i !== -1 && parts[i + 1] ? parts[i + 1] : basename(dir)
37
+ }
38
+
39
+ /**
40
+ * @param {string} lintDir абсолютний шлях до каталогу правила (передавай `import.meta.dirname`)
28
41
  * @param {() => number | Promise<number>} stepsFn реальна робота лінту; повертає код виходу
29
42
  * @param {{ttl?:number, staleThreshold?:number, waitTimeout?:number, pollInterval?:number, cacheDir?:string, getFingerprint?:() => string | null}} [opts] прокидаються у `withLock`
30
43
  * @returns {Promise<number>} код виходу
31
44
  */
32
45
  export function runStandardLint(lintDir, stepsFn, opts) {
33
- const ruleId = basename(dirname(lintDir))
46
+ const ruleId = ruleIdFromDir(lintDir)
34
47
  return withLock(`lint-${ruleId}`, stepsFn, opts)
35
48
  }
@@ -1,14 +1,14 @@
1
1
  /**
2
- * Public API per-rule orchestration. Викликається з `rules/<id>/fix.mjs`.
2
+ * Public API per-rule orchestration. Викликається з `rules/<id>/check.mjs`.
3
3
  *
4
4
  * Інкапсулює: `discoverOneRule` → `runRule(applies → JS → policy → mdc-refs)`.
5
5
  * Локальна логіка в правилах заборонена; розширення поведінки — через `ctx`-опції.
6
6
  *
7
7
  * Серіалізація: загортає виконання у `withLock('fix-<ruleId>')` — паралельні запуски
8
- * того самого правила (через `npx \@nitra/cursor fix`, прямий `bun rules/<id>/fix.mjs`
8
+ * того самого правила (через `npx \@nitra/cursor fix`, прямий `bun rules/<id>/check.mjs`
9
9
  * чи `run(ctx)`-композицію) дедупляться за станом git-дерева; різні правила можуть
10
10
  * виконуватись паралельно. Точка інтеграції — тут, щоб не дублювати лок у кожному
11
- * `fix.mjs`.
11
+ * `check.mjs`.
12
12
  */
13
13
  import { basename, dirname } from 'node:path'
14
14
 
@@ -24,7 +24,7 @@ import { withLock } from '../utils/with-lock.mjs'
24
24
  * Зарезервовано на майбутнє (поки не реалізовано — додається, коли з'явиться потреба):
25
25
  * - `skipMdcRefs`, `skipApplies`, `onlyConcerns`.
26
26
  * Розширення поведінки правила робиться лише через нові поля тут, не через локальну
27
- * логіку в `rules/<id>/fix.mjs`.
27
+ * логіку в `rules/<id>/check.mjs`.
28
28
  */
29
29
 
30
30
  /**
@@ -2,7 +2,7 @@
2
2
  * Формат таблиці-резюме часу виконання для orchestrator `fix` / `lint`.
3
3
  *
4
4
  * Дві спільні точки використання:
5
- * - `runFixCommand` у `bin/n-cursor.js` — після прогону всіх `rules/<id>/fix.mjs`.
5
+ * - `runFixCommand` у `bin/n-cursor.js` — після прогону всіх `rules/<id>/check.mjs`.
6
6
  * - `runLintCli` у `scripts/lib/run-lint-cli.mjs` — після прогону `lint-*` скриптів з кореневого `package.json`.
7
7
  *
8
8
  * Чиста функція без I/O — повертає готовий рядок (з фінальним `\n`), друк — на стороні виклику.
@@ -4,17 +4,17 @@
4
4
  *
5
5
  * Раніше хук маршрутизував змінений файл у релевантні правила й ганяв повний `fix` (автофікс
6
6
  * + LLM) — дорого, тож звужували. Тепер хук — **детект** (нуль мутацій, нуль LLM), тож роутинг
7
- * зайвий: один виклик `_fix-check` (per-rule `fix.mjs run()` = перевірка) по всіх правилах.
7
+ * зайвий: один виклик `_fix-check` (per-rule `check.mjs run()` = перевірка) по всіх правилах.
8
8
  *
9
9
  * Контракт:
10
10
  * - stdin Claude Code: JSON із `tool_input.file_path`; якщо файлу немає (напр. Bash) — exit 0 (skip);
11
- * - інакше пряма `runFixCheck` (детект усіх правил, без subprocess-обгортки), exit-код прозоро:
11
+ * - інакше пряма `runConformanceCheck` (детект усіх правил, без subprocess-обгортки), exit-код прозоро:
12
12
  * 1 — є порушення конформності (PostToolUse не блокує turn, але код лишаємо інформативним).
13
13
  */
14
14
  import { once } from 'node:events'
15
15
  import { cwd as processCwd } from 'node:process'
16
16
 
17
- import { runFixCheck } from './lib/fix/run-fix-check.mjs'
17
+ import { runConformanceCheck } from './lib/fix/run-conformance-check.mjs'
18
18
 
19
19
  /**
20
20
  * Зчитує stdin до EOF як utf8 рядок. На TTY — повертає `''` одразу.
@@ -57,20 +57,20 @@ export function extractFilePath(stdinJson) {
57
57
  }
58
58
 
59
59
  /**
60
- * Точка входу. Викликається з `bin/n-cursor.js` коли argv[0] === `post-tool-use-fix`.
60
+ * Точка входу. Викликається з `bin/n-cursor.js` коли argv[0] === `post-tool-use-check`.
61
61
  * Параметри доступні для інʼєкції для тестів: `stdinJson` обходить read від `process.stdin`,
62
- * `runFixCheckFn` — заміна `runFixCheck`.
63
- * @param {{ stdinJson?: string, runFixCheckFn?: typeof runFixCheck }} [options] параметри для тестів
62
+ * `runConformanceCheckFn` — заміна `runConformanceCheck`.
63
+ * @param {{ stdinJson?: string, runConformanceCheckFn?: typeof runConformanceCheck }} [options] параметри для тестів
64
64
  * @returns {Promise<number>} exit code (0 — пропущено / конформність ОК; 1 — є порушення)
65
65
  */
66
- export async function runPostToolUseFixCli(options = {}) {
66
+ export async function runPostToolUseCheckCli(options = {}) {
67
67
  const stdinJson = options.stdinJson ?? (await readStdin())
68
68
  const filePath = extractFilePath(stdinJson)
69
69
  // Тільки після редагування файлу (Edit/Write/MultiEdit мають file_path); Bash тощо — skip.
70
70
  if (filePath === null) {
71
71
  return 0
72
72
  }
73
- const check = options.runFixCheckFn ?? runFixCheck
73
+ const check = options.runConformanceCheckFn ?? runConformanceCheck
74
74
  // Один read-only детект конформності всіх активованих правил (пряма функція, без subprocess).
75
75
  try {
76
76
  const { failed, rules } = await check([], processCwd())
@@ -80,7 +80,7 @@ export async function runPostToolUseFixCli(options = {}) {
80
80
  }
81
81
  return 1
82
82
  } catch (error) {
83
- process.stderr.write(`post-tool-use-fix: не вдалося запустити детект конформності — ${error.message}\n`)
83
+ process.stderr.write(`post-tool-use-check: не вдалося запустити детект конформності — ${error.message}\n`)
84
84
  return 1
85
85
  }
86
86
  }
@@ -30,8 +30,8 @@ import { existsSync } from 'node:fs'
30
30
  import { chmod, mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises'
31
31
  import { join } from 'node:path'
32
32
 
33
- /** Маркер PostToolUse fix-hook'а (`npx --no \@nitra/cursor post-tool-use-fix`). */
34
- export const MANAGED_HOOK_COMMAND_MARKER = '@nitra/cursor post-tool-use-fix'
33
+ /** Маркер PostToolUse fix-hook'а (`npx --no \@nitra/cursor post-tool-use-check`). */
34
+ export const MANAGED_HOOK_COMMAND_MARKER = '@nitra/cursor post-tool-use-check'
35
35
  /** Маркер doc-files staleness-hook'ів (PostToolUse `--hook` і Stop-гейт `--git`). */
36
36
  export const DOC_FILES_HOOK_COMMAND_MARKER = '@nitra/cursor lint-doc-files'
37
37
  /** Legacy-маркер старих doc-files hook'ів (`doc-files check`) — cleanup при ресинку наявних інсталяцій. */
@@ -1,18 +0,0 @@
1
- import { isRunAsCli, runRuleCli } from '../../scripts/lib/run-rule-cli.mjs'
2
- import { runStandardRule } from '../../scripts/lib/run-standard-rule.mjs'
3
-
4
- /**
5
- * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
6
- * Library mode: викликається CLI orchestration через `import + run(ctx)`.
7
- * @param {import('../../scripts/lib/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
8
- * @returns {Promise<number>} 0 — OK, 1 — порушення
9
- */
10
- export function run(ctx) {
11
- return runStandardRule(import.meta.dirname, ctx)
12
- }
13
-
14
- if (isRunAsCli(import.meta.url)) {
15
- // Standalone: bun rules/<id>/fix.mjs — повний еквівалент `npx @nitra/cursor fix <id>`
16
- // (config-loading + whitelist + summary). Дві ролі fix.mjs: library (run) + standalone (main).
17
- process.exitCode = await runRuleCli(import.meta.dirname)
18
- }
package/rules/ci4/fix.mjs DELETED
@@ -1,18 +0,0 @@
1
- import { isRunAsCli, runRuleCli } from '../../scripts/lib/run-rule-cli.mjs'
2
- import { runStandardRule } from '../../scripts/lib/run-standard-rule.mjs'
3
-
4
- /**
5
- * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
6
- * Library mode: викликається CLI orchestration через `import + run(ctx)`.
7
- * @param {import('../../scripts/lib/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
8
- * @returns {Promise<number>} 0 — OK, 1 — порушення
9
- */
10
- export function run(ctx) {
11
- return runStandardRule(import.meta.dirname, ctx)
12
- }
13
-
14
- if (isRunAsCli(import.meta.url)) {
15
- // Standalone: bun rules/<id>/fix.mjs — повний еквівалент `npx @nitra/cursor fix <id>`
16
- // (config-loading + whitelist + summary). Дві ролі fix.mjs: library (run) + standalone (main).
17
- process.exitCode = await runRuleCli(import.meta.dirname)
18
- }
@@ -1,19 +0,0 @@
1
- import { isRunAsCli, runRuleCli } from '../../scripts/lib/run-rule-cli.mjs'
2
- import { runStandardRule } from '../../scripts/lib/run-standard-rule.mjs'
3
-
4
- /**
5
- * Запускає правило doc-files: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
6
- * Структурні concerns (наявність workflow lint-doc-files.yml, скрипт у package.json) закриває
7
- * policy-канал; контентні порушення (відсутні/застарілі доки) — поза `n-cursor fix`, їх закриває
8
- * `fix-doc-files` (генерація). Library mode: викликається через `import + run(ctx)`.
9
- * @param {import('../../scripts/lib/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону
10
- * @returns {Promise<number>} 0 — OK, 1 — порушення
11
- */
12
- export function run(ctx) {
13
- return runStandardRule(import.meta.dirname, ctx)
14
- }
15
-
16
- if (isRunAsCli(import.meta.url)) {
17
- // Standalone: bun rules/doc-files/fix.mjs — еквівалент `npx @nitra/cursor fix doc-files`.
18
- process.exitCode = await runRuleCli(import.meta.dirname)
19
- }
@@ -1,34 +0,0 @@
1
- ---
2
- type: JS Module
3
- title: lint.mjs
4
- resource: npm/rules/doc-files/js/lint.mjs
5
- docgen:
6
- crc: ca055f8f
7
- score: 100
8
- ---
9
-
10
- Адаптер правила doc-files до агрегатора `n-cursor lint`. Дає агрегатору відповідь на одне
11
- питання: чи має кожен дотичний кодовий файл актуальну файлову документацію поряд із собою.
12
-
13
- ## Поведінка
14
-
15
- У quick-фазі отримує список змінених файлів і зводить його до набору джерел для перевірки в
16
- **обидва** боки: змінене джерело перевіряється проти своєї доки, а змінена або видалена дока
17
- (`<dir>/docs/<stem>.md`) повертається до відповідного джерела з тим самим іменем у каталозі над
18
- `docs/`. У ci-фазі (списку немає) обходить усе дерево.
19
-
20
- Порушенням вважається відсутня дока (`missing`) або розбіжність контрольної суми джерела з тією,
21
- що записана у frontmatter доки (`crc-mismatch`). Документ із низькою якістю, але свіжою сумою —
22
- не порушення.
23
-
24
- ## Публічний API
25
-
26
- `lint` — перевіряє документацію для переданого набору змінених файлів (або всього репозиторію,
27
- якщо набір не задано); повертає код виходу `1`, якщо є застарілі чи відсутні доки, інакше `0`.
28
- Список проблемних файлів друкується у stderr із підказкою регенерувати.
29
-
30
- ## Гарантії поведінки
31
-
32
- - Детермінованість: жодного виклику мовної моделі, рішення лише за контрольною сумою.
33
- - Реверс-мапінг доки до джерела перебирає лише кодові розширення і повертає наявний файл-кандидат.
34
- - Порожній набір змінених файлів дає код `0` без обходу дерева.
@@ -1,11 +0,0 @@
1
- ---
2
- type: Directory Index
3
- title: npm/rules/doc-files/lint
4
- resource: npm/rules/doc-files/lint/
5
- ---
6
-
7
- # npm/rules/doc-files/lint
8
-
9
- | Файл | Тип |
10
- |---|---|
11
- | [lint.mjs](lint.md) | JS Module |
@@ -1,35 +0,0 @@
1
- ---
2
- type: JS Module
3
- title: lint.mjs
4
- resource: npm/rules/doc-files/lint/lint.mjs
5
- docgen:
6
- crc: a30dd81f
7
- score: 100
8
- ---
9
-
10
- CLI-команда `lint-doc-files` — детермінований детектор застарілості файлових док. Працює без
11
- мовної моделі скрізь: локально, в hook'ах і в CI.
12
-
13
- ## Поведінка
14
-
15
- Без прапорців або з переліком шляхів робить повний чи точковий детект і повертає код `1`, якщо є
16
- застарілі/відсутні доки. `--missing-only` звужує до самих відсутніх. `--json` друкує машинний
17
- лістинг усіх кандидатів зі станом і завершується кодом `0`. Режими `--hook`, `--git` і
18
- `--degraded` делегуються детектору hook-протоколу (PostToolUse за одним файлом зі stdin, Stop-гейт
19
- за зміненими у задачі джерелами з порогом, інформаційний звіт про доки нижчої якості).
20
-
21
- Повний прогін серіалізується спільним локом під ключем, виведеним зі шляху каталогу, тож паралельні
22
- запуски не накладаються; hook-форми навмисно виконуються без локу заради завжди-свіжого вердикту.
23
-
24
- ## Публічний API
25
-
26
- `runLintDocFilesCli` — точка входу команди: маршрутизує між делегатом hook-протоколу, JSON-лістингом
27
- і повним/точковим детектом; повертає код виходу.
28
- `runLintDocFilesSteps` — сама робота повного чи точкового детекту, придатна для прямого виклику з
29
- тестів без локу; повертає `1` за наявності застарілих док, інакше `0`.
30
-
31
- ## Гарантії поведінки
32
-
33
- - Неіснуючий корінь дає зрозумілу помилку і код `1`.
34
- - Повний прогін — код `1` (конвенція `lint-*`); hook/git — код `2` (blocking feedback для Claude Code).
35
- - Жодних викликів мовної моделі.
@@ -1,18 +0,0 @@
1
- import { isRunAsCli, runRuleCli } from '../../scripts/lib/run-rule-cli.mjs'
2
- import { runStandardRule } from '../../scripts/lib/run-standard-rule.mjs'
3
-
4
- /**
5
- * Запускає правило: applies → JS-concerns → policy → mdc-refs (через runStandardRule).
6
- * Library mode: викликається CLI orchestration через `import + run(ctx)`.
7
- * @param {import('../../scripts/lib/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
8
- * @returns {Promise<number>} 0 — OK, 1 — порушення
9
- */
10
- export function run(ctx) {
11
- return runStandardRule(import.meta.dirname, ctx)
12
- }
13
-
14
- if (isRunAsCli(import.meta.url)) {
15
- // Standalone: bun rules/<id>/fix.mjs — повний еквівалент `npx @nitra/cursor fix <id>`
16
- // (config-loading + whitelist + summary). Дві ролі fix.mjs: library (run) + standalone (main).
17
- process.exitCode = await runRuleCli(import.meta.dirname)
18
- }
@@ -1,11 +0,0 @@
1
- ---
2
- type: Directory Index
3
- title: npm/rules/docker/lint
4
- resource: npm/rules/docker/lint/
5
- ---
6
-
7
- # npm/rules/docker/lint
8
-
9
- | Файл | Тип |
10
- |---|---|
11
- | [lint.mjs](lint.md) | JS Module |