@7n/rules-lang-js 0.3.1 → 0.4.1

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 (258) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/package.json +14 -4
  3. package/rules/bun/bunfig/bunfig.mdc +17 -0
  4. package/rules/bun/bunfig/bunfig.rego +29 -0
  5. package/rules/bun/bunfig/concern.json +9 -0
  6. package/rules/bun/bunfig/template/bunfig.toml.snippet.toml +2 -0
  7. package/rules/bun/docs/index.md +11 -0
  8. package/rules/bun/layout/concern.json +16 -0
  9. package/rules/bun/layout/docs/fix-layout.md +29 -0
  10. package/rules/bun/layout/docs/main.md +34 -0
  11. package/rules/bun/layout/fix-layout.mjs +63 -0
  12. package/rules/bun/layout/layout.mdc +60 -0
  13. package/rules/bun/layout/main.mjs +53 -0
  14. package/rules/bun/licensee/concern.json +7 -0
  15. package/rules/bun/licensee/docs/fix-licensee.md +27 -0
  16. package/rules/bun/licensee/docs/index.md +12 -0
  17. package/rules/bun/licensee/docs/main.md +30 -0
  18. package/rules/bun/licensee/fix-licensee.mjs +31 -0
  19. package/rules/bun/licensee/main.mjs +68 -0
  20. package/rules/bun/lint-surface/concern.json +3 -0
  21. package/rules/bun/lint-surface/lint-surface.mdc +13 -0
  22. package/rules/bun/main.json +1 -0
  23. package/rules/bun/main.mdc +11 -0
  24. package/rules/bun/package_json/concern.json +9 -0
  25. package/rules/bun/package_json/docs/fix-package_json.md +28 -0
  26. package/rules/bun/package_json/docs/index.md +9 -0
  27. package/rules/bun/package_json/fix-package_json.mjs +311 -0
  28. package/rules/bun/package_json/package_json.mdc +14 -0
  29. package/rules/bun/package_json/package_json.rego +64 -0
  30. package/rules/bun/package_json/template/package.json.deny.json +4 -0
  31. package/rules/js/check/check.mdc +26 -0
  32. package/rules/js/check/concern.json +19 -0
  33. package/rules/js/check/docs/eslint-config.md +56 -0
  34. package/rules/js/check/docs/fix-check.md +48 -0
  35. package/rules/js/check/docs/index.md +13 -0
  36. package/rules/js/check/docs/main.md +48 -0
  37. package/rules/js/check/eslint-config.mjs +262 -0
  38. package/rules/js/check/fix-check.mjs +82 -0
  39. package/rules/js/check/main.mjs +310 -0
  40. package/rules/js/dep-policy/concern.json +4 -0
  41. package/rules/js/dep-policy/dep-policy.mdc +36 -0
  42. package/rules/js/dep-policy/docs/main.md +35 -0
  43. package/rules/js/dep-policy/main.mjs +99 -0
  44. package/rules/js/docs/index.md +11 -0
  45. package/rules/js/eslint/concern.json +8 -0
  46. package/rules/js/eslint/docs/fix-eslint.md +50 -0
  47. package/rules/js/eslint/docs/fix-worker.md +31 -0
  48. package/rules/js/eslint/docs/index.md +11 -0
  49. package/rules/js/eslint/docs/main.md +35 -0
  50. package/rules/js/eslint/fix-eslint.mjs +160 -0
  51. package/rules/js/eslint/fix-worker.mjs +139 -0
  52. package/rules/js/eslint/main.mjs +115 -0
  53. package/rules/js/file-extensions/concern.json +3 -0
  54. package/rules/js/file-extensions/file-extensions.mdc +12 -0
  55. package/rules/js/jscpd_config/concern.json +11 -0
  56. package/rules/js/jscpd_config/docs/fix-jscpd_config.md +25 -0
  57. package/rules/js/jscpd_config/docs/index.md +9 -0
  58. package/rules/js/jscpd_config/fix-jscpd_config.mjs +3 -0
  59. package/rules/js/jscpd_config/jscpd_config.mdc +42 -0
  60. package/rules/js/jscpd_config/jscpd_config.rego +44 -0
  61. package/rules/js/jscpd_config/template/.jscpd.json.snippet.json +7 -0
  62. package/rules/js/jscpd_duplicates/concern.json +7 -0
  63. package/rules/js/jscpd_duplicates/docs/main.md +29 -0
  64. package/rules/js/jscpd_duplicates/main.mjs +69 -0
  65. package/rules/js/knip/concern.json +7 -0
  66. package/rules/js/knip/docs/main.md +31 -0
  67. package/rules/js/knip/knip.mdc +15 -0
  68. package/rules/js/knip/main.mjs +89 -0
  69. package/rules/js/lint-findings/concern.json +3 -0
  70. package/rules/js/lint-findings/docs/main.md +40 -0
  71. package/rules/js/lint-findings/main.mjs +125 -0
  72. package/rules/js/main.json +1 -0
  73. package/rules/js/main.mdc +18 -0
  74. package/rules/js/package_json/concern.json +9 -0
  75. package/rules/js/package_json/docs/fix-package_json.md +25 -0
  76. package/rules/js/package_json/docs/index.md +9 -0
  77. package/rules/js/package_json/fix-package_json.mjs +3 -0
  78. package/rules/js/package_json/package_json.mdc +15 -0
  79. package/rules/js/package_json/package_json.rego +142 -0
  80. package/rules/js/package_json/template/package.json.snippet.json +6 -0
  81. package/rules/js/tooling/concern.json +3 -0
  82. package/rules/js/tooling/data/tooling/knip-canonical.json +30 -0
  83. package/rules/js/tooling/data/tooling/oxlint-canonical.json +400 -0
  84. package/rules/js/tooling/docs/main.md +53 -0
  85. package/rules/js/tooling/main.mjs +183 -0
  86. package/rules/js/utils_imports/concern.json +4 -0
  87. package/rules/js/utils_imports/docs/main.md +50 -0
  88. package/rules/js/utils_imports/main.mjs +185 -0
  89. package/rules/js/utils_imports/utils_imports.mdc +15 -0
  90. package/rules/js/vscode_extensions/concern.json +11 -0
  91. package/rules/js/vscode_extensions/docs/fix-vscode_extensions.md +24 -0
  92. package/rules/js/vscode_extensions/docs/index.md +11 -0
  93. package/rules/js/vscode_extensions/fix-vscode_extensions.mjs +1 -0
  94. package/rules/js/vscode_extensions/template/extensions.json.snippet.json +6 -0
  95. package/rules/js/vscode_extensions/vscode_extensions.mdc +11 -0
  96. package/rules/js/vscode_extensions/vscode_extensions.rego +12 -0
  97. package/rules/js-bun-db/connection/concern.json +3 -0
  98. package/rules/js-bun-db/connection/connection.mdc +42 -0
  99. package/rules/js-bun-db/docs/index.md +11 -0
  100. package/rules/js-bun-db/lib/bun-sql-scan.mjs +1047 -0
  101. package/rules/js-bun-db/lib/docs/bun-sql-scan.md +63 -0
  102. package/rules/js-bun-db/lib/docs/index.md +11 -0
  103. package/rules/js-bun-db/main.json +1 -0
  104. package/rules/js-bun-db/main.mdc +8 -0
  105. package/rules/js-bun-db/package_json/concern.json +9 -0
  106. package/rules/js-bun-db/package_json/package_json.mdc +31 -0
  107. package/rules/js-bun-db/package_json/package_json.rego +15 -0
  108. package/rules/js-bun-db/package_json/template/package.json.deny.json +6 -0
  109. package/rules/js-bun-db/pg_format_identifiers/concern.json +3 -0
  110. package/rules/js-bun-db/pg_format_identifiers/pg_format_identifiers.mdc +104 -0
  111. package/rules/js-bun-db/safety/concern.json +4 -0
  112. package/rules/js-bun-db/safety/docs/main.md +34 -0
  113. package/rules/js-bun-db/safety/main.mjs +430 -0
  114. package/rules/js-bun-db/safety/safety.mdc +458 -0
  115. package/rules/js-bun-redis/docs/index.md +11 -0
  116. package/rules/js-bun-redis/imports/concern.json +4 -0
  117. package/rules/js-bun-redis/imports/docs/main.md +36 -0
  118. package/rules/js-bun-redis/imports/imports.mdc +47 -0
  119. package/rules/js-bun-redis/imports/main.mjs +88 -0
  120. package/rules/js-bun-redis/lib/docs/index.md +11 -0
  121. package/rules/js-bun-redis/lib/docs/redis-imports.md +227 -0
  122. package/rules/js-bun-redis/lib/redis-imports.mjs +130 -0
  123. package/rules/js-bun-redis/main.json +1 -0
  124. package/rules/js-bun-redis/main.mdc +8 -0
  125. package/rules/js-bun-redis/package_json/concern.json +9 -0
  126. package/rules/js-bun-redis/package_json/package_json.mdc +11 -0
  127. package/rules/js-bun-redis/package_json/package_json.rego +15 -0
  128. package/rules/js-bun-redis/package_json/template/package.json.deny.json +12 -0
  129. package/rules/js-mssql/deps/concern.json +4 -0
  130. package/rules/js-mssql/deps/docs/main.md +33 -0
  131. package/rules/js-mssql/deps/main.mjs +297 -0
  132. package/rules/js-mssql/docs/index.md +11 -0
  133. package/rules/js-mssql/lib/docs/index.md +11 -0
  134. package/rules/js-mssql/lib/docs/mssql-pool-scan.md +380 -0
  135. package/rules/js-mssql/lib/mssql-pool-scan.mjs +610 -0
  136. package/rules/js-mssql/main.json +1 -0
  137. package/rules/js-mssql/main.mdc +144 -0
  138. package/rules/js-mssql/mssql-tvp/concern.json +3 -0
  139. package/rules/js-mssql/mssql-tvp/mssql-tvp.mdc +77 -0
  140. package/rules/js-mssql/package_json/concern.json +9 -0
  141. package/rules/js-mssql/package_json/package_json.mdc +9 -0
  142. package/rules/js-mssql/package_json/package_json.rego +57 -0
  143. package/rules/js-run/configmap/concern.json +9 -0
  144. package/rules/js-run/configmap/configmap.mdc +37 -0
  145. package/rules/js-run/configmap/configmap.rego +21 -0
  146. package/rules/js-run/configmap/template/configmap.yaml.contains.yml +4 -0
  147. package/rules/js-run/docs/index.md +11 -0
  148. package/rules/js-run/jsconfig/concern.json +9 -0
  149. package/rules/js-run/jsconfig/docs/fix-jsconfig.md +28 -0
  150. package/rules/js-run/jsconfig/docs/index.md +9 -0
  151. package/rules/js-run/jsconfig/fix-jsconfig.mjs +119 -0
  152. package/rules/js-run/jsconfig/jsconfig.mdc +48 -0
  153. package/rules/js-run/jsconfig/jsconfig.rego +59 -0
  154. package/rules/js-run/jsconfig/template/jsconfig.json.snippet.json +10 -0
  155. package/rules/js-run/lib/bunyan-imports.mjs +98 -0
  156. package/rules/js-run/lib/check-env-scan.mjs +338 -0
  157. package/rules/js-run/lib/conn-file-rules.mjs +214 -0
  158. package/rules/js-run/lib/conn-imports-scan.mjs +154 -0
  159. package/rules/js-run/lib/docs/bunyan-imports.md +121 -0
  160. package/rules/js-run/lib/docs/check-env-scan.md +438 -0
  161. package/rules/js-run/lib/docs/conn-file-rules.md +304 -0
  162. package/rules/js-run/lib/docs/conn-imports-scan.md +208 -0
  163. package/rules/js-run/lib/docs/index.md +16 -0
  164. package/rules/js-run/lib/docs/promise-settimeout-scan.md +334 -0
  165. package/rules/js-run/lib/docs/temporal-scan.md +29 -0
  166. package/rules/js-run/lib/promise-settimeout-scan.mjs +128 -0
  167. package/rules/js-run/lib/temporal-scan.mjs +52 -0
  168. package/rules/js-run/main.json +1 -0
  169. package/rules/js-run/main.mdc +16 -0
  170. package/rules/js-run/package_json/concern.json +9 -0
  171. package/rules/js-run/package_json/package_json.mdc +44 -0
  172. package/rules/js-run/package_json/package_json.rego +37 -0
  173. package/rules/js-run/package_json/template/package.json.deny.json +22 -0
  174. package/rules/js-run/project-structure/concern.json +3 -0
  175. package/rules/js-run/project-structure/project-structure.mdc +11 -0
  176. package/rules/js-run/runtime/concern.json +12 -0
  177. package/rules/js-run/runtime/docs/fix-runtime.md +27 -0
  178. package/rules/js-run/runtime/docs/main.md +35 -0
  179. package/rules/js-run/runtime/fix-runtime.mjs +46 -0
  180. package/rules/js-run/runtime/main.mjs +496 -0
  181. package/rules/js-run/runtime/runtime.mdc +184 -0
  182. package/rules/js-run/scope/concern.json +3 -0
  183. package/rules/js-run/scope/scope.mdc +11 -0
  184. package/rules/npm-module/docs/index.md +11 -0
  185. package/rules/npm-module/emit_types_config/concern.json +9 -0
  186. package/rules/npm-module/emit_types_config/docs/fix-emit_types_config.md +25 -0
  187. package/rules/npm-module/emit_types_config/docs/index.md +9 -0
  188. package/rules/npm-module/emit_types_config/emit_types_config.mdc +43 -0
  189. package/rules/npm-module/emit_types_config/emit_types_config.rego +28 -0
  190. package/rules/npm-module/emit_types_config/fix-emit_types_config.mjs +5 -0
  191. package/rules/npm-module/emit_types_config/template/tsconfig.emit-types.json.snippet.json +9 -0
  192. package/rules/npm-module/header_doc_pointer/concern.json +5 -0
  193. package/rules/npm-module/header_doc_pointer/docs/main.md +40 -0
  194. package/rules/npm-module/header_doc_pointer/header_doc_pointer.mdc +18 -0
  195. package/rules/npm-module/header_doc_pointer/main.mjs +131 -0
  196. package/rules/npm-module/main.json +1 -0
  197. package/rules/npm-module/main.mdc +36 -0
  198. package/rules/npm-module/npm_package_json/concern.json +9 -0
  199. package/rules/npm-module/npm_package_json/docs/fix-npm_package_json.md +26 -0
  200. package/rules/npm-module/npm_package_json/docs/index.md +9 -0
  201. package/rules/npm-module/npm_package_json/fix-npm_package_json.mjs +5 -0
  202. package/rules/npm-module/npm_package_json/npm_package_json.mdc +57 -0
  203. package/rules/npm-module/npm_package_json/npm_package_json.rego +73 -0
  204. package/rules/npm-module/npm_package_json/template/package.json.snippet.json +1 -0
  205. package/rules/npm-module/package_structure/concern.json +5 -0
  206. package/rules/npm-module/package_structure/docs/main.md +37 -0
  207. package/rules/npm-module/package_structure/main.mjs +448 -0
  208. package/rules/npm-module/package_structure/package_structure.mdc +63 -0
  209. package/rules/npm-module/root_package_json/concern.json +9 -0
  210. package/rules/npm-module/root_package_json/docs/fix-root_package_json.md +25 -0
  211. package/rules/npm-module/root_package_json/docs/index.md +9 -0
  212. package/rules/npm-module/root_package_json/fix-root_package_json.mjs +5 -0
  213. package/rules/npm-module/root_package_json/root_package_json.mdc +41 -0
  214. package/rules/npm-module/root_package_json/root_package_json.rego +28 -0
  215. package/rules/npm-module/root_package_json/template/package.json.snippet.json +1 -0
  216. package/rules/npm-module/rule_meta/concern.json +8 -0
  217. package/rules/npm-module/rule_meta/docs/main.md +35 -0
  218. package/rules/npm-module/rule_meta/main.mjs +119 -0
  219. package/rules/npm-module/rule_meta/rule_meta.mdc +11 -0
  220. package/rules/npm-module/skill_meta/concern.json +5 -0
  221. package/rules/npm-module/skill_meta/docs/main.md +149 -0
  222. package/rules/npm-module/skill_meta/main.mjs +91 -0
  223. package/rules/npm-module/skill_meta/skill_meta.mdc +11 -0
  224. package/rules/tool-surface/docs/index.md +11 -0
  225. package/rules/tool-surface/main.json +6 -0
  226. package/rules/tool-surface/main.mdc +72 -0
  227. package/rules/vue/composition-api/composition-api.mdc +82 -0
  228. package/rules/vue/composition-api/concern.json +3 -0
  229. package/rules/vue/docs/index.md +11 -0
  230. package/rules/vue/lib/docs/index.md +11 -0
  231. package/rules/vue/lib/docs/vue-forbidden-imports.md +265 -0
  232. package/rules/vue/lib/vue-forbidden-imports.mjs +240 -0
  233. package/rules/vue/main.json +1 -0
  234. package/rules/vue/main.mdc +18 -0
  235. package/rules/vue/nheader-layout/concern.json +3 -0
  236. package/rules/vue/nheader-layout/nheader-layout.mdc +171 -0
  237. package/rules/vue/package_json/concern.json +9 -0
  238. package/rules/vue/package_json/package_json.mdc +30 -0
  239. package/rules/vue/package_json/package_json.rego +140 -0
  240. package/rules/vue/packages/concern.json +6 -0
  241. package/rules/vue/packages/docs/index.md +11 -0
  242. package/rules/vue/packages/docs/main.md +35 -0
  243. package/rules/vue/packages/main.mjs +575 -0
  244. package/rules/vue/packages/packages.mdc +56 -0
  245. package/rules/vue/quasar-ui/concern.json +3 -0
  246. package/rules/vue/quasar-ui/quasar-ui.mdc +32 -0
  247. package/rules/vue/structure/concern.json +3 -0
  248. package/rules/vue/structure/structure.mdc +101 -0
  249. package/rules/vue/testing/concern.json +3 -0
  250. package/rules/vue/testing/testing.mdc +40 -0
  251. package/rules/vue/tfm-translations/concern.json +7 -0
  252. package/rules/vue/tfm-translations/docs/main.md +29 -0
  253. package/rules/vue/tfm-translations/main.mjs +55 -0
  254. package/rules/vue/tfm-translations/tfm-translations.mdc +32 -0
  255. package/rules/vue/vite-config/concern.json +3 -0
  256. package/rules/vue/vite-config/vite-config.mdc +153 -0
  257. package/rules/vue/vite-env/concern.json +3 -0
  258. package/rules/vue/vite-env/vite-env.mdc +61 -0
@@ -0,0 +1,63 @@
1
+ ## Структура монорепо та компактний пакет
2
+
3
+ Bun monorepo: workspace **`npm/`**, кореневий **`package.json`**, **`.github/workflows/`**; опційно **`demo/`**.
4
+
5
+ Мета — **максимально компактний** опублікований пакет: у npm потрапляє тільки те, що потрібно під час `require`/`import` користувачем.
6
+
7
+ - **`"files"` обовʼязковий** у `npm/package.json` як **whitelist** того, що публікується (без `"files"` npm пакує майже все — це антипатерн для цього правила).
8
+ - **Тести й фікстури не публікуються — через негативні glob-патерни у `"files"`.** Тести можна (і зазвичай зручніше) тримати **поруч з кодом** усередині шляхів, перелічених у `"files"` (наприклад `*.test.mjs` поруч з модулем чи `fixtures/` під `rules/<id>/js/`). Щоб вони не потрапляли у tarball, `"files"` **обовʼязково має містити негативні glob-патерни**, що їх виключають. Покрий усі форми тестового: фреймворк-тести (`bun:test`, `node:test`, `vitest`, `@jest/globals`, `mocha`, …), test-style каталоги (`tests/`, `__tests__/`, `fixtures/`, `__fixtures__/`, `spec/`, `test/`), файли за патернами `*.test.*` / `*.spec.*`. Орієнтовний набір: `"!**/*.test.*"`, `"!**/*.spec.*"`, `"!**/test-helpers.*"`, `"!**/fixtures/**"`, `"!**/__tests__/**"`. **Rego (`*_test.rego`):** за конвенцією conftest юніт-тест лежить поруч з полісі у тому самому `package` — `*_test.rego` усередині опублікованого `policy/` дозволені; якщо потрібна максимальна компактність, додай `"!**/*_test.rego"` явно (як у самому `@7n/rules`).
9
+ - **Лише runtime-залежності у `npm/package.json`.** `devDependencies` тримай у **кореневому** `package.json` монорепо — тоді `npm install @nitra/<pkg>` не тягне інструментарій, потрібний лише для розробки самого пакета.
10
+
11
+ Перевірки JS (`package_structure.mjs`):
12
+
13
+ - Наявність `package.json`, `npm/`, `npm/package.json`.
14
+ - Walk шляхів з `"files"` з застосуванням негативних patterns і скан залишку на тест-патерни (walking + AST). Якщо після застосування негативних patterns у tarball лишається test-style файл — `check` падає з вказівкою, який саме негативний glob треба додати у `"files"`.
15
+
16
+ ## TypeScript declaration (`npm/types`)
17
+
18
+ Файл **`npm/package.json`** має містити **`"types"`** (шлях до головного `.d.ts` або `.d.mts` під **`./types/…`**) і запис **`"types"`** у **`files`**, щоб npm публікував декларації.
19
+
20
+ Генерація — через **`tsc`** і **`bunx -p typescript`** (окремий пакет **`typescript`** у `devDependencies` не потрібен).
21
+
22
+ ### Варіант A: є вихідний **`.js`** під **`npm/src/`**
23
+
24
+ Якщо під **`npm/src`** (рекурсивно) є хоча б один файл **`.js`**:
25
+
26
+ - **`"types": "./types/index.d.ts"`**;
27
+ - у **hk** на **`pre-commit`** з каталогу **`npm/`** викликай:
28
+
29
+ ```bash
30
+ bunx -p typescript tsc src/**/*.js --declaration --allowJs --emitDeclarationOnly --outDir types --skipLibCheck
31
+ ```
32
+
33
+ Якщо glob не розгортається — **`bash -O globstar`** або **`include`** у **`tsconfig`** з тими самими **`compilerOptions`**.
34
+
35
+ ### Варіант B: немає **`npm/src/**/*.js`** (наприклад лише **`bin/`**, **`scripts/**/*.mjs`**)
36
+
37
+ Не створюй штучний **`src/index.js`**. Замість цього:
38
+
39
+ 1. Додай **`npm/tsconfig.emit-types.json`** з **`include`** на реальні шляхи (`.js` / `.mjs`), **`compilerOptions`**: **`allowJs`**, **`declaration`**, **`emitDeclarationOnly`**, **`outDir`: `"types"`**, **`skipLibCheck`**: **`true`** (за потреби **`rootDir`**, **`module`**, **`moduleResolution`**).
40
+ 2. Після першого **`tsc`** подивись, який **`.d.ts`** / **`.d.mts`** відповідає публічному API, і вкажи його в **`types`** (наприклад **`./types/bin/cli.d.ts`**).
41
+ 3. У **hk** на **`pre-commit`** з **`npm/`** викликай **`tsc -p tsconfig.emit-types.json`**. Якщо через імпорти **TypeScript** все одно згенерує зайві **`.d.mts`** у **`types/`**, після **`tsc`** обрізай дерево до потрібного entrypoint (наприклад залиш лише **`types/bin/n-rules.d.ts`** через **`find`**), щоб у пакеті не збирались декларації внутрішніх модулів.
42
+
43
+ Файл **`tsconfig.emit-types.json`** тримай у репозиторії для **hk** / локальної генерації; у **`files`** його не додавай, якщо не хочеш публікувати його на **npm**.
44
+
45
+ ## Git hooks: hk + pre-commit
46
+
47
+ У корені репозиторію — **`hk.pkl`** (або **`.config/hk.pkl`**) з **`["pre-commit"]`** і командою з відповідного варіанту (A або B) вище.
48
+
49
+ Після додавання **`hk.pkl`**: **`hk install`**.
50
+
51
+ ## npm publish
52
+
53
+ **`npm-publish.yml`:** push у **`main`**, **`on.push.paths`** з **`npm/**`**, **`JS-DevTools/npm-publish@v4.1.5`**, **`with.package: npm/package.json`**, **`permissions.id-token: write`** (OIDC на npm).
54
+
55
+ Workflow робить **release + publish** одним job (`release-publish`): крок **`Release (bump + CHANGELOG + tag)`** (`bunx n-rules release` — агрегує change-файли, bump `version`, генерує секцію `CHANGELOG.md`, ставить git-тег) виконується **перед** публікацією. Тому потрібні **`permissions.contents: write`** і **`persist-credentials: true`** з **`fetch-depth: 0`** на `checkout` (release пушить commit-back версії та тег), а також локальний composite **`./.github/actions/setup-bun-deps`** і крок `Configure git identity`. Це узгоджено з **`n-changelog`**: `version`/`CHANGELOG.md` змінює лише `n-rules release` у CI на `main`. Програмна перевірка (`npm_module.npm_publish_yml`) звіряє **весь канонічний сніпет** напряму (`target.json:"check":"template"`, generic deep-subset): усі поля й кроки сніпета (`on.push.paths`/`branches`, `concurrency`, `permissions.contents/id-token`, `checkout` з `persist-credentials/fetch-depth`, `setup-bun-deps`, `Configure git identity`, `Release`, publish-крок) **обовʼязкові**; зайві кроки/поля дозволені (subset-of), масиви матчаться за наявністю (порядок кроків не важить). Сніпет — єдине джерело істини: його редагування одразу змінює enforce, без правок rego й без міграторів.
56
+
57
+ - Канон: [npm-publish.yml.snippet.yml](./policy/npm_publish_yml/template/npm-publish.yml.snippet.yml)
58
+
59
+ ## Канонічні конфіги
60
+
61
+ - Кореневий `package.json` (workspaces): [package.json.snippet.json](./policy/root_package_json/template/package.json.snippet.json)
62
+ - `npm/package.json` (whitelist `files` обовʼязково має містити `types`): [package.json.snippet.json](./policy/npm_package_json/template/package.json.snippet.json)
63
+ - `npm/tsconfig.emit-types.json` (canonical `compilerOptions` для emit-types): [tsconfig.emit-types.json.snippet.json](./policy/emit_types_config/template/tsconfig.emit-types.json.snippet.json)
@@ -0,0 +1,9 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@7n/rules/schemas/concern.json",
3
+ "fixability": "config",
4
+ "policy": {
5
+ "files": {
6
+ "single": "package.json"
7
+ }
8
+ }
9
+ }
@@ -0,0 +1,25 @@
1
+ ---
2
+ type: JS Module
3
+ title: fix-root_package_json.mjs
4
+ resource: plugins/lang-js/rules/npm-module/root_package_json/fix-root_package_json.mjs
5
+ docgen:
6
+ crc: 7b0c2f93
7
+ model: openai-codex/gpt-5.4-mini
8
+ score: 100
9
+ issues: judge:inaccurate:0.97
10
+ judgeModel: openai-codex/gpt-5.4-mini
11
+ ---
12
+
13
+ ## Огляд
14
+
15
+ `patterns` перевіряє кореневий `package.json` на відповідність еталонному шаблону npm-module і використовується для контролю очікуваної структури цього конфіга. Публічна функція: `patterns`. Конфіг, на який спирається код: `package.json`.
16
+
17
+ ## Поведінка
18
+
19
+ 1. `patterns` визначає набір правил, які звіряють кореневий `package.json` з еталонним шаблоном для npm-module.
20
+ 2. Кожне правило в цьому наборі націлене на `package.json` і використовується для вирівнювання кореневого конфіга з очікуваною структурою проєкту.
21
+ 3. `patterns` потрібен, щоб централізовано підтримувати однаковий формат root `package.json` у межах цього типу пакета.
22
+
23
+ ## Гарантії поведінки
24
+
25
+ - Read-only: не виконує операцій запису (ФС/БД).
@@ -0,0 +1,9 @@
1
+ ---
2
+ type: Directory Index
3
+ title: npm/rules/npm-module/root_package_json
4
+ resource: plugins/lang-js/rules/npm-module/root_package_json/
5
+ ---
6
+
7
+ | Файл | Тип |
8
+ | ----------------------------------------------------- | --------- |
9
+ | [fix-root_package_json.mjs](fix-root_package_json.md) | JS Module |
@@ -0,0 +1,5 @@
1
+ import { createTemplateFixPattern } from '@7n/rules/scripts/lib/fix/template-deep-merge.mjs'
2
+
3
+ export const patterns = [
4
+ createTemplateFixPattern({ id: 'npm-module-root_package_json-template', targetPath: 'package.json' })
5
+ ]
@@ -0,0 +1,41 @@
1
+ ## Rego-gate: валідація кореневого `package.json`
2
+
3
+ Rego-пакет: `npm-module.root_package_json`
4
+
5
+ Цільовий файл: `package.json` (корінь репозиторію)
6
+
7
+ ### Що перевіряється
8
+
9
+ Subset-of перевірка масиву `workspaces`: кожне значення з канонічного сніпету має бути присутнє у `workspaces`. За замовчуванням обовʼязковий елемент — `"npm"`.
10
+
11
+ Якщо `workspaces` відсутнє або не є масивом — окрема deny-помилка.
12
+
13
+ Канонічний сніпет: [package.json.snippet.json](./template/package.json.snippet.json)
14
+
15
+ Решта перевірок кореневого `package.json` (заборонені поля, devDeps лише `@nitra/*`) — у пакеті `bun.package_json`. FS-перевірки (наявність директорії `npm/`, `npm/package.json`) — у JS.
16
+
17
+ ### Приклади
18
+
19
+ ✓ Правильно — `workspaces` містить `"npm"`:
20
+
21
+ ```json
22
+ { "workspaces": ["npm"] }
23
+ ```
24
+
25
+ ✓ Правильно — `workspaces` містить `"npm"` разом з іншими:
26
+
27
+ ```json
28
+ { "workspaces": ["demo", "npm", "tests"] }
29
+ ```
30
+
31
+ ✗ Неправильно — `workspaces` відсутній:
32
+
33
+ ```json
34
+ { "name": "monorepo" }
35
+ ```
36
+
37
+ ✗ Неправильно — `workspaces` без `"npm"`:
38
+
39
+ ```json
40
+ { "workspaces": ["demo"] }
41
+ ```
@@ -0,0 +1,28 @@
1
+ # Перевірка кореневого `package.json` для npm-module (npm-module.mdc).
2
+ #
3
+ # Канон надходить через --data: { "template": { "snippet": ... } }
4
+ # Структура --data сформована з template/package.json.snippet.json.
5
+ # Snippet-array subset-of: кожне значення з template-масиву має бути у input-масиві.
6
+ # Решта кореневих `package.json`-перевірок (заборонені поля, devDeps лише @nitra/*)
7
+ # — у `bun.package_json`. FS-перевірки (наявність каталогу `npm/`, `npm/package.json`)
8
+ # — у JS.
9
+ package npm_module.root_package_json
10
+
11
+ import rego.v1
12
+
13
+ # Поле має бути масивом — інакше окрема deny.
14
+ deny contains msg if {
15
+ some field in object.keys(data.template.snippet)
16
+ not is_array(object.get(input, field, null))
17
+ msg := sprintf("package.json: масив %s відсутній або не масив (npm-module.mdc)", [field])
18
+ }
19
+
20
+ # Subset-of: кожне значення з template має бути в input-масиві.
21
+ deny contains msg if {
22
+ some field, expected_values in data.template.snippet
23
+ is_array(object.get(input, field, null))
24
+ actual_set := {v | some v in input[field]}
25
+ some required in expected_values
26
+ not required in actual_set
27
+ msg := sprintf("package.json: %s має містити %q (npm-module.mdc)", [field, required])
28
+ }
@@ -0,0 +1 @@
1
+ { "workspaces": ["npm"] }
@@ -0,0 +1,8 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@7n/rules/schemas/concern.json",
3
+ "fixability": "config",
4
+ "lint": {
5
+ "scope": "full",
6
+ "glob": ["npm/rules/**/main.json", "npm/rules/**/main.mjs", "npm/rules/**/main.mdc", "npm/rules/**/auto.md"]
7
+ }
8
+ }
@@ -0,0 +1,35 @@
1
+ ---
2
+ type: JS Module
3
+ title: main.mjs
4
+ resource: plugins/lang-js/rules/npm-module/rule_meta/main.mjs
5
+ docgen:
6
+ crc: c7424bda
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 95
9
+ issues: anchor-miss:(scripts.mdc),judge:inaccurate:0.98
10
+ judgeModel: openai-codex/gpt-5.4-mini
11
+ ---
12
+
13
+ ## Огляд
14
+
15
+ Lint-детектор concern-а `npm-module/rule_meta`: валідує метадані кожного правила у `npm/rules/<id>/` — файл `main.json` та супутні конвенції каталогу правила.
16
+
17
+ ## Поведінка
18
+
19
+ 1. Якщо `npm/rules/` відсутній — pass (немає правил для валідації).
20
+ 2. Для кожної теки правила:
21
+ - `auto.md` є пережитком — якщо файл лишився, порушення (метадані тепер у `main.json`).
22
+ - `main.mdc` обовʼязковий (канон scripts.mdc) — відсутність = порушення.
23
+ - `main.json` має існувати і бути валідним JSON-обʼєктом.
24
+ - Поле `auto` (опційне) має відповідати одній з форм: `"завжди"` / масив / `{ glob }` / `{ predicate }`; предикат має бути зареєстрований у `RULE_PREDICATES`.
25
+ - Поле `lint` заборонене: rule-level lint-scope скасовано (spec 2026-06-28-concern-lint-scope-design) — lint-поверхня декларується у `<rule>/<concern>/concern.json#lint`.
26
+ - Поле `llmFix` заборонене: opt-in-прапорця немає — fix-можливість концерну визначається наявністю `fix-*.mjs`/`fix-worker.mjs`.
27
+ 3. Повертає `LintResult` зі списком порушень; валідні правила репортяться як pass.
28
+
29
+ ## Публічний API
30
+
31
+ lint — перевіряє `main.json` усіх правил у `npm/rules/` і повертає `{ violations }`.
32
+
33
+ ## Гарантії поведінки
34
+
35
+ - Read-only: не виконує операцій запису (ФС/БД).
@@ -0,0 +1,119 @@
1
+ /** @see ./docs/main.md */
2
+ import { existsSync, readdirSync } from 'node:fs'
3
+ import { join } from 'node:path'
4
+
5
+ import { createViolationReporter } from '@7n/rules/scripts/lib/lint-surface/violation-reporter.mjs'
6
+ import { parseRuleAutoSpec, readRuleMetaRaw } from '@7n/rules/scripts/lib/rule-meta.mjs'
7
+ import { RULE_PREDICATES } from '@7n/rules/scripts/lib/rule-predicates.mjs'
8
+
9
+ /**
10
+ * Перевіряє поле `auto` у meta.json одного правила.
11
+ * @param {string} id ідентифікатор правила
12
+ * @param {Record<string, unknown>} raw сирий meta.json
13
+ * @param {ReturnType<typeof createViolationReporter>} reporter репортер
14
+ * @returns {boolean} true, якщо поле валідне (або відсутнє)
15
+ */
16
+ function checkAutoField(id, raw, reporter) {
17
+ if (raw.auto === undefined) return true
18
+ const spec = parseRuleAutoSpec(raw.auto)
19
+ if (spec === null) {
20
+ const autoHint = 'нерозпізнане (очікується "завжди" / масив / {glob} / {predicate})'
21
+ reporter.fail(`rules/${id}: main.json.auto ${autoHint}`)
22
+ return false
23
+ }
24
+ if ('predicate' in spec && !Object.hasOwn(RULE_PREDICATES, spec.predicate)) {
25
+ reporter.fail(`rules/${id}: main.json — невідомий predicate "${spec.predicate}" (немає в RULE_PREDICATES)`)
26
+ return false
27
+ }
28
+ return true
29
+ }
30
+
31
+ /**
32
+ * Забороняє залишкове поле `lint` у meta.json правила.
33
+ * Канон (spec 2026-06-28-concern-lint-scope-design): lint-scope живе у
34
+ * `<rule>/<concern>/concern.json#lint`, rule-level `main.json.lint` скасовано.
35
+ * @param {string} id ідентифікатор правила
36
+ * @param {Record<string, unknown>} raw сирий meta.json
37
+ * @param {ReturnType<typeof createViolationReporter>} reporter репортер
38
+ * @returns {boolean} true, якщо поле відсутнє
39
+ */
40
+ function checkLintField(id, raw, reporter) {
41
+ if (raw.lint === undefined) return true
42
+ reporter.fail(`rules/${id}: main.json.lint скасовано — lint-scope декларується у <concern>/concern.json#lint`)
43
+ return false
44
+ }
45
+
46
+ /**
47
+ * Забороняє залишкове поле `llmFix` у meta.json правила.
48
+ * Канон (scripts.mdc, spec 2026-06-28-concern-lint-scope-design): opt-in-прапорця
49
+ * llmFix немає — fix-можливість концерну визначається наявністю `fix-*.mjs`/`fix-worker.mjs`.
50
+ * @param {string} id ідентифікатор правила
51
+ * @param {Record<string, unknown>} raw сирий meta.json
52
+ * @param {ReturnType<typeof createViolationReporter>} reporter репортер
53
+ * @returns {boolean} true, якщо поле відсутнє
54
+ */
55
+ function checkLlmFixField(id, raw, reporter) {
56
+ if (raw.llmFix === undefined) return true
57
+ reporter.fail(
58
+ `rules/${id}: main.json.llmFix скасовано — fix-можливість = наявність fix-*.mjs/fix-worker.mjs у концерні`
59
+ )
60
+ return false
61
+ }
62
+
63
+ /**
64
+ * Валідує meta.json одного правила.
65
+ * @param {string} id ідентифікатор правила
66
+ * @param {string} ruleDir каталог правила
67
+ * @param {ReturnType<typeof createViolationReporter>} reporter репортер
68
+ * @returns {void}
69
+ */
70
+ function checkRule(id, ruleDir, reporter) {
71
+ let ruleOk = true
72
+
73
+ if (existsSync(join(ruleDir, 'auto.md'))) {
74
+ reporter.fail(`rules/${id}: залишковий auto.md — видали (метадані тепер у main.json)`)
75
+ ruleOk = false
76
+ }
77
+
78
+ // Канон (scripts.mdc): main.mdc — ОБОВ'ЯЗКОВИЙ у кожному npm/rules/<id>/.
79
+ if (!existsSync(join(ruleDir, 'main.mdc'))) {
80
+ reporter.fail(`rules/${id}: відсутній main.mdc — обов'язковий (scripts.mdc)`)
81
+ ruleOk = false
82
+ }
83
+
84
+ const raw = readRuleMetaRaw(ruleDir)
85
+ if (!raw) {
86
+ reporter.fail(`rules/${id}: відсутній або невалідний main.json`)
87
+ return
88
+ }
89
+
90
+ if (!checkAutoField(id, raw, reporter)) ruleOk = false
91
+ if (!checkLintField(id, raw, reporter)) ruleOk = false
92
+ if (!checkLlmFixField(id, raw, reporter)) ruleOk = false
93
+
94
+ if (ruleOk) {
95
+ reporter.pass(`rules/${id}: main.json валідний`)
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Валідує всі `npm/rules/<id>/meta.json`.
101
+ * @param {import('@7n/rules/scripts/lib/lint-surface/types.mjs').LintContext} ctx Контекст лінту (`cwd` тощо).
102
+ * @returns {Promise<import('@7n/rules/scripts/lib/lint-surface/types.mjs').LintResult>} Результат лінту зі списком violations.
103
+ */
104
+ export function lint(ctx) {
105
+ const cwd = ctx.cwd
106
+ const reporter = createViolationReporter(ctx)
107
+ const rulesDir = join(cwd, 'npm', 'rules')
108
+ if (!existsSync(rulesDir)) {
109
+ reporter.pass('npm/rules/ відсутній — немає правил для валідації')
110
+ return Promise.resolve(reporter.result())
111
+ }
112
+
113
+ for (const entry of readdirSync(rulesDir, { withFileTypes: true })) {
114
+ if (!entry.isDirectory() || entry.name.startsWith('.')) continue
115
+ checkRule(entry.name, join(rulesDir, entry.name), reporter)
116
+ }
117
+
118
+ return Promise.resolve(reporter.result())
119
+ }
@@ -0,0 +1,11 @@
1
+ ## Валідація `main.json` правил
2
+
3
+ Кожне правило у `npm/rules/<id>/` повинно мати коректний `main.json` (метадані правила).
4
+
5
+ Перевірки (`rule_meta.mjs`):
6
+
7
+ - **`main.mdc` обовʼязковий** у кожному `npm/rules/<id>/` — без нього `check` падає.
8
+ - **`auto.md` є пережитком** — якщо такий файл залишився, `check` вимагає його видалити (метадані тепер у `main.json`).
9
+ - **`main.json` має бути валідним JSON** із коректними полями:
10
+ - **`auto`** (опційне): `"завжди"` / масив glob-рядків / `{ glob }` / `{ predicate }`. Якщо `predicate` вказано — він має бути зареєстрований у `RULE_PREDICATES`.
11
+ - **`lint` заборонене**: rule-level scope скасовано — lint-поверхня декларується per-concern у `<rule>/<concern>/concern.json#lint` (spec 2026-06-28-concern-lint-scope-design).
@@ -0,0 +1,5 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@7n/rules/schemas/concern.json",
3
+ "fixability": "config",
4
+ "lint": { "scope": "full", "glob": ["npm/skills/**/main.json", "npm/skills/**/auto.md"] }
5
+ }
@@ -0,0 +1,149 @@
1
+ ---
2
+ type: JS Module
3
+ title: main.mjs
4
+ resource: plugins/lang-js/rules/npm-module/skill_meta/main.mjs
5
+ docgen:
6
+ crc: 1bfaac0d
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 100
9
+ issues: judge:inaccurate:0.99
10
+ judgeModel: openai-codex/gpt-5.4-mini
11
+ ---
12
+
13
+ ## Огляд
14
+
15
+ system_message:
16
+ You are an expert coding assistant operating inside pi, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.
17
+
18
+ Available tools:
19
+ (none)
20
+
21
+ In addition to the tools above, you may have access to other custom tools depending on the project.
22
+
23
+ Guidelines:
24
+
25
+ - Be concise in your responses
26
+ - Show file paths clearly when working with files
27
+
28
+ Pi documentation (read only when the user asks about pi itself, its SDK, extensions, themes, skills, or TUI):
29
+
30
+ - Main documentation: /Users/vitalii/www/nitra/cursor/node_modules/@earendil-works/pi-coding-agent/README.md
31
+ - Additional docs: /Users/vitalii/www/nitra/cursor/node_modules/@earendil-works/pi-coding-agent/docs
32
+ - Examples: /Users/vitalii/www/nitra/cursor/node_modules/@earendil-works/pi-coding-agent/examples (extensions, custom tools, SDK)
33
+ - When reading pi docs or examples, resolve docs/... under Additional docs and examples/... under Examples, not the current working directory
34
+ - When asked about: extensions (docs/extensions.md, examples/extensions/), themes (docs/themes.md), skills (docs/skills.md), prompt templates (docs/prompt-templates.md), TUI components (docs/tui.md), keybindings (docs/keybindings.md), SDK integrations (docs/sdk.md), custom providers (docs/custom-provider.md), adding models (docs/models.md), pi packages (docs/packages.md)
35
+ - When working on pi topics, read the pi .md files completely and follow .md cross-references before implementing
36
+ - Always read pi .md files completely and follow links to related docs (e.g., tui.md for TUI API details)
37
+
38
+ <project_context>
39
+ Project-specific instructions and guidelines:
40
+
41
+ <project_instructions path="/Users/vitalii/www/nitra/cursor/AGENTS.md">
42
+
43
+ # AGENTS.md version: '1.0'
44
+
45
+ ## Purpose
46
+
47
+ This file is the entry point for all AI agents working with this repository.
48
+
49
+ ## Rule source
50
+
51
+ The primary development rules are stored in the Cursor rules directory:
52
+
53
+ - .cursor/rules/conftest.mdc
54
+ - .cursor/rules/dev-dep.mdc
55
+ - .cursor/rules/n-adr.mdc
56
+ - .cursor/rules/n-bun.mdc
57
+ - .cursor/rules/n-changelog.mdc
58
+ - .cursor/rules/n-ci4.mdc
59
+ - .cursor/rules/n-doc-files.mdc
60
+ - .cursor/rules/n-feedback.mdc
61
+ - .cursor/rules/n-ga.mdc
62
+ - .cursor/rules/n-js-run.mdc
63
+ - .cursor/rules/n-js.mdc
64
+ - .cursor/rules/n-npm-module.mdc
65
+ - .cursor/rules/n-python.mdc
66
+ - .cursor/rules/n-rego.mdc
67
+ - .cursor/rules/n-security.mdc
68
+ - .cursor/rules/n-style.mdc
69
+ - .cursor/rules/n-test.mdc
70
+ - .cursor/rules/n-text.mdc
71
+ - .cursor/rules/n-tool-surface.mdc
72
+ - .cursor/rules/n-vue.mdc
73
+ - .cursor/rules/n-worktree.mdc
74
+ - .cursor/rules/scripts.mdc
75
+
76
+ ## Skills
77
+
78
+ - `.cursor/skills/mdc-check/SKILL.md` — Проаналізувати правило в npm/mdc: максимум перевірюваної логіки й деталей — у check-{id}.mjs з зрозумілими коментарями/JSDoc; у .mdc залишати людинозрозумілий зміст без дублювання алгоритму перевірки
79
+ - `.cursor/skills/n-adr-normalize/SKILL.md` — Ручний запуск ADR-нормалізації — обхід порогу й min-interval, прогон одного батчу чернеток через LLM, перегляд результату через git diff
80
+ - `.cursor/skills/n-doc-files/SKILL.md` — Обовʼязковий крок задачі (як lint): для кожного зміненого/нового кодового файлу (js/mjs/ts/vue/py) JS-оркестрована генерація лаконічної поведінкової української md-документації у теку docs/ поряд із кодом, зі звіркою застарілості за CRC у frontmatter
81
+ - `.cursor/skills/n-lint/SKILL.md` — Запустити дельта-лінт (npx @7n/rules lint) по змінених файлах vs origin, виправити порушення й підтвердити чистий вихід
82
+ - `.cursor/skills/n-llm-patch/SKILL.md` — Підготовка самодостатнього текстового промпта для іншого Claude/Cursor-агента — read-only аналіз CWD без жодних змін у поточному репо
83
+ - `.cursor/skills/n-publish-telegram/SKILL.md` — Підготовка матеріалу з поточного контексту для публікації в Telegram-каналі команди
84
+ - `.cursor/skills/n-taze/SKILL.md` — Оновлення версій модулів проекту з аналізом major-змін і автоматичним рефакторингом несумісного коду
85
+
86
+ ## Commands
87
+
88
+ Generated from the root `package.json` on each `npx @7n/rules` sync. Prefer `bun run <script>` for project scripts.
89
+
90
+ - **Залежності**: `bun i`
91
+ - **test**: `bun run test`
92
+ - **start**: `bun run start`
93
+ - **Оновити правила та AGENTS.md** (після змін у правилах/шаблоні CLI): `npx @7n/rules`
94
+ - **Перевірки правил (programmatic)**: `npx @7n/rules fix`
95
+ - **knip (невикористані залежності та експорти)**: `bunx knip`
96
+
97
+ ## Instructions for all agents
98
+
99
+ Before making changes, read the relevant rule files for the area you are working on.
100
+
101
+ ## Інваріант після змін
102
+
103
+ `n-changelog.mdc` (alwaysApply) релевантне після **будь-якої** зміни файлів, не лише для релізу. Перед фінальною відповіддю виконай `npx @7n/rules fix changelog` (exit `0`) і познач результат рядком `Changelog: …` у відповіді.
104
+
105
+ ## Priority
106
+
107
+ If rules conflict:
108
+
109
+ 1. AGENTS.md
110
+ 2. task-specific rule file
111
+ 3. core rule file
112
+
113
+ ## Language
114
+
115
+ Respond in Ukrainian.
116
+ Keep technical terms in English.
117
+
118
+ ## Behavior
119
+
120
+ Do not ignore referenced rule files.
121
+ Explicitly follow repository conventions before proposing or applying changes.
122
+
123
+ </project_instructions>
124
+ </project_context>
125
+
126
+ ## Поведінка
127
+
128
+ Поведінка:
129
+
130
+ 1. Перевіряє наявність каталогу `npm/skills` у корені репозиторію. Якщо відсутній, операція завершується успіхом.
131
+ 2. Ітерується по всім підкаталогах у `npm/skills`. Для кожного каталогу виконується перевірка відповідності метаданих скіла.
132
+ 3. Для кожного скіла перевіряється, чи відсутній файл `auto.md`. Якщо знайдено, фіксується порушення, оскільки метадані мають знаходитися у `main.json`.
133
+ 4. Зчитується вміст `main.json` скіла. Якщо файл відсутній або недійсний, фіксується порушення.
134
+ 5. Виконується перевірка полів у `main.json` скіла:
135
+ - Перевіряється тип поля `worktree` — має бути булевим значенням.
136
+ - Якщо поле `auto` визначене, аналізується його значення на відповідність очікуваним форматам.
137
+ - Перевіряється тип поля `requireRoot` — має бути булевим значенням.
138
+ - Перевіряється узгодженість: якщо `worktree` дорівнює `true`, поле `requireRoot` не може бути `false`.
139
+ - Якщо поле `tier` визначене, воно має відповідати одному з визначених рівнів.
140
+ 6. Якщо всі перевірки для скіла успішно пройдені, фіксується успішний статус для цього скіла.
141
+ 7. Завершення виконання `main` та повернення коду виходу, що відображає кількість виявлених порушень.
142
+
143
+ ## Публічний API
144
+
145
+ main — перевіряє, що всі файли `npm/skills/<id>/meta.json` відповідають встановленим вимогам.
146
+
147
+ ## Гарантії поведінки
148
+
149
+ - Read-only: не виконує операцій запису (ФС/БД).
@@ -0,0 +1,91 @@
1
+ /** @see ./docs/skill_meta.md */
2
+ import { existsSync, readdirSync } from 'node:fs'
3
+ import { join } from 'node:path'
4
+
5
+ import { createViolationReporter } from '@7n/rules/scripts/lib/lint-surface/violation-reporter.mjs'
6
+ import { SKILL_TIERS, parseSkillAutoSpec, readSkillMetaRaw } from '@7n/rules/scripts/lib/skill-meta.mjs'
7
+
8
+ /**
9
+ * Перевіряє поля сирого meta.json одного скіла (без auto.md / відсутності файлу).
10
+ * @param {string} id ідентифікатор скіла
11
+ * @param {Record<string, unknown>} raw сирий meta.json
12
+ * @param {ReturnType<typeof createViolationReporter>} reporter репортер
13
+ * @returns {boolean} true, якщо всі поля валідні
14
+ */
15
+ function checkSkillFields(id, raw, reporter) {
16
+ let ok = true
17
+ if (typeof raw.worktree !== 'boolean') {
18
+ reporter.fail(`skills/${id}: main.json.worktree має бути boolean`)
19
+ ok = false
20
+ }
21
+ if (raw.auto !== undefined && parseSkillAutoSpec(raw.auto) === null) {
22
+ reporter.fail(`skills/${id}: main.json.auto нерозпізнане — очікується "завжди" або непорожній масив правил`)
23
+ ok = false
24
+ }
25
+ if (raw.requireRoot !== undefined && typeof raw.requireRoot !== 'boolean') {
26
+ reporter.fail(`skills/${id}: main.json.requireRoot має бути boolean`)
27
+ ok = false
28
+ }
29
+ if (raw.worktree === true && raw.requireRoot === false) {
30
+ reporter.fail(
31
+ `skills/${id}: requireRoot:false суперечить worktree:true (worktree вже вимагає кореня — прибери поле)`
32
+ )
33
+ ok = false
34
+ }
35
+ if (raw.tier !== undefined && !(typeof raw.tier === 'string' && SKILL_TIERS.includes(raw.tier))) {
36
+ const tierList = SKILL_TIERS.map(t => `"${t}"`).join(' | ')
37
+ reporter.fail(`skills/${id}: main.json.tier має бути ${tierList}`)
38
+ ok = false
39
+ }
40
+ return ok
41
+ }
42
+
43
+ /**
44
+ * Валідує meta.json одного скіла.
45
+ * @param {string} id ідентифікатор скіла
46
+ * @param {string} skillDir каталог скіла
47
+ * @param {ReturnType<typeof createViolationReporter>} reporter репортер
48
+ * @returns {void}
49
+ */
50
+ function checkSkill(id, skillDir, reporter) {
51
+ let skillOk = true
52
+
53
+ if (existsSync(join(skillDir, 'auto.md'))) {
54
+ reporter.fail(`skills/${id}: залишковий auto.md — видали (метадані тепер у main.json)`)
55
+ skillOk = false
56
+ }
57
+
58
+ const raw = readSkillMetaRaw(skillDir)
59
+ if (!raw) {
60
+ reporter.fail(`skills/${id}: відсутній або невалідний main.json (очікується {"auto"?, "worktree": bool})`)
61
+ return
62
+ }
63
+
64
+ if (!checkSkillFields(id, raw, reporter)) skillOk = false
65
+
66
+ if (skillOk) {
67
+ reporter.pass(`skills/${id}: main.json валідний`)
68
+ }
69
+ }
70
+
71
+ /**
72
+ * Валідує всі `npm/skills/<id>/meta.json`.
73
+ * @param {import('@7n/rules/scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст лінту.
74
+ * @returns {Promise<import('@7n/rules/scripts/lib/lint-surface/types.mjs').LintResult>} результат перевірки з порушеннями.
75
+ */
76
+ export function lint(ctx) {
77
+ const cwd = ctx.cwd
78
+ const reporter = createViolationReporter(ctx)
79
+ const skillsDir = join(cwd, 'npm', 'skills')
80
+ if (!existsSync(skillsDir)) {
81
+ reporter.pass('npm/skills/ відсутній — немає скілів для валідації')
82
+ return Promise.resolve(reporter.result())
83
+ }
84
+
85
+ for (const entry of readdirSync(skillsDir, { withFileTypes: true })) {
86
+ if (!entry.isDirectory() || entry.name.startsWith('.')) continue
87
+ checkSkill(entry.name, join(skillsDir, entry.name), reporter)
88
+ }
89
+
90
+ return Promise.resolve(reporter.result())
91
+ }
@@ -0,0 +1,11 @@
1
+ ## Валідація `main.json` скілів
2
+
3
+ Кожен скіл у `npm/skills/<id>/` повинен мати коректний `main.json` (метадані скіла).
4
+
5
+ Перевірки (`skill_meta.mjs`):
6
+
7
+ - **`auto.md` є пережитком** — якщо такий файл залишився, `check` вимагає його видалити (метадані тепер у `main.json`).
8
+ - **`main.json` має бути валідним JSON** із коректними полями:
9
+ - **`worktree`** (обовʼязкове): `boolean`. Якщо `true` — скіл запускається виключно в окремому git-worktree.
10
+ - **`auto`** (опційне): `"завжди"` або непорожній масив ідентифікаторів правил-тригерів.
11
+ - **`requireRoot`** (опційне): `boolean`. Значення `false` несумісне з `worktree: true` — таку комбінацію `check` відхиляє.