@nitra/cursor 1.13.11 → 1.13.13
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 +26 -0
- package/package.json +1 -1
- package/rules/ci4/ci4.mdc +290 -61
- package/rules/ga/fix/workflows/check.mjs +12 -3
- package/rules/ga/ga.mdc +8 -137
- package/rules/ga/policy/clean_ga_workflows/clean_ga_workflows.rego +38 -49
- package/rules/ga/policy/clean_ga_workflows/template/clean-ga-workflows.yml.snippet.yml +26 -0
- package/rules/ga/policy/clean_merged_branch/clean_merged_branch.rego +55 -57
- package/rules/ga/policy/clean_merged_branch/template/clean-merged-branch.yml.snippet.yml +37 -0
- package/rules/ga/policy/git_ai/git_ai.rego +28 -35
- package/rules/ga/policy/git_ai/template/git-ai.yml.snippet.yml +30 -0
- package/rules/ga/policy/lint_ga/lint_ga.rego +46 -55
- package/rules/ga/policy/lint_ga/template/lint-ga.yml.snippet.yml +35 -0
- package/rules/text/lint/lint.mjs +9 -3
- package/rules/text/lint/run-dotenv-linter.mjs +95 -0
- package/rules/text/text.mdc +5 -3
- package/skills/abie-clean/SKILL.md +9 -4
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: Git AI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
types: [closed]
|
|
6
|
+
|
|
7
|
+
concurrency:
|
|
8
|
+
group: ${{ github.ref }}-${{ github.workflow }}
|
|
9
|
+
cancel-in-progress: true
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
git-ai:
|
|
13
|
+
if: github.event.pull_request.merged == true
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
permissions:
|
|
16
|
+
contents: write
|
|
17
|
+
|
|
18
|
+
steps:
|
|
19
|
+
- name: Install git-ai
|
|
20
|
+
run: |
|
|
21
|
+
curl -fsSL https://usegitai.com/install.sh | bash
|
|
22
|
+
echo "$HOME/.git-ai/bin" >> $GITHUB_PATH
|
|
23
|
+
- name: Run git-ai
|
|
24
|
+
id: run-git-ai
|
|
25
|
+
env:
|
|
26
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
27
|
+
run: |
|
|
28
|
+
git config --global user.name "github-actions[bot]"
|
|
29
|
+
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
|
30
|
+
git-ai ci github run
|
|
@@ -1,44 +1,50 @@
|
|
|
1
|
-
#
|
|
2
|
-
# `npm/scripts/check-ga.mjs` (ga.mdc).
|
|
1
|
+
# Перевірка `.github/workflows/lint-ga.yml` (ga.mdc).
|
|
3
2
|
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
# -p npm/policy/ga --namespace ga.lint_ga
|
|
7
|
-
#
|
|
8
|
-
# Структура каталогу збігається зі шляхом пакету (regal: directory-package-mismatch).
|
|
9
|
-
# Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
|
|
10
|
-
# (.cursor/rules/conftest.mdc). Лінт — `bun run lint-rego` (regal).
|
|
3
|
+
# Канон надходить через --data: { "template": { "snippet": ... } }
|
|
4
|
+
# Структура --data сформована з template/lint-ga.yml.snippet.yml.
|
|
11
5
|
package ga.lint_ga
|
|
12
6
|
|
|
13
7
|
import rego.v1
|
|
14
8
|
|
|
15
|
-
# ──
|
|
16
|
-
|
|
17
|
-
expected_name := "Lint GA"
|
|
18
|
-
|
|
19
|
-
expected_branches := {"dev", "main"}
|
|
20
|
-
|
|
21
|
-
expected_push_paths := {".github/actions/**", ".github/workflows/**"}
|
|
22
|
-
|
|
23
|
-
# ── Аліаси на input ────────────────────────────────────────────────────────
|
|
24
|
-
#
|
|
25
|
-
# YAML 1.1 quirk: `on:` → boolean true → у конфтесті ключ "true".
|
|
9
|
+
# ── Аліаси ─────────────────────────────────────────────────────────────────
|
|
26
10
|
|
|
27
11
|
gha_on := input["true"]
|
|
28
12
|
|
|
29
|
-
# Job-id містить дефіс — звертаємося через `[…]`. Імʼя `job` (без префіксу пакету)
|
|
30
|
-
# — щоб уникнути regal-правила `rule-name-repeats-package`.
|
|
31
13
|
job := input.jobs["lint-ga"]
|
|
32
14
|
|
|
33
|
-
# Усі `uses:` зі steps цього job-а — для перевірки членства.
|
|
34
15
|
job_uses_set contains job.steps[_].uses
|
|
35
16
|
|
|
36
|
-
# Усі `run:` зі steps цього job-а, склеєні в один blob — для substring-перевірки.
|
|
37
17
|
job_run_blob := concat("\n", [run |
|
|
38
18
|
run := job.steps[_].run
|
|
39
19
|
])
|
|
40
20
|
|
|
41
|
-
|
|
21
|
+
expected_name := data.template.snippet.name
|
|
22
|
+
|
|
23
|
+
expected_push_branches := {b | some b in data.template.snippet.on.push.branches}
|
|
24
|
+
|
|
25
|
+
expected_pr_branches := {b | some b in data.template.snippet.on.pull_request.branches}
|
|
26
|
+
|
|
27
|
+
expected_push_paths := {p | some p in data.template.snippet.on.push.paths}
|
|
28
|
+
|
|
29
|
+
expected_runs_on := data.template.snippet.jobs["lint-ga"]["runs-on"]
|
|
30
|
+
|
|
31
|
+
expected_perms := data.template.snippet.jobs["lint-ga"].permissions
|
|
32
|
+
|
|
33
|
+
# Required `uses:` зі template — фільтруємо тільки кроки що мають `uses`.
|
|
34
|
+
expected_uses_set contains u if {
|
|
35
|
+
some step in data.template.snippet.jobs["lint-ga"].steps
|
|
36
|
+
u := object.get(step, "uses", "")
|
|
37
|
+
u != ""
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
# Required `run:` substrings — collected from steps with `run`.
|
|
41
|
+
expected_run_blob := concat("\n", [r |
|
|
42
|
+
some step in data.template.snippet.jobs["lint-ga"].steps
|
|
43
|
+
r := object.get(step, "run", "")
|
|
44
|
+
r != ""
|
|
45
|
+
])
|
|
46
|
+
|
|
47
|
+
# ── deny rules ─────────────────────────────────────────────────────────────
|
|
42
48
|
|
|
43
49
|
deny contains msg if {
|
|
44
50
|
input.name != expected_name
|
|
@@ -46,17 +52,17 @@ deny contains msg if {
|
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
deny contains msg if {
|
|
49
|
-
not
|
|
55
|
+
not branches_superset_of(gha_on.push.branches, expected_push_branches)
|
|
50
56
|
msg := "lint-ga.yml: on.push.branches має містити dev і main (ga.mdc)"
|
|
51
57
|
}
|
|
52
58
|
|
|
53
59
|
deny contains msg if {
|
|
54
|
-
not
|
|
60
|
+
not branches_superset_of(gha_on.pull_request.branches, expected_pr_branches)
|
|
55
61
|
msg := "lint-ga.yml: on.pull_request.branches має містити dev і main (ga.mdc)"
|
|
56
62
|
}
|
|
57
63
|
|
|
58
64
|
deny contains msg if {
|
|
59
|
-
not
|
|
65
|
+
not paths_superset_of(gha_on.push.paths, expected_push_paths)
|
|
60
66
|
msg := "lint-ga.yml: on.push.paths має містити .github/actions/** і .github/workflows/** (ga.mdc)"
|
|
61
67
|
}
|
|
62
68
|
|
|
@@ -66,13 +72,13 @@ deny contains msg if {
|
|
|
66
72
|
}
|
|
67
73
|
|
|
68
74
|
deny contains msg if {
|
|
69
|
-
job["runs-on"] !=
|
|
70
|
-
msg := "lint-ga.yml: runs-on має бути
|
|
75
|
+
job["runs-on"] != expected_runs_on
|
|
76
|
+
msg := sprintf("lint-ga.yml: runs-on має бути %s (ga.mdc)", [expected_runs_on])
|
|
71
77
|
}
|
|
72
78
|
|
|
73
79
|
deny contains msg if {
|
|
74
|
-
job.permissions.contents !=
|
|
75
|
-
msg := "lint-ga.yml: permissions
|
|
80
|
+
job.permissions.contents != expected_perms.contents
|
|
81
|
+
msg := sprintf("lint-ga.yml: permissions.contents має бути %s (ga.mdc)", [expected_perms.contents])
|
|
76
82
|
}
|
|
77
83
|
|
|
78
84
|
deny contains msg if {
|
|
@@ -81,38 +87,23 @@ deny contains msg if {
|
|
|
81
87
|
}
|
|
82
88
|
|
|
83
89
|
deny contains msg if {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
deny contains msg if {
|
|
89
|
-
not "./.github/actions/setup-bun-deps" in job_uses_set
|
|
90
|
-
msg := "lint-ga.yml: має бути uses: ./.github/actions/setup-bun-deps (ga.mdc)"
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
deny contains msg if {
|
|
94
|
-
not "astral-sh/setup-uv@v8.0.0" in job_uses_set
|
|
95
|
-
msg := "lint-ga.yml: має бути uses: astral-sh/setup-uv@v8.0.0 (ga.mdc)"
|
|
90
|
+
some required_use in expected_uses_set
|
|
91
|
+
not required_use in job_uses_set
|
|
92
|
+
msg := sprintf("lint-ga.yml: має бути uses: %s (ga.mdc)", [required_use])
|
|
96
93
|
}
|
|
97
94
|
|
|
98
95
|
deny contains msg if {
|
|
96
|
+
expected_run_blob != ""
|
|
99
97
|
not contains(job_run_blob, "bun run lint-ga")
|
|
100
98
|
msg := "lint-ga.yml: має бути крок run: bun run lint-ga (ga.mdc)"
|
|
101
99
|
}
|
|
102
100
|
|
|
103
101
|
# ── helpers ────────────────────────────────────────────────────────────────
|
|
104
102
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
expected_branches & {b | some b in branches} == expected_branches
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
pr_branches_have_dev_and_main if {
|
|
111
|
-
branches := gha_on.pull_request.branches
|
|
112
|
-
expected_branches & {b | some b in branches} == expected_branches
|
|
103
|
+
branches_superset_of(actual, expected) if {
|
|
104
|
+
expected & {b | some b in actual} == expected
|
|
113
105
|
}
|
|
114
106
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
expected_push_paths & {p | some p in paths} == expected_push_paths
|
|
107
|
+
paths_superset_of(actual, expected) if {
|
|
108
|
+
expected & {p | some p in actual} == expected
|
|
118
109
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: Lint GA
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- dev
|
|
7
|
+
- main
|
|
8
|
+
paths:
|
|
9
|
+
- '.github/actions/**'
|
|
10
|
+
- '.github/workflows/**'
|
|
11
|
+
pull_request:
|
|
12
|
+
branches:
|
|
13
|
+
- dev
|
|
14
|
+
- main
|
|
15
|
+
|
|
16
|
+
concurrency:
|
|
17
|
+
group: ${{ github.ref }}-${{ github.workflow }}
|
|
18
|
+
cancel-in-progress: true
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
lint-ga:
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
permissions:
|
|
24
|
+
contents: read
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@v6
|
|
27
|
+
with:
|
|
28
|
+
persist-credentials: false
|
|
29
|
+
|
|
30
|
+
- uses: ./.github/actions/setup-bun-deps
|
|
31
|
+
|
|
32
|
+
- uses: astral-sh/setup-uv@v8.0.0
|
|
33
|
+
|
|
34
|
+
- name: Lint GA
|
|
35
|
+
run: bun run lint-ga
|
package/rules/text/lint/lint.mjs
CHANGED
|
@@ -2,18 +2,20 @@
|
|
|
2
2
|
* CLI-обгортка над канонічним `lint-text` (text.mdc): послідовно
|
|
3
3
|
* 1) `cspell .` — перевірка правопису з `@nitra/cspell-dict`;
|
|
4
4
|
* 2) `runShellcheckText()` — авто-фікс і фінальна перевірка `*.sh` через `shellcheck`;
|
|
5
|
-
* 3) `
|
|
6
|
-
* 4) `
|
|
5
|
+
* 3) `runDotenvLinter()` — авто-фікс і фінальна перевірка `.env*` через `dotenv-linter`;
|
|
6
|
+
* 4) `bunx markdownlint-cli2 --fix "**\/*.md" "**\/*.mdc"` — авто-фікс Markdown;
|
|
7
|
+
* 5) `runV8rWithGlobs()` — schema-валідація json/json5/yaml/yml/toml через v8r з каталогом `@nitra/cursor`.
|
|
7
8
|
*
|
|
8
9
|
* Перший ненульовий код з ланцюжка повертається як код виходу; наступні кроки не запускаються.
|
|
9
10
|
* Експортовано як `runLintTextCli` — використовується з `bin/n-cursor.js` як підкоманда `lint-text`.
|
|
10
11
|
*/
|
|
11
12
|
import { runLintStep } from '../../../scripts/utils/run-lint-step.mjs'
|
|
13
|
+
import { runDotenvLinter } from './run-dotenv-linter.mjs'
|
|
12
14
|
import { runShellcheckText } from './run-shellcheck.mjs'
|
|
13
15
|
import { runV8rWithGlobs } from './run-v8r.mjs'
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
|
-
* Виконує канонічний `lint-text`: cspell → run-shellcheck → markdownlint-cli2 → run-v8r.
|
|
18
|
+
* Виконує канонічний `lint-text`: cspell → run-shellcheck → run-dotenv-linter → markdownlint-cli2 → run-v8r.
|
|
17
19
|
* Першу помилку повертаємо як код виходу; наступні кроки не запускаються.
|
|
18
20
|
* Усі кроки синхронні (`spawnSync` + sync-ентрі з пакета), тому функція не async.
|
|
19
21
|
* @returns {number} 0 — все OK, інакше — код першого кроку, що впав
|
|
@@ -26,6 +28,10 @@ export function runLintTextCli() {
|
|
|
26
28
|
const shellcheckCode = runShellcheckText()
|
|
27
29
|
if (shellcheckCode !== 0) return shellcheckCode
|
|
28
30
|
|
|
31
|
+
console.log('\n▶ dotenv-linter (авто-фікс + фінальна перевірка .env*)')
|
|
32
|
+
const dotenvCode = runDotenvLinter()
|
|
33
|
+
if (dotenvCode !== 0) return dotenvCode
|
|
34
|
+
|
|
29
35
|
const markdownlintCode = runLintStep('markdownlint', 'bunx', ['markdownlint-cli2', '--fix', '**/*.md', '**/*.mdc'])
|
|
30
36
|
if (markdownlintCode !== 0) return markdownlintCode
|
|
31
37
|
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Запуск dotenv-linter у ланцюжку lint-text: спочатку авто-фікс, потім фінальна перевірка.
|
|
3
|
+
*
|
|
4
|
+
* dotenv-linter — швидкий лінтер для `.env`-файлів (LowercaseKey, DuplicatedKey, IncorrectDelimiter,
|
|
5
|
+
* UnorderedKey тощо). Інструмент очікується у PATH і **не** додається в `dependencies`/`devDependencies`
|
|
6
|
+
* (аналогічно shellcheck). Якщо `dotenv-linter` відсутній — друкуємо підказки встановлення
|
|
7
|
+
* (`brew install dotenv-linter` на macOS) і повертаємо 1.
|
|
8
|
+
*
|
|
9
|
+
* Файли шукає сам `dotenv-linter` у режимі `-r` (рекурсивно по дереву проєкту). Виключаємо
|
|
10
|
+
* `node_modules` і `.envrc` (direnv shell-синтаксис, не key=value формат). `.bak`-файли інструмент
|
|
11
|
+
* ігнорує самостійно. Якщо `.env*`-файлів немає, dotenv-linter повертає 0 ("Nothing to check").
|
|
12
|
+
*
|
|
13
|
+
* Авто-фікс — один прогон `dotenv-linter fix -r --no-backup --quiet . --exclude …` (інструмент сам
|
|
14
|
+
* застосовує усі виправлення без потреби в diff/patch, на відміну від shellcheck). Після цього —
|
|
15
|
+
* фінальний `dotenv-linter check -r --quiet . --exclude …`; будь-яке залишкове порушення — ненульовий
|
|
16
|
+
* код виходу.
|
|
17
|
+
*/
|
|
18
|
+
import { spawnSync } from 'node:child_process'
|
|
19
|
+
import { resolve } from 'node:path'
|
|
20
|
+
|
|
21
|
+
import { isRunAsCli } from '../../../scripts/cli-entry.mjs'
|
|
22
|
+
import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
|
|
23
|
+
|
|
24
|
+
/** Каталоги/файли, які виключаємо з рекурсивного сканування dotenv-linter. */
|
|
25
|
+
const EXCLUDED_PATHS = ['node_modules', '.envrc']
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Друкує підказки встановлення dotenv-linter у stderr.
|
|
29
|
+
* @returns {void}
|
|
30
|
+
*/
|
|
31
|
+
function printDotenvLinterInstallHints() {
|
|
32
|
+
process.stderr.write(
|
|
33
|
+
[
|
|
34
|
+
'❌ dotenv-linter не знайдено в PATH.',
|
|
35
|
+
'Встанови інструмент і повтори lint-text:',
|
|
36
|
+
' macOS: brew install dotenv-linter',
|
|
37
|
+
' Linux: curl -sSfL https://git.io/JLbXn | sh -s -- -b /usr/local/bin',
|
|
38
|
+
' cargo: cargo install dotenv-linter',
|
|
39
|
+
''
|
|
40
|
+
].join('\n')
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Будує перелік аргументів `--exclude <path>` для dotenv-linter.
|
|
46
|
+
* @returns {string[]} плоский масив `['--exclude', 'node_modules', '--exclude', '.envrc']`
|
|
47
|
+
*/
|
|
48
|
+
function buildExcludeArgs() {
|
|
49
|
+
return EXCLUDED_PATHS.flatMap(p => ['--exclude', p])
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Запускає dotenv-linter з авто-фіксом і фінальною перевіркою.
|
|
54
|
+
* @param {string} [cwd] робочий каталог (за замовчуванням `process.cwd()`)
|
|
55
|
+
* @returns {number} 0 — OK; 1 — інструмент відсутній або є залишкові порушення
|
|
56
|
+
*/
|
|
57
|
+
export function runDotenvLinter(cwd = process.cwd()) {
|
|
58
|
+
const root = resolve(cwd)
|
|
59
|
+
const bin = resolveCmd('dotenv-linter')
|
|
60
|
+
if (!bin) {
|
|
61
|
+
printDotenvLinterInstallHints()
|
|
62
|
+
return 1
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const exclude = buildExcludeArgs()
|
|
66
|
+
const fixRun = spawnSync(bin, ['fix', '-r', '--no-backup', '--quiet', ...exclude, '.'], {
|
|
67
|
+
cwd: root,
|
|
68
|
+
encoding: 'utf8',
|
|
69
|
+
env: process.env,
|
|
70
|
+
stdio: ['ignore', 'pipe', 'pipe']
|
|
71
|
+
})
|
|
72
|
+
if (fixRun.error) {
|
|
73
|
+
process.stderr.write(`${fixRun.error.message}\n`)
|
|
74
|
+
return 1
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const checkRun = spawnSync(bin, ['check', '-r', '--quiet', ...exclude, '.'], {
|
|
78
|
+
cwd: root,
|
|
79
|
+
encoding: 'utf8',
|
|
80
|
+
env: process.env,
|
|
81
|
+
stdio: ['ignore', 'pipe', 'pipe']
|
|
82
|
+
})
|
|
83
|
+
if (checkRun.error) {
|
|
84
|
+
process.stderr.write(`${checkRun.error.message}\n`)
|
|
85
|
+
return 1
|
|
86
|
+
}
|
|
87
|
+
if (checkRun.status === 0) return 0
|
|
88
|
+
if (checkRun.stdout?.length) process.stdout.write(checkRun.stdout)
|
|
89
|
+
if (checkRun.stderr?.length) process.stderr.write(checkRun.stderr)
|
|
90
|
+
return 1
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (isRunAsCli()) {
|
|
94
|
+
process.exitCode = runDotenvLinter()
|
|
95
|
+
}
|
package/rules/text/text.mdc
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Обробка та перевірка текстових файлів, oxfmt, cspell, shellcheck (sh), markdownlint-cli2, v8r, CI
|
|
2
|
+
description: Обробка та перевірка текстових файлів, oxfmt, cspell, shellcheck (sh), dotenv-linter (.env*), markdownlint-cli2, v8r, CI
|
|
3
3
|
alwaysApply: true
|
|
4
|
-
version: '1.
|
|
4
|
+
version: '1.27'
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
**oxfmt** (`.oxfmtrc.json`, редактор), **cspell**, **shellcheck** (tracked `*.sh` у `lint-text`), **markdownlint-cli2**, **[v8r](https://chris48s.github.io/v8r/)** ([Schema Store](https://www.schemastore.org/)), розширення **DavidAnson.vscode-markdownlint** / **timonwong.shellcheck**, workflow **`lint-text`**.
|
|
7
|
+
**oxfmt** (`.oxfmtrc.json`, редактор), **cspell**, **shellcheck** (tracked `*.sh` у `lint-text`), **[dotenv-linter](https://dotenv-linter.github.io/)** (`.env*` у `lint-text`), **markdownlint-cli2**, **[v8r](https://chris48s.github.io/v8r/)** ([Schema Store](https://www.schemastore.org/)), розширення **DavidAnson.vscode-markdownlint** / **timonwong.shellcheck**, workflow **`lint-text`**.
|
|
8
8
|
|
|
9
9
|
```json title=".vscode/extensions.json"
|
|
10
10
|
{
|
|
@@ -115,6 +115,8 @@ version: '1.26'
|
|
|
115
115
|
|
|
116
116
|
**shellcheck:** інструмент лише в **`PATH`** (як у **ga.mdc** для `lint-ga`), **не** додавай до `dependencies` / `devDependencies`. Якщо `shellcheck` відсутній — встанови локально (**macOS:** `brew install shellcheck`; **Debian/Ubuntu:** `sudo apt-get install -y shellcheck`; **Arch:** `sudo pacman -S shellcheck`). Канонічний **`lint-text`** делегує до CLI **`n-cursor lint-text`** (бінарка з `node_modules/.bin/` пакету `@nitra/cursor`): після **`cspell .`** виконується **`runShellcheckText()`** з пакета — циклічно **`shellcheck -f diff`** і **`patch -p1`** для авто-виправлень, потім повний прогін **`shellcheck`** по всіх tracked `*.sh` (у git) або по `**/*.sh` без `node_modules`. Потрібен також **`patch`** у `PATH` (на macOS зазвичай уже є).
|
|
117
117
|
|
|
118
|
+
**dotenv-linter:** після shellcheck CLI запускає **`runDotenvLinter()`** з пакета — рекурсивно по `.env*`-файлах проєкту через **`dotenv-linter fix -r --no-backup --quiet . --exclude node_modules --exclude .envrc`**, далі такий самий **`check`** для фінальної перевірки. Інструмент має бути в **`PATH`** і **не** додається в `dependencies` / `devDependencies`. Якщо `dotenv-linter` відсутній — встанови локально (**macOS:** `brew install dotenv-linter`; **Linux:** `curl -sSfL https://git.io/JLbXn | sh -s -- -b /usr/local/bin`; через **cargo:** `cargo install dotenv-linter`).
|
|
119
|
+
|
|
118
120
|
У v8r **немає** прапорця тихого режиму; CLI-обгортка **`n-cursor lint-text`** на четвертому кроці викликає **`runV8rWithGlobs()`** з пакета (реалізація — `npm/rules/text/js/run-v8r.mjs`): під капотом послідовні **`bunx v8r`** для кожного типу (**json**, **json5**, **yml**, **yaml**, **toml**), бо один процес v8r з кількома глобами падає з **98**, якщо хоч один glob порожній, і тоді інші розширення не перевіряються. Вивід при кодах **0** і **98** не показується. Каталог схем **`schemas/v8r-catalog.json`** пакета `@nitra/cursor` обгортка підставляє в v8r сама.
|
|
119
121
|
|
|
120
122
|
```json title="package.json"
|
|
@@ -9,12 +9,16 @@ version: '1.1'
|
|
|
9
9
|
|
|
10
10
|
Скіл прибирає з проєкту все, що належить **ru-середовищу**. Залишаються тільки `dev` (як база) та `ua` як активне продакшн-середовище. Працюй послідовно по секціях нижче — після кожної секції перевіряй, що проєкт лишається консистентним (`kustomization.yaml` посилається лише на наявні файли, GitHub Actions-вирази синтаксично коректні).
|
|
11
11
|
|
|
12
|
+
## 0. Що НЕ чіпати
|
|
13
|
+
|
|
14
|
+
**`node_modules/`** (і будь-які `**/node_modules/`) — повністю виключаються з аналізу й модифікацій. Це згенеровані залежності: збіги на `ru`, `values-ru.*`, `cr.yandex` тощо там нерелевантні і відновляться при наступному `install`. Усі `find` / `git grep` / автозаміни мають пропускати ці шляхи. Аналогічно не чіпай `.git/`, `dist/`, `build/`, `.next/`, `.nuxt/`, `.output/`, `coverage/`.
|
|
15
|
+
|
|
12
16
|
## 1. Директорії з назвою `ru`
|
|
13
17
|
|
|
14
|
-
Видали всі директорії з назвою `ru` у
|
|
18
|
+
Видали всі директорії з назвою `ru` у проєкті (крім тих, що всередині `node_modules`):
|
|
15
19
|
|
|
16
20
|
```bash
|
|
17
|
-
find . -type d -name "ru" -exec rm -rf {} +
|
|
21
|
+
find . -type d \( -name node_modules -o -name .git \) -prune -o -type d -name "ru" -print -exec rm -rf {} +
|
|
18
22
|
```
|
|
19
23
|
|
|
20
24
|
Це чистить як `country/ru/`, так і `k8s/<...>/ru/` (overlay у kustomize). Після видалення overlay `ru/` обов’язково прибери відповідний запис у `resources:` у батьківському `kustomization.yaml`, якщо він там лишився.
|
|
@@ -27,7 +31,8 @@ find . -type d -name "ru" -exec rm -rf {} +
|
|
|
27
31
|
- будь-які файли, що закінчуються на `-ru` або `-ru.<ext>`, наприклад `site/.env.prod-ru`, `*.env.prod-ru`, `*.prod-ru.conf`
|
|
28
32
|
|
|
29
33
|
```bash
|
|
30
|
-
find . -type
|
|
34
|
+
find . -type d \( -name node_modules -o -name .git \) -prune -o \
|
|
35
|
+
-type f \( -name "values-ru.*" -o -name "*-ru" -o -name "*.prod-ru" -o -name "*.prod-ru.*" \) -print -delete
|
|
31
36
|
```
|
|
32
37
|
|
|
33
38
|
## 3. `.github/workflows/*.yml`
|
|
@@ -194,5 +199,5 @@ const tr = {
|
|
|
194
199
|
## 6. Після очистки
|
|
195
200
|
|
|
196
201
|
- Переконайся, що `kustomization.yaml` у кожній директорії `k8s/` не посилається на видалені overlay або файли.
|
|
197
|
-
- Пройдись `git grep` по репозиторію на залишки: `git grep -n -i -e '\bru\b' -e cr\.yandex -e country/ru -e prod-ru -e values-ru -e "'ya'"` — переглянь усі знахідки вручну, бо `ru` як слово може траплятися в легітимних контекстах (наприклад, `truncate`, `Aurum`, `cruft`). Видаляй лише ті входження, що належать ru-середовищу.
|
|
202
|
+
- Пройдись `git grep` по репозиторію на залишки: `git grep -n -i -e '\bru\b' -e cr\.yandex -e country/ru -e prod-ru -e values-ru -e "'ya'"` — переглянь усі знахідки вручну, бо `ru` як слово може траплятися в легітимних контекстах (наприклад, `truncate`, `Aurum`, `cruft`). Видаляй лише ті входження, що належать ru-середовищу. `git grep` за замовчуванням пропускає невідстежувані шляхи, тож `node_modules/` у вихід не потрапить, поки воно у `.gitignore`.
|
|
198
203
|
- Перевір CI локально: `npx @nitra/cursor check abie` (якщо правило **abie** ввімкнене у проєкті).
|