@nitra/cursor 1.10.0 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/CHANGELOG.md +34 -1
  2. package/bin/n-cursor.js +29 -29
  3. package/package.json +2 -1
  4. package/rules/abie/js/applies/check.mjs +24 -0
  5. package/rules/abie/js/env_dns/check.mjs +53 -0
  6. package/rules/abie/js/firebase_hosting/check.mjs +49 -0
  7. package/rules/abie/js/hc_pairing/check.mjs +58 -0
  8. package/rules/abie/js/ua_http_route/check.mjs +86 -0
  9. package/rules/abie/js/ua_node_selector/check.mjs +65 -0
  10. package/rules/abie/policy/base_deployment_preem/target.json +10 -0
  11. package/rules/abie/policy/clean_merged_ignore_branches/target.json +4 -0
  12. package/rules/abie/policy/health_check_policy/target.json +4 -0
  13. package/rules/abie/policy/http_route_base/target.json +4 -0
  14. package/rules/abie/utils/enabled.mjs +35 -0
  15. package/rules/abie/utils/env-dns.mjs +81 -0
  16. package/rules/abie/utils/hc-yaml.mjs +27 -0
  17. package/rules/abie/utils/http-route.mjs +93 -0
  18. package/rules/abie/utils/k8s-tree.mjs +102 -0
  19. package/rules/abie/utils/kustomization-patches.mjs +224 -0
  20. package/rules/abie/utils/overlay-paths.mjs +97 -0
  21. package/rules/abie/utils/yaml.mjs +72 -0
  22. package/rules/adr/policy/settings_json/target.json +4 -0
  23. package/rules/adr/policy/settings_local_json/target.json +4 -0
  24. package/rules/bun/policy/bunfig/target.json +4 -0
  25. package/rules/bun/policy/package_json/target.json +4 -0
  26. package/rules/capacitor/policy/package_json/target.json +4 -0
  27. package/rules/docker/policy/lint_docker_yml/target.json +4 -0
  28. package/rules/docker/policy/package_json/target.json +4 -0
  29. package/rules/hasura/policy/svc_hl/target.json +4 -0
  30. package/rules/image-avif/policy/package_json/target.json +4 -0
  31. package/rules/image-compress/policy/package_json/target.json +4 -0
  32. package/rules/js-bun-db/policy/package_json/target.json +4 -0
  33. package/rules/js-bun-redis/policy/package_json/target.json +4 -0
  34. package/rules/js-lint/policy/lint_js_yml/target.json +4 -0
  35. package/rules/js-lint/policy/package_json/target.json +4 -0
  36. package/rules/js-mssql/policy/package_json/target.json +4 -0
  37. package/rules/js-run/policy/configmap/target.json +4 -0
  38. package/rules/js-run/policy/package_json/target.json +4 -0
  39. package/rules/k8s/policy/base_kustomization/target.json +4 -0
  40. package/rules/k8s/policy/base_manifest/target.json +10 -0
  41. package/rules/k8s/policy/gateway/target.json +4 -0
  42. package/rules/k8s/policy/hpa_pdb/target.json +4 -0
  43. package/rules/k8s/policy/kustomization/target.json +4 -0
  44. package/rules/k8s/policy/manifest/target.json +4 -0
  45. package/rules/k8s/policy/svc_hl_yaml/target.json +4 -0
  46. package/rules/k8s/policy/svc_yaml/target.json +4 -0
  47. package/rules/npm-module/policy/emit_types_config/target.json +4 -0
  48. package/rules/npm-module/policy/npm_package_json/target.json +4 -0
  49. package/rules/npm-module/policy/npm_publish_yml/target.json +4 -0
  50. package/rules/npm-module/policy/root_package_json/target.json +4 -0
  51. package/rules/php/policy/lint_php_yml/target.json +4 -0
  52. package/rules/php/policy/package_json/target.json +4 -0
  53. package/rules/rego/js/applies/check.mjs +54 -0
  54. package/rules/rego/policy/package_json/target.json +5 -0
  55. package/rules/rego/policy/vscode_extensions/target.json +5 -0
  56. package/rules/rego/policy/vscode_settings/target.json +5 -0
  57. package/rules/style-lint/policy/lint_style_yml/target.json +4 -0
  58. package/rules/style-lint/policy/package_json/target.json +4 -0
  59. package/rules/style-lint/policy/vscode_extensions/target.json +4 -0
  60. package/rules/style-lint/policy/vscode_settings/target.json +4 -0
  61. package/rules/text/policy/cspell/target.json +4 -0
  62. package/rules/text/policy/markdownlint/target.json +4 -0
  63. package/rules/text/policy/oxfmtrc/target.json +4 -0
  64. package/rules/text/policy/package_json/target.json +4 -0
  65. package/rules/text/policy/vscode_extensions/target.json +4 -0
  66. package/rules/text/policy/vscode_settings/target.json +4 -0
  67. package/rules/vue/policy/package_json/target.json +4 -0
  68. package/schemas/target.json +58 -0
  69. package/scripts/lint-conftest.mjs +65 -414
  70. package/scripts/utils/discover-checkable-rules.mjs +123 -0
  71. package/scripts/utils/resolve-target-files.mjs +109 -0
  72. package/scripts/utils/run-rule.mjs +131 -0
  73. package/rules/abie/js/check.mjs +0 -1152
  74. package/rules/rego/js/check.mjs +0 -106
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Спільні YAML-хелпери для abie-перевірок: парсинг документів з опційним modeline,
3
+ * BOM-strip, regex для `# yaml-language-server: $schema=` і поділу на рядки.
4
+ */
5
+ import { readFile } from 'node:fs/promises'
6
+
7
+ import { parseAllDocuments } from 'yaml'
8
+
9
+ export const MODELINE_RE = /^#\s*yaml-language-server:\s*\$schema=(\S+)\s*$/
10
+ export const LINE_SPLIT_RE = /\r?\n/u
11
+
12
+ /**
13
+ * Прибирає BOM на початку файлу.
14
+ * @param {string} s вміст
15
+ * @returns {string}
16
+ */
17
+ export function stripBom(s) {
18
+ return s.startsWith('') ? s.slice(1) : s
19
+ }
20
+
21
+ /**
22
+ * Чи YAML-документ — це `kind: Deployment`.
23
+ * @param {unknown} obj корінь YAML-документа
24
+ * @returns {boolean}
25
+ */
26
+ export function isDeploymentDoc(obj) {
27
+ return (
28
+ obj !== null &&
29
+ typeof obj === 'object' &&
30
+ !Array.isArray(obj) &&
31
+ /** @type {Record<string, unknown>} */ (obj).kind === 'Deployment'
32
+ )
33
+ }
34
+
35
+ /**
36
+ * No-op fail-handler для функцій, що мовчки повертають null/[] при помилці парсингу.
37
+ * @param {string} _msg ігнорується
38
+ */
39
+ export const silentFail = _msg => {
40
+ /* silent — пошкоджені файли ловить check-k8s */
41
+ }
42
+
43
+ /**
44
+ * Зчитує і парсить YAML-документи з файлу. BOM і modeline (перший рядок `$schema`)
45
+ * автоматично прибираються перед `parseAllDocuments`. При помилці читання/парсингу
46
+ * викликає `failFn` і повертає `null`.
47
+ * @param {string} abs абсолютний шлях
48
+ * @param {string} rel відносний (для повідомлень)
49
+ * @param {(msg: string) => void} failFn
50
+ * @returns {Promise<import('yaml').Document[] | null>}
51
+ */
52
+ export async function readAndParseYamlDocs(abs, rel, failFn) {
53
+ let raw
54
+ try {
55
+ raw = await readFile(abs, 'utf8')
56
+ } catch (error) {
57
+ const msg = error instanceof Error ? error.message : String(error)
58
+ failFn(`${rel}: не вдалося прочитати (${msg})`)
59
+ return null
60
+ }
61
+ const body = stripBom(raw)
62
+ const lines = body.split(LINE_SPLIT_RE)
63
+ const first = lines[0] ?? ''
64
+ const rest = MODELINE_RE.test(first.trim()) ? lines.slice(1).join('\n') : body
65
+ try {
66
+ return parseAllDocuments(rest)
67
+ } catch (error) {
68
+ const msg = error instanceof Error ? error.message : String(error)
69
+ failFn(`${rel}: YAML (${msg})`)
70
+ return null
71
+ }
72
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": ".claude/settings.json" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": ".claude/settings.local.json" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": "bunfig.toml" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": "package.json" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": "package.json" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": ".github/workflows/lint-docker.yml" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": "package.json" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": "hasura/k8s/base/svc-hl.yaml" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "walkGlob": "**/package.json" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": "package.json" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "walkGlob": "**/package.json" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "walkGlob": "**/package.json" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": ".github/workflows/lint-js.yml" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": "package.json" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "walkGlob": "**/package.json" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "walkGlob": "**/k8s/*/configmap.yaml" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "walkGlob": "**/package.json" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "walkGlob": "**/k8s/**/base/**/kustomization.yaml" }
4
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": {
4
+ "walkGlob": [
5
+ "**/k8s/**/base/**/*.yaml",
6
+ "**/k8s/**/base/**/*.yml",
7
+ "!**/k8s/**/base/**/kustomization.yaml"
8
+ ]
9
+ }
10
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "walkGlob": ["**/k8s/**/*.yaml", "**/k8s/**/*.yml"] }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "walkGlob": ["**/k8s/**/*.yaml", "**/k8s/**/*.yml"] }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "walkGlob": "**/k8s/**/kustomization.yaml" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "walkGlob": ["**/k8s/**/*.yaml", "**/k8s/**/*.yml"] }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "walkGlob": "**/k8s/**/svc-hl.yaml" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "walkGlob": "**/k8s/**/svc.yaml" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": "npm/tsconfig.emit-types.json" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": "npm/package.json" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": ".github/workflows/npm-publish.yml" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": "package.json" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": ".github/workflows/lint-php.yml" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": "package.json" }
4
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Applies-гейт правила `rego` (rego.mdc): правило застосовне, лише якщо в репозиторії є
3
+ * хоча б один `.rego`-файл (під типовими skip-ами і `.n-cursor.json:ignore`).
4
+ *
5
+ * Якщо `.rego` нема — CLI пропускає правило цілком (включно з polices `package_json`,
6
+ * `vscode_extensions`, `vscode_settings`), бо вимоги rego-tooling неактуальні. Якщо є — CLI
7
+ * прогонить policy-концерни через `target.json`-маніфести у `rules/rego/policy/<name>/`.
8
+ *
9
+ * JS тут лишається лише як cross-file гейт: walkDir не виразити декларативно через `target.json`.
10
+ * Друк короткого pass-повідомлення з контекстом робить `check()` (необовʼязковий).
11
+ */
12
+ import { createCheckReporter } from '../../../../scripts/utils/check-reporter.mjs'
13
+ import { loadCursorIgnorePaths } from '../../../../scripts/utils/load-cursor-config.mjs'
14
+ import { walkDir } from '../../../../scripts/utils/walkDir.mjs'
15
+
16
+ /**
17
+ * Чи є хоча б один `.rego`-файл у дереві від `cwd`. Зупиняється на першому матчі.
18
+ * @param {string} root абсолютний шлях кореня
19
+ * @param {string[]} ignorePaths шляхи каталогів, повністю виключених з обходу
20
+ * @returns {Promise<boolean>} `true`, якщо знайдено хоч один `.rego`
21
+ */
22
+ async function projectHasRegoFiles(root, ignorePaths) {
23
+ let found = false
24
+ await walkDir(
25
+ root,
26
+ p => {
27
+ if (p.endsWith('.rego')) {
28
+ found = true
29
+ }
30
+ },
31
+ ignorePaths
32
+ )
33
+ return found
34
+ }
35
+
36
+ /**
37
+ * Rule-level applies-гейт: CLI пропускає правило, якщо в репо немає `.rego` файлів.
38
+ * @returns {Promise<boolean>} `true`, якщо правило застосовне
39
+ */
40
+ export async function applies() {
41
+ const root = process.cwd()
42
+ const ignorePaths = await loadCursorIgnorePaths(root)
43
+ return projectHasRegoFiles(root, ignorePaths)
44
+ }
45
+
46
+ /**
47
+ * Друкує короткий context-pass — самі полісі прогонить CLI через `policy/<name>/target.json`.
48
+ * @returns {Promise<number>} 0 — все ок (фактичні порушення повертають policy-концерни)
49
+ */
50
+ export async function check() {
51
+ const reporter = createCheckReporter()
52
+ reporter.pass('Знайдено *.rego у дереві — перевіряємо канонічні конфіги rego.mdc')
53
+ return reporter.getExitCode()
54
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": "package.json", "required": true },
4
+ "missingMessage": "package.json не існує — створи згідно rego.mdc (rego.package_json)"
5
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": ".vscode/extensions.json", "required": true },
4
+ "missingMessage": ".vscode/extensions.json не існує — створи згідно rego.mdc (rego.vscode_extensions)"
5
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": ".vscode/settings.json", "required": true },
4
+ "missingMessage": ".vscode/settings.json не існує — створи згідно rego.mdc (rego.vscode_settings)"
5
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": ".github/workflows/lint-style.yml" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": "package.json" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": ".vscode/extensions.json" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": ".vscode/settings.json" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": ".cspell.json" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": ".markdownlint-cli2.jsonc" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": ".oxfmtrc.json" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": "package.json" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": ".vscode/extensions.json" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "single": ".vscode/settings.json" }
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
+ "files": { "walkGlob": "**/package.json" }
4
+ }
@@ -0,0 +1,58 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://unpkg.com/@nitra/cursor/schemas/target.json",
4
+ "title": "Rego policy target manifest",
5
+ "description": "Маніфест поряд із <name>.rego: декларує, які файли проєкту фідити в conftest для цієї полісі. Лежить у npm/rules/<id>/policy/<name>/target.json (per-policy, поруч із <name>.rego). CLI читає й передає у runConftestBatch — JS-оркестратор у js/<name>/check.mjs не зобовʼязаний дублювати виклик. Namespace полісі обчислюється з шляху: <id>.<name>, відповідно `package <id>.<name>` у .rego.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["files"],
9
+ "properties": {
10
+ "$schema": {
11
+ "type": "string",
12
+ "format": "uri",
13
+ "description": "Опційне посилання на JSON Schema для IDE-валідації; очікувано https://unpkg.com/@nitra/cursor/schemas/target.json"
14
+ },
15
+ "files": {
16
+ "oneOf": [
17
+ {
18
+ "type": "object",
19
+ "additionalProperties": false,
20
+ "required": ["single"],
21
+ "properties": {
22
+ "single": {
23
+ "type": "string",
24
+ "minLength": 1,
25
+ "description": "Відносний шлях від кореня репозиторію (posix). Заборонені сегменти '..' і абсолютні шляхи."
26
+ },
27
+ "required": {
28
+ "type": "boolean",
29
+ "description": "true → fail при відсутності файла з відповідним missingMessage; false/відсутнє → silent skip (полісі не запускається). За замовчуванням false."
30
+ }
31
+ }
32
+ },
33
+ {
34
+ "type": "object",
35
+ "additionalProperties": false,
36
+ "required": ["walkGlob"],
37
+ "properties": {
38
+ "walkGlob": {
39
+ "oneOf": [
40
+ { "type": "string", "minLength": 1 },
41
+ {
42
+ "type": "array",
43
+ "minItems": 1,
44
+ "items": { "type": "string", "minLength": 1 }
45
+ }
46
+ ],
47
+ "description": "Один або декілька picomatch-globів (matched проти відносного posix-шляху). walkDir від cwd із загальними skip-ами + .n-cursor.json:ignore."
48
+ }
49
+ }
50
+ }
51
+ ]
52
+ },
53
+ "missingMessage": {
54
+ "type": "string",
55
+ "description": "Override дефолтного fail-повідомлення при відсутності required:single файла. Без значення CLI використає шаблон '<path> не існує (<id>.<name>)'."
56
+ }
57
+ }
58
+ }