@nitra/cursor 12.6.0 → 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 (269) hide show
  1. package/.claude-template/settings.template.json +1 -1
  2. package/CHANGELOG.md +16 -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/text/text.mdc +5 -14
  141. package/rules/tool-surface/docs/index.md +1 -0
  142. package/rules/tool-surface/docs/main.md +29 -0
  143. package/rules/tool-surface/main.mjs +20 -0
  144. package/rules/vue/docs/index.md +1 -0
  145. package/rules/vue/docs/main.md +29 -0
  146. package/rules/vue/main.mjs +20 -0
  147. package/rules/worktree/docs/index.md +1 -0
  148. package/rules/worktree/docs/main.md +28 -0
  149. package/rules/worktree/main.mjs +20 -0
  150. package/scripts/docs/index.md +1 -0
  151. package/scripts/docs/post-tool-use-check.md +29 -0
  152. package/scripts/docs/sync-claude-config.md +64 -92
  153. package/scripts/lib/adr/docs/normalize-cli.md +0 -3
  154. package/scripts/lib/adr/docs/normalize-pipeline.md +0 -3
  155. package/scripts/lib/docs/gha-workflow.md +25 -317
  156. package/scripts/lib/docs/index.md +1 -0
  157. package/scripts/lib/docs/list-project-rules-mdc.md +5 -4
  158. package/scripts/lib/docs/list-rule-ids.md +15 -148
  159. package/scripts/lib/docs/read-n-cursor-config-lite.md +12 -16
  160. package/scripts/lib/docs/run-lint-step.md +13 -13
  161. package/scripts/lib/docs/run-lint.md +30 -0
  162. package/scripts/lib/docs/run-rule-cli.md +14 -10
  163. package/scripts/lib/docs/run-standard-lint.md +27 -10
  164. package/scripts/lib/docs/run-standard-rule.md +12 -11
  165. package/scripts/lib/docs/timing-summary.md +11 -12
  166. package/scripts/lib/docs/worktree-notice.md +0 -3
  167. package/scripts/lib/fix/docs/index.md +1 -0
  168. package/scripts/lib/fix/docs/orchestrator.md +23 -18
  169. package/scripts/lib/fix/docs/run-conformance-check.md +32 -0
  170. package/scripts/lib/fix/docs/t0.md +10 -9
  171. package/scripts/lib/fix/orchestrator.mjs +5 -5
  172. package/scripts/lib/fix/{run-fix-check.mjs → run-conformance-check.mjs} +13 -13
  173. package/scripts/lib/fix/t0.mjs +3 -3
  174. package/scripts/lib/gha-workflow.mjs +1 -1
  175. package/scripts/lib/list-project-rules-mdc.mjs +1 -1
  176. package/scripts/lib/list-rule-ids.mjs +12 -3
  177. package/scripts/lib/read-n-cursor-config-lite.mjs +2 -2
  178. package/scripts/lib/run-lint-step.mjs +1 -1
  179. package/{rules/lint/js/orchestrate.mjs → scripts/lib/run-lint.mjs} +42 -20
  180. package/scripts/lib/run-rule-cli.mjs +4 -4
  181. package/scripts/lib/run-standard-lint.mjs +19 -6
  182. package/scripts/lib/run-standard-rule.mjs +4 -4
  183. package/scripts/lib/timing-summary.mjs +1 -1
  184. package/scripts/{post-tool-use-fix.mjs → post-tool-use-check.mjs} +9 -9
  185. package/scripts/sync-claude-config.mjs +2 -2
  186. package/rules/changelog/fix.mjs +0 -18
  187. package/rules/ci4/fix.mjs +0 -18
  188. package/rules/doc-files/fix.mjs +0 -19
  189. package/rules/doc-files/js/docs/lint.md +0 -34
  190. package/rules/doc-files/lint/docs/index.md +0 -11
  191. package/rules/doc-files/lint/docs/lint.md +0 -35
  192. package/rules/docker/fix.mjs +0 -18
  193. package/rules/docker/lint/docs/index.md +0 -11
  194. package/rules/docker/lint/docs/lint.md +0 -200
  195. package/rules/docker/lint/lint.mjs +0 -95
  196. package/rules/efes/fix.mjs +0 -18
  197. package/rules/feedback/fix.mjs +0 -18
  198. package/rules/ga/fix.mjs +0 -18
  199. package/rules/ga/js/docs/lint.md +0 -20
  200. package/rules/ga/js/lint.mjs +0 -12
  201. package/rules/ga/lint/docs/index.md +0 -11
  202. package/rules/ga/lint/docs/lint.md +0 -31
  203. package/rules/graphql/fix.mjs +0 -18
  204. package/rules/hasura/fix.mjs +0 -18
  205. package/rules/image-avif/fix.mjs +0 -18
  206. package/rules/image-compress/fix.mjs +0 -18
  207. package/rules/image-compress/js/docs/lint.md +0 -24
  208. package/rules/js-bun-db/fix.mjs +0 -18
  209. package/rules/js-bun-redis/fix.mjs +0 -18
  210. package/rules/js-lint/fix.mjs +0 -18
  211. package/rules/js-lint/js/docs/lint.md +0 -32
  212. package/rules/js-lint-ci/fix.mjs +0 -18
  213. package/rules/js-lint-ci/js/docs/lint.md +0 -22
  214. package/rules/js-lint-ci/js/lint.mjs +0 -15
  215. package/rules/js-mssql/fix.mjs +0 -18
  216. package/rules/js-run/fix.mjs +0 -18
  217. package/rules/k8s/fix.mjs +0 -18
  218. package/rules/k8s/js/lint.mjs +0 -14
  219. package/rules/k8s/lint/docs/index.md +0 -11
  220. package/rules/k8s/lint/docs/lint.md +0 -413
  221. package/rules/lint/docs/fix.md +0 -25
  222. package/rules/lint/docs/index.md +0 -11
  223. package/rules/lint/fix.mjs +0 -18
  224. package/rules/lint/js/docs/index.md +0 -11
  225. package/rules/lint/js/docs/orchestrate.md +0 -31
  226. package/rules/lint/meta.json +0 -1
  227. package/rules/nginx-default-tpl/fix.mjs +0 -18
  228. package/rules/npm-module/fix.mjs +0 -18
  229. package/rules/php/fix.mjs +0 -18
  230. package/rules/php/js/docs/lint.md +0 -20
  231. package/rules/php/js/lint.mjs +0 -15
  232. package/rules/php/lint/docs/index.md +0 -11
  233. package/rules/php/lint/docs/lint.md +0 -219
  234. package/rules/python/fix.mjs +0 -18
  235. package/rules/python/js/docs/lint.md +0 -21
  236. package/rules/python/js/lint.mjs +0 -14
  237. package/rules/python/lint/docs/index.md +0 -11
  238. package/rules/python/lint/docs/lint.md +0 -29
  239. package/rules/rego/fix.mjs +0 -18
  240. package/rules/rego/js/docs/lint.md +0 -21
  241. package/rules/rego/js/lint.mjs +0 -12
  242. package/rules/rego/lint/docs/index.md +0 -11
  243. package/rules/rego/lint/docs/lint.md +0 -208
  244. package/rules/rust/fix.mjs +0 -18
  245. package/rules/rust/js/docs/lint.md +0 -21
  246. package/rules/security/fix.mjs +0 -18
  247. package/rules/security/js/docs/lint.md +0 -175
  248. package/rules/security/js/lint.mjs +0 -26
  249. package/rules/style-lint/fix.mjs +0 -18
  250. package/rules/style-lint/js/docs/lint.md +0 -31
  251. package/rules/tauri/fix.mjs +0 -18
  252. package/rules/test/fix.mjs +0 -18
  253. package/rules/text/fix.mjs +0 -18
  254. package/rules/text/js/docs/lint.md +0 -23
  255. package/rules/text/js/lint.mjs +0 -15
  256. package/rules/text/lint/docs/cspell-fix.md +0 -32
  257. package/rules/text/lint/docs/index.md +0 -15
  258. package/rules/text/lint/docs/lint.md +0 -36
  259. package/rules/text/lint/docs/run-dotenv-linter.md +0 -161
  260. package/rules/text/lint/docs/run-shellcheck.md +0 -216
  261. package/rules/text/lint/docs/run-v8r.md +0 -201
  262. package/rules/tool-surface/fix.mjs +0 -18
  263. package/rules/vue/fix.mjs +0 -18
  264. package/rules/worktree/fix.mjs +0 -18
  265. /package/rules/release/{fix.mjs → main.mjs} +0 -0
  266. /package/rules/text/{lint → js}/cspell-fix.mjs +0 -0
  267. /package/rules/text/{lint → js}/run-dotenv-linter.mjs +0 -0
  268. /package/rules/text/{lint → js}/run-shellcheck.mjs +0 -0
  269. /package/rules/text/{lint → js}/run-v8r.mjs +0 -0
@@ -2,7 +2,19 @@
2
2
  import { join, dirname, basename, extname } from 'node:path'
3
3
  import { existsSync, readdirSync } from 'node:fs'
4
4
 
5
- import { describeFile, isDocCandidate, isSourceFile, scanForDocFiles } from './docgen-scan.mjs'
5
+ import { describeFile, isDocCandidate, isSourceFile, scanForDocFiles, scanOrphanedDocs } from './js/docgen-scan.mjs'
6
+ import { isRunAsCli, runRuleCli } from '../../scripts/lib/run-rule-cli.mjs'
7
+ import { runStandardRule } from '../../scripts/lib/run-standard-rule.mjs'
8
+
9
+ /**
10
+ * Єдиний entrypoint правила (ADR 2026-06-21). `run()` — check-поверхня (applies → JS-concerns
11
+ * → policy → mdc-refs); `lint()` нижче — lint-поверхня (детект застарілих файлових док), імпл інлайн тут.
12
+ * @param {import('../../scripts/lib/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону
13
+ * @returns {Promise<number>} 0 — OK, 1 — порушення
14
+ */
15
+ export function run(ctx) {
16
+ return runStandardRule(import.meta.dirname, ctx)
17
+ }
6
18
 
7
19
  /** Дока живе у `<dir>/docs/<stem>.md`; повертає `<dir>/<stem>` для реверс-мапінгу. */
8
20
  const DOC_MD_RE = /(?:^|\/)docs\/[^/]+\.md$/u
@@ -89,14 +101,52 @@ function collectStale(files, cwd) {
89
101
  */
90
102
  export async function lint(files, cwd = process.cwd(), { readOnly = false, llmFix = false } = {}) {
91
103
  const stale = collectStale(files, cwd)
92
- if (stale.length === 0) return 0
93
- if (readOnly || !llmFix) return reportStale(stale)
104
+ // Orphan-детект тільки при повному скані; при точковому (files визначено) не релевантно
105
+ const orphans = files === undefined ? scanOrphanedDocs(cwd) : []
106
+
107
+ if (stale.length === 0 && orphans.length === 0) return 0
108
+ if (readOnly || !llmFix) {
109
+ if (stale.length > 0) reportStale(stale)
110
+ if (orphans.length > 0) {
111
+ const list = orphans.map(f => ` - ${f}`).join('\n')
112
+ process.stderr.write(
113
+ `✗ doc-files: сирітських доків (source видалено) ${orphans.length}:\n${list}\n→ очисти: npx @nitra/cursor fix-doc-files\n`
114
+ )
115
+ }
116
+ return 1
117
+ }
118
+
119
+ // fix-by-default: opportunistic-генерація stale + purge orphans.
120
+ // omlx недоступний → runGenerationBatch друкує причину й повертає !=0;
121
+ // purgeOrphanedDocs не залежить від LLM і виконується завжди.
122
+ if (stale.length > 0) {
123
+ process.stdout.write(`ℹ️ doc-files: ${stale.length} застарілих — пробую авто-фікс (omlx)…\n`)
124
+ }
125
+ const { runGenerationBatch, purgeOrphanedDocs } = await import('./js/docgen-files-batch.mjs')
126
+ if (stale.length > 0) {
127
+ await runGenerationBatch(stale, cwd, { headline: `📋 doc-files: генерація ${stale.length} файл(ів)` })
128
+ }
129
+ if (orphans.length > 0) {
130
+ const deleted = purgeOrphanedDocs(cwd)
131
+ if (deleted > 0) process.stdout.write(`🗑 doc-files: видалено ${deleted} сирітських доки(ів)\n`)
132
+ }
133
+
134
+ const stillStale = collectStale(files, cwd)
135
+ const stillOrphans = files === undefined ? scanOrphanedDocs(cwd) : []
136
+ if (stillStale.length === 0 && stillOrphans.length === 0) return 0
137
+ if (stillStale.length > 0) reportStale(stillStale)
138
+ if (stillOrphans.length > 0) {
139
+ const list = stillOrphans.map(f => ` - ${f}`).join('\n')
140
+ process.stderr.write(
141
+ `✗ doc-files: сирітських доків (source видалено) ${stillOrphans.length}:\n${list}\n→ очисти: npx @nitra/cursor fix-doc-files\n`
142
+ )
143
+ }
144
+ return 1
145
+ }
146
+
147
+ export { runLintDocFilesCli } from './js/run-lint.mjs'
94
148
 
95
- // fix-by-default: opportunistic-генерація через спільне ядро (preflight omlx →
96
- // батч із circuit-breaker'ом). omlx недоступний runGenerationBatch друкує причину
97
- // й повертає !=0; ми re-detect'имо й через reportStale віддаємо exit 1 (гейт тримається).
98
- process.stdout.write(`ℹ️ doc-files: ${stale.length} застарілих — пробую авто-фікс (omlx)…\n`)
99
- const { runGenerationBatch } = await import('./docgen-files-batch.mjs')
100
- await runGenerationBatch(stale, cwd, { headline: `📋 doc-files: генерація ${stale.length} файл(ів)` })
101
- return reportStale(collectStale(files, cwd))
149
+ if (isRunAsCli(import.meta.url)) {
150
+ // Standalone: bun rules/doc-files/main.mjs повний еквівалент `npx @nitra/cursor check doc-files`.
151
+ process.exitCode = await runRuleCli(import.meta.dirname)
102
152
  }
@@ -9,3 +9,4 @@ resource: npm/rules/docker/
9
9
  | Файл | Тип |
10
10
  |---|---|
11
11
  | [fix.mjs](fix.md) | JS Module |
12
+ | [main.mjs](main.md) | JS Module |
@@ -0,0 +1,28 @@
1
+ ---
2
+ type: JS Module
3
+ title: main.mjs
4
+ resource: npm/rules/docker/main.mjs
5
+ docgen:
6
+ crc: 10e84989
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 100
9
+ ---
10
+
11
+ ## Огляд
12
+
13
+ Модуль виконує перевірку на відповідність логіці JS-зацікавленостей, політикам та посиланням MDC. Запуск правила ініціюється через публічну функцію `run`.
14
+
15
+ ## Поведінка
16
+
17
+ 1. Викликається функція `run` для виконання перевірки.
18
+ 2. Виконання перевірки застосовує логіку, пов'язану з JS-зацікавленостями, політиками та посиланнями MDC.
19
+ 3. Якщо скрипт виконується як окрема утиліта, ініціюється повний запуск правила.
20
+
21
+ ## Публічний API
22
+
23
+ run — виконує послідовність перевірок: застосовує логіку, перевіряє аспекти JavaScript, застосовує політику та посилання MDC.
24
+ lint — виконує перевірку синтаксису та стилю коду, делегуючи складну логіку зовнішньому модулю.
25
+
26
+ ## Гарантії поведінки
27
+
28
+ - Read-only: не виконує операцій запису (ФС/БД).
@@ -3,70 +3,42 @@ type: JS Module
3
3
  title: lint.mjs
4
4
  resource: npm/rules/docker/js/lint.mjs
5
5
  docgen:
6
- crc: 495d03ee
6
+ crc: bf935f19
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
7
8
  score: 100
8
9
  ---
9
10
 
10
- Модуль забезпечує декомпозицію структури Dockerfile для вилучення даних про багатостадійні збірки та залежності середовища. Функції, такі як `findDockerfilePaths` та `splitDockerfileStages`, використовуються для ідентифікації та розділення стадій збірки. Модуль надає інструменти для отримання підказок про виконання, включаючи визначення багатостадійного режиму (`getMultistageAndRuntimeHint`), компіляційних налаштувань (`getBunCompileHint`), та підказок про використання образу Nginx Alpine Slim (`getNginxAlpineSlimTagHint`). Додатково, він визначає необхідність роботи без прав root (`getNonRootRuntimeHint`). (docker.mdc)
11
+ ## Огляд
11
12
 
12
- ## Поведінка
13
-
14
- isDockerfileName
15
- Перевіряє, чи є вхідний рядок назвою Dockerfile або Containerfile.
16
-
17
- findDockerfilePaths
18
- Збирає абсолютні шляхи до Dockerfile або Containerfile від заданого кореня репозиторію, враховуючи виключені шляхи.
19
-
20
- parseFromStages
21
- Витягує інструкції FROM з вмісту файлу.
22
-
23
- splitDockerfileStages
24
- Розбиває вміст Dockerfile на окремі стадії на основі інструкцій FROM.
25
-
26
- getMultistageAndRuntimeHint
27
- Перевіряє, чи має Dockerfile мінімум дві інструкції FROM і чи є фінальний образ дозволеним runtime-образом (docker.mdc).
13
+ Модуль аналізує файли `Dockerfile` та `Containerfile` у репозиторії, використовуючи `isDockerfileName` та `findDockerfilePaths` для ідентифікації конфігурацій. Він розбиває знайдені файли на етапи за допомогою `parseFromStages` та `splitDockerfileStages`. Модуль перевіряє конфігурацію, використовуючи `check` та `lint`, щоб оцінити відповідність стандартам, враховуючи дані з `package.json`. Він визначає інформацію про багатоетапну збірку, теги образів та права користувача, відповідно до вимог (docker.mdc).
28
14
 
29
- getBunCompileHint
30
- Перевіряє наявність інструкцій `bun install` та відсутності `bun build --compile` для виявлення необхідності компіляції бінарника (docker.mdc).
31
-
32
- getNginxAlpineSlimTagHint
33
- Перевіряє, чи містить інструкція FROM для образу nginx потрібний тег `alpine-slim` (docker.mdc).
34
-
35
- getNonRootRuntimeHint
36
- Перевіряє, чи присутня інструкція USER у фінальній стадії і чи не використовується `root` або `0` для запуску (docker.mdc).
37
-
38
- check
39
- Запускає перевірки Dockerfile через hadolint, включаючи перевірки multistage, компіляції, non-root, тегів nginx та загальну валідацію.
40
-
41
- readNearestDependencies
42
- Читає залежності з найближчого package.json, розташованого у каталогах Dockerfile або вище.
15
+ ## Поведінка
43
16
 
44
- checkDockerfile
45
- Перевіряє індивідуальний Dockerfile/Containerfile на наявність інструкцій, пов'язаних з mirror.gcr.io, multistage, компіляції, non-root, тегів nginx та виконує перевірку через hadolint.
17
+ isDockerfileName визначає, чи є наданий шлях назвою Dockerfile або Containerfile.
18
+ findDockerfilePaths збирає відсортований список абсолютних шляхів до всіх Dockerfile/Containerfile, ігноруючи вказані шляхи каталогів.
19
+ parseFromStages витягує список усіх інструкцій `FROM <image>` з вмісту Dockerfile/Containerfile.
20
+ splitDockerfileStages розбиває вміст Dockerfile/Containerfile на окремі етапи (stages) на основі інструкцій `FROM`.
21
+ getMultistageAndRuntimeHint перевіряє, чи відповідає структура Dockerfile вимогам multistage build та дозволеним образам для фінального runtime (docker.mdc).
22
+ getBunCompileHint перевіряє, чи виконано необхідну компіляцію застосунку у бінарник для bun-проєктів, якщо фінальний образ — alpine (docker.mdc).
23
+ getNginxAlpineSlimTagHint перевіряє, чи використовується тег `alpine-slim` для nginx-образів (docker.mdc).
24
+ getNonRootRuntimeHint перевіряє, чи має фінальний stage інструкцію `USER <non-root>` для забезпечення не превілейованого образу (docker.mdc).
25
+ check перевіряє всі знайдені Dockerfile/Containerfile, виконуючи перевірки на відповідність стандартам, включаючи hadolint (docker.mdc).
26
+ lint оркеструє обхід репозиторію та викликає `check` для всіх знайдених Dockerfile/Containerfile.
46
27
 
47
28
  ## Публічний API
48
29
 
49
- isDockerfileName — перевіряє наявність файлів `Dockerfile` або `Containerfile` у назві.
50
- findDockerfilePaths — збирає повні шляхи до файлів `Dockerfile` або `Containerfile` від поточної робочої директорії.
51
- parseFromStages — витягує всі інструкції `FROM <image>` з вмісту файлів.
52
- splitDockerfileStages — розділяє файл `Dockerfile` на послідовні етапи за інструкціями `FROM`. Повертає порожній масив, якщо інструкції `FROM` відсутні.
53
- getMultistageAndRuntimeHint — перевіряє вимоги до структури Dockerfile:
54
- multistage — вимагає мінімум два етапи `FROM`.
55
- фінальний FROM — перевіряє, чи дозволений образ у `docker.mdc` (alpine, scratch, debian slim, php, python, nginx, openresty, тощо). Для проєктів з нативним .node-аддоном дозволено `mirror.gcr.io/oven/bun:*` (bun-рантайм).
56
- getBunCompileHintперевіряє наявність вимоги "компіляції в бінарник" для bun-проєктів на бекенд-рантаймах.
57
- Тригерперевіряє, чи присутній крок `bun install` або `bun i` у Dockerfile.
58
- Тригерперевіряє, чи фінальний образ `mirror.gcr.io/library/alpine:*` (виключаючи фронтенд nginx/openresty).
59
- getNginxAlpineSlimTagHint — перевіряє, чи містить `FROM` для nginx-образу (`mirror.gcr.io/nginxinc/nginx-unprivileged`) тег `alpine-slim` (`docker.mdc`).
60
- getNonRootRuntimeHint — перевіряє вимогу "non-root" у фінальному runtime-етапі (`docker.mdc`).
61
- Очікування — перевіряє, чи містить build stage інструкцію `bun build --compile`.
62
- Очікування — перевіряє, чи відсутні виклики `bun` у фінальному етапі (залишкові інструменти збірки).
63
- Очікування — перевіряє, чи містить фінальний етап інструкцію `USER <name|uid>`.
64
- Очікування — перевіряє, чи користувач у фінальному етапі не є `root` і не дорівнює `0`.
65
- check — виконує перевірку через hadolint (`docker.mdc`).
30
+ isDockerfileName — визначає, чи є файл `Dockerfile` або `Containerfile` у поточному каталозі.
31
+ findDockerfilePaths — збирає повні шляхи до файлів `Dockerfile` або `Containerfile` від кореня робочого каталогу.
32
+ parseFromStages — витягує всі образи, зазначені в інструкціях `FROM` у файлі.
33
+ splitDockerfileStages — розділяє вміст файлу на окремі етапи згідно з інструкціями `FROM`.
34
+ getMultistageAndRuntimeHint — оцінює відповідність структури файлу: мінімум два етапи `FROM` та відповідність базових образів списку дозволених у `docker.mdc` (з додатковим дозволом для `bun` у випадку нативного `.node-аддону`).
35
+ getBunCompileHintперевіряє, чи вимагає проєкт на базі Bun компіляції в бінарний файл для бекенд-рантайму.
36
+ getNginxAlpineSlimTagHint — перевіряє, чи використовується тег `alpine-slim` для образів Nginx, як зазначено в `docker.mdc`.
37
+ getNonRootRuntimeHintперевіряє, чи встановлено користувача, відмінного від `root` (не `0`), у фінальному етапі виконання, згідно з `docker.mdc`.
38
+ checkвиконує статичний аналіз файлу `Dockerfile`/`Containerfile` за допомогою hadolint (`docker.mdc`).
39
+ lintзапускає стандартний лінтер для Docker-файлів через адаптер `n-cursor lint docker`.
66
40
 
67
41
  ## Гарантії поведінки
68
42
 
69
- - Read-only: файл не виконує операцій запису у файлову систему.
43
+ - Read-only: не виконує операцій запису (ФС/БД).
70
44
  - Перехоплює помилки і не пропускає винятків назовні (fail-safe).
71
- - За невдалої перевірки повертає `false`/`null` замість винятку.
72
- - Не звертається до мережі.
@@ -1,6 +1,7 @@
1
1
  /** @see ./docs/lint.md */
2
2
  import { readFile } from 'node:fs/promises'
3
3
  import { basename, dirname, join } from 'node:path'
4
+ import { runStandardLint } from '../../../scripts/lib/run-standard-lint.mjs'
4
5
 
5
6
  import { getMirrorGcrHint, getFromImageToken } from '../lib/docker-mirror.mjs'
6
7
  import { getNativeAddonDeps, getNativeAddonNoCompileHint } from '../lib/docker-native-addon.mjs'
@@ -369,3 +370,13 @@ async function checkDockerfile(reporter, root, abs) {
369
370
  fail(`${rel} (${via})${detail}`)
370
371
  }
371
372
  }
373
+
374
+ /**
375
+ * Оркестраторний адаптер `n-cursor lint docker`: обгортає `check()` у `runStandardLint` (лок).
376
+ * @param {string[] | undefined} _files ігнорується (whole-repo обхід)
377
+ * @param {string} [cwd] корінь
378
+ * @returns {Promise<number>} exit code
379
+ */
380
+ export function lint(_files, cwd = process.cwd()) {
381
+ return runStandardLint(import.meta.dirname, () => check(cwd))
382
+ }
@@ -4,7 +4,7 @@
4
4
  * Відносні шляхи з прямими слешами; hadolint резолвиться через `ensureTool`
5
5
  * (PATH → кеш → авто-install brew/scoop/GitHub Release per-platform). Docker-fallback
6
6
  * прибрано — hadolint ставиться як **нативний бінарник**, без `docker run`.
7
- * Використовується `./check.mjs` (check-docker) та `../../lint/lint.mjs` (run-docker).
7
+ * Використовується `../js/lint.mjs` (правило `n-cursor lint docker` / check-docker).
8
8
  */
9
9
  import { spawnSync } from 'node:child_process'
10
10
  import { relative, sep } from 'node:path'
@@ -3,186 +3,29 @@ type: JS Module
3
3
  title: docker-hadolint.mjs
4
4
  resource: npm/rules/docker/lib/docker-hadolint.mjs
5
5
  docgen:
6
- crc: b97701f3
6
+ crc: ebab2135
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 90
7
9
  ---
8
10
 
9
- Модуль `docker-hadolint.mjs` інкапсулює спільну логіку запуску статичного аналізатора `hadolint` для перевірки `Dockerfile`-ів у межах правила `docker` (див. `.cursor/rules/docker.mdc` / `n-docker`). Він є тонким адаптером поверх системного бінарника `hadolint` та надає двом викликачам — `check.mjs` (skill `check-docker`) і `../../lint/lint.mjs` (skill `run-docker`) — єдину функцію перевірки одного `Dockerfile` плюс утиліту нормалізації шляхів.
11
+ ## Огляд
10
12
 
11
- Ключові архітектурні рішення:
13
+ Спільна логіка виклику hadolint для шляхів до Dockerfile. Модуль створює стандартизовані відносні шляхи з прямими слешами. Він ініціює перевірку Dockerfile, використовуючи hadolint як нативний бінарник, який резолвиться через `ensureTool` (PATH → кеш → авто-install brew/scoop/GitHub Release per-platform). Для отримання інформації про встановлення можна звертатися до https://github.com/hadolint/hadolint/releases. Публічна функція `lintDockerfileWithHadolint` виконує перевірку за правилом `n-cursor lint docker` / check-docker.
12
14
 
13
- - `hadolint` запускається **виключно як нативний бінарник**. Будь-який Docker-fallback (наприклад, `docker run hadolint/hadolint`) свідомо прибраний, тож модуль не залежить від запущеного Docker Engine.
14
- - Розв’язання шляху до бінарника делеговано в `ensureTool('hadolint')`, який реалізує ланцюжок `PATH → локальний кеш інструментів → авто-install` через `brew` / `scoop` / GitHub Release, відповідно до платформи.
15
- - Якщо `ensureTool` падає (інструмент відсутній і авто-install вимкнено через `N_CURSOR_NO_AUTO_INSTALL` або фізично не вдався), модуль **не кидає виняток назовні**, а повертає структурований результат `{ ok: false, stderr: <інструкція з установки> }`. Це дозволяє викликачам однаково обробляти і реальні порушення hadolint, і відсутність інструмента.
16
- - Шляхи у виводі нормалізуються через `posixRel` (відносно `root`, з прямими слешами `/`), щоб лог і повідомлення про помилки були стабільними між macOS / Linux / Windows.
15
+ ## Поведінка
17
16
 
18
- ## Експорти / API
17
+ posixRel
18
+ Створює відносний шлях від кореня з використанням прямих слешів.
19
19
 
20
- Модуль є ESM (`.mjs`) і має два іменовані експорти:
20
+ lintDockerfileWithHadolint
21
+ Запускає hadolint як нативний бінарник для перевірки Dockerfile. Якщо не вдається знайти hadolint, повертає помилку з інструкцією для встановлення (наприклад, https://github.com/hadolint/hadolint/releases).
21
22
 
22
- | Експорт | Тип | Призначення |
23
- | ------------------------------------------- | -------- | ---------------------------------------------------------------------------------- |
24
- | `posixRel(root, absPath)` | function | Перетворити абсолютний шлях на відносний від `root` з прямими слешами. |
25
- | `lintDockerfileWithHadolint(root, absPath)` | function | Запустити `hadolint` для одного `Dockerfile` і повернути структурований результат. |
23
+ ## Публічний API
26
24
 
27
- Default-експорту немає. Глобальних побічних ефектів на рівні модуля немає імпорт лише підтягує `ensureTool`, не виконуючи його.
25
+ * posixRel Генерує абсолютний шлях від кореня з використанням лише слешів, забезпечуючи стабільність незалежно від операційної системи.
26
+ * lintDockerfileWithHadolint — Запускає інструмент hadolint для аналізу Dockerfile. Якщо інструмент не знайдено у системних шляхах, він намагається встановити його. У разі невдачі встановлення або відключення автоматичного встановлення, повертає помилку, надаючи користувачеві підказку для ручного запуску (детальніше про інструмент можна знайти на https://github.com/hadolint/hadolint/releases).
28
27
 
29
- ## Функції
28
+ ## Гарантії поведінки
30
29
 
31
- ### `posixRel(root, absPath)`
32
-
33
- Утиліта нормалізації шляхів для стабільного логування й передачі в `hadolint`.
34
-
35
- **Сигнатура:**
36
-
37
- ```js
38
- export function posixRel(root: string, absPath: string): string
39
- ```
40
-
41
- **Параметри:**
42
-
43
- - `root` — абсолютний шлях до кореня репозиторію (або будь-якого опорного каталогу), відносно якого треба отримати шлях.
44
- - `absPath` — абсолютний шлях до файлу, який треба представити відносно `root`.
45
-
46
- **Повертає:**
47
-
48
- - Рядок із відносним шляхом, де всі системні розділювачі (`path.sep`) замінено на прямий слеш `/`. На POSIX-системах результат фактично збігається з `path.relative`, на Windows — конвертує `\` на `/`.
49
-
50
- **Алгоритм:**
51
-
52
- 1. Викликає `relative(root, absPath)` з `node:path` для обчислення відносного шляху.
53
- 2. Розбиває результат за поточним `sep` (`path.sep`) і склеює знову через `'/'`.
54
-
55
- **Side effects:** немає; функція чиста й детермінована.
56
-
57
- **Примітка:** функція не валідовує, чи `absPath` справді абсолютний і чи він знаходиться під `root` — у такому випадку `relative` поверне відносний шлях із `..`, що теж буде нормалізовано до прямих слешів.
58
-
59
- ---
60
-
61
- ### `lintDockerfileWithHadolint(root, absPath)`
62
-
63
- Основна точка входу модуля: виконує `hadolint` для одного `Dockerfile` і повертає уніфікований результат.
64
-
65
- **Сигнатура:**
66
-
67
- ```js
68
- export function lintDockerfileWithHadolint(
69
- root: string,
70
- absPath: string
71
- ): {
72
- ok: boolean,
73
- stdout: string,
74
- stderr: string,
75
- via: string
76
- }
77
- ```
78
-
79
- **Параметри:**
80
-
81
- - `root` — абсолютний шлях до кореня репозиторію. Використовується одночасно як `cwd` для дочірнього процесу і як база для `posixRel`.
82
- - `absPath` — абсолютний шлях до конкретного `Dockerfile` (або файлу, який треба перевірити hadolint’ом).
83
-
84
- **Повертає об’єкт із полями:**
85
-
86
- - `ok` — `true`, якщо `hadolint` завершився з кодом виходу `0` (порушень немає). `false` — у будь-якому іншому випадку: інструмент знайшов проблеми, не запустився, або не зміг бути встановленим/знайденим.
87
- - `stdout` — stdout процесу hadolint як рядок (UTF-8). При помилці отримання інструмента — порожній рядок.
88
- - `stderr` — stderr процесу hadolint як рядок. Якщо інструмент не вдалося отримати, тут міститься українська інструкція з установки (`brew install hadolint` / `scoop install hadolint` / посилання на GitHub Releases) разом із повідомленням оригінальної помилки.
89
- - `via` — завжди константа `'hadolint'`. Поле залишене для зворотної сумісності з API, де раніше міг бути ще варіант на кшталт `'docker'`; зараз інших значень не повертається.
90
-
91
- **Алгоритм:**
92
-
93
- 1. Обчислює відносний шлях `rel = posixRel(root, absPath)`.
94
- 2. Намагається отримати шлях до бінарника через `hadolintPath = ensureTool('hadolint')`.
95
- - Якщо `ensureTool` кидає виняток, функція **перехоплює** його і повертає об’єкт з `ok: false`, порожнім `stdout`, інструктивним `stderr` (текст помилки + поради з установки) і `via: 'hadolint'`. На цьому виконання завершується.
96
- 3. Викликає `spawnSync(hadolintPath, [rel], { cwd: root, encoding: 'utf8', maxBuffer: 10 * 1024 * 1024 })`:
97
- - `cwd: root` — щоб hadolint бачив правильну робочу директорію і `rel` коректно резолвився.
98
- - `encoding: 'utf8'` — `stdout`/`stderr` одразу приходять як рядки, а не `Buffer`.
99
- - `maxBuffer: 10 МіБ` — захист від великих обсягів виводу при множинних попередженнях.
100
- 4. Формує результат: `ok = local.status === 0`, `stdout`/`stderr` приходять з процесу (з фолбеком на порожній рядок через `??`), `via: 'hadolint'`.
101
-
102
- **Side effects:**
103
-
104
- - Може ініціювати **авто-install** `hadolint` через `ensureTool` (мережа, brew/scoop/завантаження GitHub Release, запис у локальний кеш інструментів), якщо інструмент відсутній і авто-install не вимкнено `N_CURSOR_NO_AUTO_INSTALL`.
105
- - Синхронно запускає дочірній процес `hadolint`, що блокує цикл подій Node.js до завершення (через `spawnSync`).
106
- - Не пише в stdout/stderr поточного процесу самостійно — увесь вивід hadolint повертає викликачу.
107
- - Не змінює `process.cwd()` поточного процесу (тільки `cwd` дочірнього).
108
-
109
- **Обробка помилок:**
110
-
111
- - Виняток від `ensureTool` ловиться і конвертується у м’який `ok: false` з підказкою.
112
- - Помилки запуску `spawnSync` (наприклад, права доступу) **не обгортаються окремо**: у такому разі `spawnSync` повертає об’єкт з `status: null` і `error`-полем, відповідно `ok` буде `false`, а `stdout`/`stderr` — порожніми (через `??`). Поле `error` об’єкта `spawnSync` у результат не транслюється.
113
- - Ненульовий `status` від самого `hadolint` (тобто знайдені порушення) трактується як `ok: false`, але `stderr`/`stdout` несуть звіт hadolint для подальшого парсингу/виводу користувачу.
114
-
115
- ## Залежності
116
-
117
- ### Node.js (стандартні)
118
-
119
- - `node:child_process` — імпортується `spawnSync` для синхронного запуску `hadolint`.
120
- - `node:path` — імпортуються `relative` і `sep` для побудови відносного шляху з нормалізацією роздільників.
121
-
122
- ### Внутрішні (моноpепо)
123
-
124
- - `../../../scripts/lib/ensure-tool.mjs` — функція `ensureTool(name)`, яка:
125
- - повертає абсолютний шлях до бінарника;
126
- - намагається знайти його у `PATH`, у локальному кеші інструментів;
127
- - за потреби виконує авто-install через `brew` (macOS), `scoop` (Windows) чи GitHub Release (Linux);
128
- - кидає виняток, якщо інструмент недоступний і авто-install неможливий / вимкнено `N_CURSOR_NO_AUTO_INSTALL`.
129
-
130
- ### Зовнішні (runtime)
131
-
132
- - Бінарник `hadolint` (нативний; брати з `brew`, `scoop`, GitHub Release). **Не** використовується `docker run hadolint/hadolint` — Docker-fallback явно прибраний.
133
-
134
- ### Імпорт-споживачі (всередині правила `docker`)
135
-
136
- - `./check.mjs` — скіл `check-docker`: разова перевірка обраних `Dockerfile`-ів.
137
- - `../../lint/lint.mjs` — скіл `run-docker`: інтеграція в загальний `lint`-конвеєр.
138
-
139
- ## Потік виконання / Використання
140
-
141
- Типовий сценарій використання модуля викликачем:
142
-
143
- 1. Викликач (наприклад, `check-docker` або `run-docker`) визначає `root` репозиторію і список абсолютних шляхів до `Dockerfile`-ів.
144
- 2. Для кожного шляху викликається `lintDockerfileWithHadolint(root, absPath)`.
145
- 3. Модуль:
146
- - нормалізує шлях у POSIX-форму (`posixRel`);
147
- - резолвить `hadolint` через `ensureTool` (можливо з авто-install);
148
- - синхронно запускає `hadolint <rel>` у `cwd = root`;
149
- - повертає `{ ok, stdout, stderr, via }`.
150
- 4. Викликач інтерпретує результат:
151
- - `ok === true` → файл чистий, нічого не виводити (або вивести позитивний статус);
152
- - `ok === false` → показати `stdout`/`stderr` користувачу, зарахувати як порушення; якщо `stderr` містить інструкцію з установки — повідомити користувача, як отримати інструмент.
153
-
154
- ### Приклад використання
155
-
156
- ```js
157
- import { lintDockerfileWithHadolint, posixRel } from './docker-hadolint.mjs'
158
-
159
- const root = process.cwd()
160
- const absPath = '/abs/path/to/repo/services/api/Dockerfile'
161
-
162
- const result = lintDockerfileWithHadolint(root, absPath)
163
-
164
- if (!result.ok) {
165
- console.error(`hadolint failed for ${posixRel(root, absPath)} (via=${result.via})`)
166
- if (result.stdout) console.error(result.stdout)
167
- if (result.stderr) console.error(result.stderr)
168
- process.exitCode = 1
169
- }
170
- ```
171
-
172
- ### Поведінка за відсутності `hadolint`
173
-
174
- - Якщо `hadolint` відсутній і `N_CURSOR_NO_AUTO_INSTALL` **не** виставлена, `ensureTool` спробує встановити бінарник автоматично (за платформою).
175
- - Якщо `N_CURSOR_NO_AUTO_INSTALL` виставлена або авто-install не вдався, `lintDockerfileWithHadolint` повертає:
176
- - `ok: false`,
177
- - `stdout: ''`,
178
- - `stderr: 'Не вдалося отримати hadolint (<повідомлення>). Встанови: brew install hadolint (macOS) / scoop install hadolint (Windows) / https://github.com/hadolint/hadolint/releases (Linux).'`,
179
- - `via: 'hadolint'`.
180
- - Завдяки м’якій обробці викликач може коректно показати інструкцію користувачу замість аварійного завершення.
181
-
182
- ### Особливості та обмеження
183
-
184
- - **Синхронність**: усі виклики блокуючі (`spawnSync`). Для пакетної перевірки сотень файлів варіант — викликати модуль із зовнішнього оркестратора, який сам керує паралелізмом (з урахуванням обмежень середовища).
185
- - **Один файл за виклик**: функція передає у `hadolint` рівно один аргумент `rel`. Для масової перевірки слід викликати функцію в циклі — це свідомий вибір, щоб уніфікувати результат і прив’язку до конкретного файлу.
186
- - **Розмір буфера**: `maxBuffer = 10 МіБ` достатньо для звичайних `Dockerfile`-звітів; для аномально великих виводів значення доведеться змінювати на рівні форку модуля.
187
- - **`via` константно `'hadolint'`**: поле залишене для майбутньої сумісності, але наразі ніколи не приймає інших значень.
188
- - **Стабільність шляхів**: завдяки `posixRel` повідомлення про порушення містять однакові шляхи з прямими слешами на всіх ОС — це важливо для дифу логів у CI.
30
+ - Read-only: не виконує операцій запису (ФС/БД).
31
+ - Перехоплює помилки і не пропускає винятків назовні (fail-safe).
@@ -0,0 +1,20 @@
1
+ import { isRunAsCli, runRuleCli } from '../../scripts/lib/run-rule-cli.mjs'
2
+ import { runStandardRule } from '../../scripts/lib/run-standard-rule.mjs'
3
+
4
+ /**
5
+ * Єдиний entrypoint правила (ADR 2026-06-21). `run()` — check-поверхня: applies →
6
+ * JS-concerns → policy → mdc-refs. `lint()` — lint-поверхня; важка реалізація лишається
7
+ * у js/-хелпері `js/lint.mjs` (main.mjs тонкий — лише re-export).
8
+ * @param {import('../../scripts/lib/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону
9
+ * @returns {Promise<number>} 0 — OK, 1 — порушення
10
+ */
11
+ export function run(ctx) {
12
+ return runStandardRule(import.meta.dirname, ctx)
13
+ }
14
+
15
+ export { lint } from './js/lint.mjs'
16
+
17
+ if (isRunAsCli(import.meta.url)) {
18
+ // Standalone: bun rules/<id>/main.mjs — повний еквівалент `npx @nitra/cursor check <id>`.
19
+ process.exitCode = await runRuleCli(import.meta.dirname)
20
+ }
@@ -9,3 +9,4 @@ resource: npm/rules/efes/
9
9
  | Файл | Тип |
10
10
  |---|---|
11
11
  | [fix.mjs](fix.md) | JS Module |
12
+ | [main.mjs](main.md) | JS Module |
@@ -0,0 +1,29 @@
1
+ ---
2
+ type: JS Module
3
+ title: main.mjs
4
+ resource: npm/rules/efes/main.mjs
5
+ docgen:
6
+ crc: 762b6875
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 100
9
+ ---
10
+
11
+ ## Огляд
12
+
13
+ Модуль перевіряє відповідність коду визначеним правилам, використовуючи конфігурацію з meta.json. Він виконує аналіз, який може бути ініційований через публічну функцію run. Модуль є read-only, тобто не здійснює записів у файлову систему чи бази даних. Кешування даних відбувається у межах одного прогону. При завершенні роботи як окремий інструмент, він надає підсумковий звіт.
14
+
15
+ ## Поведінка
16
+
17
+ 1. Виконує перевірку правила, застосовуючи логіку, визначену в конфігах, зокрема `meta.json`.
18
+ 2. Виконує перевірку, що включає аналіз JS-залежностей та політик.
19
+ 3. Виконує перевірку, що включає посилання на MDC.
20
+ 4. Якщо код запускається як окремий інструмент (standalone), виконується повний цикл роботи з конфігурацією, білистами дозволених елементів та підсумковим звітом, завершуючи роботу з відповідним кодом виходу.
21
+
22
+ ## Публічний API
23
+
24
+ run — єдиний вхідний пункт правила; виконує послідовність перевірок: застосовує JS-занепокоєння, застосовує політику, перевіряє посилання MDC.
25
+
26
+ ## Гарантії поведінки
27
+
28
+ - Read-only: не виконує операцій запису (ФС/БД).
29
+ - Кешує результати в межах одного прогону.
@@ -0,0 +1,20 @@
1
+ import { isRunAsCli, runRuleCli } from '../../scripts/lib/run-rule-cli.mjs'
2
+ import { runStandardRule } from '../../scripts/lib/run-standard-rule.mjs'
3
+
4
+ /**
5
+ * Єдиний entrypoint правила (ADR 2026-06-21). `run()` — check-поверхня: applies →
6
+ * JS-concerns → policy → mdc-refs (через runStandardRule). Lint-поверхні правило не має
7
+ * (`meta.json` без `lint`), тож експорту `lint` тут немає.
8
+ * Library mode: викликається CLI orchestration через `import + run(ctx)`.
9
+ * @param {import('../../scripts/lib/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
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/<id>/main.mjs — повний еквівалент `npx @nitra/cursor check <id>`
18
+ // (config-loading + whitelist + summary): library-роль (run) + standalone-роль (CLI-блок).
19
+ process.exitCode = await runRuleCli(import.meta.dirname)
20
+ }
@@ -9,3 +9,4 @@ resource: npm/rules/feedback/
9
9
  | Файл | Тип |
10
10
  |---|---|
11
11
  | [fix.mjs](fix.md) | JS Module |
12
+ | [main.mjs](main.md) | JS Module |
@@ -0,0 +1,30 @@
1
+ ---
2
+ type: JS Module
3
+ title: main.mjs
4
+ resource: npm/rules/feedback/main.mjs
5
+ docgen:
6
+ crc: 762b6875
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 100
9
+ ---
10
+
11
+ ## Огляд
12
+
13
+ Модуль перевіряє відповідність даних заданим правилам, використовуючи конфігурації, політики та посилання на MDC, які визначаються у meta.json. Він застосовує білий список для формування підсумку. Публічний інтерфейс run завершує роботу, інформуючи про успішне виконання або виявлені порушення. Модуль є Read-only і не виконує записів у файлову систему чи бази даних.
14
+
15
+ ## Поведінка
16
+
17
+ 1. Викликається функція `run` для виконання перевірки.
18
+ 2. Виконання `run` застосовує логіку правила, включаючи перевірку конфігурацій, політик та посилання на MDC.
19
+ 3. Якщо скрипт виконується як окрема програма (CLI), виконується логіка оркестрації правила.
20
+ 4. Оркестрація правила зчитує конфігурації, застосовує білий список та генерує підсумок.
21
+ 5. Вихідний код завершує роботу з кодом, що вказує на успіх або наявність порушень.
22
+
23
+ ## Публічний API
24
+
25
+ run — виконує основну логіку правила: застосовує перевірки JS-зацікавленостей, політики та посилання на MDC.
26
+
27
+ ## Гарантії поведінки
28
+
29
+ - Read-only: не виконує операцій запису (ФС/БД).
30
+ - Кешує результати в межах одного прогону.
@@ -0,0 +1,20 @@
1
+ import { isRunAsCli, runRuleCli } from '../../scripts/lib/run-rule-cli.mjs'
2
+ import { runStandardRule } from '../../scripts/lib/run-standard-rule.mjs'
3
+
4
+ /**
5
+ * Єдиний entrypoint правила (ADR 2026-06-21). `run()` — check-поверхня: applies →
6
+ * JS-concerns → policy → mdc-refs (через runStandardRule). Lint-поверхні правило не має
7
+ * (`meta.json` без `lint`), тож експорту `lint` тут немає.
8
+ * Library mode: викликається CLI orchestration через `import + run(ctx)`.
9
+ * @param {import('../../scripts/lib/run-standard-rule.mjs').RuleContext} [ctx] контекст прогону (walkCache тощо)
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/<id>/main.mjs — повний еквівалент `npx @nitra/cursor check <id>`
18
+ // (config-loading + whitelist + summary): library-роль (run) + standalone-роль (CLI-блок).
19
+ process.exitCode = await runRuleCli(import.meta.dirname)
20
+ }
@@ -9,3 +9,4 @@ resource: npm/rules/ga/
9
9
  | Файл | Тип |
10
10
  |---|---|
11
11
  | [fix.mjs](fix.md) | JS Module |
12
+ | [main.mjs](main.md) | JS Module |