@nitra/cursor 3.27.0 → 3.29.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.
- package/CHANGELOG.md +17 -0
- package/package.json +1 -3
- package/rules/abie/js/applies.mjs +1 -5
- package/rules/abie/js/env_dns.mjs +1 -9
- package/rules/abie/js/firebase_hosting.mjs +1 -5
- package/rules/abie/js/hc_pairing.mjs +1 -8
- package/rules/abie/js/ua_http_route.mjs +1 -10
- package/rules/abie/js/ua_node_selector.mjs +1 -8
- package/rules/adr/js/hooks.mjs +1 -20
- package/rules/bun/js/layout.mjs +1 -19
- package/rules/capacitor/js/platforms.mjs +1 -23
- package/rules/changelog/js/consistency.mjs +1 -29
- package/rules/ci4/js/marksman_config.mjs +1 -19
- package/rules/docker/js/lint.mjs +1 -34
- package/rules/ga/docs/fix.md +4 -4
- package/rules/ga/js/docs/lint.md +3 -3
- package/rules/ga/js/docs/workflows.md +14 -14
- package/rules/ga/js/workflows.mjs +1 -16
- package/rules/ga/lint/docs/lint.md +9 -9
- package/rules/graphql/js/tooling.mjs +1 -9
- package/rules/hasura/js/internal_urls.mjs +1 -24
- package/rules/image-avif/js/avif_generation.mjs +1 -27
- package/rules/image-compress/js/package_setup.mjs +1 -18
- package/rules/js-bun-db/js/safety.mjs +1 -31
- package/rules/js-bun-redis/js/imports.mjs +1 -12
- package/rules/js-lint/js/docs/lint-findings.md +30 -0
- package/rules/js-lint/js/lint-findings.mjs +1 -7
- package/rules/js-lint/js/lint.mjs +1 -10
- package/rules/js-lint/js/tooling.mjs +1 -13
- package/rules/js-lint/js/utils_imports.mjs +1 -18
- package/rules/js-lint-ci/js/lint.mjs +1 -6
- package/rules/js-mssql/js/deps.mjs +1 -10
- package/rules/js-run/js/runtime.mjs +1 -37
- package/rules/js-run/lib/docs/temporal-scan.md +25 -0
- package/rules/k8s/js/manifests.mjs +1 -137
- package/rules/nginx-default-tpl/js/template.mjs +1 -18
- package/rules/npm-module/js/docs/header_doc_pointer.md +25 -0
- package/rules/npm-module/js/header_doc_pointer.mjs +82 -0
- package/rules/npm-module/js/package_structure.mjs +1 -28
- package/rules/npm-module/js/rule_meta.mjs +1 -10
- package/rules/npm-module/js/skill_meta.mjs +1 -13
- package/rules/php/js/tooling.mjs +1 -11
- package/rules/python/js/applies.mjs +1 -8
- package/rules/python/js/tooling.mjs +1 -21
- package/rules/rego/js/applies.mjs +1 -11
- package/rules/rust/js/applies.mjs +1 -7
- package/rules/security/js/sample_secret.mjs +1 -28
- package/rules/security/js/trufflehog.mjs +1 -8
- package/rules/style-lint/js/lint.mjs +1 -5
- package/rules/style-lint/js/tooling.mjs +1 -19
- package/rules/tauri/js/cargo_mutants_config.mjs +1 -20
- package/rules/tauri/js/tooling.mjs +1 -21
- package/rules/test/js/cargo_mutants_config.mjs +1 -12
- package/rules/test/js/location.mjs +1 -9
- package/rules/test/js/no-process-chdir.mjs +1 -21
- package/rules/test/js/no-relative-fs-path.mjs +1 -23
- package/rules/test/js/stryker_config.mjs +4 -25
- package/rules/test/js/vitest-config-pool-forks.mjs +1 -17
- package/rules/text/js/forbidden-prettier.mjs +1 -10
- package/rules/text/js/formatting.mjs +1 -31
- package/rules/vue/js/packages.mjs +1 -24
- package/scripts/coverage-classify/index.mjs +60 -72
- package/scripts/coverage-fix.mjs +26 -23
- package/scripts/dispatcher/lib/subagent-runner.mjs +33 -102
- package/scripts/docs/coverage-fix-extract.md +32 -0
- package/scripts/docs/lint-cli.md +25 -0
- package/scripts/docs/post-tool-use-fix.md +27 -0
- package/scripts/docs/rename-yaml-extensions.md +36 -0
- package/scripts/docs/skills-cli.md +35 -0
- package/scripts/docs/sync-claude-config.md +52 -0
- package/scripts/docs/sync-setup-bun-deps-action.md +26 -0
- package/scripts/docs/upgrade-nitra-cursor-and-install.md +29 -0
- package/scripts/docs/worktree-cli.md +46 -0
- package/scripts/lib/docs/assert-project-root.md +28 -0
- package/scripts/lib/docs/diff-added-lines.md +34 -0
- package/scripts/lib/docs/read-n-cursor-config-lite.md +28 -0
- package/scripts/lib/docs/resolve-target-files.md +34 -0
- package/scripts/lib/docs/root-notice.md +28 -0
- package/scripts/lib/docs/rule-meta-helpers.md +34 -0
- package/scripts/lib/docs/rule-meta.md +34 -0
- package/scripts/lib/docs/rule-predicates.md +30 -0
- package/scripts/lib/docs/run-conftest-batch.md +26 -0
- package/scripts/lib/docs/run-lint-step.md +25 -0
- package/scripts/lib/docs/run-rule-cli.md +27 -0
- package/scripts/lib/docs/run-rule.md +32 -0
- package/scripts/lib/docs/run-standard-lint.md +22 -0
- package/scripts/lib/docs/run-standard-rule.md +24 -0
- package/scripts/lib/docs/skill-meta.md +31 -0
- package/scripts/lib/docs/sync-gitignore-worktree.md +31 -0
- package/scripts/lib/docs/template.md +40 -0
- package/scripts/lib/docs/timing-summary.md +24 -0
- package/scripts/lib/docs/workspaces.md +30 -0
- package/scripts/lib/docs/worktree-notice.md +27 -0
- package/scripts/lib/docs/worktree.md +38 -0
- package/scripts/utils/docs/ast-scan-utils.md +50 -0
- package/scripts/utils/docs/ensure-gitignore-entries.md +28 -0
- package/scripts/utils/docs/find-package-json-paths.md +26 -0
- package/scripts/utils/docs/lock-cache-dir.md +25 -0
- package/scripts/utils/docs/pass.md +25 -0
- package/scripts/utils/docs/resolve-cargo-manifest.md +23 -0
- package/scripts/utils/docs/resolve-cmd.md +29 -0
- package/scripts/utils/docs/resolve-js-root.md +25 -0
- package/scripts/utils/docs/test-helpers.md +36 -0
- package/scripts/utils/docs/walk-cache.md +27 -0
- package/scripts/utils/docs/walkDir.md +32 -0
- package/scripts/utils/docs/with-lock.md +25 -0
- package/scripts/utils/docs/worktree-fingerprint.md +27 -0
- package/skills/docgen/js/docgen-batch.mjs +95 -0
- package/skills/docgen/js/docgen-extract.mjs +33 -18
- package/skills/docgen/js/docgen-gen.mjs +140 -154
- package/skills/docgen/js/docgen-ignore.mjs +1 -6
- package/skills/docgen/js/docgen-prompts.mjs +33 -22
- package/skills/docgen/js/docgen-scan.mjs +1 -8
- package/skills/docgen/js/docs/docgen-extract.md +28 -0
- package/skills/docgen/js/docs/docgen-gen.md +41 -0
- package/skills/docgen/js/docs/docgen-ignore.md +24 -0
- package/skills/docgen/js/docs/docgen-prompts.md +24 -0
- package/skills/docgen/js/docs/docgen-scan.md +48 -0
- package/skills/fix/js/docs/llm-worker.md +27 -0
- package/skills/fix/js/docs/orchestrator.md +32 -0
- package/skills/fix/js/docs/t0.md +29 -0
- package/skills/fix/js/llm-worker.mjs +64 -29
- package/skills/fix/js/orchestrator.mjs +45 -54
- package/skills/fix/js/t0.mjs +16 -32
- package/skills/start-check/js/check.mjs +1 -16
- package/skills/start-check/js/docs/check.md +34 -0
- package/skills/taze/js/diff.mjs +1 -15
- package/skills/taze/js/docs/diff.md +33 -0
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Нормалізація й класифікація lint-findings (oxlint + eslint) на introduced
|
|
3
|
-
* (рядок у diff від HEAD) vs pre-existing (борг файлу) — беклог #6, варіант A.
|
|
4
|
-
*
|
|
5
|
-
* Формати: oxlint `--format=json` → `{ diagnostics:[{ filename, code, labels:[{span:{line}}] }] }`;
|
|
6
|
-
* eslint `--format=json` → `[{ filePath, messages:[{ ruleId, line, message }] }]`. Шляхи абсолютні.
|
|
7
|
-
*/
|
|
1
|
+
/** @see ./docs/lint-findings.md */
|
|
8
2
|
import { isAbsolute, relative } from 'node:path'
|
|
9
3
|
|
|
10
4
|
import { isIntroducedLine } from '../../../scripts/lib/diff-added-lines.mjs'
|
|
@@ -1,13 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Quick-крок lint правила js-lint: oxlint + eslint (з автофіксом).
|
|
3
|
-
*
|
|
4
|
-
* Викликається lint-оркестратором (`n-cursor lint` / `lint-ci`):
|
|
5
|
-
* - `files` = масив змінених файлів (quick) → лінтимо лише js-подібні з них і
|
|
6
|
-
* КЛАСИФІКУЄМО лишені findings на introduced (рядок у diff від HEAD) vs
|
|
7
|
-
* pre-existing (борг файлу) — беклог #6, варіант A (видимість; блокування без змін);
|
|
8
|
-
* - `files` = undefined (ci) → лінтимо весь проєкт (стрімінг, без класифікації).
|
|
9
|
-
* Крос-файлові jscpd/knip — окреме правило js-lint-ci (фаза ci).
|
|
10
|
-
*/
|
|
1
|
+
/** @see ./docs/lint.md */
|
|
11
2
|
import { spawnSync } from 'node:child_process'
|
|
12
3
|
|
|
13
4
|
import { addedLinesByFile } from '../../../scripts/lib/diff-added-lines.mjs'
|
|
@@ -1,16 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Перевіряє лінт JavaScript за правилом js-lint.mdc.
|
|
3
|
-
*
|
|
4
|
-
* Flat ESLint з getConfig і ignore для auto-imports,
|
|
5
|
-
* `.oxlintrc.json` має збігатися з каноном oxlint у пакеті (`npm/rules/js-lint/js/data/tooling/oxlint-canonical.json`):
|
|
6
|
-
* plugins, jsPlugins, categories, усі правила з канону (додаткові записи в `rules` дозволені), settings, env,
|
|
7
|
-
* globals, ignorePatterns. Також перевіряє workspace `package.json` на `type: "module"`
|
|
8
|
-
* і `engines`, workflow-дубль у `lint.yml`, `knip.json` autofill і застарілі `.eslintrc*`.
|
|
9
|
-
*
|
|
10
|
-
* Per-document вимоги (`lint-js`, `@nitra/eslint-config`, root `engines`, `.jscpd.json`,
|
|
11
|
-
* `.vscode/extensions.json`, `lint-js.yml`) — у policy-пакетах `js_lint.*`.
|
|
12
|
-
* @param {string} cwd корінь репозиторію
|
|
13
|
-
*/
|
|
1
|
+
/** @see ./docs/tooling.md */
|
|
14
2
|
import { existsSync } from 'node:fs'
|
|
15
3
|
import { copyFile, readFile } from 'node:fs/promises'
|
|
16
4
|
import { dirname, join } from 'node:path'
|
|
@@ -1,21 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Перевіряє, що файли всередині будь-якого `utils/` каталогу не мають імпортів за межі
|
|
3
|
-
* самого каталогу (relative-import з `..`). За правилом `js-lint.mdc` каталог `utils/` — це
|
|
4
|
-
* generic helpers без бізнес-логіки і без залежностей від домену; якщо файлу потрібен
|
|
5
|
-
* сусідній модуль, конфіг проєкту чи cross-rule helper — він має жити в `lib/`, а не в `utils/`.
|
|
6
|
-
*
|
|
7
|
-
* Перевіряються лише не-тестові `.mjs|.mts|.cjs|.cts|.js|.ts|.jsx|.tsx` під будь-яким
|
|
8
|
-
* `utils/`-каталогом у monorepo-воркспейсах. Файли всередині `utils/tests/` (тести)
|
|
9
|
-
* і будь-які `__fixtures__/` ігноруються — тести легально імпортують свій модуль через `../X`.
|
|
10
|
-
*
|
|
11
|
-
* Дозволені імпорти:
|
|
12
|
-
* - `./X`, `./sub/X` — same-dir чи глибше всередині самої `utils/`
|
|
13
|
-
* - bare-package (`oxc-parser`, `@scope/pkg`) — npm-залежність
|
|
14
|
-
* - `node:fs`, `fs` тощо — Node-builtin
|
|
15
|
-
*
|
|
16
|
-
* Заборонено:
|
|
17
|
-
* - будь-який `..`-шлях (`../X`, `../../X`) — це порушення granular `utils/`-кордону
|
|
18
|
-
*/
|
|
1
|
+
/** @see ./docs/utils_imports.md */
|
|
19
2
|
import { readdir, readFile } from 'node:fs/promises'
|
|
20
3
|
import { join, relative, sep } from 'node:path'
|
|
21
4
|
|
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Ci-крок: jscpd (детектор клонів) + knip (невикористані експорти).
|
|
3
|
-
*
|
|
4
|
-
* Крос-файлові аналізатори — працюють лише по всьому репо, тож `files` ігнорується
|
|
5
|
-
* (викликається лише у `lint-ci` з undefined). Per-file режиму ці інструменти не мають.
|
|
6
|
-
*/
|
|
1
|
+
/** @see ./docs/lint.md */
|
|
7
2
|
import { spawnSync } from 'node:child_process'
|
|
8
3
|
|
|
9
4
|
/**
|
|
@@ -1,13 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Перевіряє правило js-mssql.mdc.
|
|
3
|
-
*
|
|
4
|
-
* Якщо в будь-якому `package.json` у репозиторії (включно з workspace-пакетами) в секції `dependencies`
|
|
5
|
-
* присутній пакет `mssql`, його версія має бути не менше 12.5.0.
|
|
6
|
-
*
|
|
7
|
-
* Додатково, якщо `mssql` використовується в репозиторії, перевіряє що підключення
|
|
8
|
-
* не створюється “на кожен запит”: `new sql.ConnectionPool(...)` не має знаходитись
|
|
9
|
-
* всередині функцій. Пул має бути singleton (на рівні модуля) і повторно використовуватись.
|
|
10
|
-
*/
|
|
1
|
+
/** @see ./docs/deps.md */
|
|
11
2
|
import { existsSync } from 'node:fs'
|
|
12
3
|
import { readFile } from 'node:fs/promises'
|
|
13
4
|
import { join, relative } from 'node:path'
|
|
@@ -1,40 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Для кожного workspace-пакета перевіряє правило js-run.mdc.
|
|
3
|
-
*
|
|
4
|
-
* Покрито:
|
|
5
|
-
* - заборона `@nitra/bunyan` / `bunyan` як у залежностях `package.json`, так і в коді
|
|
6
|
-
* (`import` / `require` / динамічний `import()`); імпорти сканує AST через `oxc-parser`
|
|
7
|
-
* (див. `utils/bunyan-imports.mjs`);
|
|
8
|
-
* - наявність `OTEL_RESOURCE_ATTRIBUTES` зі значеннями `service.name=` та `service.namespace=`
|
|
9
|
-
* у `k8s/base/configmap.yaml`, якщо такий файл існує (відповідність імені ConfigMap імені
|
|
10
|
-
* Deployment перевіряється в `rules/k8s/fix.mjs`);
|
|
11
|
-
* - «Внутрішні аліаси» (`#conn/*`): імпорти `bun#SQL`, будь-який `mssql`, `@nitra/graphql-request#GraphQLClient`
|
|
12
|
-
* дозволені лише у каталозі conn (за замовчуванням `src/conn/`; за наявності
|
|
13
|
-
* `package.json#imports['#conn/*']` — у його цільовому каталозі); поза ним — порушення
|
|
14
|
-
* (див. `utils/conn-imports-scan.mjs`);
|
|
15
|
-
* - «Нейминг та експорти у `#conn/`»: всередині conn-каталогу basename файла має відповідати
|
|
16
|
-
* канону `ql-<id>` / `(pg|mysql|mssql)-(read|write)[-<id>]`; `export default` заборонений; має бути
|
|
17
|
-
* іменований експорт з імʼям, що дорівнює camelCase від basename файла (`pg-write-contract.js`
|
|
18
|
-
* → `export const pgWriteContract`); `index.*` як reexport-барель пропускаємо
|
|
19
|
-
* (див. `utils/conn-file-rules.mjs`);
|
|
20
|
-
* - «process.env / CheckEnv»: пряме `process.env.X` має бути замінено на `env` —
|
|
21
|
-
* з `@nitra/check-env` (для обов'язкових змінних, із `checkEnv([...])`) або з
|
|
22
|
-
* `node:process` (для опційних). Коли `env` імпортовано з `@nitra/check-env`,
|
|
23
|
-
* кожен `env.X` має бути закритий літеральним викликом `checkEnv(['X', ...])`
|
|
24
|
-
* у тому ж файлі або коментарем `// \@nitra/cursor ignore-next-line checkEnv`
|
|
25
|
-
* на попередньому рядку (див. `utils/check-env-scan.mjs`);
|
|
26
|
-
* - «Паузи через setTimeout»: `new Promise(resolve => setTimeout(resolve, ms))` (з/без `await`)
|
|
27
|
-
* треба замінити на `await setTimeout(ms)` з `node:timers/promises`
|
|
28
|
-
* (див. `utils/promise-settimeout-scan.mjs`);
|
|
29
|
-
* - «Temporal у Bun runtime»: identifier `Temporal` заборонений, бо поточний Bun runtime
|
|
30
|
-
* не має глобального Temporal API (див. `utils/temporal-scan.mjs`);
|
|
31
|
-
* - «jsconfig.json»: у backend-пакеті з каталогом `src/` у корені має бути `jsconfig.json`,
|
|
32
|
-
* вміст якого збігається з каноном js-run.mdc (NodeNext і include на дерево `src`).
|
|
33
|
-
*
|
|
34
|
-
* Per-document валідація `package.json` (bunyan, `node` у `scripts`) делегована rego-пакету
|
|
35
|
-
* `js_run.package_json` у `npm/rules/js-run/policy/package_json/`; JS — cross-file (AST, FS).
|
|
36
|
-
* @param {string} cwd корінь репозиторію
|
|
37
|
-
*/
|
|
1
|
+
/** @see ./docs/runtime.md */
|
|
38
2
|
import { existsSync, statSync } from 'node:fs'
|
|
39
3
|
import { readFile } from 'node:fs/promises'
|
|
40
4
|
import { join, relative } from 'node:path'
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# temporal-scan.mjs
|
|
2
|
+
|
|
3
|
+
## Огляд
|
|
4
|
+
|
|
5
|
+
Цей файл є частиною системи, яка сканує код Bun workspace на наявність використання ключового слова `Temporal`. Він запобігає використанню `Temporal` у backend-коді, оскільки Bun 1.3.x ще не має глобального `Temporal`, та охоплює сценарії з імпортом та polyfill. Це забезпечує відповідність коду поточним вимогам Bun runtime щодо обробки часу.
|
|
6
|
+
|
|
7
|
+
## Поведінка
|
|
8
|
+
|
|
9
|
+
Знаходить використання identifier `Temporal` у тексті. Повертає список рядків та фрагментів коду, де зустрічається `Temporal`.
|
|
10
|
+
Чи сканувати файл за розширенням (JS/TS-сім'я, виключно з `.d.ts`). Повертає `true`, якщо файл має відповідне розширення, і не є файлом `.d.ts`.
|
|
11
|
+
|
|
12
|
+
## Публічний API
|
|
13
|
+
|
|
14
|
+
- findTemporalUsageInText — Знаходить згадки про `Temporal` у тексті.
|
|
15
|
+
- isTemporalScanSourceFile — Визначає, чи потрібно сканувати файл за розширенням (JavaScript/TypeScript або `.d.ts`).
|
|
16
|
+
|
|
17
|
+
## Гарантії поведінки
|
|
18
|
+
|
|
19
|
+
- Функція `findTemporalUsageInText` повертає `true` лише якщо знайде identifier `Temporal` у наданому тексті.
|
|
20
|
+
- Функція `findTemporalUsageInText` повертає `false` якщо identifier `Temporal` не знайдено.
|
|
21
|
+
- Функція `isTemporalScanSourceFile` повертає `true` якщо у файлі є identifier `Temporal`.
|
|
22
|
+
- Функція `isTemporalScanSourceFile` повертає `false` якщо у файлі немає identifier `Temporal`.
|
|
23
|
+
- Результат роботи `findTemporalUsageInText` не гарантує, що identifier `Temporal` використовується правильно.
|
|
24
|
+
- Результат роботи `isTemporalScanSourceFile` не гарантує, що використання `Temporal` є допустимим.
|
|
25
|
+
- Кеш не використовується.
|
|
@@ -1,140 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Перевіряє Kubernetes YAML у шляхах з сегментом `k8s` (див. k8s.mdc).
|
|
3
|
-
*
|
|
4
|
-
* Перший рядок `# yaml-language-server: $schema=…` (URL за `https://`), без дублікатів, розширення `.yaml`
|
|
5
|
-
* (окрім `kustomization.yaml`); URL схеми за першим документом — kustomization / yannh / datree
|
|
6
|
-
* (**виняток:** `apiVersion: alb.yc.io/v1alpha1`, `kind: HttpBackendGroup` — рядка `# yaml-language-server:` у файлі бути не має).
|
|
7
|
-
* (datree за замовчуванням: GitHub Pages `https://datreeio.github.io/CRDs-catalog/…`).
|
|
8
|
-
*
|
|
9
|
-
* Modeline **опційний**: якщо публічної схеми немає (yannh/datree/schemastore не покривають це поєднання
|
|
10
|
-
* apiVersion/kind), залиш файл **без** рядка `# yaml-language-server: $schema=…` — `check-k8s` пропустить
|
|
11
|
-
* перевірку URL. **Заборонено** ставити `$schema=file:…` як заглушку (це фальшива валідація). Якщо modeline
|
|
12
|
-
* присутній, він має бути **першим рядком** і містити `https://` URL, що відповідає очікуваному за apiVersion/kind.
|
|
13
|
-
*
|
|
14
|
-
* Додатково: у кожному YAML-документі з **`kind: Deployment`** у кожного контейнера
|
|
15
|
-
* **`spec.template.spec.containers[]`** має бути **`resources.requests.cpu`** і **`resources.requests.memory`**
|
|
16
|
-
* (непорожні скаляри). У шарі **`…/k8s/…/base/…`** значення жорстко **`cpu: '0.02'`**, **`memory: '128Mi'`**
|
|
17
|
-
* (для **cpu** допускається число **`0.02`**). Поза base, якщо ще не підібрано власні
|
|
18
|
-
* ліміти — орієнтир **`DEFAULT_CONTAINER_CPU_REQUEST`** = **`"0.5"`**, **`DEFAULT_CONTAINER_MEMORY_REQUEST`**
|
|
19
|
-
* = **`"512Mi"`**. Поле **`imagePullPolicy`**
|
|
20
|
-
* не перевіряється — діють типові правила Kubernetes (`:latest` або коли тег не вказано → **Always**,
|
|
21
|
-
* інші теги → **IfNotPresent**). Якщо серед **`containers`** / **`initContainers`** є образ
|
|
22
|
-
* **`hasura/graphql-engine`**, дозволено лише канонічний тег зі списку `allowed_hasura_images`
|
|
23
|
-
* у rego-пакеті `k8s.manifest` (`policy/manifest/manifest.rego`) — пер-документна перевірка делегована rego.
|
|
24
|
-
*
|
|
25
|
-
* **Namespace і Kustomize:** YAML у **`…/k8s/base/`** (окрім імені **`kustomization.yaml`**)
|
|
26
|
-
* завжди має **непорожній** **`metadata.namespace`** у відповідних документах (узгоджено з dev у репозиторії),
|
|
27
|
-
* навіть якщо **`namespace:`** заданий у **`base/kustomization.yaml`**.
|
|
28
|
-
* Поза **`k8s/base`**: для файлів, досяжних з kustomization через **`resources`**, **`bases`**, **`components`**,
|
|
29
|
-
* **`crds`**, **`patches[].path`**, **`patchesStrategicMerge`**, **`metadata.namespace`** у маніфесті **не** додають;
|
|
30
|
-
* файли **поза** цим графом — **непорожній** **`metadata.namespace`** (крім **кластерних** kind; див. k8s.mdc).
|
|
31
|
-
*
|
|
32
|
-
* **`kind: Ingress`** заборонено (потрібен перехід на Gateway API).
|
|
33
|
-
* **`apiVersion: autoscaling/v1`** заборонено (мігруй **HorizontalPodAutoscaler** на **`autoscaling/v2`**).
|
|
34
|
-
* Рядок **`apiVersion: batch/v1beta1`** (CronJob, Job) **автоматично** переписується на **`apiVersion: batch/v1`**
|
|
35
|
-
* (окрім рядків-коментарів і рядків, де після значення йде наприклад `# …`).
|
|
36
|
-
*
|
|
37
|
-
* Файли під **`k8s`**, де всі YAML-документи — лише **`kind: BackendConfig`**, **видаляються** автоматично.
|
|
38
|
-
* Якщо **BackendConfig** змішано з іншими ресурсами в одному файлі — перевірка завершується помилкою (розділи маніфести).
|
|
39
|
-
*
|
|
40
|
-
* У **`kind: Service`** у **`metadata.annotations`** не повинно бути ключів **`cloud.google.com/neg`**
|
|
41
|
-
* та **`cloud.google.com/backend-config`** (див. k8s.mdc).
|
|
42
|
-
*
|
|
43
|
-
* Файли **`svc.yaml`** / **`svc-hl.yaml`** у **одному каталозі** (див. k8s.mdc): для кожного **`svc.yaml`**
|
|
44
|
-
* поруч обов’язковий **`svc-hl.yaml`** (headless-копія: той самий селектор/порти, **`metadata.name`** з суфіксом **`-hl`**,
|
|
45
|
-
* **`spec.clusterIP: None`**). У **`svc.yaml`** кожен **Service** має **`spec.type: ClusterIP`**. У **`svc-hl.yaml`**
|
|
46
|
-
* кожен **Service** — **`spec.clusterIP: None`** та ім’я на **`-hl`**. У маршрутах **Gateway API**
|
|
47
|
-
* (**`HTTPRoute`**, **`GRPCRoute`**, **`TCPRoute`**, **`TLSRoute`**, **`UDPRoute`**, група **`gateway.networking.k8s.io`**)
|
|
48
|
-
* посилання **`backendRefs` / `backendRef`** на **Service** мають вказувати лише сервіси з суфіксом **`-hl`** у **`name`**.
|
|
49
|
-
* Поле **`namespace`** у **`backendRef`**, що збігається з **`metadata.namespace`** самого маршруту, — надлишкове:
|
|
50
|
-
* прибери його, бо за замовчуванням Gateway API визначає backend у тому ж namespace, що й маршрут (див. k8s.mdc).
|
|
51
|
-
* **HealthCheckPolicy** (**`networking.gke.io/v1`**, GKE): **`spec.targetRef`** на **Service** — **`name`** з суфіксом **`-hl`** (див. k8s.mdc).
|
|
52
|
-
* Якщо **`kustomization.yaml`** посилається на **`svc.yaml`** (**`resources`**, **`bases`**, **`components`**, **`crds`**,
|
|
53
|
-
* **`patches[].path`**, **`patchesStrategicMerge`**), у **тому ж** файлі має бути посилання на відповідний **`svc-hl.yaml`**
|
|
54
|
-
* в **тому ж каталозі**, що й **`svc.yaml`** (логіка збігається з **`pathsFromKustomizationObject`**).
|
|
55
|
-
*
|
|
56
|
-
* Структура **Kustomize** (див. k8s.mdc): заборона шляхів **`…/k8s/dev/…`**; у **`k8s/base/kustomization.yaml`**
|
|
57
|
-
* завжди має бути непорожнє поле **`namespace:`** (перевірка, якщо файл існує). У **`apiVersion: kustomize.config.k8s.io/…`**, **`kind: Kustomization`**
|
|
58
|
-
* перелік **`resources:`** (лише непорожні рядки) має бути відсортовано за алфавітом (**en**, `localeCompare`).
|
|
59
|
-
*
|
|
60
|
-
* **Структурний сорт `patches[]` у kustomization.yaml:** масив **`patches`** має бути відсортовано за tuple
|
|
61
|
-
* **`[target.kind, target.name, target.namespace, path]`** (`localeCompare('en', base)`). Поля **`group`** / **`version`**
|
|
62
|
-
* у tuple не входять — для них діє правило «patches[].target: лише kind і name». Додатково: вміст
|
|
63
|
-
* **inline `patches[i].patch`** (literal block scalar — масив JSON6902-операцій) має бути відсортовано за **`path`**,
|
|
64
|
-
* але **лише** якщо всі операції — **`add`** / **`replace`** і всі **`path`** попарно дизʼюнктні (жоден не префікс іншого).
|
|
65
|
-
* Інакше порядок не чіпається — `move` / `copy` / `test` / `remove` чи спільні шляхи можуть бути семантично залежні (RFC 6902).
|
|
66
|
-
*
|
|
67
|
-
* **Inline JSON6902** у **`patches`** (і зовнішні файли з **`patches[].path`** під **`k8s`**, якщо вміст — масив JSON Patch): не допускається пара **`remove`** і **`add`**
|
|
68
|
-
* на один і той самий **`path`** у межах одного фрагмента — потрібен **`op: replace`** (k8s.mdc). **check-k8s** це перевіряє.
|
|
69
|
-
*
|
|
70
|
-
* **Мішень patch:** у **`patches[].target`** і **`patchesJson6902[].target`** (без **labelSelector** / **annotationSelector**)
|
|
71
|
-
* має існувати відповідний ресурс у зібраному з **`resources`**, **`bases`**, **`components`**, **`crds`** каталозі (рекурсивно для підкаталогів з **`kustomization.yaml`**).
|
|
72
|
-
* Для **`patchesStrategicMerge`** і для **`patches[].path`** без **`target`** і без inline **`patch`** (зовнішній strategic-merge)
|
|
73
|
-
* кожен YAML-документ з кореневим **`kind`** і **`metadata.name`** також звіряється з цим каталогом.
|
|
74
|
-
*
|
|
75
|
-
* **Зайві `group` / `version` у `patches[].target` / `patchesJson6902[].target`:** якщо в інвентарі **`resources`** /
|
|
76
|
-
* **`bases`** / **`components`** / **`crds`** (рекурсивно) за **`kind`** + **`name`** немає колізії між різними
|
|
77
|
-
* API-групами/версіями, поля **`group`** і **`version`** у **`target`** треба прибрати — Kustomize визначає ціль
|
|
78
|
-
* за **GVK + name**, а зайві поля ламаються мовчки під час змін API (k8s.mdc «patches[].target: лише kind і name»).
|
|
79
|
-
*
|
|
80
|
-
* Явні винятки до загальної логіки yannh/datree — таблиця **`EXPLICIT_K8S_SCHEMAS`** (`Map`): ключ
|
|
81
|
-
* **`apiVersion`, `kind`, `type`** (для CRD без поля `type` у маніфесті — зірочка **`*`** як третій
|
|
82
|
-
* компонент). Спочатку шукається збіг за фактичним `type`, потім за **`*`**.
|
|
83
|
-
* Dockerfile — правило docker.mdc, скрипт rules/docker/fix.mjs.
|
|
84
|
-
*
|
|
85
|
-
* **Структура `HTTPRoute` для Hasura-Deployment:** звіряється канон 4 правил у **`spec.rules`** (редиректи **`<prefix>/ql`** і **`<prefix>/ql/`** на **`<prefix>/ql/console`** 302, **`PathPrefix <prefix>/ql`** + **URLRewrite** на **`/`**, окреме WebSocket-правило з **`RequestHeaderModifier`** remove **`Authorization`**). **Префікс параметризовано** (рядок перед **`/ql`** у першому Hasura-правилі). **Прив'язка** — за **`metadata.name`** у тому ж каталозі, що й **Deployment** з образом **`hasura/graphql-engine`** (див. k8s.mdc). **Додаткові правила** поверх канону дозволені.
|
|
86
|
-
*
|
|
87
|
-
* **ConfigMap для Hasura-Deployment:** якщо в `k8s/base/` є `configmap.yaml` і поруч Deployment з образом
|
|
88
|
-
* **`hasura/graphql-engine`**, то в `data` ConfigMap обов'язково має бути ключ
|
|
89
|
-
* **`HASURA_GRAPHQL_ENABLE_REMOTE_SCHEMA_PERMISSIONS`** зі значенням **`"true"`** (приймається булеве `true`
|
|
90
|
-
* або рядок `"true"`, без регістрової залежності).
|
|
91
|
-
*
|
|
92
|
-
* **HPA / PDB / topologySpreadConstraints:** для кожного **`Deployment`** у шарі **`…/k8s/…/base/`**
|
|
93
|
-
* (будь-який `.yaml` у цьому каталозі) обов'язкові канонічні **topologySpreadConstraints**, а HPA і PDB
|
|
94
|
-
* живуть у sibling каталозі **`…/k8s/…/components/`** (Kustomize Component, фіксована назва каталогу `components`). У `base/`
|
|
95
|
-
* заборонено тримати локальні `hpa.yaml` і `pdb.yaml` (file-existence error) і також у дереві
|
|
96
|
-
* base-kustomize не повинно бути HPA/PDB через `resources` / `components` / `bases`.
|
|
97
|
-
* **NetworkPolicy:** для кожного **`Deployment`**, **`StatefulSet`**, **`DaemonSet`**, **`Job`**, **`CronJob`** під `k8s`
|
|
98
|
-
* обов'язковий канонічний NetworkPolicy у `networkpolicy.yaml` поруч з workload-маніфестом — у base
|
|
99
|
-
* (`base/networkpolicy.yaml`, підключений через `base/kustomization.yaml` `resources:` — обмеження діють і на dev)
|
|
100
|
-
* і у не-base overlay (опційно — overlay-specific override).
|
|
101
|
-
* Egress: kube-dns; **TCP 80/443** на `0.0.0.0/0`; інші порти — `namespaceSelector: {}` (in-cluster / `*.svc`). Заборонено `egress: [{}]`.
|
|
102
|
-
* Відсутні документи **`check k8s`** створює автоматично (multi-doc у одному файлі, якщо workload-ів кілька).
|
|
103
|
-
* Структура `components/`: `kustomization.yaml` з `apiVersion: kustomize.config.k8s.io/v1alpha1`, `kind: Component`,
|
|
104
|
-
* `resources` що містять `hpa.yaml` і `pdb.yaml`, `hpa.yaml` (валідний `autoscaling/v2`
|
|
105
|
-
* HorizontalPodAutoscaler з `scaleTargetRef.name` = ім'я Deployment, dev-like `min=max=1`), `pdb.yaml` (валідний
|
|
106
|
-
* `policy/v1` PodDisruptionBudget з `selector.matchLabels.app` = мітка `app` Deployment, dev-like `minAvailable=0`).
|
|
107
|
-
* Overlays (`ua/`, прод-overlays) підключають `components: [- ../components]` і додають JSON6902-патчі для
|
|
108
|
-
* прод-значень: `/spec/minReplicas`, `/spec/maxReplicas` (HPA), `/spec/minAvailable` (PDB). HPA поруч із Deployment
|
|
109
|
-
* у не-base оверлеях — як раніше (див. k8s.mdc).
|
|
110
|
-
* Env-залежні межі за сегментом після `/k8s/`: **dev-like** (`base`, `dev`, `*-qa`) — для HPA, що лишився після
|
|
111
|
-
* збірки, `minReplicas === 1`, `maxReplicas === 1`, PDB `minAvailable === 0`; **прод** — `minReplicas >= 2`,
|
|
112
|
-
* `maxReplicas >= 2`, `minAvailable >= 1`.
|
|
113
|
-
*
|
|
114
|
-
* **Прод-оверрайди в kustomization.yaml:** для прод overlays (не dev-like) у `patches[]` потрібні перевизначення
|
|
115
|
-
* **`/spec/minReplicas`** і **`/spec/maxReplicas`** для **HorizontalPodAutoscaler** і **`/spec/minAvailable`** для
|
|
116
|
-
* **PDB** — якщо overlay-tree (через `resources` / `components`) містить HPA / PDB (тобто overlay підключив
|
|
117
|
-
* `…/k8s/…/components/`). Формат patch — JSON6902 або Strategic Merge; наявність шляхів —
|
|
118
|
-
* `kustomizationPatchPathsByTargetKind`.
|
|
119
|
-
*
|
|
120
|
-
* **Існування шляхів у `kustomization.yaml`:** кожне локальне посилання (без `://`) з `resources` / `bases` /
|
|
121
|
-
* `components` / `crds`, `patchesStrategicMerge`, `patches[].path`, `patchesJson6902[].path`, `configurations[]`,
|
|
122
|
-
* `replacements[].path` має вказувати на наявний у репозиторії файл (`.yaml` / `.yml`) або каталог; інакше
|
|
123
|
-
* помилка `check k8s` (k8s.mdc).
|
|
124
|
-
*
|
|
125
|
-
* **Images у Kustomize — `images:`, не patch:** для кожного `kustomization.yaml` автоматично:
|
|
126
|
-
* (а) конвертує JSON6902 `op: replace` на `/spec/template/spec/containers/<N>/image` (target `kind: Deployment`) у
|
|
127
|
-
* запис **`images:`** — `name` береться з оригінального `image:` у base (без тегу), `newName` — з patch.value (без тегу),
|
|
128
|
-
* `newTag` — лише якщо тег у patch.value відрізняється від тега в base; якщо `patches[]` після цього порожній — ключ
|
|
129
|
-
* прибирається; (б) чистить існуючий блок **`images:`** — зрізає `:tag` з `name` (digest `@…` не чіпає) і видаляє
|
|
130
|
-
* `newTag`, який збігається з відрізаним тегом.
|
|
131
|
-
*
|
|
132
|
-
* **HPA / PDB заборонені у base-дереві Kustomize:** у дереві з `…/k8s/…/base/kustomization.yaml` не дозволяти
|
|
133
|
-
* `HorizontalPodAutoscaler` / `PodDisruptionBudget` у `resources` / `bases` / `components` / `crds` (рекурсивно)
|
|
134
|
-
* взагалі. Канон — HPA/PDB у sibling `…/k8s/…/components/` (Kustomize Component) і підключаються лише з overlay.
|
|
135
|
-
* У `kustomization.yaml` overlay, який підключає каталог `…/k8s/…/base`, не додавай окремі YAML-файли з HPA / PDB,
|
|
136
|
-
* поки в наслідуваному `base` у дереві не з'явиться такий Deployment (k8s.mdc).
|
|
137
|
-
*/
|
|
1
|
+
/** @see ./docs/manifests.md */
|
|
138
2
|
import { existsSync, readFileSync } from 'node:fs'
|
|
139
3
|
import { readFile, readdir, stat, unlink, writeFile } from 'node:fs/promises'
|
|
140
4
|
import { basename, dirname, join, relative, resolve } from 'node:path'
|
|
@@ -1,21 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Перевіряє nginx-шаблон і супутні файли за правилом nginx-default-tpl.mdc.
|
|
3
|
-
*
|
|
4
|
-
* Якщо в дереві є **default.conf.template**: канонічні директиви (порт 8080, /healthz, gzip_static,
|
|
5
|
-
* без proxy), поруч **\*.ini** (ключі з ini мають зустрічатися в шаблоні як **$KEY**), у будь-якому
|
|
6
|
-
* Dockerfile — **find** + **gzip** для каталогу `/usr/share/nginx/html` та **envsubst** з
|
|
7
|
-
* **default.conf.template**. Приклад **HTTPRoute** з правила — для рев’ю; автоматична перевірка
|
|
8
|
-
* вимкнена (різні схеми маршрутизації). Функція **`httpRouteMatchesNginxDefaultTpl`** лишається для
|
|
9
|
-
* тестів і майбутнього вузького застосування. VSCode: **extensions.json** та **settings.json** з
|
|
10
|
-
* форматером nginx і **formatOnSave**.
|
|
11
|
-
*
|
|
12
|
-
* У дереві від **cwd** усі **default.tpl.conf** стають **default.conf.template**: перейменування, або
|
|
13
|
-
* якщо **default.conf.template** уже є — він перезаписується вмістом **default.tpl.conf**, після чого
|
|
14
|
-
* **default.tpl.conf** видаляється. Якщо після міграції шаблону немає — перевірка пропускається (0).
|
|
15
|
-
*
|
|
16
|
-
* Невалідна директива **`error_log off;`** (nginx трактує "off" як ім'я файлу `/etc/nginx/off` і падає під
|
|
17
|
-
* readOnlyRootFilesystem) автоматично замінюється на **`error_log /dev/null crit;`** у кожному шаблоні.
|
|
18
|
-
*/
|
|
1
|
+
/** @see ./docs/template.md */
|
|
19
2
|
import { existsSync } from 'node:fs'
|
|
20
3
|
import { readdir, readFile, rename, unlink, writeFile } from 'node:fs/promises'
|
|
21
4
|
import { basename, dirname, join, relative } from 'node:path'
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# header_doc_pointer.mjs
|
|
2
|
+
|
|
3
|
+
## Огляд
|
|
4
|
+
|
|
5
|
+
Концерн правила `npm-module`, що закріплює контракт між `docs/<stem>.md` і module-level JSDoc у скриптах правил і скілів. Якщо файл вже описано у `docs/<stem>.md` — наратив у заголовному коментарі файлу є дублюванням і заборонений. Якщо `docs` немає — header залишається єдиним джерелом опису поведінки і жодних обмежень немає.
|
|
6
|
+
|
|
7
|
+
## Поведінка
|
|
8
|
+
|
|
9
|
+
1. Сканує всі `.mjs`-файли (крім `.test.mjs`) у `npm/rules/*/js/` та `npm/skills/*/js/`.
|
|
10
|
+
2. Для кожного файлу перевіряє наявність `docs/<stem>.md` поруч із `js/`.
|
|
11
|
+
3. Якщо `docs/<stem>.md` **відсутній** — пропускає файл: перевірка не застосовується.
|
|
12
|
+
4. Якщо `docs/<stem>.md` **присутній** — знаходить module-level JSDoc (перший `/** ... */` до першого `import`/`export` на початку рядка).
|
|
13
|
+
5. Рахує непорожні змістовні рядки блоку (після зрізання відступу `*`). Більше одного → порушення.
|
|
14
|
+
|
|
15
|
+
Допустимі форми при наявних docs:
|
|
16
|
+
- відсутній module-level JSDoc (0 рядків)
|
|
17
|
+
- `/** @see ./docs/<stem>.md */` (1 рядок)
|
|
18
|
+
- `/** Контракт: ./docs/<stem>.md */` (1 рядок)
|
|
19
|
+
|
|
20
|
+
## Гарантії поведінки
|
|
21
|
+
|
|
22
|
+
- Файли без `docs/`-відповідника повністю ігноруються — перевірка не створює обмежень до того, як docgen запишеться.
|
|
23
|
+
- Якщо у файлі немає жодного module-level JSDoc — перевірка проходить.
|
|
24
|
+
- Тестові файли (`*.test.mjs`) не скануються.
|
|
25
|
+
- Підкаталоги `tests/`, `data/`, `templates/` у `js/` не скануються (discovery бере лише `*.mjs` безпосередньо в `js/`, не рекурсивно).
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/** Контракт: ./docs/header_doc_pointer.md */
|
|
2
|
+
import { existsSync } from 'node:fs'
|
|
3
|
+
import { readFile, readdir } from 'node:fs/promises'
|
|
4
|
+
import { basename, join } from 'node:path'
|
|
5
|
+
|
|
6
|
+
import { createCheckReporter } from '../../../scripts/lib/check-reporter.mjs'
|
|
7
|
+
|
|
8
|
+
/** Перший JSDoc-блок у файлі (не-жадібний). */
|
|
9
|
+
const MODULE_JSDOC_RE = /\/\*\*[\s\S]*?\*\//
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* `import` або `export` на початку рядка — межа між module-level і body.
|
|
13
|
+
* Regex, не AST: нас цікавить тільки текстова позиція, не семантика JS.
|
|
14
|
+
*/
|
|
15
|
+
const CODE_START_RE = /^(?:import|export)\b/m
|
|
16
|
+
|
|
17
|
+
/** Кількість непорожніх рядків між `/**` і `*\/` (після зрізання `*`-відступу). */
|
|
18
|
+
function contentLineCount(block) {
|
|
19
|
+
return block
|
|
20
|
+
.split('\n')
|
|
21
|
+
.slice(1, -1)
|
|
22
|
+
.filter(l => /\S/.test(l.replace(/^\s*\*\s?/, '')))
|
|
23
|
+
.length
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Повертає module-level JSDoc або `null`, якщо його немає. */
|
|
27
|
+
function moduleJsDoc(source) {
|
|
28
|
+
const codeStart = CODE_START_RE.exec(source)
|
|
29
|
+
const prefix = codeStart ? source.slice(0, codeStart.index) : source
|
|
30
|
+
const m = MODULE_JSDOC_RE.exec(prefix)
|
|
31
|
+
return m ? m[0] : null
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Сканує `npm/rules/*\/js/*.mjs` і `npm/skills/*\/js/*.mjs`.
|
|
36
|
+
* Якщо поряд існує `docs/<stem>.md` — module-level JSDoc має бути pointer (≤1 рядок),
|
|
37
|
+
* а не наратив; якщо docs немає — без обмежень.
|
|
38
|
+
* @param {string} [cwd] корінь репозиторію
|
|
39
|
+
* @returns {Promise<number>} 0 — OK, 1 — порушення
|
|
40
|
+
*/
|
|
41
|
+
export async function check(cwd = process.cwd()) {
|
|
42
|
+
const reporter = createCheckReporter()
|
|
43
|
+
|
|
44
|
+
for (const baseSegment of ['npm/rules', 'npm/skills']) {
|
|
45
|
+
const absBase = join(cwd, baseSegment)
|
|
46
|
+
if (!existsSync(absBase)) continue
|
|
47
|
+
|
|
48
|
+
for (const ruleEntry of await readdir(absBase, { withFileTypes: true })) {
|
|
49
|
+
if (!ruleEntry.isDirectory() || ruleEntry.name.startsWith('.')) continue
|
|
50
|
+
|
|
51
|
+
const jsDir = join(absBase, ruleEntry.name, 'js')
|
|
52
|
+
if (!existsSync(jsDir)) continue
|
|
53
|
+
|
|
54
|
+
for (const fileEntry of await readdir(jsDir, { withFileTypes: true })) {
|
|
55
|
+
if (
|
|
56
|
+
!fileEntry.isFile() ||
|
|
57
|
+
!fileEntry.name.endsWith('.mjs') ||
|
|
58
|
+
fileEntry.name.endsWith('.test.mjs')
|
|
59
|
+
)
|
|
60
|
+
continue
|
|
61
|
+
|
|
62
|
+
const stem = basename(fileEntry.name, '.mjs')
|
|
63
|
+
const docsPath = join(jsDir, 'docs', `${stem}.md`)
|
|
64
|
+
if (!existsSync(docsPath)) continue
|
|
65
|
+
|
|
66
|
+
const filePath = join(jsDir, fileEntry.name)
|
|
67
|
+
const source = await readFile(filePath, 'utf8')
|
|
68
|
+
const block = moduleJsDoc(source)
|
|
69
|
+
if (!block) continue
|
|
70
|
+
|
|
71
|
+
const count = contentLineCount(block)
|
|
72
|
+
if (count > 1) {
|
|
73
|
+
reporter.fail(
|
|
74
|
+
`${filePath.slice(cwd.length + 1)}: docs/${stem}.md вже описує поведінку — module-level JSDoc має бути pointer (≤1 рядок, зараз ${count})`
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return reporter.getExitCode()
|
|
82
|
+
}
|
|
@@ -1,31 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Перевіряє структуру npm-модуля в монорепо за правилом npm-module.mdc.
|
|
3
|
-
*
|
|
4
|
-
* Workspace `npm/`, `npm/package.json`, workflow `npm-publish.yml` з OIDC, `on.push.paths` з glob для каталогу npm.
|
|
5
|
-
*
|
|
6
|
-
* Якщо під `npm/src` є хоча б один файл `.js`, очікується канонічний layout: `types` → `./types/index.d.ts`,
|
|
7
|
-
* згенерований `index.d.ts` у `npm/types/`, і hk з викликом `tsc` по файлах під `npm/src`.
|
|
8
|
-
*
|
|
9
|
-
* Якщо таких файлів немає — layout через `npm/tsconfig.emit-types.json`: поле `types` має вказувати на існуючий
|
|
10
|
-
* файл під `./types/…`, у hk — `tsc -p tsconfig.emit-types.json`, у JSON-конфігу — потрібні compilerOptions для emit.
|
|
11
|
-
*
|
|
12
|
-
* Поля workflow перевіряються після **YAML parse**, щоб не плутати з коментарями.
|
|
13
|
-
*
|
|
14
|
-
* Компактність опублікованого пакета (cross-file / FS / AST частина):
|
|
15
|
-
* - Пер-документні структурні deny для `npm/package.json` (`files` whitelist обовʼязковий,
|
|
16
|
-
* без `devDependencies`) — у rego-пакеті `npm_module.npm_package_json` (Rego-authoritative).
|
|
17
|
-
* - Тут лишається лише `checkNoTestsInPublishedFiles`: walk шляхів з `"files"` (з урахуванням
|
|
18
|
-
* негативних glob-патернів) і скан test-style каталогів (`tests/`, `__tests__/`, `fixtures/`,
|
|
19
|
-
* `__fixtures__/`, `spec/`, `test/`), імен файлів (`*.test.*` / `*.spec.*`) і AST-імпортів
|
|
20
|
-
* test-фреймворків (`bun:test`, `node:test`, `vitest`, `@jest/globals`, `mocha`, `jest`, `ava`, …).
|
|
21
|
-
* Виняток: `*_test.rego` дозволені поруч з полісі — це конвенція conftest.
|
|
22
|
-
*
|
|
23
|
-
* Версія та CHANGELOG тут НЕ перевіряються: єдиний артефакт зміни — change-файл, а узгодженість
|
|
24
|
-
* `version`/`CHANGELOG.md` (включно з drift від ручного bump) валідує `changelog/js/consistency.mjs`
|
|
25
|
-
* за моделлю `n-changelog.mdc`. Інваріант «верхня секція CHANGELOG == package.json.version» істинний
|
|
26
|
-
* лише post-release і його гарантує `n-cursor release` у CI — локально його не підтримують руками.
|
|
27
|
-
* @param {string} cwd корінь репозиторію
|
|
28
|
-
*/
|
|
1
|
+
/** @see ./docs/package_structure.md */
|
|
29
2
|
import { existsSync } from 'node:fs'
|
|
30
3
|
import { readFile, stat } from 'node:fs/promises'
|
|
31
4
|
import { join, sep } from 'node:path'
|
|
@@ -1,13 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Перевірка метаданих правил пакета `@nitra/cursor` (концерн правила npm-module).
|
|
3
|
-
*
|
|
4
|
-
* Кожен `npm/rules/<id>/` має містити валідний `meta.json`:
|
|
5
|
-
* - `auto` (якщо присутнє) — розпізнане `parseRuleAutoSpec` (завжди / масив / glob / predicate);
|
|
6
|
-
* - для `predicate` — імʼя є в реєстрі `RULE_PREDICATES`;
|
|
7
|
-
* - залишковий `auto.md` заборонено (міграція на meta.json завершена).
|
|
8
|
-
*
|
|
9
|
-
* Застосовний лише в репо пакета (де є `npm/rules/`); у споживача каталогу нема — пропуск.
|
|
10
|
-
*/
|
|
1
|
+
/** @see ./docs/rule_meta.md */
|
|
11
2
|
import { existsSync, readdirSync } from 'node:fs'
|
|
12
3
|
import { join } from 'node:path'
|
|
13
4
|
|
|
@@ -1,16 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Перевірка метаданих скілів пакета `@nitra/cursor` (концерн правила npm-module).
|
|
3
|
-
*
|
|
4
|
-
* Кожен `npm/skills/<id>/` має містити валідний `meta.json`:
|
|
5
|
-
* - `worktree` присутнє і boolean;
|
|
6
|
-
* - `auto` (якщо присутнє) — розпізнане (`"завжди"` або непорожній масив рядків);
|
|
7
|
-
* - `requireRoot` (якщо присутнє) — boolean; не може бути `false` при `worktree:true`
|
|
8
|
-
* (worktree вже вимагає кореня — суперечність вводить в оману);
|
|
9
|
-
* - залишковий `auto.md` заборонено (міграція на meta.json завершена).
|
|
10
|
-
*
|
|
11
|
-
* Концерн застосовний лише в репо самого пакета (де є `npm/skills/`); у споживача
|
|
12
|
-
* каталогу `npm/skills/` нема, тож перевірка мовчки проходить.
|
|
13
|
-
*/
|
|
1
|
+
/** @see ./docs/skill_meta.md */
|
|
14
2
|
import { existsSync, readdirSync } from 'node:fs'
|
|
15
3
|
import { join } from 'node:path'
|
|
16
4
|
|
package/rules/php/js/tooling.mjs
CHANGED
|
@@ -1,14 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Перевіряє вимоги правила php.mdc для PHP-проєктів.
|
|
3
|
-
*
|
|
4
|
-
* **Що тут лишилося** (FS-existence — не покривається conftest):
|
|
5
|
-
* - наявність `composer.json` у корені;
|
|
6
|
-
* - наявність `.github/workflows/lint-php.yml`.
|
|
7
|
-
*
|
|
8
|
-
* **Що покрила Rego** (`npx \@nitra/cursor check`):
|
|
9
|
-
* - `npm/policy/php/package_json/` — наявність скрипта `lint-php` у `package.json`;
|
|
10
|
-
* - `npm/policy/php/lint_php_yml/` — крок `run: bun run lint-php` у workflow.
|
|
11
|
-
*/
|
|
1
|
+
/** @see ./docs/tooling.md */
|
|
12
2
|
import { existsSync } from 'node:fs'
|
|
13
3
|
|
|
14
4
|
import { createCheckReporter } from '../../../scripts/lib/check-reporter.mjs'
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Applies-гейт правила `python` (python.mdc): правило застосовне, лише якщо в корені є
|
|
3
|
-
* `pyproject.toml`. Інакше CLI пропускає всі concerns (JS і policy) — інакше rego
|
|
4
|
-
* `python/package_json` хибно вимагає `scripts.lint-python` навіть для не-Python репо.
|
|
5
|
-
*
|
|
6
|
-
* JS тут — гейт на наявність кореневого `pyproject.toml`. Подальші FS-перевірки
|
|
7
|
-
* (`uv.lock`, `package.json`, `lint-python.yml`, заборона Poetry) — у `tooling.mjs`.
|
|
8
|
-
*/
|
|
1
|
+
/** @see ./docs/applies.md */
|
|
9
2
|
import { existsSync } from 'node:fs'
|
|
10
3
|
import { join } from 'node:path'
|
|
11
4
|
|
|
@@ -1,24 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Перевіряє FS-вимоги правила python.mdc для Python-проєктів на uv.
|
|
3
|
-
*
|
|
4
|
-
* **Що тут лишилося** (FS-existence — не покривається conftest):
|
|
5
|
-
* - наявність `uv.lock` поруч (uv-проєкт коммітить lock-файл);
|
|
6
|
-
* - наявність кореневого `package.json` (для `bun run lint-python`);
|
|
7
|
-
* - наявність `.github/workflows/lint-python.yml`;
|
|
8
|
-
* - заборона Poetry-артефактів `poetry.lock` / `poetry.toml` (міграція на uv).
|
|
9
|
-
*
|
|
10
|
-
* Гейт на `pyproject.toml` робить `applies.mjs` — CLI пропускає правило цілком
|
|
11
|
-
* без нього. Захисний early-return лишається тут лише для прямого виклику
|
|
12
|
-
* `check()` (тести/standalone) без `applies.mjs`-гейту.
|
|
13
|
-
*
|
|
14
|
-
* **Що покрила Rego** (`npx \@nitra/cursor fix python`):
|
|
15
|
-
* - `python/pyproject_toml/` — заборона `[tool.poetry]` + вимога PEP 621 `[project].name/version`;
|
|
16
|
-
* - `python/package_json/` — наявність скрипта `lint-python` у `package.json`;
|
|
17
|
-
* - `python/lint_python_yml/` — `uses`/`run`-кроки канонічного workflow.
|
|
18
|
-
*
|
|
19
|
-
* `.venv/` навмисно НЕ перевіряється: uv теж створює `.venv`, тож його наявність
|
|
20
|
-
* не є ознакою Poetry й давала б хибні спрацювання.
|
|
21
|
-
*/
|
|
1
|
+
/** @see ./docs/tooling.md */
|
|
22
2
|
import { existsSync } from 'node:fs'
|
|
23
3
|
import { join } from 'node:path'
|
|
24
4
|
|
|
@@ -1,14 +1,4 @@
|
|
|
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
|
-
*/
|
|
1
|
+
/** @see ./docs/applies.md */
|
|
12
2
|
import { createCheckReporter } from '../../../scripts/lib/check-reporter.mjs'
|
|
13
3
|
import { loadCursorIgnorePaths } from '../../../scripts/lib/load-cursor-config.mjs'
|
|
14
4
|
import { walkDir } from '../../../scripts/utils/walkDir.mjs'
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Applies-гейт правила rust: маркер — наявність `Cargo.toml` у `cwd` або
|
|
3
|
-
* в будь-якому workspace-підкаталозі (рекурсивний пошук з пропуском
|
|
4
|
-
* `node_modules`, `.git`, `.next`, `.turbo`). Якщо повертає `false` —
|
|
5
|
-
* `runStandardRule` пропускає всі концерни (JS і policy) цього правила.
|
|
6
|
-
* `check()` друкує тільки context-pass; реальна робота — у policy-концернах.
|
|
7
|
-
*/
|
|
1
|
+
/** @see ./docs/applies.md */
|
|
8
2
|
import { existsSync } from 'node:fs'
|
|
9
3
|
import { join } from 'node:path'
|
|
10
4
|
|