@nitra/cursor 1.11.3 → 1.11.4
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 +8 -2
- package/bin/n-cursor.js +3 -2
- package/package.json +1 -1
- package/rules/abie/js/applies/check.mjs +4 -4
- package/rules/abie/js/env_dns/check.mjs +1 -1
- package/rules/abie/js/firebase_hosting/check.mjs +1 -1
- package/rules/abie/js/hc_pairing/check.mjs +3 -3
- package/rules/abie/js/ua_http_route/check.mjs +3 -3
- package/rules/abie/js/ua_node_selector/check.mjs +4 -2
- package/rules/abie/policy/base_deployment_preem/target.json +1 -5
- package/rules/abie/utils/enabled.mjs +1 -1
- package/rules/abie/utils/env-dns.mjs +4 -4
- package/rules/abie/utils/http-route.mjs +4 -4
- package/rules/abie/utils/k8s-tree.mjs +15 -6
- package/rules/abie/utils/kustomization-patches.mjs +20 -20
- package/rules/abie/utils/overlay-paths.mjs +7 -7
- package/rules/abie/utils/yaml.mjs +4 -4
- package/rules/hasura/js/internal_urls/check.mjs +1 -1
- package/rules/js-bun-redis/js/imports/check.mjs +5 -1
- package/rules/js-run/js/runtime/check.mjs +4 -1
- package/rules/k8s/policy/base_manifest/target.json +1 -5
- package/rules/nginx-default-tpl/js/template/check.mjs +4 -2
- package/rules/npm-module/js/package_structure/check.mjs +6 -1
- package/rules/rego/js/applies/check.mjs +2 -2
- package/rules/tauri/js/tooling/check.mjs +3 -1
- package/scripts/auto-skills.mjs +2 -4
- package/scripts/utils/discover-checkable-rules.mjs +4 -3
- package/scripts/utils/run-rule.mjs +3 -2
- package/skills/abie-clean/SKILL.md +4 -6
- package/skills/adr-normalize/SKILL.md +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
Формат — [Keep a Changelog](https://keepachangelog.com/uk/1.1.0/), нумерація — [SemVer](https://semver.org/lang/uk/).
|
|
6
6
|
|
|
7
|
+
## [1.11.4] - 2026-05-15
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **`npm/rules/nginx-default-tpl/js/template/check.mjs`** — `findDefaultConfTemplatePaths` пропускає тестові `fixtures/` за будь-яким сегментом шляху, не лише `tests/fixtures/`. Після concern-split (фази 1-4) fixtures лежать у `rules/<rule>/js/<concern>/fixtures/`, і старий патерн пропускав їх повз → check шукав Dockerfile поруч із тестовим шаблоном і фалс-фейлив.
|
|
12
|
+
|
|
7
13
|
## [1.11.3] - 2026-05-15
|
|
8
14
|
|
|
9
15
|
### Fixed
|
|
@@ -55,7 +61,7 @@
|
|
|
55
61
|
- **Інкрементальна міграція правил на `target.json`** (декларативні маніфести поруч із кожним `<concern>.rego`):
|
|
56
62
|
- **Single-file правила** (11): `bun`, `text`, `style-lint`, `php`, `docker`, `npm-module`, `js-lint`, `image-compress`, `capacitor`, `hasura`, `adr` — `target.json` з `single` для кожного канонічного конфіг-файлу. Сумарно 27 нових маніфестів. `bun.bunfig`, `text.cspell`, `npm_module.npm_publish_yml` тощо тепер прогоняються через CLI `check <id>` без додаткового `bun run lint-conftest`.
|
|
57
63
|
- **Walk-glob правила** (6): `js-mssql`, `js-bun-db`, `js-bun-redis`, `js-run` (package_json + configmap), `vue`, `image-avif` — `walkGlob: "**/package.json"` або відповідний патерн.
|
|
58
|
-
- **k8s
|
|
64
|
+
- **k8s.\* концерни** (8): `manifest`, `gateway`, `hpa_pdb`, `kustomization`, `svc_yaml`, `svc_hl_yaml`, `base_kustomization`, `base_manifest` — `walkGlob` по YAML під сегментом `k8s/`; `base_manifest` використовує негативний glob для виключення `kustomization.yaml`.
|
|
59
65
|
- **abie концерни** (4): `clean_merged_ignore_branches` (single), `health_check_policy` (walkGlob `**/k8s/**/hc.yaml`), `http_route_base` (walkGlob `**/k8s/**/base/**/hr.yaml`), `base_deployment_preem` (walkGlob `**/k8s/**/base/**/*.{yaml,yml}` з виключенням `kustomization.yaml`).
|
|
60
66
|
- **`capture-decisions.sh` тепер пише чернетки напряму в `docs/adr/<timestamp>-<sid>.md`** (раніше — у `docs/adr/_inbox/`). Сам каталог `_inbox/` більше не створюється, але `normalize-decisions.sh` бачить його рекурсивно — старі чернетки з `_inbox/` поступово розчищаються нормалізацією. Можна також одноразово `git mv docs/adr/_inbox/*.md docs/adr/` і прибрати порожній каталог.
|
|
61
67
|
- **Правило `adr` (`npm/rules/adr/adr.mdc`)**: повне переписування під дві фази (capture + normalize). Видалено згадки `_inbox/`. Версія `version: '2.0'`.
|
|
@@ -84,7 +90,7 @@
|
|
|
84
90
|
|
|
85
91
|
### Changed
|
|
86
92
|
|
|
87
|
-
- **Rule-centric структура пакета.** Кожне правило тепер живе в одній директорії `npm/rules/{rule}/` з усіма своїми артефактами: `{rule}.mdc`, `auto.md` (умова автоактивації), `policy/` (rego-поліси), `js/` (check.mjs + опційні run/lint + co-located
|
|
93
|
+
- **Rule-centric структура пакета.** Кожне правило тепер живе в одній директорії `npm/rules/{rule}/` з усіма своїми артефактами: `{rule}.mdc`, `auto.md` (умова автоактивації), `policy/` (rego-поліси), `js/` (check.mjs + опційні run/lint + co-located \*.test.mjs + fixtures/). Видалив каталог правила — правило зникло без слідів у `bin/auto-rules.md`, `npm/policy/`, `npm/scripts/`. Дзеркальна структура для скілів у `npm/skills/{skill}/` (SKILL.md + auto.md + js/).
|
|
88
94
|
- **Тести співрозташовуються з джерелами.** ~50 файлів з `npm/tests/` переїхали в `npm/rules/{rule}/js/*.test.mjs` (тести правил), `npm/scripts/*.test.mjs` (тести інфраструктури), `npm/scripts/utils/*.test.mjs` (тести утиліт). `tests/helpers.mjs` → `scripts/utils/test-helpers.mjs`. `npm/tests/` залишається тільки для 3 крос-правильних інтеграційних тестів.
|
|
89
95
|
- **`bin/n-cursor.js`**: `BUNDLED_MDC_DIR` → `BUNDLED_RULES_DIR`. `discoverBundledRuleNames` і `discoverCheckScripts` тепер обходять підкаталоги `rules/` замість файлів у `mdc/` чи `check-*.mjs` у `scripts/`. Резолвер check-скриптів: `rules/{rule}/js/check.mjs`. `readBundledRuleContent` читає `rules/{rule}/{rule}.mdc`.
|
|
90
96
|
- **`scripts/utils/run-conftest-batch.mjs` та `scripts/lint-conftest.mjs`**: шляхи до rego-полісі — `rules/{rule}/policy/{name}/` (замість `policy/{rule}/{name}/`). Snake_case `policyDirRel` у JS-call sites замінено на kebab-case.
|
package/bin/n-cursor.js
CHANGED
|
@@ -266,8 +266,9 @@ async function readConfig(paths = {}) {
|
|
|
266
266
|
// правило, додане вручну (напр. `adr` без auto.md-умови), не активувало б залежні
|
|
267
267
|
// скіли (`adr-normalize`).
|
|
268
268
|
const disableRulesSet = new Set(disableRules)
|
|
269
|
-
const effectiveRulesForSkills = [
|
|
270
|
-
.
|
|
269
|
+
const effectiveRulesForSkills = [
|
|
270
|
+
...new Set([...normalizeIdList(parsedConfig.rules), ...autoDetectedRules.rules])
|
|
271
|
+
].filter(id => !disableRulesSet.has(id))
|
|
271
272
|
const autoDetectedSkills = detectAutoSkills({
|
|
272
273
|
availableSkills,
|
|
273
274
|
detectedRules: effectiveRulesForSkills,
|
package/package.json
CHANGED
|
@@ -8,16 +8,16 @@ import { createCheckReporter } from '../../../../scripts/utils/check-reporter.mj
|
|
|
8
8
|
import { isAbieRuleEnabled } from '../../utils/enabled.mjs'
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* @returns {Promise<boolean>}
|
|
11
|
+
* @returns {Promise<boolean>} `true` — правило застосовне; `false` — пропустити
|
|
12
12
|
*/
|
|
13
|
-
export
|
|
13
|
+
export function applies() {
|
|
14
14
|
return isAbieRuleEnabled(process.cwd())
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
* @returns {
|
|
18
|
+
* @returns {number} exit-код (0 — OK, 1 — порушення)
|
|
19
19
|
*/
|
|
20
|
-
export
|
|
20
|
+
export function check() {
|
|
21
21
|
const reporter = createCheckReporter()
|
|
22
22
|
reporter.pass('Правило abie увімкнено — виконуємо перевірки')
|
|
23
23
|
return reporter.getExitCode()
|
|
@@ -15,7 +15,7 @@ import { loadCursorIgnorePaths } from '../../../../scripts/utils/load-cursor-con
|
|
|
15
15
|
import { abieEnvNameFromBasename, collectAbieEnvFiles, validateAbieEnvInternalUrls } from '../../utils/env-dns.mjs'
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
* @returns {Promise<number>}
|
|
18
|
+
* @returns {Promise<number>} результат
|
|
19
19
|
*/
|
|
20
20
|
export async function check() {
|
|
21
21
|
const reporter = createCheckReporter()
|
|
@@ -12,7 +12,7 @@ import { createCheckReporter } from '../../../../scripts/utils/check-reporter.mj
|
|
|
12
12
|
const SKIP_TOP_DIR_NAMES = new Set(['.git', 'node_modules'])
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* @returns {Promise<number>}
|
|
15
|
+
* @returns {Promise<number>} результат
|
|
16
16
|
*/
|
|
17
17
|
export async function check() {
|
|
18
18
|
const reporter = createCheckReporter()
|
|
@@ -17,7 +17,7 @@ import { validateAbieHcModeline } from '../../utils/hc-yaml.mjs'
|
|
|
17
17
|
import { collectDeploymentDirs, findK8sYamlFiles } from '../../utils/k8s-tree.mjs'
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
|
-
* @returns {Promise<number>}
|
|
20
|
+
* @returns {Promise<number>} результат
|
|
21
21
|
*/
|
|
22
22
|
export async function check() {
|
|
23
23
|
const reporter = createCheckReporter()
|
|
@@ -50,8 +50,8 @@ export async function check() {
|
|
|
50
50
|
continue
|
|
51
51
|
}
|
|
52
52
|
const modelineErr = validateAbieHcModeline(hcRaw, relHc)
|
|
53
|
-
if (modelineErr
|
|
54
|
-
else
|
|
53
|
+
if (modelineErr === null) pass(`${relHc}: modeline OK`)
|
|
54
|
+
else fail(modelineErr)
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
return reporter.getExitCode()
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
} from '../../utils/overlay-paths.mjs'
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
|
-
* @returns {Promise<number>}
|
|
29
|
+
* @returns {Promise<number>} результат
|
|
30
30
|
*/
|
|
31
31
|
export async function check() {
|
|
32
32
|
const reporter = createCheckReporter()
|
|
@@ -78,8 +78,8 @@ export async function check() {
|
|
|
78
78
|
}
|
|
79
79
|
const combined = getCombinedNginxRunPatchTextFromKustomization(raw)
|
|
80
80
|
const v = validateAbieNginxRunHttpRoutePatches(combined, 'ua', raw, sharedAnalysis.refCount)
|
|
81
|
-
if (v
|
|
82
|
-
else
|
|
81
|
+
if (v === null) pass(`${rel}: HTTPRoute patch (ua) відповідає abie.mdc`)
|
|
82
|
+
else fail(`${rel}: ${v}`)
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
return reporter.getExitCode()
|
|
@@ -16,7 +16,7 @@ import { kustomizationHasAbieDeploymentNodeSelectorPatch } from '../../utils/kus
|
|
|
16
16
|
import { abieOverlayK8sTreeHasDeployment, isUaKustomizationPath } from '../../utils/overlay-paths.mjs'
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
* @returns {Promise<number>}
|
|
19
|
+
* @returns {Promise<number>} результат
|
|
20
20
|
*/
|
|
21
21
|
export async function check() {
|
|
22
22
|
const reporter = createCheckReporter()
|
|
@@ -55,7 +55,9 @@ export async function check() {
|
|
|
55
55
|
continue
|
|
56
56
|
}
|
|
57
57
|
if (!kustomizationHasAbieDeploymentNodeSelectorPatch(raw, 'ua')) {
|
|
58
|
-
fail(
|
|
58
|
+
fail(
|
|
59
|
+
`${rel}: потрібен patch target kind Deployment: path /spec/template/spec/nodeSelector та preem: false (abie.mdc)`
|
|
60
|
+
)
|
|
59
61
|
continue
|
|
60
62
|
}
|
|
61
63
|
pass(`${rel}: nodeSelector patch (ua) відповідає abie.mdc`)
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
|
|
3
3
|
"files": {
|
|
4
|
-
"walkGlob": [
|
|
5
|
-
"**/k8s/**/base/**/*.yaml",
|
|
6
|
-
"**/k8s/**/base/**/*.yml",
|
|
7
|
-
"!**/k8s/**/base/**/kustomization.yaml"
|
|
8
|
-
]
|
|
4
|
+
"walkGlob": ["**/k8s/**/base/**/*.yaml", "**/k8s/**/base/**/*.yml", "!**/k8s/**/base/**/kustomization.yaml"]
|
|
9
5
|
}
|
|
10
6
|
}
|
|
@@ -12,7 +12,7 @@ const CONFIG_FILE = '.n-cursor.json'
|
|
|
12
12
|
/**
|
|
13
13
|
* Чи увімкнено правило **abie** у `.n-cursor.json:rules`.
|
|
14
14
|
* @param {string} root корінь репозиторію (cwd)
|
|
15
|
-
* @returns {Promise<boolean>}
|
|
15
|
+
* @returns {Promise<boolean>} `true` — `rules` містить `abie`; `false` — інакше
|
|
16
16
|
*/
|
|
17
17
|
export async function isAbieRuleEnabled(root) {
|
|
18
18
|
const p = join(root, CONFIG_FILE)
|
|
@@ -23,8 +23,8 @@ const ABIE_ENV_CLUSTER_DNS_MAP = Object.freeze({
|
|
|
23
23
|
/**
|
|
24
24
|
* Дістає `dev` / `ua` з basename env-файлу abie.
|
|
25
25
|
* Не-abie env-файли (`production.env`, `.env` без імені) → null.
|
|
26
|
-
* @param {string} basenameOfEnvFile
|
|
27
|
-
* @returns {('dev' | 'ua') | null}
|
|
26
|
+
* @param {string} basenameOfEnvFile опис.
|
|
27
|
+
* @returns {('dev' | 'ua') | null} результат
|
|
28
28
|
*/
|
|
29
29
|
export function abieEnvNameFromBasename(basenameOfEnvFile) {
|
|
30
30
|
const m = basenameOfEnvFile.match(ABIE_ENV_FILE_BASENAME_RE)
|
|
@@ -35,7 +35,7 @@ export function abieEnvNameFromBasename(basenameOfEnvFile) {
|
|
|
35
35
|
* Сканує вміст env-файла, повертає помилки невідповідності кластерного DNS / namespace
|
|
36
36
|
* для кожного internal URL (один URL у двох змінних = дві окремі помилки).
|
|
37
37
|
* @param {string} content вміст env-файла (UTF-8)
|
|
38
|
-
* @param {'dev' | 'ua'} envName
|
|
38
|
+
* @param {'dev' | 'ua'} envName опис.
|
|
39
39
|
* @returns {string[]} порожній масив, якщо все OK
|
|
40
40
|
*/
|
|
41
41
|
export function validateAbieEnvInternalUrls(content, envName) {
|
|
@@ -63,7 +63,7 @@ export function validateAbieEnvInternalUrls(content, envName) {
|
|
|
63
63
|
* Збирає `*.env` файли, які є abie env (`dev.env`/`ua.env`, опц. з провідною крапкою).
|
|
64
64
|
* @param {string} root корінь репозиторію
|
|
65
65
|
* @param {string[]} ignorePaths абсолютні шляхи каталогів-виключень
|
|
66
|
-
* @returns {Promise<string[]>}
|
|
66
|
+
* @returns {Promise<string[]>} результат
|
|
67
67
|
*/
|
|
68
68
|
export async function collectAbieEnvFiles(root, ignorePaths) {
|
|
69
69
|
/** @type {string[]} */
|
|
@@ -14,7 +14,7 @@ const ABIE_SHARED_CROSS_NS_BACKEND_SET = new Set(ABIE_SHARED_CROSS_NS_BACKEND_NA
|
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Перевіряє один `backendRef`: якщо це спільний `-hl` сервіс, має бути `namespace: dev`.
|
|
17
|
-
* @param {unknown} br
|
|
17
|
+
* @param {unknown} br опис.
|
|
18
18
|
* @param {string} rel rel-шлях файла
|
|
19
19
|
* @param {string[]} errors мутабельний список помилок
|
|
20
20
|
* @returns {number} 1 — це shared backend, 0 — інакше
|
|
@@ -33,8 +33,8 @@ function checkSharedBackendRef(br, rel, errors) {
|
|
|
33
33
|
/**
|
|
34
34
|
* Збирає по HTTPRoute-документу кількість посилань на shared backends і порушення namespace.
|
|
35
35
|
* @param {unknown} obj корінь YAML
|
|
36
|
-
* @param {string} rel
|
|
37
|
-
* @returns {{ refCount: number, errors: string[] }}
|
|
36
|
+
* @param {string} rel опис.
|
|
37
|
+
* @returns {{ refCount: number, errors: string[] }} статистика shared-backend посилань і порушення namespace
|
|
38
38
|
*/
|
|
39
39
|
function httpRouteDocSharedCrossNsBackendStats(obj, rel) {
|
|
40
40
|
/** @type {string[]} */
|
|
@@ -66,7 +66,7 @@ function httpRouteDocSharedCrossNsBackendStats(obj, rel) {
|
|
|
66
66
|
* @param {string} root корінь репозиторію
|
|
67
67
|
* @param {string} pkgAbs абсолютний шлях каталогу пакета
|
|
68
68
|
* @param {string[]} yamlFilesAbs усі yaml під k8s
|
|
69
|
-
* @returns {Promise<{ refCount: number, baseErrors: string[] }>}
|
|
69
|
+
* @returns {Promise<{ refCount: number, baseErrors: string[] }>} агрегована статистика й помилки base-шару
|
|
70
70
|
*/
|
|
71
71
|
export async function analyzeAbieSharedBackendRefsInPackageK8s(root, pkgAbs, yamlFilesAbs) {
|
|
72
72
|
const pkgRel = relative(root, pkgAbs).replaceAll('\\', '/') || pkgAbs
|
|
@@ -22,7 +22,7 @@ const deploymentCache = new Map()
|
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* Скидає кеш — тести мусять викликати між фікстурами.
|
|
25
|
-
* @returns {void}
|
|
25
|
+
* @returns {void} результат
|
|
26
26
|
*/
|
|
27
27
|
export function resetAbieK8sTreeCache() {
|
|
28
28
|
yamlCache.clear()
|
|
@@ -31,9 +31,9 @@ export function resetAbieK8sTreeCache() {
|
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* Стабільний ключ кешу за (root, ignorePaths).
|
|
34
|
-
* @param {string} root
|
|
35
|
-
* @param {string[]} ignorePaths
|
|
36
|
-
* @returns {string}
|
|
34
|
+
* @param {string} root опис.
|
|
35
|
+
* @param {string[]} ignorePaths опис.
|
|
36
|
+
* @returns {string} результат
|
|
37
37
|
*/
|
|
38
38
|
function cacheKey(root, ignorePaths) {
|
|
39
39
|
return `${root}|${[...ignorePaths].toSorted((a, b) => a.localeCompare(b)).join(':')}`
|
|
@@ -44,7 +44,7 @@ function cacheKey(root, ignorePaths) {
|
|
|
44
44
|
* Каталог `.github/` свідомо пропускається (належить `ga.mdc`).
|
|
45
45
|
* @param {string} root корінь репозиторію
|
|
46
46
|
* @param {string[]} [ignorePaths] абсолютні шляхи каталогів-виключень
|
|
47
|
-
* @returns {Promise<string[]>}
|
|
47
|
+
* @returns {Promise<string[]>} результат
|
|
48
48
|
*/
|
|
49
49
|
export function findK8sYamlFiles(root, ignorePaths = []) {
|
|
50
50
|
const key = cacheKey(root, ignorePaths)
|
|
@@ -77,7 +77,16 @@ export function findK8sYamlFiles(root, ignorePaths = []) {
|
|
|
77
77
|
* @param {(msg: string) => void} [fail] репортер помилок парсингу (опц.)
|
|
78
78
|
* @returns {Promise<Set<string>>} абсолютні шляхи директорій
|
|
79
79
|
*/
|
|
80
|
-
|
|
80
|
+
/**
|
|
81
|
+
* No-op fail-handler за замовчуванням для `collectDeploymentDirs` — пошкоджені YAML
|
|
82
|
+
* під час cross-rule сканування мовчки пропускаються; формальний reporter передає сам caller.
|
|
83
|
+
* @param {string} _msg повідомлення про помилку (ігнорується)
|
|
84
|
+
*/
|
|
85
|
+
const silentFail = _msg => {
|
|
86
|
+
// noop
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function collectDeploymentDirs(root, yamlAbs, fail = silentFail) {
|
|
81
90
|
const key = `${root}|${[...yamlAbs].toSorted((a, b) => a.localeCompare(b)).join(':')}`
|
|
82
91
|
const cached = deploymentCache.get(key)
|
|
83
92
|
if (cached) return cached
|
|
@@ -24,8 +24,8 @@ const ABIE_UA_HTTPROUTE_HOST_MARKERS = ['abie.app', 'vybeerai.com.ua', '*.abie.a
|
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* Чи patch-рядок містить очікуваний ua nodeSelector (preem: false).
|
|
27
|
-
* @param {string} patchText
|
|
28
|
-
* @returns {boolean}
|
|
27
|
+
* @param {string} patchText опис.
|
|
28
|
+
* @returns {boolean} результат
|
|
29
29
|
*/
|
|
30
30
|
function jsonPatchTextHasUaDeploymentNodeSelector(patchText) {
|
|
31
31
|
if (typeof patchText !== 'string' || patchText.trim() === '') return false
|
|
@@ -36,9 +36,9 @@ function jsonPatchTextHasUaDeploymentNodeSelector(patchText) {
|
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* Чи один елемент `patches` відповідає abie nodeSelector для `mode`.
|
|
39
|
-
* @param {unknown} p
|
|
40
|
-
* @param {'ua'} mode
|
|
41
|
-
* @returns {boolean}
|
|
39
|
+
* @param {unknown} p опис.
|
|
40
|
+
* @param {'ua'} mode опис.
|
|
41
|
+
* @returns {boolean} результат
|
|
42
42
|
*/
|
|
43
43
|
function inlineKustomizationPatchMatchesAbieMode(p, mode) {
|
|
44
44
|
if (p === null || typeof p !== 'object' || Array.isArray(p)) return false
|
|
@@ -55,9 +55,9 @@ function inlineKustomizationPatchMatchesAbieMode(p, mode) {
|
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
57
|
* Чи документ Kustomization містить відповідний inline patch на Deployment.
|
|
58
|
-
* @param {import('yaml').Document} doc
|
|
59
|
-
* @param {'ua'} mode
|
|
60
|
-
* @returns {boolean}
|
|
58
|
+
* @param {import('yaml').Document} doc опис.
|
|
59
|
+
* @param {'ua'} mode опис.
|
|
60
|
+
* @returns {boolean} результат
|
|
61
61
|
*/
|
|
62
62
|
function kustomizationDocumentHasAbieDeploymentNodeSelectorPatch(doc, mode) {
|
|
63
63
|
if (doc.errors.length > 0) return false
|
|
@@ -76,8 +76,8 @@ function kustomizationDocumentHasAbieDeploymentNodeSelectorPatch(doc, mode) {
|
|
|
76
76
|
/**
|
|
77
77
|
* Чи `kustomization.yaml` містить валідні inline patch для Deployment nodeSelector (ua).
|
|
78
78
|
* @param {string} raw повний текст файла
|
|
79
|
-
* @param {'ua'} mode
|
|
80
|
-
* @returns {boolean}
|
|
79
|
+
* @param {'ua'} mode опис.
|
|
80
|
+
* @returns {boolean} результат
|
|
81
81
|
*/
|
|
82
82
|
export function kustomizationHasAbieDeploymentNodeSelectorPatch(raw, mode) {
|
|
83
83
|
const body = stripBom(raw)
|
|
@@ -100,8 +100,8 @@ export function kustomizationHasAbieDeploymentNodeSelectorPatch(raw, mode) {
|
|
|
100
100
|
// ── HTTPRoute (ua) ────────────────────────────────────────────────────────
|
|
101
101
|
|
|
102
102
|
/**
|
|
103
|
-
* @param {unknown} p
|
|
104
|
-
* @returns {string | null}
|
|
103
|
+
* @param {unknown} p опис.
|
|
104
|
+
* @returns {string | null} результат
|
|
105
105
|
*/
|
|
106
106
|
function extractHttpRoutePatchString(p) {
|
|
107
107
|
if (p === null || typeof p !== 'object' || Array.isArray(p)) return null
|
|
@@ -116,8 +116,8 @@ function extractHttpRoutePatchString(p) {
|
|
|
116
116
|
|
|
117
117
|
/**
|
|
118
118
|
* Збирає inline `patch`-рядки для HTTPRoute (непорожній `target.name`) з одного Kustomization-документа.
|
|
119
|
-
* @param {import('yaml').Document} doc
|
|
120
|
-
* @returns {string[]}
|
|
119
|
+
* @param {import('yaml').Document} doc опис.
|
|
120
|
+
* @returns {string[]} результат
|
|
121
121
|
*/
|
|
122
122
|
function collectAbieHttpRoutePatchStringsFromKustomizationDoc(doc) {
|
|
123
123
|
if (doc.errors.length > 0) return []
|
|
@@ -137,7 +137,7 @@ function collectAbieHttpRoutePatchStringsFromKustomizationDoc(doc) {
|
|
|
137
137
|
/**
|
|
138
138
|
* Збирає всі inline JSON6902-фрагменти HTTPRoute (непорожній `target.name`) у kustomization.yaml.
|
|
139
139
|
* @param {string} raw повний текст файла
|
|
140
|
-
* @returns {string}
|
|
140
|
+
* @returns {string} результат
|
|
141
141
|
*/
|
|
142
142
|
export function getCombinedNginxRunPatchTextFromKustomization(raw) {
|
|
143
143
|
const body = stripBom(raw)
|
|
@@ -162,8 +162,8 @@ export function getCombinedNginxRunPatchTextFromKustomization(raw) {
|
|
|
162
162
|
/**
|
|
163
163
|
* Рахує операції JSON6902 з `path: /spec/rules/.../backendRefs/.../namespace` і `value: ua[-…]`.
|
|
164
164
|
* @param {string} combined сукупний текст patch
|
|
165
|
-
* @param {'ua'} mode
|
|
166
|
-
* @returns {number}
|
|
165
|
+
* @param {'ua'} mode опис.
|
|
166
|
+
* @returns {number} результат
|
|
167
167
|
*/
|
|
168
168
|
function countAbieHttpRouteBackendRefNamespacePatchesInCombined(combined, mode) {
|
|
169
169
|
if (mode !== 'ua') return 0
|
|
@@ -175,7 +175,7 @@ function countAbieHttpRouteBackendRefNamespacePatchesInCombined(combined, mode)
|
|
|
175
175
|
/**
|
|
176
176
|
* Перевіряє сукупний текст patch(ів) HTTPRoute на відповідність abie.mdc.
|
|
177
177
|
* @param {string} combined сукупний текст patch
|
|
178
|
-
* @param {'ua'} mode
|
|
178
|
+
* @param {'ua'} mode опис.
|
|
179
179
|
* @param {string} [_fullKustomizationRaw] зберігається для API-сумісності, не використовується
|
|
180
180
|
* @param {number} [sharedCrossNsBackendRefCount] кількість `auth-run-hl`/`file-link-hl` у base HTTPRoute
|
|
181
181
|
* @returns {string | null} повідомлення про помилку або null
|
|
@@ -215,8 +215,8 @@ export function validateAbieNginxRunHttpRoutePatches(
|
|
|
215
215
|
/**
|
|
216
216
|
* Чи kustomization містить валідні patch для HTTPRoute (ua).
|
|
217
217
|
* @param {string} raw повний текст kustomization.yaml
|
|
218
|
-
* @param {'ua'} mode
|
|
219
|
-
* @returns {boolean}
|
|
218
|
+
* @param {'ua'} mode опис.
|
|
219
|
+
* @returns {boolean} результат
|
|
220
220
|
*/
|
|
221
221
|
export function kustomizationHasAbieNginxRunHttpRoutePatch(raw, mode) {
|
|
222
222
|
const combined = getCombinedNginxRunPatchTextFromKustomization(raw)
|
|
@@ -17,7 +17,7 @@ const TRAILING_SLASH_RE = /\/$/u
|
|
|
17
17
|
/**
|
|
18
18
|
* Чи `rel` — це `…/ua/kustomization.yaml` (abie overlay).
|
|
19
19
|
* @param {string} rel посі від кореня репозиторію
|
|
20
|
-
* @returns {boolean}
|
|
20
|
+
* @returns {boolean} результат
|
|
21
21
|
*/
|
|
22
22
|
export function isUaKustomizationPath(rel) {
|
|
23
23
|
const norm = rel.replaceAll('\\', '/')
|
|
@@ -28,7 +28,7 @@ export function isUaKustomizationPath(rel) {
|
|
|
28
28
|
* Каталог пакета (батько `k8s/`) для overlay `…/k8s/ua/kustomization.yaml`.
|
|
29
29
|
* @param {string} root корінь репозиторію
|
|
30
30
|
* @param {string} kustomizationAbs абсолютний шлях до ua kustomization
|
|
31
|
-
* @returns {string | null}
|
|
31
|
+
* @returns {string | null} результат
|
|
32
32
|
*/
|
|
33
33
|
export function abiePackageDirFromK8sOverlay(root, kustomizationAbs) {
|
|
34
34
|
const rel = relative(root, kustomizationAbs).replaceAll('\\', '/') || kustomizationAbs
|
|
@@ -41,7 +41,7 @@ export function abiePackageDirFromK8sOverlay(root, kustomizationAbs) {
|
|
|
41
41
|
* застосовується лише до Vite-пакетів.
|
|
42
42
|
* @param {string} root корінь репозиторію
|
|
43
43
|
* @param {string} kustomizationAbs абсолютний шлях до ua kustomization
|
|
44
|
-
* @returns {boolean}
|
|
44
|
+
* @returns {boolean} результат
|
|
45
45
|
*/
|
|
46
46
|
export function abieOverlayRequiresHttpRouteByVite(root, kustomizationAbs) {
|
|
47
47
|
const pkg = abiePackageDirFromK8sOverlay(root, kustomizationAbs)
|
|
@@ -58,7 +58,7 @@ export function abieOverlayRequiresHttpRouteByVite(root, kustomizationAbs) {
|
|
|
58
58
|
* @param {Set<string>} deploymentDirs абсолютні каталоги з Deployment
|
|
59
59
|
* @param {string} root корінь репозиторію
|
|
60
60
|
* @param {string} kustomizationAbs абсолютний шлях до ua kustomization
|
|
61
|
-
* @returns {boolean}
|
|
61
|
+
* @returns {boolean} результат
|
|
62
62
|
*/
|
|
63
63
|
export function abieOverlayK8sTreeHasDeployment(deploymentDirs, root, kustomizationAbs) {
|
|
64
64
|
const pkg = abiePackageDirFromK8sOverlay(root, kustomizationAbs)
|
|
@@ -73,8 +73,8 @@ export function abieOverlayK8sTreeHasDeployment(deploymentDirs, root, kustomizat
|
|
|
73
73
|
|
|
74
74
|
/**
|
|
75
75
|
* Чи rel-шлях `…/k8s/base/…` (base-шар abie, не overlay).
|
|
76
|
-
* @param {string} rel
|
|
77
|
-
* @returns {boolean}
|
|
76
|
+
* @param {string} rel опис.
|
|
77
|
+
* @returns {boolean} результат
|
|
78
78
|
*/
|
|
79
79
|
export function isAbieK8sBaseYamlPath(rel) {
|
|
80
80
|
const norm = rel.replaceAll('\\', '/')
|
|
@@ -85,7 +85,7 @@ export function isAbieK8sBaseYamlPath(rel) {
|
|
|
85
85
|
* Чи yaml належить до `<pkgRel>/k8s/**` поза `ua/` піддеревом (base-шар abie).
|
|
86
86
|
* @param {string} relFromRoot шлях від кореня
|
|
87
87
|
* @param {string} pkgRelFromRoot каталог пакета від кореня
|
|
88
|
-
* @returns {boolean}
|
|
88
|
+
* @returns {boolean} результат
|
|
89
89
|
*/
|
|
90
90
|
export function isK8sYamlInAbiePackageExcludingUaOverlay(relFromRoot, pkgRelFromRoot) {
|
|
91
91
|
const normRel = relFromRoot.replaceAll('\\', '/')
|
|
@@ -12,7 +12,7 @@ export const LINE_SPLIT_RE = /\r?\n/u
|
|
|
12
12
|
/**
|
|
13
13
|
* Прибирає BOM на початку файлу.
|
|
14
14
|
* @param {string} s вміст
|
|
15
|
-
* @returns {string}
|
|
15
|
+
* @returns {string} результат
|
|
16
16
|
*/
|
|
17
17
|
export function stripBom(s) {
|
|
18
18
|
return s.startsWith('') ? s.slice(1) : s
|
|
@@ -21,7 +21,7 @@ export function stripBom(s) {
|
|
|
21
21
|
/**
|
|
22
22
|
* Чи YAML-документ — це `kind: Deployment`.
|
|
23
23
|
* @param {unknown} obj корінь YAML-документа
|
|
24
|
-
* @returns {boolean}
|
|
24
|
+
* @returns {boolean} результат
|
|
25
25
|
*/
|
|
26
26
|
export function isDeploymentDoc(obj) {
|
|
27
27
|
return (
|
|
@@ -46,8 +46,8 @@ export const silentFail = _msg => {
|
|
|
46
46
|
* викликає `failFn` і повертає `null`.
|
|
47
47
|
* @param {string} abs абсолютний шлях
|
|
48
48
|
* @param {string} rel відносний (для повідомлень)
|
|
49
|
-
* @param {(msg: string) => void} failFn
|
|
50
|
-
* @returns {Promise<import('yaml').Document[] | null>}
|
|
49
|
+
* @param {(msg: string) => void} failFn опис.
|
|
50
|
+
* @returns {Promise<import('yaml').Document[] | null>} результат
|
|
51
51
|
*/
|
|
52
52
|
export async function readAndParseYamlDocs(abs, rel, failFn) {
|
|
53
53
|
let raw
|
|
@@ -143,7 +143,7 @@ async function checkEnvFile(relPath, expected, reporter) {
|
|
|
143
143
|
const value = m[1].trim()
|
|
144
144
|
const parsed = parseInternalHasuraEndpoint(value)
|
|
145
145
|
if (!parsed.ok) {
|
|
146
|
-
const example =
|
|
146
|
+
const example = 'https://<service>.<namespace>.svc.<cluster>.internal:<port>'
|
|
147
147
|
fail(
|
|
148
148
|
`${relPath}: HASURA_GRAPHQL_ENDPOINT="${value}" — потрібен внутрішній кластерний URL виду ${example} (hasura.mdc)`
|
|
149
149
|
)
|
|
@@ -16,7 +16,11 @@ import { join, relative } from 'node:path'
|
|
|
16
16
|
|
|
17
17
|
import { createCheckReporter } from '../../../../scripts/utils/check-reporter.mjs'
|
|
18
18
|
import { loadCursorIgnorePaths } from '../../../../scripts/utils/load-cursor-config.mjs'
|
|
19
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
findRedisImportsInText,
|
|
21
|
+
isRedisScanSourceFile,
|
|
22
|
+
shouldSkipFileForRedisScan
|
|
23
|
+
} from '../../../../scripts/utils/redis-imports.mjs'
|
|
20
24
|
import { walkDir } from '../../../../scripts/utils/walkDir.mjs'
|
|
21
25
|
|
|
22
26
|
/**
|
|
@@ -49,7 +49,10 @@ import {
|
|
|
49
49
|
resolveConnDirFromPackageJson
|
|
50
50
|
} from '../../../../scripts/utils/conn-imports-scan.mjs'
|
|
51
51
|
import { loadCursorIgnorePaths } from '../../../../scripts/utils/load-cursor-config.mjs'
|
|
52
|
-
import {
|
|
52
|
+
import {
|
|
53
|
+
findPromiseSetTimeoutInText,
|
|
54
|
+
isPromiseSetTimeoutScanSourceFile
|
|
55
|
+
} from '../../../../scripts/utils/promise-settimeout-scan.mjs'
|
|
53
56
|
import { walkDir } from '../../../../scripts/utils/walkDir.mjs'
|
|
54
57
|
import { getMonorepoPackageRootDirs } from '../../../../scripts/utils/workspaces.mjs'
|
|
55
58
|
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
|
|
3
3
|
"files": {
|
|
4
|
-
"walkGlob": [
|
|
5
|
-
"**/k8s/**/base/**/*.yaml",
|
|
6
|
-
"**/k8s/**/base/**/*.yml",
|
|
7
|
-
"!**/k8s/**/base/**/kustomization.yaml"
|
|
8
|
-
]
|
|
4
|
+
"walkGlob": ["**/k8s/**/base/**/*.yaml", "**/k8s/**/base/**/*.yml", "!**/k8s/**/base/**/kustomization.yaml"]
|
|
9
5
|
}
|
|
10
6
|
}
|
|
@@ -34,7 +34,9 @@ const GZIP_CMD_RE = /\bgzip\b/u
|
|
|
34
34
|
const GZIP_EXTENSION_RE = /\*\.(?:js|css)/u
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
|
-
* Збирає абсолютні шляхи до **default.conf.template** у репозиторії;
|
|
37
|
+
* Збирає абсолютні шляхи до **default.conf.template** у репозиторії; будь-який сегмент
|
|
38
|
+
* `fixtures/` у шляху виключається — це тестові артефакти (як `tests/fixtures/` так і
|
|
39
|
+
* co-located `rules/<rule>/js/<concern>/fixtures/`).
|
|
38
40
|
* @param {string} root корінь cwd
|
|
39
41
|
* @param {string[]} ignorePaths абсолютні шляхи каталогів, повністю виключених з обходу
|
|
40
42
|
* @returns {Promise<string[]>} відсортовані абсолютні шляхи до шаблонів
|
|
@@ -47,7 +49,7 @@ export async function findDefaultConfTemplatePaths(root, ignorePaths = []) {
|
|
|
47
49
|
p => {
|
|
48
50
|
if (basename(p) !== 'default.conf.template') return
|
|
49
51
|
const rel = relative(root, p).replaceAll('\\', '/')
|
|
50
|
-
if (rel.includes('
|
|
52
|
+
if (rel.split('/').includes('fixtures')) return
|
|
51
53
|
out.push(p)
|
|
52
54
|
},
|
|
53
55
|
ignorePaths
|
|
@@ -32,7 +32,12 @@ import { promisify } from 'node:util'
|
|
|
32
32
|
|
|
33
33
|
import { parseSync } from 'oxc-parser'
|
|
34
34
|
|
|
35
|
-
import {
|
|
35
|
+
import {
|
|
36
|
+
dynamicImportModule,
|
|
37
|
+
langFromPath,
|
|
38
|
+
requireCallModule,
|
|
39
|
+
walkAstWithAncestors
|
|
40
|
+
} from '../../../../scripts/utils/ast-scan-utils.mjs'
|
|
36
41
|
import { createCheckReporter } from '../../../../scripts/utils/check-reporter.mjs'
|
|
37
42
|
import { loadCursorIgnorePaths } from '../../../../scripts/utils/load-cursor-config.mjs'
|
|
38
43
|
import { walkDir } from '../../../../scripts/utils/walkDir.mjs'
|
|
@@ -45,9 +45,9 @@ export async function applies() {
|
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
47
|
* Друкує короткий context-pass — самі полісі прогонить CLI через `policy/<name>/target.json`.
|
|
48
|
-
* @returns {
|
|
48
|
+
* @returns {number} 0 — все ок (фактичні порушення повертають policy-концерни)
|
|
49
49
|
*/
|
|
50
|
-
export
|
|
50
|
+
export function check() {
|
|
51
51
|
const reporter = createCheckReporter()
|
|
52
52
|
reporter.pass('Знайдено *.rego у дереві — перевіряємо канонічні конфіги rego.mdc')
|
|
53
53
|
return reporter.getExitCode()
|
|
@@ -70,7 +70,9 @@ export async function check() {
|
|
|
70
70
|
|
|
71
71
|
const extPath = '.vscode/extensions.json'
|
|
72
72
|
if (!existsSync(extPath)) {
|
|
73
|
-
fail(
|
|
73
|
+
fail(
|
|
74
|
+
`${extPath} не існує — створи з recommendations "tauri-apps.tauri-vscode" і "rust-lang.rust-analyzer" (tauri.mdc)`
|
|
75
|
+
)
|
|
74
76
|
return reporter.getExitCode()
|
|
75
77
|
}
|
|
76
78
|
const violations = runConftestBatch({
|
package/scripts/auto-skills.mjs
CHANGED
|
@@ -52,7 +52,7 @@ function parseSkillAutoSpec(text) {
|
|
|
52
52
|
* Сканує `npm/skills/<id>/auto.md`. Скіли без `auto.md` або з нерозпізнаним
|
|
53
53
|
* вмістом не потрапляють у результат — їх можна вмикати лише вручну в конфізі.
|
|
54
54
|
* @param {string} [skillsDir] override для тестів
|
|
55
|
-
* @returns {Record<string, SkillAutoSpec>}
|
|
55
|
+
* @returns {Record<string, SkillAutoSpec>} мапа `skillId → spec`
|
|
56
56
|
*/
|
|
57
57
|
export function discoverSkillAutoActivation(skillsDir = SKILLS_DIR) {
|
|
58
58
|
if (!existsSync(skillsDir)) return {}
|
|
@@ -75,9 +75,7 @@ const SKILL_AUTO_ACTIVATION = discoverSkillAutoActivation()
|
|
|
75
75
|
* Стабільний алфавітний порядок скілів з автоактивацією. Експортовано для зворотної
|
|
76
76
|
* сумісності (попередня версія мала жорстко прописаний `AUTO_SKILL_ORDER`).
|
|
77
77
|
*/
|
|
78
|
-
export const AUTO_SKILL_ORDER = Object.freeze(
|
|
79
|
-
Object.keys(SKILL_AUTO_ACTIVATION).toSorted((a, b) => a.localeCompare(b))
|
|
80
|
-
)
|
|
78
|
+
export const AUTO_SKILL_ORDER = Object.freeze(Object.keys(SKILL_AUTO_ACTIVATION).toSorted((a, b) => a.localeCompare(b)))
|
|
81
79
|
|
|
82
80
|
/**
|
|
83
81
|
* Похідна view на `SKILL_AUTO_ACTIVATION`: лише скіли з rule-залежностями.
|
|
@@ -32,8 +32,8 @@ const TEST_SUFFIX = '.test.mjs'
|
|
|
32
32
|
/**
|
|
33
33
|
* @typedef {object} CheckableRule
|
|
34
34
|
* @property {string} id ідентифікатор правила (імʼя каталогу `rules/<id>/`)
|
|
35
|
-
* @property {JsConcern[]} jsConcerns
|
|
36
|
-
* @property {PolicyConcern[]} policyConcerns
|
|
35
|
+
* @property {JsConcern[]} jsConcerns JS-концерни правила (алфавітно)
|
|
36
|
+
* @property {PolicyConcern[]} policyConcerns policy-концерни правила (алфавітно)
|
|
37
37
|
*/
|
|
38
38
|
|
|
39
39
|
/**
|
|
@@ -52,7 +52,8 @@ async function listJsConcerns(jsDir) {
|
|
|
52
52
|
for (const entry of topLevel) {
|
|
53
53
|
if (!entry.isDirectory() || entry.name === 'utils' || entry.name.startsWith('.')) continue
|
|
54
54
|
const concernDir = join(jsDir, entry.name)
|
|
55
|
-
const
|
|
55
|
+
const dirContents = await readdir(concernDir)
|
|
56
|
+
const files = dirContents
|
|
56
57
|
.filter(n => CHECK_FILENAME_RE.test(n) && !n.endsWith(TEST_SUFFIX))
|
|
57
58
|
.toSorted((a, b) => a.localeCompare(b))
|
|
58
59
|
if (files.length > 0) {
|
|
@@ -68,7 +68,8 @@ async function runPolicyConcern(bundledRulesDir, ruleId, concernName, walkCache)
|
|
|
68
68
|
if (files.length === 0) {
|
|
69
69
|
if (target.files.required && target.files.single) {
|
|
70
70
|
const msg =
|
|
71
|
-
target.missingMessage ??
|
|
71
|
+
target.missingMessage ??
|
|
72
|
+
`${target.files.single} не існує — створи згідно ${ruleId}.mdc (${ruleId}.${concernName})`
|
|
72
73
|
reporter.fail(msg)
|
|
73
74
|
}
|
|
74
75
|
return reporter.getExitCode()
|
|
@@ -91,7 +92,7 @@ async function runPolicyConcern(bundledRulesDir, ruleId, concernName, walkCache)
|
|
|
91
92
|
|
|
92
93
|
/**
|
|
93
94
|
* Запускає одне правило: applies-гейт → JS-концерни → policy-концерни.
|
|
94
|
-
* @param {import('./discover-checkable-rules.mjs').CheckableRule} rule
|
|
95
|
+
* @param {import('./discover-checkable-rules.mjs').CheckableRule} rule опис правила з discovery
|
|
95
96
|
* @param {string} bundledRulesDir абсолютний шлях до `rules/`
|
|
96
97
|
* @param {Map<string, Promise<string[]>>} walkCache shared cache (один на check-прогон)
|
|
97
98
|
* @returns {Promise<number>} 0 — OK, 1 — є порушення в одному чи більше концернів
|
|
@@ -131,7 +131,6 @@ RUN bun install && bun vite build --mode "prod-$BRANCH" --base="$BASE"
|
|
|
131
131
|
|
|
132
132
|
Те саме стосується `nginx`-конфігів (`server_name`, `proxy_pass` з ru-доменами), `*.sh`-скриптів та `package.json` scripts (`build:ru`, `deploy:ru`, `prod-ru` тощо).
|
|
133
133
|
|
|
134
|
-
|
|
135
134
|
## 5. Переклади
|
|
136
135
|
|
|
137
136
|
Замінити переклад з російської на англійську в @nitra/tfm, @nitra/tf та @nitra/tfm-node. Якщо англійська вже є, то прибираємо російську:
|
|
@@ -175,8 +174,8 @@ const t = tf.bind({ tr })
|
|
|
175
174
|
import { tf } from '@nitra/tfm'
|
|
176
175
|
|
|
177
176
|
const tr = {
|
|
178
|
-
|
|
179
|
-
|
|
177
|
+
Так: { ru: 'Да' },
|
|
178
|
+
Ні: { ru: 'Нет' }
|
|
180
179
|
}
|
|
181
180
|
|
|
182
181
|
на
|
|
@@ -184,11 +183,10 @@ const tr = {
|
|
|
184
183
|
import { tf } from '@nitra/tfm'
|
|
185
184
|
|
|
186
185
|
const tr = {
|
|
187
|
-
|
|
188
|
-
|
|
186
|
+
Так: { ru: 'Yes' },
|
|
187
|
+
Ні: { ru: 'No' }
|
|
189
188
|
}
|
|
190
189
|
|
|
191
|
-
|
|
192
190
|
## 6. Після очистки
|
|
193
191
|
|
|
194
192
|
- Переконайся, що `kustomization.yaml` у кожній директорії `k8s/` не посилається на видалені overlay або файли.
|
|
@@ -51,7 +51,6 @@ description: >-
|
|
|
51
51
|
Видалені файли — `delete`-операція. Нові файли `<slug>.md` — `rewrite`. Модифіковані clean-файли — `merge-into`.
|
|
52
52
|
|
|
53
53
|
4. **Прийняти / відкотити:**
|
|
54
|
-
|
|
55
54
|
- Прийняти все: `git add docs/adr/ && git commit -m "adr: normalize batch"`.
|
|
56
55
|
- Відкотити конкретний файл: `git checkout -- docs/adr/<file>` (для `rewrite` цього мало — треба ще `git restore --staged` і `rm` нового).
|
|
57
56
|
- Відкотити весь батч: `git checkout -- docs/adr/ && git clean -f docs/adr/` (видалить і untracked rewrite-результати).
|