@nitra/cursor 12.8.5 → 12.8.7

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 (202) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/bin/n-cursor.js +5 -5
  3. package/package.json +1 -1
  4. package/rules/abie/js/http_route_base.mdc +25 -0
  5. package/rules/abie/js/ua_http_route.mdc +1 -1
  6. package/rules/abie/main.mdc +12 -0
  7. package/rules/adr/js/hooks.mdc +32 -0
  8. package/rules/adr/js/madr_format.mdc +96 -0
  9. package/rules/adr/js/settings_policy.mdc +34 -0
  10. package/rules/adr/main.mdc +13 -95
  11. package/rules/bun/js/bunfig.mdc +12 -0
  12. package/rules/bun/js/layout.mdc +60 -0
  13. package/rules/bun/js/lint.mdc +9 -0
  14. package/rules/bun/js/package_json.mdc +19 -0
  15. package/rules/bun/main.mdc +9 -61
  16. package/rules/capacitor/js/ios_spm.mdc +69 -0
  17. package/rules/capacitor/js/version.mdc +29 -0
  18. package/rules/capacitor/main.mdc +8 -22
  19. package/rules/changelog/js/agent-workflow.mdc +15 -0
  20. package/rules/changelog/js/changelog-format.mdc +33 -0
  21. package/rules/changelog/js/comparison-models.mdc +40 -0
  22. package/rules/changelog/main.mdc +4 -98
  23. package/rules/ci4/js/marksman_config.mdc +31 -0
  24. package/rules/ci4/js/vscode_extensions.mdc +33 -0
  25. package/rules/ci4/main.mdc +14 -14
  26. package/rules/docker/js/compile.mdc +44 -0
  27. package/rules/docker/js/hadolint.mdc +50 -0
  28. package/rules/docker/js/mirror.mdc +13 -0
  29. package/rules/docker/js/multistage.mdc +13 -0
  30. package/rules/docker/js/native-addon.mdc +43 -0
  31. package/rules/docker/js/nginx-tag.mdc +7 -0
  32. package/rules/docker/js/nginx-user.mdc +37 -0
  33. package/rules/docker/js/non-root.mdc +39 -0
  34. package/rules/docker/main.mdc +15 -196
  35. package/rules/ga/js/lint_toolchain.mdc +15 -0
  36. package/rules/ga/js/required_workflows.mdc +35 -0
  37. package/rules/ga/js/vscode.mdc +17 -0
  38. package/rules/ga/js/workflow_common.mdc +108 -0
  39. package/rules/ga/js/workflows.mdc +32 -0
  40. package/rules/ga/js/zizmor.mdc +7 -0
  41. package/rules/ga/main.mdc +17 -125
  42. package/rules/graphql/js/tooling.mdc +13 -0
  43. package/rules/graphql/js/vscode_extensions.mdc +13 -0
  44. package/rules/graphql/main.mdc +3 -22
  45. package/rules/hasura/js/internal_urls.mdc +27 -0
  46. package/rules/hasura/js/migrations.mdc +13 -0
  47. package/rules/hasura/js/svc_hl.mdc +17 -0
  48. package/rules/hasura/main.mdc +8 -30
  49. package/rules/image-avif/js/avif_generation.mdc +26 -0
  50. package/rules/image-avif/js/package_json_optout.mdc +21 -0
  51. package/rules/image-avif/main.mdc +7 -34
  52. package/rules/image-compress/js/package_json.mdc +7 -0
  53. package/rules/image-compress/js/package_setup.mdc +13 -0
  54. package/rules/image-compress/main.mdc +4 -12
  55. package/rules/js/docs/index.md +3 -3
  56. package/rules/js/js/dep-policy.mdc +17 -0
  57. package/rules/js/js/eslint-config.mdc +28 -0
  58. package/rules/js/js/extensions.mdc +8 -0
  59. package/rules/js/js/file-extensions.mdc +12 -0
  60. package/rules/js/js/for-in.mdc +26 -0
  61. package/rules/js/js/jscpd.mdc +42 -0
  62. package/rules/js/js/knip.mdc +15 -0
  63. package/rules/js/js/lint-js-workflow.mdc +58 -0
  64. package/rules/js/js/oxlintrc.mdc +20 -0
  65. package/rules/js/js/package-json.mdc +31 -0
  66. package/rules/js/js/tests.mdc +9 -0
  67. package/rules/js/js/utils-lib-structure.mdc +15 -0
  68. package/rules/js/main.mdc +21 -214
  69. package/rules/js-bun-db/js/bun-sql-migration.mdc +15 -0
  70. package/rules/js-bun-db/js/connection.mdc +42 -0
  71. package/rules/js-bun-db/js/pg-format-identifiers.mdc +102 -0
  72. package/rules/js-bun-db/js/pg-format-shim.mdc +99 -0
  73. package/rules/js-bun-db/js/pg-leftover.mdc +27 -0
  74. package/rules/js-bun-db/js/pg-listen-notify.mdc +51 -0
  75. package/rules/js-bun-db/js/query-safety.mdc +117 -0
  76. package/rules/js-bun-db/js/sql-array.mdc +88 -0
  77. package/rules/js-bun-db/js/unsafe.mdc +65 -0
  78. package/rules/js-bun-db/main.mdc +15 -605
  79. package/rules/js-bun-redis/js/imports.mdc +47 -0
  80. package/rules/js-bun-redis/js/package_json.mdc +44 -0
  81. package/rules/js-bun-redis/main.mdc +3 -11
  82. package/rules/js-mssql/js/mssql-in-list.mdc +38 -0
  83. package/rules/js-mssql/js/mssql-pool.mdc +56 -0
  84. package/rules/js-mssql/js/mssql-query-template.mdc +33 -0
  85. package/rules/js-mssql/js/mssql-tvp.mdc +75 -0
  86. package/rules/js-mssql/js/mssql-version.mdc +7 -0
  87. package/rules/js-mssql/main.mdc +10 -198
  88. package/rules/js-run/js/check-env.mdc +35 -0
  89. package/rules/js-run/js/conn-aliases.mdc +109 -0
  90. package/rules/js-run/js/jsconfig.mdc +20 -0
  91. package/rules/js-run/js/otel-configmap.mdc +6 -0
  92. package/rules/js-run/js/pino.mdc +6 -0
  93. package/rules/js-run/js/project-structure.mdc +11 -0
  94. package/rules/js-run/js/runtime.mdc +14 -0
  95. package/rules/js-run/js/scope.mdc +11 -0
  96. package/rules/js-run/js/settimeout.mdc +11 -0
  97. package/rules/js-run/js/temporal.mdc +5 -0
  98. package/rules/js-run/main.mdc +16 -218
  99. package/rules/k8s/js/configmap.mdc +41 -0
  100. package/rules/k8s/js/deployment_resources.mdc +49 -0
  101. package/rules/k8s/js/hasura_httproute.mdc +91 -0
  102. package/rules/k8s/js/hpa_apiversion.mdc +27 -0
  103. package/rules/k8s/js/ingress_gateway.mdc +16 -0
  104. package/rules/k8s/js/kustomize_structure.mdc +144 -0
  105. package/rules/k8s/js/lint_k8s.mdc +72 -0
  106. package/rules/k8s/js/multidoc_yaml.mdc +5 -0
  107. package/rules/k8s/js/network_policy.mdc +136 -0
  108. package/rules/k8s/js/schema_modeline.mdc +57 -0
  109. package/rules/k8s/js/service.mdc +44 -0
  110. package/rules/k8s/js/topology_hpa_pdb.mdc +181 -0
  111. package/rules/k8s/main.mdc +30 -843
  112. package/rules/nginx-default-tpl/js/dockerfile.mdc +36 -0
  113. package/rules/nginx-default-tpl/js/http-route.mdc +41 -0
  114. package/rules/nginx-default-tpl/js/ini-keys.mdc +21 -0
  115. package/rules/nginx-default-tpl/js/template-structure.mdc +86 -0
  116. package/rules/nginx-default-tpl/js/vscode.mdc +37 -0
  117. package/rules/nginx-default-tpl/main.mdc +6 -112
  118. package/rules/npm-module/js/docs/index.md +5 -5
  119. package/rules/npm-module/js/docs/rule_meta.md +6 -6
  120. package/rules/npm-module/js/docs/skill_meta.md +8 -8
  121. package/rules/npm-module/js/header_doc_pointer.mdc +18 -0
  122. package/rules/npm-module/js/package_structure.mdc +62 -0
  123. package/rules/npm-module/js/rule_meta.mdc +11 -0
  124. package/rules/npm-module/js/skill_meta.mdc +11 -0
  125. package/rules/npm-module/main.mdc +10 -55
  126. package/rules/php/js/lint_php_yml.mdc +12 -0
  127. package/rules/php/js/tooling.mdc +66 -0
  128. package/rules/php/main.mdc +7 -66
  129. package/rules/python/js/lint_python_yml.mdc +23 -0
  130. package/rules/python/js/pyproject_toml.mdc +32 -0
  131. package/rules/python/js/tooling.mdc +23 -0
  132. package/rules/python/main.mdc +9 -33
  133. package/rules/rego/js/rego-lint.mdc +31 -0
  134. package/rules/rego/js/vscode_extensions.mdc +11 -0
  135. package/rules/rego/js/vscode_settings.mdc +13 -0
  136. package/rules/rego/main.mdc +8 -24
  137. package/rules/rust/js/coverage.mdc +28 -0
  138. package/rules/rust/js/lint.mdc +22 -0
  139. package/rules/rust/js/tauri_composition.mdc +8 -0
  140. package/rules/rust/js/vscode_extensions.mdc +12 -0
  141. package/rules/rust/main.mdc +8 -38
  142. package/rules/security/js/rego_policies.mdc +15 -0
  143. package/rules/security/js/sample_secret.mdc +19 -0
  144. package/rules/security/js/trufflehog.mdc +21 -0
  145. package/rules/security/main.mdc +7 -35
  146. package/rules/style/js/admin-table.mdc +88 -0
  147. package/rules/style/js/colors.mdc +21 -0
  148. package/rules/style/js/gap.mdc +22 -0
  149. package/rules/style/js/quasar-fixes.mdc +32 -0
  150. package/rules/style/js/quasar.mdc +7 -0
  151. package/rules/style/js/tooling.mdc +85 -0
  152. package/rules/style/main.mdc +13 -253
  153. package/rules/tauri/js/cargo_mutants_config.mdc +39 -0
  154. package/rules/tauri/js/tool_surface.mdc +21 -0
  155. package/rules/tauri/js/tooling.mdc +25 -0
  156. package/rules/tauri/main.mdc +8 -78
  157. package/rules/test/js/cargo_mutants_config.mdc +18 -0
  158. package/rules/test/js/docs/index.md +7 -7
  159. package/rules/test/js/location.mdc +52 -0
  160. package/rules/test/js/no-console-store-restore.mdc +11 -0
  161. package/rules/test/js/no-process-chdir.mdc +15 -0
  162. package/rules/test/js/no-relative-fs-path.mdc +22 -0
  163. package/rules/test/js/sandbox-aware-test.mdc +28 -0
  164. package/rules/test/js/stryker_config.mdc +26 -0
  165. package/rules/test/js/vitest-config-pool-forks.mdc +33 -0
  166. package/rules/test/main.mdc +18 -184
  167. package/rules/text/js/ci-lint-text.mdc +15 -0
  168. package/rules/text/js/cspell.mdc +81 -0
  169. package/rules/text/js/dotenv-linter.mdc +16 -0
  170. package/rules/text/js/forbidden-prettier.mdc +13 -0
  171. package/rules/text/js/markdownlint.mdc +25 -0
  172. package/rules/text/js/oxfmt.mdc +35 -0
  173. package/rules/text/js/package-json.mdc +26 -0
  174. package/rules/text/js/shellcheck.mdc +18 -0
  175. package/rules/text/js/v8r.mdc +23 -0
  176. package/rules/text/js/vscode.mdc +86 -0
  177. package/rules/text/main.mdc +20 -237
  178. package/rules/vue/js/composition-api.mdc +82 -0
  179. package/rules/vue/js/nheader-layout.mdc +171 -0
  180. package/rules/vue/js/node-imports.mdc +25 -0
  181. package/rules/vue/js/quasar-ui.mdc +32 -0
  182. package/rules/vue/js/structure.mdc +101 -0
  183. package/rules/vue/js/testing.mdc +32 -0
  184. package/rules/vue/js/tfm-translations.mdc +26 -0
  185. package/rules/vue/js/vite-config.mdc +126 -0
  186. package/rules/vue/js/vite-env.mdc +55 -0
  187. package/rules/vue/js/vue-imports.mdc +25 -0
  188. package/rules/vue/main.mdc +16 -640
  189. package/scripts/auto-rules.mjs +6 -6
  190. package/scripts/auto-skills.mjs +3 -3
  191. package/scripts/docs/auto-rules.md +17 -31
  192. package/scripts/docs/auto-skills.md +18 -163
  193. package/scripts/docs/index.md +16 -16
  194. package/scripts/lib/docs/index.md +36 -36
  195. package/scripts/lib/docs/mirror-parity.md +7 -7
  196. package/scripts/lib/docs/rule-meta.md +12 -12
  197. package/scripts/lib/docs/skill-meta.md +9 -9
  198. package/scripts/lib/docs/worktree-notice.md +10 -8
  199. package/scripts/lib/rule-meta.mjs +6 -6
  200. package/scripts/lib/skill-meta.mjs +6 -6
  201. package/scripts/lib/worktree-notice.mjs +2 -2
  202. package/scripts/utils/docs/index.md +14 -14
@@ -0,0 +1,36 @@
1
+ ## Dockerfile — стиснення статики та envsubst шаблону
2
+
3
+ Dockerfile потребує двох кроків, пов'язаних з nginx-шаблоном.
4
+
5
+ ### Стиснення статики (gzip_static)
6
+
7
+ Щоб nginx міг використовувати `gzip_static on`, файли необхідно стиснути під час збирання образу:
8
+
9
+ ```dockerfile
10
+ RUN find /usr/share/nginx/html -type f \( \
11
+ -name '*.js' -o -name '*.css' -o -name '*.map' -o -name '*.xml' -o \
12
+ -name '*.webmanifest' -o -name '*.html' -o -name '*.wasm' -o -name '*.ttf' \
13
+ \) -exec gzip -k {} +
14
+ ```
15
+
16
+ Прапорець `-k` зберігає оригінальний файл поруч зі стиснутим `.gz`.
17
+
18
+ ### envsubst для default.conf.template
19
+
20
+ Для підстановки змінних середовища у шаблон:
21
+
22
+ ```dockerfile
23
+ # 1) Витягнути імена змінних з ini (ігноруємо коментарі/порожні)
24
+ # 2) Зробити список для envsubst: $NAMESPACE $NAMESPACE2 ...
25
+ # 3) Підвантажити значення з ini і підставити лише їх
26
+ RUN NAMES=$(sed -nE '/^\s*[#;]/d; /^\s*$/d; s/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=.*/\1/p' /tpl/values-$BRANCH.ini) && \
27
+ VARS=$(printf '%s\n' $NAMES | awk '{printf "$%s ", $0}') && \
28
+ export $(grep -v '^#' /tpl/values-$BRANCH.ini | xargs) && \
29
+ envsubst "$VARS" < /tpl/default.conf.template > /app/default.conf
30
+ ```
31
+
32
+ Перевірки (автоматичні):
33
+
34
+ - Dockerfile містить `find … /usr/share/nginx/html … gzip -k` — крок стиснення статики
35
+ - Dockerfile містить `envsubst` і посилання на `default.conf.template`
36
+ - Якщо немає жодного Dockerfile / Containerfile поруч з `default.conf.template` — це помилка
@@ -0,0 +1,41 @@
1
+ ## HTTPRoute в k8s — редирект і backendRefs
2
+
3
+ Якщо в `default.conf.template` були `proxy_pass`-секції — їхню логіку потрібно перенести
4
+ до HTTPRoute в k8s. `default.conf.template` **не повинен** містити жодного proxy.
5
+
6
+ HTTPRoute має містити два правила:
7
+
8
+ 1. **Exact → RequestRedirect 301 (https)** — редирект з `/$PUBLIC_PATH` на `/$PUBLIC_PATH/`
9
+ 2. **PathPrefix → backendRefs:8080** — проксі трафіку на сервіс
10
+
11
+ ```yaml
12
+ spec:
13
+ rules:
14
+ - matches:
15
+ - path:
16
+ type: Exact
17
+ value: /$PUBLIC_PATH
18
+ filters:
19
+ - type: RequestRedirect
20
+ requestRedirect:
21
+ scheme: https
22
+ path:
23
+ type: ReplaceFullPath
24
+ replaceFullPath: /$PUBLIC_PATH/
25
+ statusCode: 301
26
+ - matches:
27
+ - path:
28
+ type: PathPrefix
29
+ value: /$PUBLIC_PATH/
30
+ backendRefs:
31
+ - name: $SERVICE_NAME
32
+ port: 8080
33
+ ```
34
+
35
+ де `$PUBLIC_PATH` підставляється з ini-файлу dev-середовища, а для інших середовищ — через `kustomization.yaml`.
36
+ `$SERVICE_NAME` — ім'я k8s-сервісу, що приймає трафік на порту 8080.
37
+
38
+ Перевірки (автоматичні):
39
+
40
+ - перше правило має `path.type: Exact` і фільтр `RequestRedirect` з `scheme: https`, `path.type: ReplaceFullPath`, `statusCode: 301`
41
+ - друге правило має `path.type: PathPrefix` і `backendRefs` з `port: 8080`
@@ -0,0 +1,21 @@
1
+ ## Конфігураційні *.ini файли і envsubst
2
+
3
+ Поруч з `default.conf.template` мають бути конфігураційні файли `*.ini` для кожного
4
+ середовища (наприклад, `values-dev.ini`, `values-prod.ini`).
5
+
6
+ Формат ini-файлу:
7
+
8
+ ```ini
9
+ PUBLIC_PATH=/app
10
+ SERVICE_NAME=my-frontend
11
+ ```
12
+
13
+ Кожна змінна з `*.ini` **повинна використовуватись** у `default.conf.template` як `$KEY`
14
+ (через envsubst). Якщо у `*.ini` є ключ, що відсутній у шаблоні — його треба вилучити з ini
15
+ або додати в шаблон.
16
+
17
+ Перевірки (автоматичні):
18
+
19
+ - Поруч з кожним `default.conf.template` є щонайменше один `*.ini` файл
20
+ - Кожен ключ з `*.ini` (рядки виду `KEY=value`, без коментарів `#`/`;` і порожніх рядків)
21
+ присутній у шаблоні як `$KEY`
@@ -0,0 +1,86 @@
1
+ ## Канонічна структура default.conf.template
2
+
3
+ `default.conf.template` — єдиний nginx-конфіг для фронтенду зі статичними файлами.
4
+ Він **не повинен** містити жодних `proxy_pass`, `proxy_redirect`, `proxy_set_header`,
5
+ `fastcgi_pass`, `grpc_pass`, `uwsgi_pass`. Усю проксі-логіку потрібно винести в HTTPRoute (k8s).
6
+
7
+ Канонічний вигляд файлу:
8
+
9
+ ```nginx
10
+ server_tokens off;
11
+ port_in_redirect off;
12
+ client_max_body_size 0;
13
+ client_body_buffer_size 512M;
14
+
15
+ server {
16
+ listen 8080;
17
+ server_name _;
18
+
19
+ # disable all log
20
+ access_log off;
21
+ # `error_log off;` — НЕ валідний nginx: "off" трактується як ім'я файлу (/etc/nginx/off)
22
+ # і падає під readOnlyRootFilesystem. /dev/null — writable device.
23
+ error_log /dev/null crit;
24
+
25
+ # This would be the directory where your Vite app's static files are stored at
26
+ root /usr/share/nginx/html;
27
+
28
+ location /healthz {
29
+ add_header Content-Type text/plain;
30
+ access_log off;
31
+ return 200 "healthy";
32
+ }
33
+
34
+ # Без gz стиснених файлів, 1 year is 31536000 seconds
35
+ location ~ ^$PUBLIC_PATH/(.+\.(?:gif|jpe?g|png|ico|woff2|xlsx))$ {
36
+ alias /usr/share/nginx/html/$1;
37
+ add_header 'Cache-Control' "public,max-age=31536000,immutable";
38
+ }
39
+
40
+ # С gz стисненими файлами, 1 year is 31536000 seconds
41
+ location ~ ^$PUBLIC_PATH/(.+\.(?:svg|js|css|ttf|map|xml|webmanifest|wasm))$ {
42
+ alias /usr/share/nginx/html/$1;
43
+ add_header 'Cache-Control' "public,max-age=31536000,immutable";
44
+
45
+ # дозволяє віддавати замість звичайного файлу попередньо стиснутий файл з таким же ім'ям та з розширенням ".gz"
46
+ gzip_static on;
47
+ }
48
+
49
+ location $PUBLIC_PATH/ {
50
+ index index.html;
51
+ alias /usr/share/nginx/html/;
52
+
53
+ # eliminates the step of copying the data into the buffer and enables direct copying data from one file descriptor to another.
54
+ sendfile on;
55
+ # to prevent one fast connection from entirely occupying the worker process
56
+ sendfile_max_chunk 512k;
57
+ # to send HTTP response headers in one packet right after the chunk of data has been obtained by sendfile().
58
+ tcp_nopush on;
59
+
60
+ # дозволяє віддавати замість звичайного файлу попередньо стиснутий файл з таким же ім'ям та з розширенням ".gz"
61
+ gzip_static on;
62
+
63
+ try_files $uri $uri/ /index.html =404;
64
+ }
65
+ }
66
+ ```
67
+
68
+ Обов'язкові вимоги до структури (перевіряються автоматично):
69
+
70
+ - `server_tokens off` — приховує версію nginx у відповідях
71
+ - `port_in_redirect off` — виключає порт з redirect-заголовків
72
+ - `client_max_body_size 0` — без ліміту тіла запиту
73
+ - `client_body_buffer_size 512M`
74
+ - `listen 8080`
75
+ - `server_name _` — catch-all
76
+ - `access_log off`
77
+ - `error_log /dev/null crit` (НЕ `error_log off;` — це некоректно в nginx)
78
+ - `root /usr/share/nginx/html`
79
+ - `location /healthz` з `return 200` і рядком `healthy`
80
+ - location для статики без gzip (`gif|jpeg|png|ico|woff2|xlsx`) з `Cache-Control: max-age=31536000,immutable`
81
+ - location для статики з gzip (`svg|js|css|ttf|map|xml|webmanifest|wasm`) з `gzip_static on`
82
+ - `gzip_static on` щонайменше двічі (два location зі стисненням)
83
+ - `$PUBLIC_PATH` у location — плейсхолдер підставляється через envsubst
84
+ - `sendfile on`, `sendfile_max_chunk 512k`, `tcp_nopush on`
85
+ - `try_files $uri $uri/ /index.html =404`
86
+ - **Відсутність** будь-якого `proxy_pass` / `fastcgi_pass` / `grpc_pass` / `uwsgi_pass`
@@ -0,0 +1,37 @@
1
+ ## VS Code — розширення та налаштування nginx
2
+
3
+ Коли у проєкті є `default.conf.template`, очікуються відповідні VS Code конфігурації
4
+ для підтримки nginx-синтаксису.
5
+
6
+ ### .vscode/extensions.json
7
+
8
+ `recommendations` має містити розширення `ahmadalli.vscode-nginx-conf`:
9
+
10
+ ```json
11
+ {
12
+ "recommendations": [
13
+ "ahmadalli.vscode-nginx-conf"
14
+ ]
15
+ }
16
+ ```
17
+
18
+ ### .vscode/settings.json
19
+
20
+ Має бути увімкнений `formatOnSave` і встановлений форматер nginx:
21
+
22
+ ```json
23
+ {
24
+ "editor.formatOnSave": true,
25
+ "[nginx]": {
26
+ "editor.defaultFormatter": "ahmadalli.vscode-nginx-conf"
27
+ }
28
+ }
29
+ ```
30
+
31
+ Перевірки виконуються через Rego-пакети (conftest):
32
+
33
+ - `nginx_default_tpl.vscode_extensions` — перевіряє наявність `ahmadalli.vscode-nginx-conf` у `recommendations`
34
+ - `nginx_default_tpl.vscode_settings` — перевіряє `editor.formatOnSave: true` і `[nginx].editor.defaultFormatter: "ahmadalli.vscode-nginx-conf"`
35
+
36
+ Ці перевірки активуються **лише** якщо в проєкті знайдено `default.conf.template`
37
+ (умовне правило, не auto-discoverable без JS-gate).
@@ -5,120 +5,14 @@ globs: "**/default.{conf.template,tpl.conf}"
5
5
  alwaysApply: false
6
6
  ---
7
7
 
8
- default.conf.template повинен виглядати так:
8
+ Правило забезпечує відповідність `default.conf.template` канонічній структурі nginx для фронтенду зі статичними файлами, а також перевіряє пов'язані артефакти: HTTPRoute (k8s), Dockerfile, ini-файли середовищ і VS Code конфігурацію.
9
9
 
10
- ```nginx
11
- server_tokens off;
12
- port_in_redirect off;
13
- client_max_body_size 0;
14
- client_body_buffer_size 512M;
10
+ [nginx-default-tpl-template-structure](./js/template-structure.mdc)
15
11
 
16
- server {
17
- listen 8080;
18
- server_name _;
12
+ [nginx-default-tpl-http-route](./js/http-route.mdc)
19
13
 
20
- # disable all log
21
- access_log off;
22
- # `error_log off;` — НЕ валідний nginx: "off" трактується як ім'я файлу (/etc/nginx/off)
23
- # і падає під readOnlyRootFilesystem. /dev/null — writable device.
24
- error_log /dev/null crit;
14
+ [nginx-default-tpl-dockerfile](./js/dockerfile.mdc)
25
15
 
26
- # This would be the directory where your Vite app's static files are stored at
27
- root /usr/share/nginx/html;
16
+ [nginx-default-tpl-ini-keys](./js/ini-keys.mdc)
28
17
 
29
- location /healthz {
30
- add_header Content-Type text/plain;
31
- access_log off;
32
- return 200 "healthy";
33
- }
34
-
35
- # Без gz стиснених файлів, 1 year is 31536000 seconds
36
- location ~ ^$PUBLIC_PATH/(.+\.(?:gif|jpe?g|png|ico|woff2|xlsx))$ {
37
- alias /usr/share/nginx/html/$1;
38
- add_header 'Cache-Control' "public,max-age=31536000,immutable";
39
- }
40
-
41
- # С gz стисненими файлами, 1 year is 31536000 seconds
42
- location ~ ^$PUBLIC_PATH/(.+\.(?:svg|js|css|ttf|map|xml|webmanifest|wasm))$ {
43
- alias /usr/share/nginx/html/$1;
44
- add_header 'Cache-Control' "public,max-age=31536000,immutable";
45
-
46
- # дозволяє віддавати замість звичайного файлу попередньо стиснутий файл з таким же ім'ям та з розширенням ".gz"
47
- gzip_static on;
48
- }
49
-
50
- location $PUBLIC_PATH/ {
51
- index index.html;
52
- alias /usr/share/nginx/html/;
53
-
54
- # eliminates the step of copying the data into the buffer and enables direct copying data from one file descriptor to another.
55
- sendfile on;
56
- # to prevent one fast connection from entirely occupying the worker process
57
- sendfile_max_chunk 512k;
58
- # to send HTTP response headers in one packet right after the chunk of data has been obtained by sendfile().
59
- tcp_nopush on;
60
-
61
- # дозволяє віддавати замість звичайного файлу попередньо стиснутий файл з таким же ім'ям та з розширенням ".gz"
62
- gzip_static on;
63
-
64
- try_files $uri $uri/ /index.html =404;
65
- }
66
- }
67
- ```
68
-
69
- Тобто в ньому не потрібно щоб було жодного proxy_pass секціі і інших опцій для proxy.
70
-
71
- Якщо в файлі вже були proxy_pass секції, то їх логіку потрібно перенести до HTTPRoute в k8s.
72
-
73
- В HTTPRoute повинна бути секція Exact редиректу на версію з /
74
-
75
- ```yaml
76
- spec:
77
- rules:
78
- - matches:
79
- - path:
80
- type: Exact
81
- value: /$PUBLIC_PATH
82
- filters:
83
- - type: RequestRedirect
84
- requestRedirect:
85
- scheme: https
86
- path:
87
- type: ReplaceFullPath
88
- replaceFullPath: /$PUBLIC_PATH/
89
- statusCode: 301
90
- - matches:
91
- - path:
92
- type: PathPrefix
93
- value: /$PUBLIC_PATH/
94
- backendRefs:
95
- - name: $SERVICE_NAME
96
- port: 8080
97
- ```
98
-
99
- де $PUBLIC_PATH підставляється з ini файлу з dev середовища, а якщо для інших середовищ відрізняється то підставляється в kustomization.yaml відповідні значення з ini середовища.
100
-
101
- В $SERVICE_NAME повинно бути вказано ім'я сервісу, яке буде використовуватися в k8s.
102
-
103
- В Dockerfile потрібно додати команду для стиснення файлів, які потім використовуватимуться з `gzip_static on`:
104
-
105
- ```dockerfile
106
- RUN find /usr/share/nginx/html -type f \( \
107
- -name '*.js' -o -name '*.css' -o -name '*.map' -o -name '*.xml' -o \
108
- -name '*.webmanifest' -o -name '*.html' -o -name '*.wasm' -o -name '*.ttf' \
109
- \) -exec gzip -k {} +
110
- ```
111
-
112
- Поруч з файлом default.conf.template повинні бути конфігураційні файли *.ini для різних середовищ. В Dockerfile повинна бути команда, для заміни плейсхолдерів в цих файлах на значення з середовища:
113
-
114
- ```dockerfile
115
- # 1) Витягнути імена змінних з ini (ігноруємо коментарі/порожні)
116
- # 2) Зробити список для envsubst: $NAMESPACE $NAMESPACE2 ...
117
- # 3) Підвантажити значення з ini і підставити лише їх
118
- RUN NAMES=$(sed -nE '/^\s*[#;]/d; /^\s*$/d; s/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=.*/\1/p' /tpl/values-$BRANCH.ini) && \
119
- VARS=$(printf '%s\n' $NAMES | awk '{printf "$%s ", $0}') && \
120
- export $(grep -v '^#' /tpl/values-$BRANCH.ini | xargs) && \
121
- envsubst "$VARS" < /tpl/default.conf.template > /app/default.conf
122
- ```
123
-
124
- Якщо у конфігураційних файлах *.ini є змінні які відсутні в default.conf.template, то їх потрібно вилучити.
18
+ [nginx-default-tpl-vscode](./js/vscode.mdc)
@@ -6,9 +6,9 @@ resource: npm/rules/npm-module/js/
6
6
 
7
7
  # npm/rules/npm-module/js
8
8
 
9
- | Файл | Тип |
10
- |---|---|
9
+ | Файл | Тип |
10
+ | ----------------------------------------------- | --------- |
11
11
  | [header_doc_pointer.mjs](header_doc_pointer.md) | JS Module |
12
- | [package_structure.mjs](package_structure.md) | JS Module |
13
- | [rule_meta.mjs](rule_meta.md) | JS Module |
14
- | [skill_meta.mjs](skill_meta.md) | JS Module |
12
+ | [package_structure.mjs](package_structure.md) | JS Module |
13
+ | [rule_meta.mjs](rule_meta.md) | JS Module |
14
+ | [skill_meta.mjs](skill_meta.md) | JS Module |
@@ -17,12 +17,12 @@ docgen:
17
17
  1. Перевіряє наявність каталогу `npm/rules` у корені репозиторію. Якщо каталог відсутній, завершує роботу, повідомляючи про відсутність правил для валідації.
18
18
  2. Ітерує по всім підкаталогах у `npm/rules`, ігноруючи приховані каталоги.
19
19
  3. Для кожного каталогу виконує перевірку правила:
20
- а. Перевіряє відсутність файлу `auto.md`. Якщо знайдено, повідомляє про залишковий файл.
21
- б. Перевіряє наявність файлу `main.mdc`. Якщо відсутній, повідомляє про відсутність обов'язкового файлу (scripts.mdc).
22
- в. Зчитує вміст `main.json` каталогу правила. Якщо файл відсутній або невалідний, повідомляє про це та пропускає подальшу валідацію цього правила.
23
- г. Перевіряє поле `auto` у `main.json`. Якщо поле присутнє, валідує його структуру та перевіряє, чи всі використані предикати визначені.
24
- ґ. Перевіряє поле `lint` у `main.json`. Якщо поле присутнє, валідує його структуру та перевіряє, чи експортує файл `main.mjs` відповідну функцію `lint`.
25
- і. Якщо всі перевірки для правила пройдені успішно, повідомляє про валідність `main.json`.
20
+ а. Перевіряє відсутність файлу `auto.md`. Якщо знайдено, повідомляє про залишковий файл.
21
+ б. Перевіряє наявність файлу `main.mdc`. Якщо відсутній, повідомляє про відсутність обов'язкового файлу (scripts.mdc).
22
+ в. Зчитує вміст `main.json` каталогу правила. Якщо файл відсутній або невалідний, повідомляє про це та пропускає подальшу валідацію цього правила.
23
+ г. Перевіряє поле `auto` у `main.json`. Якщо поле присутнє, валідує його структуру та перевіряє, чи всі використані предикати визначені.
24
+ ґ. Перевіряє поле `lint` у `main.json`. Якщо поле присутнє, валідує його структуру та перевіряє, чи експортує файл `main.mjs` відповідну функцію `lint`.
25
+ і. Якщо всі перевірки для правила пройдені успішно, повідомляє про валідність `main.json`.
26
26
  4. Після обробки всіх правил повертає код виходу, що відображає загальний статус валідації.
27
27
 
28
28
  ## Публічний API
@@ -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,11 @@ 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
65
-
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).
67
-
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 й без міграторів.
69
-
70
- - Канон: [npm-publish.yml.snippet.yml](./policy/npm_publish_yml/template/npm-publish.yml.snippet.yml)
24
+ ## Швидкий gate через conftest
71
25
 
72
- ## Канонічні конфіги
26
+ Rego-пакети (запускаються через `npx @nitra/cursor fix`):
73
27
 
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)
28
+ - `npm_module.npm_package_json` — валідує `npm/package.json`: поле `types`, наявність і непорожність `files`, subset-of з template (зокрема `"types"` у `files`), заборона `devDependencies`.
29
+ - `npm_module.root_package_json` — валідує кореневий `package.json`: поле `workspaces` має містити `"npm"`.
30
+ - `npm_module.emit_types_config` — валідує `npm/tsconfig.emit-types.json`: `compilerOptions` відповідає канонічному сніпету (allowJs, declaration, emitDeclarationOnly, outDir, skipLibCheck).
31
+ - `npm_module.npm_publish_yml` — template-driven перевірка `.github/workflows/npm-publish.yml` (deep-subset: усі обовʼязкові поля й кроки з канонічного сніпету).