@nitra/cursor 3.26.0 → 3.28.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 (128) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/bin/n-cursor.js +29 -9
  3. package/package.json +1 -1
  4. package/rules/abie/js/applies.mjs +1 -5
  5. package/rules/abie/js/env_dns.mjs +1 -9
  6. package/rules/abie/js/firebase_hosting.mjs +1 -5
  7. package/rules/abie/js/hc_pairing.mjs +1 -8
  8. package/rules/abie/js/ua_http_route.mjs +1 -10
  9. package/rules/abie/js/ua_node_selector.mjs +1 -8
  10. package/rules/adr/js/hooks.mjs +1 -20
  11. package/rules/bun/js/layout.mjs +1 -19
  12. package/rules/capacitor/js/platforms.mjs +1 -23
  13. package/rules/changelog/js/consistency.mjs +1 -29
  14. package/rules/ci4/js/marksman_config.mjs +1 -19
  15. package/rules/docker/js/lint.mjs +1 -34
  16. package/rules/ga/docs/fix.md +16 -149
  17. package/rules/ga/js/docs/lint.md +12 -93
  18. package/rules/ga/js/docs/workflows.md +28 -213
  19. package/rules/ga/js/workflows.mjs +1 -16
  20. package/rules/ga/lint/docs/lint.md +24 -206
  21. package/rules/graphql/js/tooling.mjs +1 -9
  22. package/rules/hasura/js/internal_urls.mjs +1 -24
  23. package/rules/image-avif/js/avif_generation.mjs +1 -27
  24. package/rules/image-compress/js/package_setup.mjs +1 -18
  25. package/rules/js-bun-db/js/safety.mjs +1 -31
  26. package/rules/js-bun-redis/js/imports.mjs +1 -12
  27. package/rules/js-lint/js/docs/lint-findings.md +30 -0
  28. package/rules/js-lint/js/lint-findings.mjs +1 -7
  29. package/rules/js-lint/js/lint.mjs +1 -10
  30. package/rules/js-lint/js/tooling.mjs +1 -13
  31. package/rules/js-lint/js/utils_imports.mjs +1 -18
  32. package/rules/js-lint-ci/js/lint.mjs +1 -6
  33. package/rules/js-mssql/js/deps.mjs +1 -10
  34. package/rules/js-run/js/runtime.mjs +1 -37
  35. package/rules/js-run/lib/docs/temporal-scan.md +25 -0
  36. package/rules/k8s/js/manifests.mjs +1 -137
  37. package/rules/nginx-default-tpl/js/template.mjs +1 -18
  38. package/rules/npm-module/js/docs/header_doc_pointer.md +25 -0
  39. package/rules/npm-module/js/header_doc_pointer.mjs +82 -0
  40. package/rules/npm-module/js/package_structure.mjs +1 -28
  41. package/rules/npm-module/js/rule_meta.mjs +1 -10
  42. package/rules/npm-module/js/skill_meta.mjs +1 -13
  43. package/rules/php/js/tooling.mjs +1 -11
  44. package/rules/python/js/applies.mjs +1 -8
  45. package/rules/python/js/tooling.mjs +1 -21
  46. package/rules/rego/js/applies.mjs +1 -11
  47. package/rules/rust/js/applies.mjs +1 -7
  48. package/rules/security/js/sample_secret.mjs +1 -28
  49. package/rules/security/js/trufflehog.mjs +1 -8
  50. package/rules/style-lint/js/lint.mjs +1 -5
  51. package/rules/style-lint/js/tooling.mjs +1 -19
  52. package/rules/tauri/js/cargo_mutants_config.mjs +1 -20
  53. package/rules/tauri/js/tooling.mjs +1 -21
  54. package/rules/test/js/cargo_mutants_config.mjs +1 -12
  55. package/rules/test/js/location.mjs +1 -9
  56. package/rules/test/js/no-process-chdir.mjs +1 -21
  57. package/rules/test/js/no-relative-fs-path.mjs +1 -23
  58. package/rules/test/js/stryker_config.mjs +4 -25
  59. package/rules/test/js/vitest-config-pool-forks.mjs +1 -17
  60. package/rules/text/js/forbidden-prettier.mjs +1 -10
  61. package/rules/text/js/formatting.mjs +1 -31
  62. package/rules/vue/js/packages.mjs +1 -24
  63. package/scripts/docs/coverage-fix-extract.md +32 -0
  64. package/scripts/docs/lint-cli.md +25 -0
  65. package/scripts/docs/post-tool-use-fix.md +27 -0
  66. package/scripts/docs/rename-yaml-extensions.md +36 -0
  67. package/scripts/docs/skills-cli.md +35 -0
  68. package/scripts/docs/sync-claude-config.md +52 -0
  69. package/scripts/docs/sync-setup-bun-deps-action.md +26 -0
  70. package/scripts/docs/upgrade-nitra-cursor-and-install.md +29 -0
  71. package/scripts/docs/worktree-cli.md +46 -0
  72. package/scripts/lib/docs/assert-project-root.md +28 -0
  73. package/scripts/lib/docs/diff-added-lines.md +34 -0
  74. package/scripts/lib/docs/read-n-cursor-config-lite.md +28 -0
  75. package/scripts/lib/docs/resolve-target-files.md +34 -0
  76. package/scripts/lib/docs/root-notice.md +28 -0
  77. package/scripts/lib/docs/rule-meta-helpers.md +34 -0
  78. package/scripts/lib/docs/rule-meta.md +34 -0
  79. package/scripts/lib/docs/rule-predicates.md +30 -0
  80. package/scripts/lib/docs/run-conftest-batch.md +26 -0
  81. package/scripts/lib/docs/run-lint-step.md +25 -0
  82. package/scripts/lib/docs/run-rule-cli.md +27 -0
  83. package/scripts/lib/docs/run-rule.md +32 -0
  84. package/scripts/lib/docs/run-standard-lint.md +22 -0
  85. package/scripts/lib/docs/run-standard-rule.md +24 -0
  86. package/scripts/lib/docs/skill-meta.md +31 -0
  87. package/scripts/lib/docs/sync-gitignore-worktree.md +31 -0
  88. package/scripts/lib/docs/template.md +40 -0
  89. package/scripts/lib/docs/timing-summary.md +24 -0
  90. package/scripts/lib/docs/workspaces.md +30 -0
  91. package/scripts/lib/docs/worktree-notice.md +27 -0
  92. package/scripts/lib/docs/worktree.md +38 -0
  93. package/scripts/utils/docs/ast-scan-utils.md +50 -0
  94. package/scripts/utils/docs/ensure-gitignore-entries.md +28 -0
  95. package/scripts/utils/docs/find-package-json-paths.md +26 -0
  96. package/scripts/utils/docs/lock-cache-dir.md +25 -0
  97. package/scripts/utils/docs/pass.md +25 -0
  98. package/scripts/utils/docs/resolve-cargo-manifest.md +23 -0
  99. package/scripts/utils/docs/resolve-cmd.md +29 -0
  100. package/scripts/utils/docs/resolve-js-root.md +25 -0
  101. package/scripts/utils/docs/test-helpers.md +36 -0
  102. package/scripts/utils/docs/walk-cache.md +27 -0
  103. package/scripts/utils/docs/walkDir.md +32 -0
  104. package/scripts/utils/docs/with-lock.md +25 -0
  105. package/scripts/utils/docs/worktree-fingerprint.md +27 -0
  106. package/skills/docgen/js/docgen-batch.mjs +95 -0
  107. package/skills/docgen/js/docgen-extract.mjs +33 -18
  108. package/skills/docgen/js/docgen-gen.mjs +258 -30
  109. package/skills/docgen/js/docgen-ignore.mjs +4 -7
  110. package/skills/docgen/js/docgen-prompts.mjs +40 -23
  111. package/skills/docgen/js/docgen-scan.mjs +1 -8
  112. package/skills/docgen/js/docs/docgen-extract.md +28 -0
  113. package/skills/docgen/js/docs/docgen-gen.md +41 -0
  114. package/skills/docgen/js/docs/docgen-ignore.md +24 -0
  115. package/skills/docgen/js/docs/docgen-prompts.md +24 -0
  116. package/skills/docgen/js/docs/docgen-scan.md +48 -0
  117. package/skills/fix/SKILL.md +5 -31
  118. package/skills/fix/js/docs/llm-worker.md +27 -0
  119. package/skills/fix/js/docs/orchestrator.md +32 -0
  120. package/skills/fix/js/docs/t0.md +29 -0
  121. package/skills/fix/js/llm-worker.mjs +216 -0
  122. package/skills/fix/js/orchestrator.mjs +119 -0
  123. package/skills/fix/js/t0.mjs +213 -0
  124. package/skills/fix/meta.json +1 -1
  125. package/skills/start-check/js/check.mjs +1 -16
  126. package/skills/start-check/js/docs/check.md +34 -0
  127. package/skills/taze/js/diff.mjs +1 -15
  128. package/skills/taze/js/docs/diff.md +33 -0
@@ -1,100 +1,19 @@
1
- # `npm/rules/ga/js/lint.mjs`
1
+ # lint.mjs
2
2
 
3
3
  ## Огляд
4
4
 
5
- Файл `lint.mjs` у теці `npm/rules/ga/js/` є тонкою адаптерною ланкою (CI-кроком) правила `ga` (GitHub Actions). Він не реалізує жодної самостійної логіки лінтингу натомість делегує виклик у канонічну CLI-обгортку правила, яка живе у сусідньому модулі `npm/rules/ga/lint/lint.mjs` (експортує `runLintGaCli`).
5
+ Файл `lint` делегує перевірку коду інструменту, який запускається з командного рядка. Він використовується для автоматизованої перевірки коду на відповідність певним правилам. Це забезпечує консистентність та якість коду в проєкті.
6
6
 
7
- Призначення модуля — надати уніфікований lint-entry для правила `ga`, який відповідає інтерфейсному контракту «JS-частини правила» (експорт `async function lint(files)`), і одночасно явно зафіксувати, що правило `ga` працює **тільки в whole-repo режимі**: per-file-аналіз не підтримується, а вхідний аргумент `files` ігнорується.
7
+ ## Поведінка
8
8
 
9
- Контекст:
9
+ 1. Запускає наявний CLI для перевірки правил.
10
+ 2. Проводить аналіз всього репозиторію, ігноруючи вказаний список файлів.
11
+ 3. Повертає код завершення процесу.
12
+ 4. Не використовує кеш результатів.
13
+ 5. Не здійснює взаємодії з мережею.
10
14
 
11
- - Правило `ga` перевіряє конфіги GitHub Actions (`.github/workflows/*.{yml,yaml}`) — як через Rego (conftest), так і через JS cross-file-перевірки в `npm/rules/ga/js/workflows.mjs`.
12
- - Канонічний CLI правила (`runLintGaCli`) у `npm/rules/ga/lint/lint.mjs` додатково запускає preflight для зовнішніх інструментів (`shellcheck`, `conftest`, `uv`/`uvx`), а потім послідовно — `bunx github-actionlint`, `uvx zizmor --offline --collect=workflows .` і делегує далі.
13
- - Сам адаптер `npm/rules/ga/js/lint.mjs` лише викликає цей CLI і повертає його exit code.
15
+ ## Гарантії поведінки
14
16
 
15
- ## Експорти / API
16
-
17
- Модуль є ES-модулем (`.mjs`) з одним публічним експортом.
18
-
19
- | Експорт | Тип | Призначення |
20
- | ------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------- |
21
- | `lint` | `async function (files?: string[]) => Promise<number>` | CI-крок (whole-repo lint) для правила `ga`. Параметр `files` ігнорується. Повертає exit code від канонічного CLI правила. |
22
-
23
- Інших експортів (`default`, named) у файлі немає.
24
-
25
- ## Функції
26
-
27
- ### `lint(_files)`
28
-
29
- Єдина функція файлу. Адаптер навколо `runLintGaCli`.
30
-
31
- - **Сигнатура:**
32
- ```
33
- async function lint(_files: string[] | undefined): Promise<number>
34
- ```
35
- - **Параметри:**
36
- - `_files` — `string[] | undefined`. **Ігнорується.** Префікс `_` у назві параметра — конвенційний маркер «не використовується». Документація в JSDoc явно вказує: «whole-repo аналіз», per-file режиму немає. Аргумент усе одно приймається, щоб задовольнити загальний контракт «JS-частини правила» (інші правила можуть мати per-file lint, який отримує список змінених файлів).
37
- - **Повертає:** `Promise<number>` — exit code, отриманий від `runLintGaCli()`. Семантика стандартна для CLI: `0` — успіх, ненульове — помилка/порушення.
38
- - **Виключення:** функція сама не кидає винятків і не обгортає `runLintGaCli` у `try/catch`. Будь-яка нерозвʼязана `Promise` чи синхронний `throw` всередині `runLintGaCli` пробʼється назовні без модифікації.
39
- - **Side effects:** прямих side effects сам адаптер не виконує. Усі side effects (preflight installs через `ensureTool`, запуск зовнішніх процесів `bunx github-actionlint`, `uvx zizmor`, `conftest`, друк у stdout/stderr, можливі мутації CWD) — на стороні `runLintGaCli` та модулів, до яких він делегує далі (`rules/ga/fix.mjs::check()`, Rego-полісі `npm/policy/ga/`, JS-перевірки `workflows.mjs`).
40
-
41
- ## Залежності
42
-
43
- ### Імпорти
44
-
45
- | Імпорт | Шлях | Тип | Призначення |
46
- | -------------- | -------------------- | ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
47
- | `runLintGaCli` | `'../lint/lint.mjs'` | Іменований імпорт із сусіднього модуля (відносний шлях у межах правила `ga`) | Канонічний CLI правила `ga`: робить preflight, виконує `actionlint`, `zizmor`, делегує в `rules/ga/fix.mjs::check()`. |
48
-
49
- Інших імпортів немає — ані вбудованих модулів Node, ані сторонніх npm-пакетів.
50
-
51
- ### Транзитивні залежності (інформативно)
52
-
53
- Через `runLintGaCli` адаптер опосередковано залежить від:
54
-
55
- - `node:process` (платформа);
56
- - внутрішніх хелперів `npm/scripts/lib/`: `ensureTool`, `runLintStep`, `runStandardLint`;
57
- - утиліти `npm/scripts/utils/resolve-cmd.mjs`;
58
- - JS-перевірок правила `ga` у `npm/rules/ga/js/workflows.mjs` (експорт `check`);
59
- - Rego-полісі `npm/policy/ga/` (через `runConftestBatch` у `rules/ga/fix.mjs`);
60
- - зовнішніх бінарників: `bunx`, `github-actionlint`, `shellcheck`, `uv`/`uvx`, `zizmor`, `conftest`.
61
-
62
- Прямого знання про ці транзитивні залежності адаптер не має — для нього існує тільки контракт «`runLintGaCli` повертає `Promise<number>` з exit code».
63
-
64
- ## Потік виконання / Використання
65
-
66
- ### Внутрішній потік
67
-
68
- 1. Викликається `lint(_files)`.
69
- 2. Параметр `_files` приймається й ігнорується (whole-repo режим).
70
- 3. Викликається `runLintGaCli()` без аргументів.
71
- 4. Результат (`Promise<number>`) повертається безпосередньо викликачу через `return runLintGaCli()`. Жодного `await` тут немає — функція позначена `async`, тому повернутий проміс автоматично «розтекстується» у проміс async-функції; виклик семантично еквівалентний `return await runLintGaCli()`.
72
-
73
- ### Як використовується
74
-
75
- Модуль є JS-точкою входу правила `ga` для уніфікованих lint-pipelin-ів проєкту. Типові викликачі:
76
-
77
- - **Загальний lint-оркестратор** (наприклад, кореневий `bun run lint` або `npx @nitra/cursor lint`), який обходить активні правила й для кожного, що має JS-частину, викликає експортовану функцію `lint`. Передає список файлів (зі staged/змінених) — для правила `ga` цей список буде проігноровано.
78
- - **CI workflows** — через ту саму lint-команду, але з повним списком файлів репо або без нього.
79
-
80
- Те, що адаптер ігнорує `files`, — свідома архітектурна декларація: лінт `ga` не вміє швидко перевіряти одинокі workflow-файли, бо правила `ga.mdc` мають cross-file семантику (узгодженість назв джоб, повторювані workflows, спільний `workflow_common` тощо), плюс зовнішні інструменти (`actionlint`, `zizmor`) самі обходять директорію `.github/workflows/` цілком.
81
-
82
- ### Звʼязок з канонічним CLI
83
-
84
- Існує **дві** окремі точки входу до лінтингу правила `ga`:
85
-
86
- 1. `bin/n-cursor.js` → підкоманда `lint-ga` → `runLintGaCli` напряму (CLI-користувач, дзвонить руками або в скриптах).
87
- 2. Загальний lint pipeline → `npm/rules/ga/js/lint.mjs::lint(files)` → `runLintGaCli` (програмний шлях для обхідника правил).
88
-
89
- Обидві дороги ведуть у одну й ту саму функцію `runLintGaCli`, що гарантує ідентичну поведінку, exit code і побічні ефекти незалежно від точки входу.
90
-
91
- ### Контракт повернення
92
-
93
- - Викликач має право трактувати результат як стандартний POSIX exit code: `0` — лінт пройшов, інше — є порушення або інфраструктурна помилка (наприклад, відсутній `uv` без можливості auto-install).
94
- - Адаптер не нормалізує код помилки й не маскує його — якщо `runLintGaCli` повернув `2`, `lint` поверне `2`.
95
-
96
- ### Обмеження та крайні випадки
97
-
98
- - **Per-file режиму немає.** Передача `files` нічого не змінює; для оптимізації CI краще запускати правило `ga` тільки коли реально змінилися файли в `.github/workflows/` (це — рішення викликача, а не адаптера).
99
- - **Жодного захисту від конкурентного запуску** на рівні цього адаптера: серіалізація важких CLI-команд (по конвенції `scripts.mdc`) реалізована всередині `runLintGaCli` через `runStandardLint`.
100
- - **Жодного preflight тут не виконується** — увесь preflight (ensureTool для `shellcheck`/`conftest`, перевірка `uv`) живе всередині `runLintGaCli`.
17
+ - Делегує правила до існуючого CLI.
18
+ - Не враховує `files` в режимі per-file.
19
+ - Не має кешування.
@@ -2,216 +2,31 @@
2
2
 
3
3
  ## Огляд
4
4
 
5
- Модуль `workflows.mjs` реалізує JS-частину перевірки правила **ga.mdc** (GitHub Actions) у пакеті `@nitra/cursor`. Він валідує конфігурацію `.github/workflows/` цільового репозиторію: розширення файлів (`.yml`, не `.yaml`), наявність обовʼязкових workflow, відсутність MegaLinter-залишків, коректність triggers `on.*.paths`, наявність composite-action `setup-bun-deps` і локальне встановлення `shellcheck`.
6
-
7
- Модуль працює в парі з **Rego-полісі** з `npm/policy/ga/`: пер-документні структурні перевірки (поля YAML, `concurrency`, заборона `oven-sh/setup-bun` / `actions/cache` / `bun install`, мінімальні версії `uses`, наявність `actions/checkout@v6` перед локальним `setup-bun-deps`, shell-продовження `\` у `run`) делеговані Rego і викликаються через `runConftestBatch`. У JS лишилися ті перевірки, які потребують доступу до файлової системи / git-індексу (`git ls-files :(glob)`, `existsSync`, читання `readdir`) і не можуть бути виражені declarative-полісі.
8
-
9
- Точка входу — асинхронна функція `check(cwd)`, яка повертає exit code (`0` успіх, `1` — є проблеми). Її викликає `bun run lint-ga` разом з `actionlint` і `zizmor`.
10
-
11
- Plan B-патерн: rego-частина авторитетна для пер-документних правил; JS виконує cross-file і tooling-перевірки. Hard-fail якщо `conftest` відсутній у PATH (узгоджено з `runConftestBatch`).
12
-
13
- ## Експорти / API
14
-
15
- | Експорт | Тип | Призначення |
16
- | -------------------------------------- | ---------------- | ------------------------------------------------------------------------------- |
17
- | `check(cwd?)` | `async function` | Головна точка входу: валідує `ga.mdc` для репозиторію `cwd`. |
18
- | `checkShellcheckInstalled(pass, fail)` | `function` | Перевіряє наявність бінарника `shellcheck` у PATH (актуальне для `actionlint`). |
19
-
20
- Решта функцій модуля — приватні (module-local) хелпери, які не експортуються.
21
-
22
- ## Функції
23
-
24
- ### `gitHasAnyTrackedFileMatchingGlob(globPattern, cwd)`
25
-
26
- - **Сигнатура:** `(globPattern: string, cwd: string) => boolean`
27
- - **Параметри:**
28
- - `globPattern` glob із workflow (наприклад `files/**`, `image-migration-new/**`).
29
- - `cwd` робочий каталог для виклику `git`.
30
- - **Повертає:** `true`, якщо хоча б один tracked-файл у git-індексі матчить glob; `true` для негативних патернів (починаються з `!`); `false` — якщо patternstring порожній або `git` упав.
31
- - **Side effects:** спавн дочірнього процесу `git ls-files -z -- :(glob)<pattern>` через `execFileSync` (синхронно).
32
- - **Особливості:** використовує pathspec `:(glob)`, щоб делегувати glob-матчинг git-у, без ручної реалізації glob-engine і без рекурсивного сканування FS.
33
-
34
- ### `shouldValidateWorkflowPathsGlob(p)`
35
-
36
- - **Сигнатура:** `(p: string) => boolean`
37
- - **Параметри:** `p` — рядковий glob із `on.*.paths`.
38
- - **Повертає:** `true`, якщо glob варто валідувати на існування файлів; `false` для негативних патернів (`!...`) та для патернів зі вставкою `*.` (типу `*.vue`, `*.php` — заготовки для майбутніх файлів).
39
- - **Side effects:** немає (чиста функція).
40
-
41
- ### `verifyOnePathsGlob(relPath, eventName, raw, passFn, failFn, cwd)`
42
-
43
- - **Сигнатура:** `(relPath: string, eventName: string, raw: unknown, passFn: (msg: string) => void, failFn: (msg: string) => void, cwd: string) => void`
44
- - **Параметри:**
45
- - `relPath` — відносний шлях workflow-файлу для повідомлень.
46
- - `eventName` — назва події (`push` або `pull_request`).
47
- - `raw` — сирий елемент із масиву `paths` (може бути будь-яким типом).
48
- - `passFn`/`failFn` — колбеки звітування.
49
- - `cwd` — корінь репозиторію для `git`.
50
- - **Повертає:** `void`.
51
- - **Side effects:** виклики `passFn` або `failFn` (запис у reporter).
52
- - **Поведінка:**
53
- - Порожній/нерядковий glob — ігнорує.
54
- - Glob, який не треба валідувати (`shouldValidateWorkflowPathsGlob === false`) — звітує `pass` з поясненням «пропущено для перевірки існування».
55
- - Інакше викликає `gitHasAnyTrackedFileMatchingGlob` і звітує відповідно `pass` (є збіги) або `fail` (немає жодного).
56
-
57
- ### `verifyWorkflowEventPathsGlobsExist(relPath, root, passFn, failFn, cwd)`
58
-
59
- - **Сигнатура:** `(relPath: string, root: Record<string, unknown>, passFn, failFn, cwd: string) => void`
60
- - **Параметри:** `root` — розпарсений YAML workflow.
61
- - **Повертає:** `void`.
62
- - **Side effects:** делеговано `verifyOnePathsGlob`.
63
- - **Логіка:** дістає `on.push.paths` та `on.pull_request.paths` через `getObjKey`, ітерує масивами і викликає `verifyOnePathsGlob` для кожного елемента. Якщо `on` відсутній, не є обʼєктом, або `paths` не є масивом — нічого не робить.
64
-
65
- ### `getObjKey(obj, key)`
66
-
67
- - **Сигнатура:** `(obj: unknown, key: string) => unknown`
68
- - **Повертає:** значення поля `obj[key]`, якщо `obj` — non-array object; інакше `undefined`.
69
- - **Side effects:** немає.
70
- - **Призначення:** безпечний доступ до вкладеного поля YAML, де root може виявитись не-обʼєктом після парсингу.
71
-
72
- ### `checkApplyWorkflow(wfDir, files, filename, expectedPath, passFn, failFn)`
73
-
74
- - **Сигнатура:** `async (wfDir: string, files: string[], filename: string, expectedPath: string, passFn, failFn) => Promise<void>`
75
- - **Параметри:**
76
- - `wfDir` — абсолютна директорія `.github/workflows`.
77
- - `files` — список файлів у `wfDir`.
78
- - `filename` — імʼя apply-workflow (наприклад `apply-k8s.yml`).
79
- - `expectedPath` — очікуваний шаблон у `on.push.paths` (наприклад `**/k8s/**/*.yaml`).
80
- - **Повертає:** `Promise<void>`.
81
- - **Side effects:** читає файл `wfDir/filename`, звітує через `passFn`/`failFn`.
82
- - **Логіка:** якщо `filename` відсутній у `files` — повертає без перевірки. Інакше парсить YAML через `parseWorkflowYaml`; перевірку наявності `expectedPath` у `on.push.paths` робить точно через `eventPathsIncludeExact`, а якщо YAML не розпарсився — fallback на наївний `content.includes`.
83
-
84
- ### `checkMegalinter(wfDir, ymlWorkflows, wfDirRel, cwd, passFn, failFn)`
85
-
86
- - **Сигнатура:** `async (wfDir, ymlWorkflows: string[], wfDirRel, cwd, passFn, failFn) => Promise<void>`
87
- - **Повертає:** `Promise<void>`.
88
- - **Side effects:** читає всі `*.yml` у `wfDir`, перевіряє `existsSync` для кореневих конфіг-файлів.
89
- - **Що шукає:**
90
- 1. У вмісті кожного `.yml` workflow — патерни `MEGALINTER_USE_PATTERNS` (`oxsecurity/megalinter-action`, `megalinter/megalinter`).
91
- 2. У корені репо — файли з `MEGALINTER_CONFIG_NAMES` (`.mega-linter.yml`, `.megalinter.yaml`, `.mega-linter.yaml`).
92
- - Знайшов — `fail` з вимогою видалити інтеграцію; не знайшов — один `pass`.
93
-
94
- ### `checkShellcheckInstalled(passFn, failFn)` _(export)_
95
-
96
- - **Сигнатура:** `(passFn, failFn) => void`
97
- - **Повертає:** `void`.
98
- - **Side effects:** `resolveCmd('shellcheck')` (`which`/`where`).
99
- - **Призначення:** `actionlint` (через `bunx github-actionlint`) перевіряє shell-код у `run:` блоках лише коли `shellcheck` доступний; інакше тихо пропускає SC-правила. Локальний `bun lint-ga` міг би бути зеленим, тоді як CI на `ubuntu-latest` (де `shellcheck` передвстановлений) падатиме. Тому відсутність бінарника локально — `fail` з порадами встановлення для macOS/Debian/Ubuntu/Arch.
100
- - **Крос-платформність:** через `resolveCmd` коректно знаходить `shellcheck` і `shellcheck.exe` на Windows.
101
-
102
- ### `checkGaWorkflowFiles(wfDirRel, files, pass, fail)`
103
-
104
- - **Сигнатура:** `(wfDirRel: string, files: string[], pass, fail) => void`
105
- - **Повертає:** `void`.
106
- - **Side effects:** виклики `pass`/`fail`.
107
- - **Перевірки:**
108
- - Файли з розширенням `.yaml` → `fail` (вимога перейменувати на `.yml`); якщо таких немає — один `pass` про відповідність розширень.
109
- - Файли без розширення `.yml` → `fail`.
110
- - Кожен з `REQUIRED_WORKFLOWS` (`clean-ga-workflows.yml`, `clean-merged-branch.yml`, `lint-ga.yml`, `git-ai.yml`) має існувати: є — `pass`, немає — `fail`.
111
-
112
- ### `runAllGaRego(wfDir, ymlWorkflows, cwd, pass, fail)`
113
-
114
- - **Сигнатура:** `async (wfDir: string, ymlWorkflows: string[], cwd: string, pass, fail) => Promise<void>`
115
- - **Повертає:** `Promise<void>`.
116
- - **Side effects:** спавн `conftest` через `runConftestBatch`; читання шаблонів через `loadTemplate`.
117
- - **Логіка:**
118
- 1. **Per-workflow Rego (4 окремих спавни):** для кожного запису в `GA_PER_WORKFLOW_REGO_TARGETS` (4 канонічні workflow), якщо файл існує — підтягує `loadTemplate(concernDir)`, бере `templateData[basename(workflow)]` і викликає `runConftestBatch` з відповідним `policyDirRel`/`namespace`/одним файлом. Кожне порушення → `fail` з префіксом шляху; нуль порушень → один `pass` «відповідає `<namespace>` (rego)».
119
- 2. **Workflow-common батч:** один спавн `conftest` з полісі `ga/workflow_common` на ВСІ `*.yml` у `wfDir`. Шаблон `uses-min-versions.snippet` (якщо є) передається у `templateData`. Порушення → `fail` з префіксом filename; нуль — `pass` про кількість файлів, що відповідають `ga.workflow_common`.
120
- - **Чому 4 окремих спавни, а не один:** namespace ↔ конкретний workflow; інакше правила одного workflow застосуються до неправильного файла.
121
-
122
- ### `check(cwd?)` _(export, точка входу)_
123
-
124
- - **Сигнатура:** `async (cwd?: string) => Promise<number>`
125
- - **Параметри:** `cwd` — корінь репозиторію (за замовчуванням `process.cwd()`).
126
- - **Повертає:** exit code: `0` — все OK, `1` — є порушення (отримується з `reporter.getExitCode()`).
127
- - **Side effects:** створення reporter, читання FS, виклики `git`, спавни `conftest`.
128
- - **Послідовність перевірок:**
129
- 1. Створює `reporter` через `createCheckReporter()`.
130
- 2. Перевіряє наявність директорії `.github/workflows` — якщо немає, негайно `fail` і повертає exit code.
131
- 3. Зчитує `files = readdir(wfDir)`; виокремлює `ymlWorkflows` (`*.yml`).
132
- 4. **Rego-крок** (`runAllGaRego`) — першим, як authoritative source для пер-документних правил.
133
- 5. Наявність `composite action` `.github/actions/setup-bun-deps/action.yml` (його розкочує `npx @nitra/cursor`).
134
- 6. `checkGaWorkflowFiles` — розширення і обовʼязкові workflow.
135
- 7. `checkApplyWorkflow` × 2 — `apply-k8s.yml` (`**/k8s/**/*.yaml`) і `apply-nats-consumer.yml` (`**/consumer.yaml`).
136
- 8. `checkMegalinter` — залишки інтеграції/конфіги.
137
- 9. Для кожного `*.yml` — парсить YAML і викликає `verifyWorkflowEventPathsGlobsExist` (git-залежна перевірка `on.*.paths`).
138
- 10. `checkShellcheckInstalled` — наявність бінарника локально.
139
- 11. Повертає `reporter.getExitCode()`.
140
-
141
- ## Залежності
142
-
143
- ### Node.js core
144
-
145
- - `node:fs` — `existsSync` (синхронна перевірка існування шляхів).
146
- - `node:fs/promises` — `readdir`, `readFile` (асинхронні).
147
- - `node:child_process` — `execFileSync` (для `git ls-files`).
148
- - `node:path` — `basename`, `dirname`, `join`.
149
- - `node:url` — `fileURLToPath` (резолв `import.meta.url` → шлях).
150
-
151
- ### Внутрішні модулі (`@nitra/cursor`)
152
-
153
- - `../../../scripts/lib/check-reporter.mjs` → `createCheckReporter` — фабрика reporter з `pass`/`fail`/`getExitCode`.
154
- - `../../../scripts/lib/gha-workflow.mjs` → `eventPathsIncludeExact`, `parseWorkflowYaml` — YAML-парсер workflow і helper для перевірки точного шляху в `on.<event>.paths`.
155
- - `../../../scripts/utils/resolve-cmd.mjs` → `resolveCmd` — крос-платформний `which`/`where`.
156
- - `../../../scripts/lib/run-conftest-batch.mjs` → `runConftestBatch` — батч-обгортка над `conftest` (hard-fail без `conftest` у PATH).
157
- - `../../../scripts/lib/template.mjs` → `loadTemplate` — підтягує `template.json`-снипети з директорій Rego-полісі.
158
-
159
- ### Зовнішні бінарники (runtime)
160
-
161
- - `git` — для `git ls-files -z -- :(glob)<pattern>`.
162
- - `conftest` — викликається через `runConftestBatch` (hard-fail без нього).
163
- - `shellcheck` — перевіряється на наявність у PATH (інформаційно).
164
-
165
- ### Дані конфігурації
166
-
167
- - `MEGALINTER_USE_PATTERNS` — regexp-патерни для пошуку MegaLinter у workflow.
168
- - `MEGALINTER_CONFIG_NAMES` — імена конфіг-файлів MegaLinter у корені.
169
- - `REQUIRED_WORKFLOWS` — 4 обовʼязкових workflow з ga.mdc.
170
- - `GA_PER_WORKFLOW_REGO_TARGETS` — мапінг `workflow → namespace → policyDirRel` для пер-документного rego.
171
- - `GA_POLICY_DIR` — обчислюється як `dirname(import.meta.url)/../policy` → абсолютний шлях до `npm/rules/ga/policy/`.
172
- - `HERE` — `dirname(fileURLToPath(import.meta.url))` (директорія самого `workflows.mjs`).
173
-
174
- ## Потік виконання / Використання
175
-
176
- ### Виклик з лінт-пайплайну
177
-
178
- Модуль викликається непрямо через CLI `@nitra/cursor` як частина правила ga (роутер у `npm/rules/ga/`). Цільовий репозиторій запускає `bun run lint-ga`, який також виконує `actionlint` і `zizmor` поза цією функцією, але `check()` цього модуля — інтегрована частина того ж run.
179
-
180
- ### Програмний виклик
181
-
182
- ```js
183
- import { check } from '@nitra/cursor/rules/ga/js/workflows.mjs'
184
-
185
- const exitCode = await check(process.cwd())
186
- process.exit(exitCode)
187
- ```
188
-
189
- ### Послідовність на рівні `check()`
190
-
191
- 1. `createCheckReporter()` створює пару колбеків `pass`/`fail` і лічильник exit code.
192
- 2. Перевірка наявності `.github/workflows/` — early return при відсутності.
193
- 3. `readdir` всіх файлів у директорії, фільтрація `*.yml`.
194
- 4. **Rego-фаза:** 4 окремих `conftest` для канонічних workflow + 1 батч `ga.workflow_common` на всі `*.yml`. Усі порушення → `fail` через reporter.
195
- 5. **JS-фаза cross-file:**
196
- - Перевірка `.github/actions/setup-bun-deps/action.yml`.
197
- - Розширення (`yaml→yml`) і набір обовʼязкових workflow.
198
- - `apply-k8s.yml` / `apply-nats-consumer.yml` — точна перевірка `paths` через AST.
199
- - MegaLinter-залишки (workflow + конфіги).
200
- - Кожен workflow → парс YAML → перевірка `on.*.paths` через `git ls-files :(glob)`.
201
- - `shellcheck` у PATH.
202
- 6. Повертає `reporter.getExitCode()` (`0` або `1`).
203
-
204
- ### Інтерпретація результатів
205
-
206
- - Кожен виклик `pass(msg)` додає ОК-рядок у reporter.
207
- - Кожен виклик `fail(msg)` додає помилку і встановлює exit code = 1.
208
- - Звіт виводиться форматтером `check-reporter.mjs` (поза цим модулем).
209
-
210
- ### Розширення модуля
211
-
212
- Нові пер-документні перевірки workflow слід додавати в Rego-полісі (`npm/policy/ga/<concern>/`) — не сюди. Тут — лише ті перевірки, які потребують FS/git/external-tool доступу. Якщо додаєш новий канонічний workflow:
213
-
214
- 1. Додай у `REQUIRED_WORKFLOWS`.
215
- 2. Створи новий пакет у `npm/policy/ga/<name>/` з Rego-правилами.
216
- 3. Зареєструй у `GA_PER_WORKFLOW_REGO_TARGETS` (`workflow`/`namespace`/`policyDirRel`).
217
- 4. За потреби — додай `apply-...` стилю trigger-перевірку через `checkApplyWorkflow`.
5
+ Файл перевіряє GitHub Actions workflows на відповідність певним правилам та стандартам. Він забезпечує консистентність та якість workflow, виявляючи потенційні проблеми, такі як відсутність clean/lint workflow або використання непідтримуваних інструментів. Це частина автоматизованого процесу забезпечення дотримання найкращих практик при розробці GitHub Actions.
6
+
7
+ ## Поведінка
8
+
9
+ - `checkShellcheckInstalled`: Перевіряє наявність бінарника `shellcheck` в системному PATH.
10
+ - `checkGaWorkflowFiles`: Перевіряє наявність workflow-файлів з розширенням `.yml` та відсутність інших розширень.
11
+ - `runAllGaRego`: Запускає Rego-перевірки для всіх workflow-файлів, використовуючи `conftest` для аналізу.
12
+ - `check`: Координує всі перевірки, включаючи Rego-аналіз, перевірку workflow-структури та перевірку наявність файлів.
13
+
14
+ ## Публічний API
15
+
16
+ - checkShellcheckInstalled Перевіряє наявність `shellcheck` у системі та зупиняє workflow, якщо його немає.
17
+ - check Перевіряє відповідність проєкту правилам валідації.
18
+ - runAllGaRego Запускає Rego-перевірку правил, як перший етап валідації.
19
+ - lint-ga — Запускає перевірку `bun lint-ga` з використанням `actionlint` та `zizmor`.
20
+
21
+ ## Гарантії поведінки
22
+
23
+ - Гарантується наявність файлів `package.json`, `.vscode/*` та `.github/zizmor.yml`.
24
+ - Гарантується, що workflow використовує `actions/checkout@v6` перед локальними операціями.
25
+ - Гарантується, що workflow використовує composite action `action.yml` з `npx @nitra/cursor`.
26
+ - Гарантується, що workflow містить `clean-ga-workflows.yml`, `clean-merged-branch.yml`, `lint-ga.yml` та `git-ai.yml`.
27
+ - Гарантується, що workflow використовує `concurrency` для паралельного виконання.
28
+ - Гарантується, що workflow не містить `oven-sh/setup-bun`, `actions/cache`, `bun install` у `uses` або `run`.
29
+ - Гарантується, що workflow не використовує shell-продовження `\` у `run`.
30
+ - Гарантується, що workflow використовує `shellcheck` локально.
31
+ - Гарантується, що workflow перевіряє наявність файлів за допомогою `git ls-files :(glob)` та `on.*.paths`.
32
+ - Гарантується, що workflow перевіряє наявність файлів, що залишилися від MegaLinter.
@@ -1,19 +1,4 @@
1
- /**
2
- * Перевіряє GitHub Actions за правилом ga.mdc.
3
- *
4
- * Workflows лише з розширенням `.yml`, наявність clean/lint workflow,
5
- * відсутність MegaLinter, виклик у `lint-ga.yml`,
6
- * наявність composite `.github/actions/setup-bun-deps/action.yml` (його записує npx `\@nitra/cursor`),
7
- *
8
- * Структурні поля 4 канонічних workflow (`clean-ga-workflows.yml`, `clean-merged-branch.yml`,
9
- * `lint-ga.yml`, `git-ai.yml`) і УНІВЕРСАЛЬНІ перевірки для всіх `.github/workflows/*.yml`
10
- * (`concurrency`, заборонені `oven-sh/setup-bun` / `actions/cache` / `bun install` у `uses`/`run`,
11
- * shell-продовження `\` у `run`, обов'язковий `actions/checkout@v6` перед локальним
12
- * `setup-bun-deps`), а також `package.json`, `.vscode/*` і `.github/zizmor.yml` —
13
- * у Rego-полісі під `npm/policy/ga/`. Тут лишилися FS/git/tooling перевірки:
14
- * наявність файлів, MegaLinter leftovers, `on.*.paths` через `git ls-files :(glob)`,
15
- * і локальний `shellcheck`.
16
- */
1
+ /** @see ./docs/workflows.md */
17
2
  import { existsSync } from 'node:fs'
18
3
  import { readdir, readFile } from 'node:fs/promises'
19
4
  import { execFileSync } from 'node:child_process'