@nitra/cursor 12.8.6 → 12.8.8

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 (263) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/package.json +1 -1
  3. package/rules/abie/main.mdc +9 -5
  4. package/rules/abie/policy/base_deployment_preem/base_deployment_preem.mdc +22 -0
  5. package/rules/abie/policy/clean_merged_ignore_branches/clean_merged_ignore_branches.mdc +19 -0
  6. package/rules/abie/policy/health_check_policy/health_check_policy.mdc +17 -0
  7. package/rules/abie/policy/http_route_base/http_route_base.mdc +9 -0
  8. package/rules/abie/policy/package_json_shared/package_json_shared.mdc +17 -0
  9. package/rules/adr/js/hooks.mdc +32 -0
  10. package/rules/adr/js/madr_format.mdc +96 -0
  11. package/rules/adr/js/settings_policy.mdc +34 -0
  12. package/rules/adr/main.mdc +17 -95
  13. package/rules/adr/policy/settings_json/settings_json.mdc +7 -0
  14. package/rules/adr/policy/settings_local_json/settings_local_json.mdc +7 -0
  15. package/rules/bun/js/bunfig.mdc +12 -0
  16. package/rules/bun/js/layout.mdc +60 -0
  17. package/rules/bun/js/lint.mdc +9 -0
  18. package/rules/bun/js/package_json.mdc +19 -0
  19. package/rules/bun/main.mdc +7 -60
  20. package/rules/bun/policy/bunfig/bunfig.mdc +12 -0
  21. package/rules/bun/policy/package_json/package_json.mdc +14 -0
  22. package/rules/capacitor/js/ios_spm.mdc +69 -0
  23. package/rules/capacitor/js/version.mdc +29 -0
  24. package/rules/capacitor/main.mdc +6 -22
  25. package/rules/capacitor/policy/package_json/package_json.mdc +9 -0
  26. package/rules/changelog/js/agent-workflow.mdc +15 -0
  27. package/rules/changelog/js/changelog-format.mdc +33 -0
  28. package/rules/changelog/js/comparison-models.mdc +40 -0
  29. package/rules/changelog/main.mdc +4 -98
  30. package/rules/ci4/js/marksman_config.mdc +31 -0
  31. package/rules/ci4/js/vscode_extensions.mdc +33 -0
  32. package/rules/ci4/main.mdc +16 -14
  33. package/rules/ci4/policy/vscode_extensions/vscode_extensions.mdc +9 -0
  34. package/rules/docker/js/compile.mdc +44 -0
  35. package/rules/docker/js/hadolint.mdc +50 -0
  36. package/rules/docker/js/mirror.mdc +13 -0
  37. package/rules/docker/js/multistage.mdc +13 -0
  38. package/rules/docker/js/native-addon.mdc +43 -0
  39. package/rules/docker/js/nginx-tag.mdc +7 -0
  40. package/rules/docker/js/nginx-user.mdc +37 -0
  41. package/rules/docker/js/non-root.mdc +39 -0
  42. package/rules/docker/main.mdc +13 -196
  43. package/rules/docker/policy/lint_docker_yml/lint_docker_yml.mdc +14 -0
  44. package/rules/efes/main.mdc +1 -1
  45. package/rules/efes/policy/package_json_shared/package_json_shared.mdc +30 -0
  46. package/rules/ga/js/lint_toolchain.mdc +15 -0
  47. package/rules/ga/js/required_workflows.mdc +35 -0
  48. package/rules/ga/js/vscode.mdc +17 -0
  49. package/rules/ga/js/workflow_common.mdc +108 -0
  50. package/rules/ga/js/workflows.mdc +32 -0
  51. package/rules/ga/js/zizmor.mdc +7 -0
  52. package/rules/ga/main.mdc +16 -119
  53. package/rules/ga/policy/clean_ga_workflows/clean_ga_workflows.mdc +18 -0
  54. package/rules/ga/policy/clean_merged_branch/clean_merged_branch.mdc +22 -0
  55. package/rules/ga/policy/git_ai/git_ai.mdc +19 -0
  56. package/rules/ga/policy/lint_ga/lint_ga.mdc +21 -0
  57. package/rules/ga/policy/vscode_extensions/vscode_extensions.mdc +9 -0
  58. package/rules/ga/policy/vscode_settings/vscode_settings.mdc +9 -0
  59. package/rules/ga/policy/workflow_common/workflow_common.mdc +18 -0
  60. package/rules/ga/policy/zizmor_yml/zizmor_yml.mdc +9 -0
  61. package/rules/graphql/js/tooling.mdc +13 -0
  62. package/rules/graphql/js/vscode_extensions.mdc +13 -0
  63. package/rules/graphql/main.mdc +4 -21
  64. package/rules/graphql/policy/vscode_extensions/vscode_extensions.mdc +9 -0
  65. package/rules/hasura/js/internal_urls.mdc +27 -0
  66. package/rules/hasura/js/migrations.mdc +13 -0
  67. package/rules/hasura/js/svc_hl.mdc +17 -0
  68. package/rules/hasura/main.mdc +6 -30
  69. package/rules/hasura/policy/svc_hl/svc_hl.mdc +15 -0
  70. package/rules/image-avif/js/avif_generation.mdc +26 -0
  71. package/rules/image-avif/js/package_json_optout.mdc +21 -0
  72. package/rules/image-avif/main.mdc +5 -34
  73. package/rules/image-avif/policy/package_json/package_json.mdc +18 -0
  74. package/rules/image-compress/js/package_json.mdc +7 -0
  75. package/rules/image-compress/js/package_setup.mdc +13 -0
  76. package/rules/image-compress/main.mdc +4 -12
  77. package/rules/image-compress/policy/package_json/package_json.mdc +13 -0
  78. package/rules/js/docs/index.md +3 -3
  79. package/rules/js/js/dep-policy.mdc +17 -0
  80. package/rules/js/js/eslint-config.mdc +28 -0
  81. package/rules/js/js/extensions.mdc +8 -0
  82. package/rules/js/js/file-extensions.mdc +12 -0
  83. package/rules/js/js/for-in.mdc +26 -0
  84. package/rules/js/js/jscpd.mdc +42 -0
  85. package/rules/js/js/knip.mdc +15 -0
  86. package/rules/js/js/lint-js-workflow.mdc +58 -0
  87. package/rules/js/js/oxlintrc.mdc +20 -0
  88. package/rules/js/js/package-json.mdc +31 -0
  89. package/rules/js/js/tests.mdc +9 -0
  90. package/rules/js/js/utils-lib-structure.mdc +15 -0
  91. package/rules/js/main.mdc +19 -211
  92. package/rules/js/policy/jscpd/jscpd.mdc +14 -0
  93. package/rules/js/policy/lint_js_yml/lint_js_yml.mdc +14 -0
  94. package/rules/js/policy/package_json/package_json.mdc +15 -0
  95. package/rules/js/policy/vscode_extensions/vscode_extensions.mdc +11 -0
  96. package/rules/js-bun-db/js/bun-sql-migration.mdc +15 -0
  97. package/rules/js-bun-db/js/connection.mdc +42 -0
  98. package/rules/js-bun-db/js/pg-format-identifiers.mdc +102 -0
  99. package/rules/js-bun-db/js/pg-format-shim.mdc +99 -0
  100. package/rules/js-bun-db/js/pg-leftover.mdc +27 -0
  101. package/rules/js-bun-db/js/pg-listen-notify.mdc +51 -0
  102. package/rules/js-bun-db/js/query-safety.mdc +117 -0
  103. package/rules/js-bun-db/js/sql-array.mdc +88 -0
  104. package/rules/js-bun-db/js/unsafe.mdc +65 -0
  105. package/rules/js-bun-db/main.mdc +12 -607
  106. package/rules/js-bun-db/policy/package_json/package_json.mdc +17 -0
  107. package/rules/js-bun-redis/js/imports.mdc +47 -0
  108. package/rules/js-bun-redis/js/package_json.mdc +44 -0
  109. package/rules/js-bun-redis/main.mdc +4 -10
  110. package/rules/js-bun-redis/policy/package_json/package_json.mdc +11 -0
  111. package/rules/js-mssql/js/mssql-in-list.mdc +38 -0
  112. package/rules/js-mssql/js/mssql-pool.mdc +56 -0
  113. package/rules/js-mssql/js/mssql-query-template.mdc +33 -0
  114. package/rules/js-mssql/js/mssql-tvp.mdc +75 -0
  115. package/rules/js-mssql/js/mssql-version.mdc +7 -0
  116. package/rules/js-mssql/main.mdc +10 -198
  117. package/rules/js-mssql/policy/package_json/package_json.mdc +9 -0
  118. package/rules/js-run/js/check-env.mdc +35 -0
  119. package/rules/js-run/js/conn-aliases.mdc +109 -0
  120. package/rules/js-run/js/jsconfig.mdc +20 -0
  121. package/rules/js-run/js/otel-configmap.mdc +6 -0
  122. package/rules/js-run/js/pino.mdc +6 -0
  123. package/rules/js-run/js/project-structure.mdc +11 -0
  124. package/rules/js-run/js/runtime.mdc +14 -0
  125. package/rules/js-run/js/scope.mdc +11 -0
  126. package/rules/js-run/js/settimeout.mdc +11 -0
  127. package/rules/js-run/js/temporal.mdc +5 -0
  128. package/rules/js-run/main.mdc +16 -216
  129. package/rules/js-run/policy/configmap/configmap.mdc +31 -0
  130. package/rules/js-run/policy/jsconfig/jsconfig.mdc +25 -0
  131. package/rules/js-run/policy/package_json/package_json.mdc +38 -0
  132. package/rules/k8s/js/configmap.mdc +41 -0
  133. package/rules/k8s/js/deployment_resources.mdc +49 -0
  134. package/rules/k8s/js/hasura_httproute.mdc +91 -0
  135. package/rules/k8s/js/hpa_apiversion.mdc +27 -0
  136. package/rules/k8s/js/ingress_gateway.mdc +16 -0
  137. package/rules/k8s/js/kustomize_structure.mdc +144 -0
  138. package/rules/k8s/js/lint_k8s.mdc +72 -0
  139. package/rules/k8s/js/multidoc_yaml.mdc +5 -0
  140. package/rules/k8s/js/network_policy.mdc +136 -0
  141. package/rules/k8s/js/schema_modeline.mdc +57 -0
  142. package/rules/k8s/js/service.mdc +44 -0
  143. package/rules/k8s/js/topology_hpa_pdb.mdc +181 -0
  144. package/rules/k8s/main.mdc +29 -834
  145. package/rules/k8s/policy/base_kustomization/base_kustomization.mdc +12 -0
  146. package/rules/k8s/policy/base_manifest/base_manifest.mdc +14 -0
  147. package/rules/k8s/policy/gateway/gateway.mdc +17 -0
  148. package/rules/k8s/policy/hasura_configmap/hasura_configmap.mdc +20 -0
  149. package/rules/k8s/policy/hasura_httproute/hasura_httproute.mdc +16 -0
  150. package/rules/k8s/policy/hpa_pdb/hpa_pdb.mdc +23 -0
  151. package/rules/k8s/policy/kustomization/kustomization.mdc +20 -0
  152. package/rules/k8s/policy/manifest/manifest.mdc +17 -0
  153. package/rules/k8s/policy/network_policy/network_policy.mdc +22 -0
  154. package/rules/k8s/policy/svc_hl_yaml/svc_hl_yaml.mdc +13 -0
  155. package/rules/k8s/policy/svc_yaml/svc_yaml.mdc +12 -0
  156. package/rules/nginx-default-tpl/js/dockerfile.mdc +36 -0
  157. package/rules/nginx-default-tpl/js/http-route.mdc +41 -0
  158. package/rules/nginx-default-tpl/js/ini-keys.mdc +21 -0
  159. package/rules/nginx-default-tpl/js/template-structure.mdc +86 -0
  160. package/rules/nginx-default-tpl/js/vscode.mdc +37 -0
  161. package/rules/nginx-default-tpl/main.mdc +8 -110
  162. package/rules/nginx-default-tpl/policy/vscode_extensions/vscode_extensions.mdc +11 -0
  163. package/rules/nginx-default-tpl/policy/vscode_settings/vscode_settings.mdc +15 -0
  164. package/rules/npm-module/js/docs/index.md +5 -5
  165. package/rules/npm-module/js/docs/rule_meta.md +6 -6
  166. package/rules/npm-module/js/docs/skill_meta.md +8 -8
  167. package/rules/npm-module/js/header_doc_pointer.mdc +18 -0
  168. package/rules/npm-module/js/package_structure.mdc +62 -0
  169. package/rules/npm-module/js/rule_meta.mdc +11 -0
  170. package/rules/npm-module/js/skill_meta.mdc +11 -0
  171. package/rules/npm-module/main.mdc +10 -52
  172. package/rules/npm-module/policy/emit_types_config/emit_types_config.mdc +40 -0
  173. package/rules/npm-module/policy/npm_package_json/npm_package_json.mdc +50 -0
  174. package/rules/npm-module/policy/root_package_json/root_package_json.mdc +37 -0
  175. package/rules/php/js/lint_php_yml.mdc +12 -0
  176. package/rules/php/js/tooling.mdc +66 -0
  177. package/rules/php/main.mdc +5 -66
  178. package/rules/php/policy/lint_php_yml/lint_php_yml.mdc +21 -0
  179. package/rules/python/js/lint_python_yml.mdc +23 -0
  180. package/rules/python/js/pyproject_toml.mdc +32 -0
  181. package/rules/python/js/tooling.mdc +23 -0
  182. package/rules/python/main.mdc +7 -32
  183. package/rules/python/policy/lint_python_yml/lint_python_yml.mdc +12 -0
  184. package/rules/python/policy/pyproject_toml/pyproject_toml.mdc +13 -0
  185. package/rules/rego/js/rego-lint.mdc +31 -0
  186. package/rules/rego/js/vscode_extensions.mdc +11 -0
  187. package/rules/rego/js/vscode_settings.mdc +13 -0
  188. package/rules/rego/main.mdc +10 -22
  189. package/rules/rego/policy/vscode_extensions/vscode_extensions.mdc +11 -0
  190. package/rules/rego/policy/vscode_settings/vscode_settings.mdc +19 -0
  191. package/rules/rust/js/coverage.mdc +28 -0
  192. package/rules/rust/js/lint.mdc +22 -0
  193. package/rules/rust/js/tauri_composition.mdc +8 -0
  194. package/rules/rust/js/vscode_extensions.mdc +12 -0
  195. package/rules/rust/main.mdc +8 -38
  196. package/rules/rust/policy/lint_rust_yml/lint_rust_yml.mdc +12 -0
  197. package/rules/rust/policy/vscode_extensions/vscode_extensions.mdc +9 -0
  198. package/rules/security/js/rego_policies.mdc +15 -0
  199. package/rules/security/js/sample_secret.mdc +19 -0
  200. package/rules/security/js/trufflehog.mdc +21 -0
  201. package/rules/security/main.mdc +7 -34
  202. package/rules/security/policy/lint_security_yml/lint_security_yml.mdc +7 -0
  203. package/rules/security/policy/package_json/package_json.mdc +7 -0
  204. package/rules/style/js/admin-table.mdc +88 -0
  205. package/rules/style/js/colors.mdc +21 -0
  206. package/rules/style/js/gap.mdc +22 -0
  207. package/rules/style/js/quasar-fixes.mdc +32 -0
  208. package/rules/style/js/quasar.mdc +7 -0
  209. package/rules/style/js/tooling.mdc +85 -0
  210. package/rules/style/main.mdc +12 -251
  211. package/rules/style/policy/lint_style_yml/lint_style_yml.mdc +13 -0
  212. package/rules/style/policy/package_json/package_json.mdc +18 -0
  213. package/rules/style/policy/vscode_extensions/vscode_extensions.mdc +13 -0
  214. package/rules/style/policy/vscode_settings/vscode_settings.mdc +19 -0
  215. package/rules/tauri/js/cargo_mutants_config.mdc +39 -0
  216. package/rules/tauri/js/tool_surface.mdc +21 -0
  217. package/rules/tauri/js/tooling.mdc +25 -0
  218. package/rules/tauri/main.mdc +6 -78
  219. package/rules/tauri/policy/vscode_extensions/vscode_extensions.mdc +21 -0
  220. package/rules/test/js/cargo_mutants_config.mdc +18 -0
  221. package/rules/test/js/docs/index.md +7 -7
  222. package/rules/test/js/location.mdc +52 -0
  223. package/rules/test/js/no-console-store-restore.mdc +11 -0
  224. package/rules/test/js/no-process-chdir.mdc +15 -0
  225. package/rules/test/js/no-relative-fs-path.mdc +22 -0
  226. package/rules/test/js/sandbox-aware-test.mdc +28 -0
  227. package/rules/test/js/stryker_config.mdc +26 -0
  228. package/rules/test/js/vitest-config-pool-forks.mdc +33 -0
  229. package/rules/test/main.mdc +16 -184
  230. package/rules/test/policy/package_json/package_json.mdc +16 -0
  231. package/rules/text/js/ci-lint-text.mdc +15 -0
  232. package/rules/text/js/cspell.mdc +81 -0
  233. package/rules/text/js/dotenv-linter.mdc +16 -0
  234. package/rules/text/js/forbidden-prettier.mdc +13 -0
  235. package/rules/text/js/markdownlint.mdc +25 -0
  236. package/rules/text/js/oxfmt.mdc +35 -0
  237. package/rules/text/js/package-json.mdc +26 -0
  238. package/rules/text/js/shellcheck.mdc +18 -0
  239. package/rules/text/js/v8r.mdc +23 -0
  240. package/rules/text/js/vscode.mdc +86 -0
  241. package/rules/text/main.mdc +20 -231
  242. package/rules/text/policy/cspell/cspell.mdc +34 -0
  243. package/rules/text/policy/lint_text/lint_text.mdc +19 -0
  244. package/rules/text/policy/markdownlint/markdownlint.mdc +38 -0
  245. package/rules/text/policy/oxfmtrc/oxfmtrc.mdc +11 -0
  246. package/rules/text/policy/package_json/package_json.mdc +33 -0
  247. package/rules/text/policy/vscode_extensions/vscode_extensions.mdc +13 -0
  248. package/rules/text/policy/vscode_settings/vscode_settings.mdc +13 -0
  249. package/rules/vue/js/composition-api.mdc +82 -0
  250. package/rules/vue/js/nheader-layout.mdc +171 -0
  251. package/rules/vue/js/node-imports.mdc +25 -0
  252. package/rules/vue/js/quasar-ui.mdc +32 -0
  253. package/rules/vue/js/structure.mdc +101 -0
  254. package/rules/vue/js/testing.mdc +32 -0
  255. package/rules/vue/js/tfm-translations.mdc +26 -0
  256. package/rules/vue/js/vite-config.mdc +126 -0
  257. package/rules/vue/js/vite-env.mdc +55 -0
  258. package/rules/vue/js/vue-imports.mdc +25 -0
  259. package/rules/vue/main.mdc +15 -641
  260. package/rules/vue/policy/package_json/package_json.mdc +30 -0
  261. package/scripts/docs/index.md +16 -16
  262. package/scripts/lib/docs/index.md +36 -36
  263. package/scripts/utils/docs/index.md +14 -14
@@ -17,14 +17,14 @@ docgen:
17
17
  1. Перевіряє наявність каталогу `npm/skills` у поточному робочому каталозі. Якщо каталог відсутній, операція завершується успішно.
18
18
  2. Ітерує по всіх підкаталогах у `npm/skills`.
19
19
  3. Для кожного підкаталогу виконується перевірка метаданих скіла:
20
- а. Перевіряється наявність файлу `auto.md` у каталозі скіла. Якщо він присутній, це вважається порушенням.
21
- б. Зчитується вміст `main.json` скіла. Якщо файл відсутній або невалідний, перевірка для цього скіла припиняється.
22
- в. Виконується перевірка полів `main.json` скіла:
23
- i. `worktree` має бути булевим значенням.
24
- ii. Якщо поле `auto` визначене, його вміст має бути розпізнаним як "завжди" або непорожній масив правил.
25
- iii. `requireRoot` має бути булевим значенням, якщо визначений.
26
- iv. Якщо `worktree` встановлено як `true`, а `requireRoot` як `false`, це вважається порушенням.
27
- г. Якщо всі поля `main.json` валідні, це вважається успішним результатом для скіла.
20
+ а. Перевіряється наявність файлу `auto.md` у каталозі скіла. Якщо він присутній, це вважається порушенням.
21
+ б. Зчитується вміст `main.json` скіла. Якщо файл відсутній або невалідний, перевірка для цього скіла припиняється.
22
+ в. Виконується перевірка полів `main.json` скіла:
23
+ i. `worktree` має бути булевим значенням.
24
+ ii. Якщо поле `auto` визначене, його вміст має бути розпізнаним як "завжди" або непорожній масив правил.
25
+ iii. `requireRoot` має бути булевим значенням, якщо визначений.
26
+ iv. Якщо `worktree` встановлено як `true`, а `requireRoot` як `false`, це вважається порушенням.
27
+ г. Якщо всі поля `main.json` валідні, це вважається успішним результатом для скіла.
28
28
  4. Після перевірки всіх скілів повертається код виходу, що відображає загальний статус (0 — успіх, 1 — порушення).
29
29
 
30
30
  ## Публічний API
@@ -0,0 +1,18 @@
1
+ ## Module-level JSDoc як pointer
2
+
3
+ Якщо поряд із `js/<stem>.mjs` є файл `js/docs/<stem>.md` — module-level JSDoc у `.mjs` має бути **pointer** (не більше одного непорожнього рядка), а не повноцінний наратив.
4
+
5
+ Логіка перевірки (`header_doc_pointer.mjs`):
6
+
7
+ - Сканується перший JSDoc-блок (`/** … */`) до першого `import`/`export` у файлі.
8
+ - Підраховуються непорожні рядки тіла (після зрізання `*`-відступу).
9
+ - Якщо їх більше одного — `check` падає з повідомленням про те, що `docs/<stem>.md` вже описує поведінку і module-level JSDoc має залишатись коротким.
10
+
11
+ **Покриття:** `npm/rules/*/js/*.mjs` і `npm/skills/*/js/*.mjs` (не тестові файли `*.test.mjs`). Якщо `docs/<stem>.md` відсутня — обмежень на довжину JSDoc немає.
12
+
13
+ **Приклад правильного pointer-JSDoc:**
14
+
15
+ ```js
16
+ /** @see ./docs/package_structure.md */
17
+ import { existsSync } from 'node:fs'
18
+ ```
@@ -0,0 +1,62 @@
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"` явно (як у самому `@nitra/cursor`).
9
+ - **Лише runtime-залежності у `npm/package.json`.** `devDependencies` тримай у **кореневому** `package.json` монорепо — тоді `npm install @nitra/<pkg>` не тягне інструментарій, потрібний лише для розробки самого пакета.
10
+
11
+ Перевірки JS (`package_structure.mjs`):
12
+ - Наявність `package.json`, `npm/`, `npm/package.json`.
13
+ - Walk шляхів з `"files"` з застосуванням негативних patterns і скан залишку на тест-патерни (walking + AST). Якщо після застосування негативних patterns у tarball лишається test-style файл — `check` падає з вказівкою, який саме негативний glob треба додати у `"files"`.
14
+
15
+ ## TypeScript declaration (`npm/types`)
16
+
17
+ Файл **`npm/package.json`** має містити **`"types"`** (шлях до головного `.d.ts` або `.d.mts` під **`./types/…`**) і запис **`"types"`** у **`files`**, щоб npm публікував декларації.
18
+
19
+ Генерація — через **`tsc`** і **`bunx -p typescript`** (окремий пакет **`typescript`** у `devDependencies` не потрібен).
20
+
21
+ ### Варіант A: є вихідний **`.js`** під **`npm/src/`**
22
+
23
+ Якщо під **`npm/src`** (рекурсивно) є хоча б один файл **`.js`**:
24
+
25
+ - **`"types": "./types/index.d.ts"`**;
26
+ - у **hk** на **`pre-commit`** з каталогу **`npm/`** викликай:
27
+
28
+ ```bash
29
+ bunx -p typescript tsc src/**/*.js --declaration --allowJs --emitDeclarationOnly --outDir types --skipLibCheck
30
+ ```
31
+
32
+ Якщо glob не розгортається — **`bash -O globstar`** або **`include`** у **`tsconfig`** з тими самими **`compilerOptions`**.
33
+
34
+ ### Варіант B: немає **`npm/src/**/*.js`** (наприклад лише **`bin/`**, **`scripts/**/*.mjs`**)
35
+
36
+ Не створюй штучний **`src/index.js`**. Замість цього:
37
+
38
+ 1. Додай **`npm/tsconfig.emit-types.json`** з **`include`** на реальні шляхи (`.js` / `.mjs`), **`compilerOptions`**: **`allowJs`**, **`declaration`**, **`emitDeclarationOnly`**, **`outDir`: `"types"`**, **`skipLibCheck`**: **`true`** (за потреби **`rootDir`**, **`module`**, **`moduleResolution`**).
39
+ 2. Після першого **`tsc`** подивись, який **`.d.ts`** / **`.d.mts`** відповідає публічному API, і вкажи його в **`types`** (наприклад **`./types/bin/cli.d.ts`**).
40
+ 3. У **hk** на **`pre-commit`** з **`npm/`** викликай **`tsc -p tsconfig.emit-types.json`**. Якщо через імпорти **TypeScript** все одно згенерує зайві **`.d.mts`** у **`types/`**, після **`tsc`** обрізай дерево до потрібного entrypoint (наприклад залиш лише **`types/bin/n-cursor.d.ts`** через **`find`**), щоб у пакеті не збирались декларації внутрішніх модулів.
41
+
42
+ Файл **`tsconfig.emit-types.json`** тримай у репозиторії для **hk** / локальної генерації; у **`files`** його не додавай, якщо не хочеш публікувати його на **npm**.
43
+
44
+ ## Git hooks: hk + pre-commit
45
+
46
+ У корені репозиторію — **`hk.pkl`** (або **`.config/hk.pkl`**) з **`["pre-commit"]`** і командою з відповідного варіанту (A або B) вище.
47
+
48
+ Після додавання **`hk.pkl`**: **`hk install`**.
49
+
50
+ ## npm publish
51
+
52
+ **`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).
53
+
54
+ Workflow робить **release + publish** одним job (`release-publish`): крок **`Release (bump + CHANGELOG + tag)`** (`bunx n-cursor 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-cursor 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 й без міграторів.
55
+
56
+ - Канон: [npm-publish.yml.snippet.yml](./policy/npm_publish_yml/template/npm-publish.yml.snippet.yml)
57
+
58
+ ## Канонічні конфіги
59
+
60
+ - Кореневий `package.json` (workspaces): [package.json.snippet.json](./policy/root_package_json/template/package.json.snippet.json)
61
+ - `npm/package.json` (whitelist `files` обовʼязково має містити `types`): [package.json.snippet.json](./policy/npm_package_json/template/package.json.snippet.json)
62
+ - `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,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`** (опційне): `"per-file"` або `"full"`. Якщо вказано — `main.mjs` повинен експортувати функцію `lint` (або `export { lint } from …`).
@@ -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` відхиляє.
@@ -7,53 +7,13 @@ version: '1.14'
7
7
 
8
8
  Bun monorepo: workspace **`npm/`**, кореневий **`package.json`**, **`.github/workflows/`**; опційно **`demo/`**.
9
9
 
10
- ## Компактний пакет
10
+ [npm-module-package_structure](./js/package_structure.mdc)
11
11
 
12
- Мета — **максимально компактний** опублікований пакет: у npm потрапляє тільки те, що потрібно під час `require`/`import` користувачем.
12
+ [npm-module-rule_meta](./js/rule_meta.mdc)
13
13
 
14
- - **`"files"` обовʼязковий** у `npm/package.json` як **whitelist** того, що публікується (без `"files"` npm пакує майже все — це антипатерн для цього правила).
15
- - **Тести й фікстури не публікуються — через негативні 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"` явно (як у самому `@nitra/cursor`).
16
- - **Лише runtime-залежності у `npm/package.json`.** `devDependencies` тримай у **кореневому** `package.json` монорепо — тоді `npm install @nitra/<pkg>` не тягне інструментарій, потрібний лише для розробки самого пакета.
14
+ [npm-module-skill_meta](./js/skill_meta.mdc)
17
15
 
18
- Деталі алгоритму перевірки:
19
-
20
- - Пер-документні правила для `npm/package.json` (whitelist `files`, заборона `devDependencies`, форма `types`) — у rego-пакеті `npm_module.npm_package_json` (`npm/policy/npm_module/npm_package_json/`).
21
- - Walk шляхів з `"files"` з застосуванням негативних patterns і скан залишку на тест-патерни (walking + AST JS/TS) — у `check.mjs::checkNoTestsInPublishedFiles` (FS / AST не лягають у rego). Якщо після застосування негативних patterns у tarball лишається test-style файл — `check` падає з вказівкою, який саме негативний glob треба додати у `"files"`.
22
-
23
- ## TypeScript declaration (`npm/types`)
24
-
25
- Файл **`npm/package.json`** має містити **`"types"`** (шлях до головного `.d.ts` або `.d.mts` під **`./types/…`**) і запис **`"types"`** у **`files`**, щоб npm публікував декларації.
26
-
27
- Генерація — через **`tsc`** і **`bunx -p typescript`** (окремий пакет **`typescript`** у `devDependencies` не потрібен).
28
-
29
- ### Варіант A: є вихідний **`.js`** під **`npm/src/`**
30
-
31
- Якщо під **`npm/src`** (рекурсивно) є хоча б один файл **`.js`**:
32
-
33
- - **`"types": "./types/index.d.ts"`**;
34
- - у **hk** на **`pre-commit`** з каталогу **`npm/`** викликай:
35
-
36
- ```bash
37
- bunx -p typescript tsc src/**/*.js --declaration --allowJs --emitDeclarationOnly --outDir types --skipLibCheck
38
- ```
39
-
40
- Якщо glob не розгортається — **`bash -O globstar`** або **`include`** у **`tsconfig`** з тими самими **`compilerOptions`**.
41
-
42
- ### Варіант B: немає **`npm/src/**/*.js`** (наприклад лише **`bin/`**, **`scripts/**/*.mjs`**)
43
-
44
- Не створюй штучний **`src/index.js`**. Замість цього:
45
-
46
- 1. Додай **`npm/tsconfig.emit-types.json`** з **`include`** на реальні шляхи (`.js` / `.mjs`), **`compilerOptions`**: **`allowJs`**, **`declaration`**, **`emitDeclarationOnly`**, **`outDir`: `"types"`**, **`skipLibCheck`**: **`true`** (за потреби **`rootDir`**, **`module`**, **`moduleResolution`**).
47
- 2. Після першого **`tsc`** подивись, який **`.d.ts`** / **`.d.mts`** відповідає публічному API, і вкажи його в **`types`** (наприклад **`./types/bin/cli.d.ts`**).
48
- 3. У **hk** на **`pre-commit`** з **`npm/`** викликай **`tsc -p tsconfig.emit-types.json`**. Якщо через імпорти **TypeScript** все одно згенерує зайві **`.d.mts`** у **`types/`**, після **`tsc`** обрізай дерево до потрібного entrypoint (наприклад залиш лише **`types/bin/n-cursor.d.ts`** через **`find`**), щоб у пакеті не збирались декларації внутрішніх модулів.
49
-
50
- Файл **`tsconfig.emit-types.json`** тримай у репозиторії для **hk** / локальної генерації; у **`files`** його не додавай, якщо не хочеш публікувати його на **npm**.
51
-
52
- ## Git hooks: hk + pre-commit
53
-
54
- У корені репозиторію — **`hk.pkl`** (або **`.config/hk.pkl`**) з **`["pre-commit"]`** і командою з відповідного варіанту (A або B) вище.
55
-
56
- Після додавання **`hk.pkl`**: **`hk install`**.
16
+ [npm-module-header_doc_pointer](./js/header_doc_pointer.mdc)
57
17
 
58
18
  ## Версія та CHANGELOG
59
19
 
@@ -61,16 +21,14 @@ bunx -p typescript tsc src/**/*.js --declaration --allowJs --emitDeclarationOnly
61
21
 
62
22
  Повна модель (база порівняння, інверсія шляхів, формат CHANGELOG, post-release-інваріант «верхня секція CHANGELOG == `version`») — у **`n-changelog.mdc`** (джерело істини). Це правило їй підпорядковане й власних інструкцій bump/CHANGELOG не дублює.
63
23
 
64
- ## npm publish
24
+ ## Швидкий gate через conftest
65
25
 
66
- **`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).
26
+ Rego-пакети (запускаються через `npx @nitra/cursor fix`):
67
27
 
68
- Workflow робить **release + publish** одним job (`release-publish`): крок **`Release (bump + CHANGELOG + tag)`** (`bunx n-cursor 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-cursor 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 й без міграторів.
28
+ [npm-module-npm_package_json](./policy/npm_package_json/npm_package_json.mdc)
69
29
 
70
- - Канон: [npm-publish.yml.snippet.yml](./policy/npm_publish_yml/template/npm-publish.yml.snippet.yml)
30
+ [npm-module-root_package_json](./policy/root_package_json/root_package_json.mdc)
71
31
 
72
- ## Канонічні конфіги
32
+ [npm-module-emit_types_config](./policy/emit_types_config/emit_types_config.mdc)
73
33
 
74
- - Кореневий `package.json` (workspaces): [package.json.snippet.json](./policy/root_package_json/template/package.json.snippet.json)
75
- - `npm/package.json` (whitelist `files` обовʼязково має містити `types`): [package.json.snippet.json](./policy/npm_package_json/template/package.json.snippet.json)
76
- - `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)
34
+ - `npm_module.npm_publish_yml` template-driven перевірка `.github/workflows/npm-publish.yml` (deep-subset: усі обовʼязкові поля й кроки з канонічного сніпету).
@@ -0,0 +1,40 @@
1
+ ## Rego-gate: конфігурація генерації типів `npm/tsconfig.emit-types.json`
2
+
3
+ Rego-пакет: `npm-module.emit_types_config`
4
+
5
+ Цільовий файл: `npm/tsconfig.emit-types.json`
6
+
7
+ ### Що перевіряється
8
+
9
+ Leaf-by-leaf порівняння з канонічним сніпетом (через `--data`): кожне поле всередині `compilerOptions` має точно відповідати очікуваному значенню. Якщо секція `compilerOptions` відсутня або не є обʼєктом — окрема deny-помилка.
10
+
11
+ Канонічний сніпет: [tsconfig.emit-types.json.snippet.json](./template/tsconfig.emit-types.json.snippet.json)
12
+
13
+ ### Допустимі відхилення
14
+
15
+ Додаткові поля у `compilerOptions` (наприклад `rootDir`, `baseUrl`) не спричиняють помилку — перевіряється лише наявність і коректність обовʼязкових ключів зі сніпету.
16
+
17
+ ### Приклади
18
+
19
+ ✓ Правильно:
20
+ ```json
21
+ {
22
+ "compilerOptions": {
23
+ "allowJs": true,
24
+ "declaration": true,
25
+ "emitDeclarationOnly": true,
26
+ "outDir": "types",
27
+ "skipLibCheck": true
28
+ }
29
+ }
30
+ ```
31
+
32
+ ✗ Неправильно — неправильний `outDir`:
33
+ ```json
34
+ { "compilerOptions": { "outDir": "dist" } }
35
+ ```
36
+
37
+ ✗ Неправильно — відсутній `compilerOptions`:
38
+ ```json
39
+ {}
40
+ ```
@@ -0,0 +1,50 @@
1
+ ## Rego-gate: валідація `npm/package.json`
2
+
3
+ Rego-пакет: `npm-module.npm_package_json`
4
+
5
+ Цільовий файл: `npm/package.json`
6
+
7
+ ### Що перевіряється
8
+
9
+ **Поле `types`** (логіка в rego, не template-driven):
10
+ - Має відповідати патерну `./types/index.d.ts` або `./types/<назва>.d.ts|.d.mts`.
11
+ - Шляхи поза директорією `types/` або з іншими розширеннями (`.ts` без `.d`) — deny.
12
+
13
+ **Поле `files`** (частково template-driven):
14
+ - Обовʼязкове, має бути непорожнім масивом.
15
+ - Subset-of перевірка: кожне значення з канонічного сніпету має бути присутнє у `files`. За замовчуванням — `"types"` обовʼязковий.
16
+
17
+ **Поле `devDependencies`** (inverse-pattern, логіка в rego):
18
+ - Не публікуються користувачам пакета — має бути відсутнє або порожнє `{}`.
19
+ - Наявність будь-яких devDeps → deny з переліком залежностей. Перенести у кореневий `package.json`.
20
+
21
+ Канонічний сніпет `files`: [package.json.snippet.json](./template/package.json.snippet.json)
22
+
23
+ FS-перевірки (наявність файлу зі шляху `types`, скан tarball на тест-патерни) — у JS-перевірці, не тут.
24
+
25
+ ### Приклади
26
+
27
+ ✓ Правильно:
28
+ ```json
29
+ {
30
+ "name": "@nitra/cursor",
31
+ "types": "./types/bin/n-cursor.d.ts",
32
+ "files": ["types", "mdc", "bin", "CHANGELOG.md"],
33
+ "dependencies": { "oxc-parser": "^0.128.0" }
34
+ }
35
+ ```
36
+
37
+ ✗ Неправильно — `types` поза директорією `types/`:
38
+ ```json
39
+ { "types": "./dist/index.d.ts" }
40
+ ```
41
+
42
+ ✗ Неправильно — `files` без `"types"`:
43
+ ```json
44
+ { "files": ["bin", "mdc"] }
45
+ ```
46
+
47
+ ✗ Неправильно — наявні `devDependencies`:
48
+ ```json
49
+ { "devDependencies": { "@nitra/cursor": "^1.0.0" } }
50
+ ```
@@ -0,0 +1,37 @@
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
+ ```json
21
+ { "workspaces": ["npm"] }
22
+ ```
23
+
24
+ ✓ Правильно — `workspaces` містить `"npm"` разом з іншими:
25
+ ```json
26
+ { "workspaces": ["demo", "npm", "tests"] }
27
+ ```
28
+
29
+ ✗ Неправильно — `workspaces` відсутній:
30
+ ```json
31
+ { "name": "monorepo" }
32
+ ```
33
+
34
+ ✗ Неправильно — `workspaces` без `"npm"`:
35
+ ```json
36
+ { "workspaces": ["demo"] }
37
+ ```
@@ -0,0 +1,12 @@
1
+ ## CI: `.github/workflows/lint-php.yml`
2
+
3
+ Канон workflow — [lint-php.yml.snippet.yml](./policy/lint_php_yml/template/lint-php.yml.snippet.yml).
4
+
5
+ Файл запускається при push/PR до `dev`/`main` за змінами в `**/*.php`, `composer.json`, `composer.lock`, `phpstan.neon`, `phpstan.neon.dist`, `psalm.xml` або самого workflow.
6
+
7
+ Кроки job `php`:
8
+ 1. `actions/checkout@v6` (без persist-credentials)
9
+ 2. `./.github/actions/setup-bun-deps`
10
+ 3. `shivammathur/setup-php@v2` — PHP 8.5
11
+ 4. `composer install --no-interaction --no-progress --prefer-dist`
12
+ 5. `n-cursor lint php --read-only`
@@ -0,0 +1,66 @@
1
+ ## PHP-інструменти лінту
2
+
3
+ Весь код повинен відповідати PHP 8.5, перевірятися через PHPCompatibility і конвертуватися через Rector.
4
+
5
+ Код має бути добре задокументований через phpDoc:
6
+
7
+ ```php
8
+ /** @param array<int, string> $items */
9
+ function process($items) {
10
+ foreach ($items as $id => $name) {
11
+ // PHPStan знає, що $id — int, $name — string
12
+ }
13
+ }
14
+ ```
15
+
16
+ ### PHP_CodeSniffer (phpcs) і пакет `squizlabs/php_codesniffer`
17
+
18
+ Стиль, базові ризики, за потреби окремі стандарти. Для **SQL injection**, **XSS**, **небезпечні функції** — PHPCS + **php-security-audit** (стандарт `Security`).
19
+
20
+ ```bash
21
+ phpcs --standard=Security app/
22
+ ```
23
+
24
+ ### PHPStan
25
+
26
+ Статичний аналіз типів і смертельних слабких місць; **PHPStan Taint Analysis** (`phpstan/phpstan-taint-analysis`) — для потоку даних (taint) у стилі security-аналізу.
27
+
28
+ ```bash
29
+ vendor/bin/phpstan analyse
30
+ # після підключення розширення taint — у phpstan.neon/ neon.dist
31
+ ```
32
+
33
+ ### PHP-CS-Fixer
34
+
35
+ Форматтер/фіксер коду; у **lint** зазвичай перевірка без змін (`--dry-run`).
36
+
37
+ ```bash
38
+ vendor/bin/php-cs-fixer fix --dry-run --diff
39
+ ```
40
+
41
+ ### Psalm
42
+
43
+ Альтернативний/додатковий аналізатор; **Psalm Security Plugin** (`vimeo/psalm` + пакет на кшталт `psalm/plugin-security` залежно від вибраної збірки) — для security-орієнтованих правил.
44
+
45
+ ```bash
46
+ vendor/bin/psalm
47
+ ```
48
+
49
+ ### `composer audit`
50
+
51
+ Перевірка відомих вразливостей залежностей за даними **Packagist/security-advisories**.
52
+
53
+ ```bash
54
+ composer audit
55
+ ```
56
+
57
+ ## Запуск lint-php
58
+
59
+ `composer`-інструменти не мають єдиного CLI, який сам обходить репозиторій, тому php-лінт делегується у JS-скрипт-обгортку. Запуск — через **`n-cursor lint php`** (CI — `--read-only`); окремого `package.json`-скрипта немає.
60
+
61
+ Скрипт `run-php.mjs`:
62
+
63
+ - якщо `composer.json` у корені відсутній — вихід 0 (перевірка пропущена);
64
+ - якщо `composer.json` є, але `composer` не знайдено в PATH — це помилка;
65
+ - `composer audit` — обовʼязковий;
66
+ - `vendor/bin/php-cs-fixer`, `vendor/bin/phpcs`, `vendor/bin/phpstan`, `vendor/bin/psalm` — запускаються лише якщо встановлені (інакше крок пропускається з повідомленням).
@@ -5,73 +5,12 @@ globs: "**/*.php"
5
5
  alwaysApply: false
6
6
  ---
7
7
 
8
- Весь код повинен відповідати PHP 8.5, перевіряти за допомогою PHPCompatibility, конвертувати за допомогою Rector.
8
+ Весь код повинен відповідати PHP 8.5 (PHPCompatibility + Rector). Лінт запускається через `n-cursor lint php`.
9
9
 
10
- Код повинен бути добре документований за допомогою phpDoc-ів:
10
+ [php-tooling](./js/tooling.mdc)
11
11
 
12
- ```php
13
- /** @param array<int, string> $items */
14
- function process($items) {
15
- foreach ($items as $id => $name) {
16
- // PHPStan знає, що $id — int, $name — string
17
- }
18
- }
19
- ```
12
+ [php-lint_php_yml](./js/lint_php_yml.mdc)
20
13
 
21
- ## Потрібно додати до lint-php
14
+ ## Швидкий gate через conftest
22
15
 
23
- ### PHP_CodeSniffer (phpcs) і пакет `squizlabs/php_codesniffer`
24
-
25
- Стиль, базові ризики, за потреби окремі стандарти. Для **SQL injection**, **XSS**, **небезпечні функції** — PHPCS + **php-security-audit** (стандарт `Security`).
26
-
27
- ```bash
28
- phpcs --standard=Security app/
29
- ```
30
-
31
- ### PHPStan
32
-
33
- Статичний аналіз типів і смертельних слабких місць; **PHPStan Taint Analysis** (`phpstan/phpstan-taint-analysis`) — для потоку даних (taint) у стилі security-аналізу.
34
-
35
- ```bash
36
- vendor/bin/phpstan analyse
37
- # після підключення розширення taint — у phpstan.neon/ neon.dist
38
- ```
39
-
40
- ### PHP-CS-Fixer
41
-
42
- Форматтер/фіксер коду; у **lint** зазвичай перевірка без змін (`--dry-run`).
43
-
44
- ```bash
45
- vendor/bin/php-cs-fixer fix --dry-run --diff
46
- ```
47
-
48
- ### Psalm
49
-
50
- Альтернативний/додатковий аналізатор; **Psalm Security Plugin** (`vimeo/psalm` + пакет на кшталт `psalm/plugin-security` залежно від вибраної збірки) — для security-орієнтованих правил.
51
-
52
- ```bash
53
- vendor/bin/psalm
54
- ```
55
-
56
- ### `composer audit`
57
-
58
- Перевірка відомих вразливостей залежностей за даними **Packagist/security-advisories**.
59
-
60
- ```bash
61
- composer audit
62
- ```
63
-
64
- ## lint-php
65
-
66
- `composer`-інструмененти не мають єдиного CLI, який сам обходить репозиторій, тому php-лінт делегується у JS-скрипт-обгортку. Запуск — через **`n-cursor lint php`** (CI — `--read-only`); окремого `package.json`-скрипта немає.
67
-
68
- Скрипт `run-php.mjs`:
69
-
70
- - якщо `composer.json` у корені відсутній — вихід 0 (перевірка пропущена);
71
- - якщо `composer.json` є, але `composer` не знайдено в PATH — це помилка;
72
- - `composer audit` — обовʼязковий;
73
- - `vendor/bin/php-cs-fixer`, `vendor/bin/phpcs`, `vendor/bin/phpstan`, `vendor/bin/psalm` — запускаються лише якщо встановлені (інакше крок пропускається з повідомленням).
74
-
75
- ## CI: `.github/workflows/lint-php.yml`
76
-
77
- - Канон: [lint-php.yml.snippet.yml](./policy/lint_php_yml/template/lint-php.yml.snippet.yml)
16
+ [php-lint_php_yml](./policy/lint_php_yml/lint_php_yml.mdc)
@@ -0,0 +1,21 @@
1
+ ## Структура `.github/workflows/lint-php.yml`
2
+
3
+ Rego-пакет: `php.lint_php_yml`
4
+
5
+ Цільовий файл: `.github/workflows/lint-php.yml` (парситься як YAML).
6
+
7
+ Перевіряє, що у workflow присутні всі канонічні `run:`-кроки з template-сніпету — крок `n-cursor lint php --read-only` має бути в одному зі steps jobs.
8
+
9
+ Канонічний template-сніпет: [lint-php.yml.snippet.yml](./template/lint-php.yml.snippet.yml)
10
+
11
+ **✓ Правильно** — job `php` містить крок:
12
+ ```yaml
13
+ - name: Lint PHP
14
+ run: n-cursor lint php --read-only
15
+ ```
16
+
17
+ **✗ Неправильно** — крок відсутній або містить інший run-рядок:
18
+ ```yaml
19
+ - name: Lint PHP
20
+ run: echo something
21
+ ```
@@ -0,0 +1,23 @@
1
+ ## CI: `.github/workflows/lint-python.yml`
2
+
3
+ Канонічний workflow: [lint-python.yml.snippet.yml](./policy/lint_python_yml/template/lint-python.yml.snippet.yml)
4
+
5
+ Без кроків `poetry install` / `snok/install-poetry` — лише `astral-sh/setup-uv@v8.0.0` + `uv sync --frozen`.
6
+
7
+ Обовʼязкові кроки:
8
+ - `actions/checkout@v6` з `persist-credentials: false`;
9
+ - `./.github/actions/setup-bun-deps` — встановлення JS-залежностей (для `n-cursor lint`);
10
+ - `astral-sh/setup-uv@v8.0.0` — встановлення uv;
11
+ - `uv sync --frozen` — встановлення Python-залежностей строго з lock-файлу;
12
+ - `n-cursor lint python --read-only` — запуск lint (без auto-fix у CI).
13
+
14
+ `uv` / `ruff` / `mypy` **не** додаються в кореневі `devDependencies` споживача — це окремий toolchain, що ставиться через `astral-sh/setup-uv` у CI або локально.
15
+
16
+ ## Rego: python.lint_python_yml
17
+
18
+ Polісі `policy/lint_python_yml/lint_python_yml.rego` — drift-safe перевірка через `--data template`:
19
+
20
+ - кожен `uses` з template має бути присутнім у workflow input;
21
+ - кожен `run` з template має бути substring серед run-кроків input.
22
+
23
+ Заборона Poetry-кроків (`snok/install-poetry`, `poetry install`) забезпечується відсутністю у каноні: правило вимагає uv-кроки, і жодних poetry-кроків у template немає.
@@ -0,0 +1,32 @@
1
+ ## pyproject.toml: PEP 621 і заборона Poetry
2
+
3
+ Метадані проєкту — у секції **`[project]`** (PEP 621), а **не** в `[tool.poetry]`.
4
+
5
+ Обовʼязкові поля:
6
+ - `[project].name` — назва пакета;
7
+ - `[project].version` — статична версія;
8
+ - `[project].requires-python` — мінімальна версія Python;
9
+ - `[project].dependencies` — залежності (навіть порожній список).
10
+
11
+ Lock-файл — **`uv.lock`** (коммітиться). `poetry.lock` / `poetry.toml` мають бути відсутні.
12
+
13
+ Залежності: `uv add <pkg>`; dev-залежності: `uv add --dev <pkg>`.
14
+
15
+ Канонічний цільовий вигляд `pyproject.toml`: [pyproject.toml.snippet.toml](./policy/pyproject_toml/template/pyproject.toml.snippet.toml)
16
+
17
+ Заборонені під-таблиці `[tool.*]` (Poetry): [pyproject.toml.deny.toml](./policy/pyproject_toml/template/pyproject.toml.deny.toml)
18
+
19
+ ## Міграція з Poetry на uv
20
+
21
+ 1. Прибери `[tool.poetry]` і `poetry.lock` / `poetry.toml`.
22
+ 2. Перенеси метадані в `[project]` (name, version, requires-python, dependencies) за PEP 621.
23
+ 3. Згенеруй lock: `uv lock` → `uv.lock`.
24
+ 4. Dev-залежності: `uv add --dev ruff mypy …`.
25
+
26
+ ## Rego: python.pyproject_toml
27
+
28
+ Polисі `policy/pyproject_toml/pyproject_toml.rego` — дві групи правил:
29
+
30
+ **1. Заборона Poetry** — перевіряє, чи є заборонені під-таблиці `[tool.*]` з `pyproject.toml.deny.toml` (drift-safe через `--data template`).
31
+
32
+ **2. PEP 621** — `[project].name` і `[project].version` мають бути непорожніми рядками.
@@ -0,0 +1,23 @@
1
+ ## Перевірка наявності uv-toolchain і відсутності Poetry
2
+
3
+ JS-перевірка (`js/tooling.mjs`) запускається, якщо в корені репо є `pyproject.toml`. Перевіряє:
4
+
5
+ - `uv.lock` — має існувати (зафіксувати командою `uv lock`);
6
+ - `poetry.lock` / `poetry.toml` — мають **бути відсутніми** (Poetry заборонено);
7
+ - `package.json` — має бути у корені (js-обгортка lint є частиною монорепо);
8
+ - `.github/workflows/lint-python.yml` — має існувати (структуру перевіряє Rego-полісі `python.lint_python_yml`).
9
+
10
+ Якщо `pyproject.toml` відсутній — перевірка пропускається з кодом 0 (проєкт не Python).
11
+
12
+ ## lint-python: JS-скрипт-обгортка
13
+
14
+ Інструменти uv-екосистеми не мають єдиного CLI-обходу репо, тому python-лінт делегується у JS-скрипт-обгортку. Запуск — через **`n-cursor lint python`** (CI — `--read-only`); окремого `package.json`-скрипта немає.
15
+
16
+ Скрипт `rules/python/lint/lint.mjs`:
17
+
18
+ - якщо `pyproject.toml` у корені відсутній — вихід 0 (перевірка пропущена);
19
+ - якщо `pyproject.toml` є, але `uv` не знайдено в PATH — це помилка;
20
+ - `uv lock --check` і `uv sync --frozen` — обовʼязкові;
21
+ - `uv run ruff check --fix .` + `uv run ruff format .` — auto-fix (мутують робоче дерево, як `markdownlint-cli2 --fix` у lint-text);
22
+ - `uv run mypy .` — статична перевірка типів;
23
+ - усі `ruff`/`mypy`-кроки запускаються лише якщо інструмент доступний у середовищі (інакше крок пропускається з повідомленням).