@nitra/cursor 1.13.38 → 1.13.40
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 +12 -0
- package/bin/n-cursor.js +4 -0
- package/package.json +1 -1
- package/rules/ga/lint/lint.mjs +23 -3
- package/rules/ga/policy/lint_ga/lint_ga.rego +6 -0
- package/rules/ga/policy/lint_ga/template/lint-ga.yml.snippet.yml +6 -0
- package/rules/text/fix/formatting/check.mjs +1 -1
- package/rules/text/lint/lint.mjs +113 -5
- package/rules/text/policy/lint_text/lint_text.rego +100 -0
- package/rules/text/policy/lint_text/target.json +4 -0
- package/rules/text/policy/lint_text/template/lint-text.yml.snippet.yml +61 -0
- package/rules/text/text.mdc +3 -57
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,18 @@
|
|
|
4
4
|
|
|
5
5
|
Формат — [Keep a Changelog](https://keepachangelog.com/uk/1.1.0/), нумерація — [SemVer](https://semver.org/lang/uk/).
|
|
6
6
|
|
|
7
|
+
## [1.13.40] - 2026-05-18
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- `lint-text` CLI: preflight на `shellcheck`, `patch` і `dotenv-linter` до ланцюжка cspell/shellcheck/dotenv. Канон `lint-text.yml.snippet.yml` — кроки `Install shellcheck` (apt) і `Install dotenv-linter` (curl); rego `text.lint_text`. Bump `text.mdc` `1.28` → `1.29`.
|
|
12
|
+
|
|
13
|
+
## [1.13.39] - 2026-05-18
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- `lint-ga` CLI: preflight на `conftest` (поряд із `shellcheck`/`uv`) з install-hint; глобальний `catch` у `bin/n-cursor.js` більше не ковтає повідомлення `failConftestMissing()`. Канон `lint-ga.yml.snippet.yml` — крок `Install conftest` для CI; rego `ga.lint_ga` вимагає curl на release conftest.
|
|
18
|
+
|
|
7
19
|
## [1.13.38] - 2026-05-18
|
|
8
20
|
|
|
9
21
|
### Added
|
package/bin/n-cursor.js
CHANGED
|
@@ -1405,7 +1405,11 @@ try {
|
|
|
1405
1405
|
} catch (error) {
|
|
1406
1406
|
if (error instanceof ReexecHandoff) {
|
|
1407
1407
|
process.exitCode = error.code
|
|
1408
|
+
} else if (error instanceof Error && error.message) {
|
|
1409
|
+
console.error(error.message)
|
|
1410
|
+
process.exitCode = 1
|
|
1408
1411
|
} else {
|
|
1412
|
+
console.error(error)
|
|
1409
1413
|
process.exitCode = 1
|
|
1410
1414
|
}
|
|
1411
1415
|
}
|
package/package.json
CHANGED
package/rules/ga/lint/lint.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CLI-обгортка над канонічним `lint-ga` (ga.mdc): робить preflight на `shellcheck
|
|
2
|
+
* CLI-обгортка над канонічним `lint-ga` (ga.mdc): робить preflight на `shellcheck`, `uv` (для `uvx`)
|
|
3
|
+
* і `conftest` (для rego-полісі у `check-ga`),
|
|
3
4
|
* тоді послідовно виконує `bunx github-actionlint`, `uvx zizmor --offline --collect=workflows .` і
|
|
4
5
|
* делегує до `check-ga.mjs::check()` — там і Rego-частина (через `runConftestBatch`),
|
|
5
6
|
* і JS cross-file перевірки правил `ga.mdc`.
|
|
@@ -17,6 +18,10 @@
|
|
|
17
18
|
* `uv` потрібен для `uvx zizmor`. Якщо його нема — `uvx zizmor` падає неінформативно («command not
|
|
18
19
|
* found»); підказка з командою встановлення коротша й корисніша.
|
|
19
20
|
*
|
|
21
|
+
* `conftest` потрібен для `check-ga.mjs::runAllGaRego` (`runConftestBatch`). Без preflight крок
|
|
22
|
+
* check-ga кидає виняток, який глобальний `catch` у `bin/n-cursor.js` раніше ковтав без логу —
|
|
23
|
+
* локально це виглядало як мовчазний exit 1.
|
|
24
|
+
*
|
|
20
25
|
* Експортовано окремо `runLintGaCli` — використовується з `bin/n-cursor.js` як підкоманда `lint-ga`.
|
|
21
26
|
*/
|
|
22
27
|
import { platform } from 'node:process'
|
|
@@ -68,6 +73,21 @@ const UV_PREFLIGHT = {
|
|
|
68
73
|
successMsg: '✅ uv знайдено в PATH — uvx zizmor запуститься'
|
|
69
74
|
}
|
|
70
75
|
|
|
76
|
+
/** @type {PreflightDep} */
|
|
77
|
+
const CONFTEST_PREFLIGHT = {
|
|
78
|
+
bin: 'conftest',
|
|
79
|
+
winBins: ['conftest.exe'],
|
|
80
|
+
explanation: [
|
|
81
|
+
'Без нього не запускається пер-документна валідація через rego-полісі (npm/rules/*/policy/)',
|
|
82
|
+
'у кроці check-ga — `runConftestBatch` завершується hard-fail.'
|
|
83
|
+
].join('\n '),
|
|
84
|
+
install: [
|
|
85
|
+
'macOS: brew install conftest',
|
|
86
|
+
'Universal: https://www.conftest.dev/install/'
|
|
87
|
+
],
|
|
88
|
+
successMsg: '✅ conftest знайдено в PATH — check-ga виконає rego-полісі через runConftestBatch'
|
|
89
|
+
}
|
|
90
|
+
|
|
71
91
|
/**
|
|
72
92
|
* Шукає бінарник у PATH з урахуванням Windows: спершу `winBins`, потім `bin`.
|
|
73
93
|
* @param {PreflightDep} dep опис залежності
|
|
@@ -116,7 +136,7 @@ function preflight(dep) {
|
|
|
116
136
|
* Виконує канонічний `lint-ga` з preflight-перевірками і делегує до `check-ga.check()`.
|
|
117
137
|
*
|
|
118
138
|
* Послідовність:
|
|
119
|
-
* 1) preflight: `shellcheck` (для
|
|
139
|
+
* 1) preflight: `shellcheck`, `uv` (для `uvx zizmor`) і `conftest` (для check-ga); відсутній → exit 1;
|
|
120
140
|
* 2) `bunx github-actionlint`;
|
|
121
141
|
* 3) `uvx zizmor --offline --collect=workflows .`;
|
|
122
142
|
* 4) `check-ga.mjs::check()` — Rego-полісі (батч conftest з `npm/policy/ga/`) + JS cross-file
|
|
@@ -132,7 +152,7 @@ function preflight(dep) {
|
|
|
132
152
|
*/
|
|
133
153
|
export async function runLintGaCli() {
|
|
134
154
|
let preflightOk = true
|
|
135
|
-
for (const dep of [SHELLCHECK_PREFLIGHT, UV_PREFLIGHT]) {
|
|
155
|
+
for (const dep of [SHELLCHECK_PREFLIGHT, UV_PREFLIGHT, CONFTEST_PREFLIGHT]) {
|
|
136
156
|
if (!preflight(dep)) preflightOk = false
|
|
137
157
|
}
|
|
138
158
|
if (!preflightOk) return 1
|
|
@@ -92,6 +92,12 @@ deny contains msg if {
|
|
|
92
92
|
msg := sprintf("lint-ga.yml: має бути uses: %s (ga.mdc)", [required_use])
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
deny contains msg if {
|
|
96
|
+
expected_run_blob != ""
|
|
97
|
+
not contains(job_run_blob, "open-policy-agent/conftest")
|
|
98
|
+
msg := "lint-ga.yml: має бути крок Install conftest (ga.mdc)"
|
|
99
|
+
}
|
|
100
|
+
|
|
95
101
|
deny contains msg if {
|
|
96
102
|
expected_run_blob != ""
|
|
97
103
|
not contains(job_run_blob, "bun run lint-ga")
|
|
@@ -31,5 +31,11 @@ jobs:
|
|
|
31
31
|
|
|
32
32
|
- uses: astral-sh/setup-uv@v8.0.0
|
|
33
33
|
|
|
34
|
+
- name: Install conftest
|
|
35
|
+
run: >-
|
|
36
|
+
curl -fsSL
|
|
37
|
+
https://github.com/open-policy-agent/conftest/releases/download/v0.62.0/conftest_0.62.0_Linux_x86_64.tar.gz
|
|
38
|
+
| sudo tar -xz -C /usr/local/bin conftest
|
|
39
|
+
|
|
34
40
|
- name: Lint GA
|
|
35
41
|
run: bun run lint-ga
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* `npm/mdc/text.mdc` (markdown-текст, не JSON/YAML);
|
|
13
13
|
* - складна валідація скрипта `lint-text` (cspell, markdownlint, v8r у трьох
|
|
14
14
|
* варіантах, run-shellcheck-text.mjs, обовʼязкові glob-и);
|
|
15
|
-
* - workflow `lint-text.yml` має крок `bun run lint-text
|
|
15
|
+
* - workflow `lint-text.yml` має крок `bun run lint-text` (структура — rego `text.lint_text`).
|
|
16
16
|
*
|
|
17
17
|
* **Що покрила Rego** (`npx \@nitra/cursor check`):
|
|
18
18
|
* - `npm/policy/text/oxfmtrc/` — обовʼязкові ключі `.oxfmtrc.json` і канонічні
|
package/rules/text/lint/lint.mjs
CHANGED
|
@@ -1,26 +1,134 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CLI-обгортка над канонічним `lint-text` (text.mdc):
|
|
2
|
+
* CLI-обгортка над канонічним `lint-text` (text.mdc): preflight на `shellcheck`, `patch`
|
|
3
|
+
* (для авто-фіксу shellcheck) і `dotenv-linter`; далі послідовно
|
|
3
4
|
* 1) `cspell .` — перевірка правопису з `@nitra/cspell-dict`;
|
|
4
5
|
* 2) `runShellcheckText()` — авто-фікс і фінальна перевірка `*.sh` через `shellcheck`;
|
|
5
6
|
* 3) `runDotenvLinter()` — авто-фікс і фінальна перевірка `.env*` через `dotenv-linter`;
|
|
6
7
|
* 4) `bunx markdownlint-cli2 --fix "**\/*.md" "**\/*.mdc"` — авто-фікс Markdown;
|
|
7
|
-
* 5) `runV8rWithGlobs()` — schema-валідація json/json5/yaml/yml/toml через v8r
|
|
8
|
+
* 5) `runV8rWithGlobs()` — schema-валідація json/json5/yaml/yml/toml через v8r.
|
|
9
|
+
*
|
|
10
|
+
* Без preflight локальний прогін може пройти cspell/markdownlint, а CI на ubuntu-latest
|
|
11
|
+
* (де shellcheck передвстановлений, але dotenv-linter — ні) падає на кроці dotenv-linter
|
|
12
|
+
* з неінформативним повідомленням. Preflight збирає всі відсутні бінарники до першого кроку.
|
|
8
13
|
*
|
|
9
14
|
* Перший ненульовий код з ланцюжка повертається як код виходу; наступні кроки не запускаються.
|
|
10
15
|
* Експортовано як `runLintTextCli` — використовується з `bin/n-cursor.js` як підкоманда `lint-text`.
|
|
11
16
|
*/
|
|
17
|
+
import { platform } from 'node:process'
|
|
18
|
+
|
|
12
19
|
import { runLintStep } from '../../../scripts/utils/run-lint-step.mjs'
|
|
20
|
+
import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
|
|
13
21
|
import { runDotenvLinter } from './run-dotenv-linter.mjs'
|
|
14
22
|
import { runShellcheckText } from './run-shellcheck.mjs'
|
|
15
23
|
import { runV8rWithGlobs } from './run-v8r.mjs'
|
|
16
24
|
|
|
17
25
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
26
|
+
* Опис залежності preflight-ом.
|
|
27
|
+
* @typedef {object} PreflightDep
|
|
28
|
+
* @property {string} bin ім'я виконуваного файлу
|
|
29
|
+
* @property {string[]} [winBins] альтернативні імена на Windows
|
|
30
|
+
* @property {string} explanation наслідки відсутності
|
|
31
|
+
* @property {string[]} install команди встановлення
|
|
32
|
+
* @property {string} successMsg повідомлення на pass-шлях
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/** @type {PreflightDep} */
|
|
36
|
+
const SHELLCHECK_PREFLIGHT = {
|
|
37
|
+
bin: 'shellcheck',
|
|
38
|
+
winBins: ['shellcheck.exe'],
|
|
39
|
+
explanation: [
|
|
40
|
+
'Без нього `runShellcheckText()` пропускає перевірку tracked `*.sh` — локально lint-text',
|
|
41
|
+
'може бути зеленим, а CI (shellcheck + patch) падає на тих самих скриптах.'
|
|
42
|
+
].join('\n '),
|
|
43
|
+
install: [
|
|
44
|
+
'macOS: brew install shellcheck',
|
|
45
|
+
'Debian/Ubuntu: sudo apt-get install -y shellcheck',
|
|
46
|
+
'Arch: sudo pacman -S shellcheck'
|
|
47
|
+
],
|
|
48
|
+
successMsg: '✅ shellcheck знайдено в PATH — lint-text перевірить *.sh'
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** @type {PreflightDep} */
|
|
52
|
+
const PATCH_PREFLIGHT = {
|
|
53
|
+
bin: 'patch',
|
|
54
|
+
explanation: [
|
|
55
|
+
'Без `patch` не застосуються авто-виправлення shellcheck (`shellcheck -f diff` + `patch -p1`).'
|
|
56
|
+
].join('\n '),
|
|
57
|
+
install: [
|
|
58
|
+
'macOS: зазвичай уже є в системі',
|
|
59
|
+
'Debian/Ubuntu: sudo apt-get install -y patch'
|
|
60
|
+
],
|
|
61
|
+
successMsg: '✅ patch знайдено в PATH — shellcheck auto-fix працюватиме'
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** @type {PreflightDep} */
|
|
65
|
+
const DOTENV_LINTER_PREFLIGHT = {
|
|
66
|
+
bin: 'dotenv-linter',
|
|
67
|
+
winBins: ['dotenv-linter.exe'],
|
|
68
|
+
explanation: [
|
|
69
|
+
'Без нього не виконається крок `.env*` у lint-text — локально cspell/markdownlint',
|
|
70
|
+
'пройдуть, а CI без Install dotenv-linter впаде неінформативно.'
|
|
71
|
+
].join('\n '),
|
|
72
|
+
install: [
|
|
73
|
+
'macOS: brew install dotenv-linter',
|
|
74
|
+
'Linux: curl -sSfL https://git.io/JLbXn | sh -s -- -b /usr/local/bin',
|
|
75
|
+
'cargo: cargo install dotenv-linter'
|
|
76
|
+
],
|
|
77
|
+
successMsg: '✅ dotenv-linter знайдено в PATH — lint-text перевірить .env*'
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @param {PreflightDep} dep
|
|
82
|
+
* @returns {string | null}
|
|
83
|
+
*/
|
|
84
|
+
function resolvePreflightBin(dep) {
|
|
85
|
+
if (platform === 'win32' && dep.winBins) {
|
|
86
|
+
for (const name of dep.winBins) {
|
|
87
|
+
const r = resolveCmd(name)
|
|
88
|
+
if (r) return r
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return resolveCmd(dep.bin)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @param {PreflightDep} dep
|
|
96
|
+
* @returns {void}
|
|
97
|
+
*/
|
|
98
|
+
function printPreflightMissingMessage(dep) {
|
|
99
|
+
console.error(`❌ ${dep.bin} не знайдено в PATH.`)
|
|
100
|
+
console.error(` ${dep.explanation}`)
|
|
101
|
+
console.error(' Встанови:')
|
|
102
|
+
for (const line of dep.install) {
|
|
103
|
+
console.error(` ${line}`)
|
|
104
|
+
}
|
|
105
|
+
console.error(' Деталі: text.mdc → секція про lint-text.')
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* @param {PreflightDep} dep
|
|
110
|
+
* @returns {boolean}
|
|
111
|
+
*/
|
|
112
|
+
function preflight(dep) {
|
|
113
|
+
if (resolvePreflightBin(dep)) {
|
|
114
|
+
console.log(dep.successMsg)
|
|
115
|
+
return true
|
|
116
|
+
}
|
|
117
|
+
printPreflightMissingMessage(dep)
|
|
118
|
+
return false
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Виконує канонічний `lint-text` з preflight і ланцюжком cspell → shellcheck → dotenv → markdownlint → v8r.
|
|
21
123
|
* @returns {number} 0 — все OK, інакше — код першого кроку, що впав
|
|
22
124
|
*/
|
|
23
125
|
export function runLintTextCli() {
|
|
126
|
+
let preflightOk = true
|
|
127
|
+
for (const dep of [SHELLCHECK_PREFLIGHT, PATCH_PREFLIGHT, DOTENV_LINTER_PREFLIGHT]) {
|
|
128
|
+
if (!preflight(dep)) preflightOk = false
|
|
129
|
+
}
|
|
130
|
+
if (!preflightOk) return 1
|
|
131
|
+
|
|
24
132
|
const cspellCode = runLintStep('cspell', 'npx', ['cspell', '.'])
|
|
25
133
|
if (cspellCode !== 0) return cspellCode
|
|
26
134
|
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Перевірка `.github/workflows/lint-text.yml` (text.mdc).
|
|
2
|
+
#
|
|
3
|
+
# Канон надходить через --data: { "template": { "snippet": ... } }
|
|
4
|
+
# Структура --data сформована з template/lint-text.yml.snippet.yml.
|
|
5
|
+
# Універсальні workflow-перевірки (checkout, permissions) — у `ga.workflow_common`.
|
|
6
|
+
package text.lint_text
|
|
7
|
+
|
|
8
|
+
import rego.v1
|
|
9
|
+
|
|
10
|
+
expected_name := data.template.snippet.name
|
|
11
|
+
|
|
12
|
+
expected_push_branches := {b | some b in data.template.snippet.on.push.branches}
|
|
13
|
+
|
|
14
|
+
expected_pr_branches := {b | some b in data.template.snippet.on.pull_request.branches}
|
|
15
|
+
|
|
16
|
+
expected_push_paths := {p | some p in data.template.snippet.on.push.paths}
|
|
17
|
+
|
|
18
|
+
expected_runs_on := data.template.snippet.jobs.text["runs-on"]
|
|
19
|
+
|
|
20
|
+
expected_perms := data.template.snippet.jobs.text.permissions
|
|
21
|
+
|
|
22
|
+
job := input.jobs.text
|
|
23
|
+
|
|
24
|
+
job_uses_set contains job.steps[_].uses
|
|
25
|
+
|
|
26
|
+
job_run_blob := concat("\n", [run |
|
|
27
|
+
run := job.steps[_].run
|
|
28
|
+
])
|
|
29
|
+
|
|
30
|
+
expected_uses_set contains u if {
|
|
31
|
+
some step in data.template.snippet.jobs.text.steps
|
|
32
|
+
u := object.get(step, "uses", "")
|
|
33
|
+
u != ""
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
expected_run_substrings contains r if {
|
|
37
|
+
some step in data.template.snippet.jobs.text.steps
|
|
38
|
+
r := object.get(step, "run", "")
|
|
39
|
+
r != ""
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
deny contains msg if {
|
|
43
|
+
input.name != expected_name
|
|
44
|
+
msg := sprintf("lint-text.yml: name має бути %q (text.mdc)", [expected_name])
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
deny contains msg if {
|
|
48
|
+
not branches_superset_of(input.on.push.branches, expected_push_branches)
|
|
49
|
+
msg := "lint-text.yml: on.push.branches має містити dev і main (text.mdc)"
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
deny contains msg if {
|
|
53
|
+
not branches_superset_of(input.on.pull_request.branches, expected_pr_branches)
|
|
54
|
+
msg := "lint-text.yml: on.pull_request.branches має містити dev і main (text.mdc)"
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
deny contains msg if {
|
|
58
|
+
not paths_superset_of(input.on.push.paths, expected_push_paths)
|
|
59
|
+
msg := "lint-text.yml: on.push.paths має містити очікувані glob-и (text.mdc)"
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
deny contains msg if {
|
|
63
|
+
not job
|
|
64
|
+
msg := "lint-text.yml: jobs.text відсутній (text.mdc)"
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
deny contains msg if {
|
|
68
|
+
job["runs-on"] != expected_runs_on
|
|
69
|
+
msg := sprintf("lint-text.yml: runs-on має бути %s (text.mdc)", [expected_runs_on])
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
deny contains msg if {
|
|
73
|
+
job.permissions.contents != expected_perms.contents
|
|
74
|
+
msg := sprintf("lint-text.yml: permissions.contents має бути %s (text.mdc)", [expected_perms.contents])
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
deny contains msg if {
|
|
78
|
+
count(job.steps) == 0
|
|
79
|
+
msg := "lint-text.yml: jobs.text.steps відсутні (text.mdc)"
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
deny contains msg if {
|
|
83
|
+
some required_use in expected_uses_set
|
|
84
|
+
not required_use in job_uses_set
|
|
85
|
+
msg := sprintf("lint-text.yml: має бути uses: %s (text.mdc)", [required_use])
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
deny contains msg if {
|
|
89
|
+
some required_run in expected_run_substrings
|
|
90
|
+
not contains(job_run_blob, required_run)
|
|
91
|
+
msg := sprintf("lint-text.yml: жоден крок run не містить %q (text.mdc)", [required_run])
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
branches_superset_of(actual, expected) if {
|
|
95
|
+
expected & {b | some b in actual} == expected
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
paths_superset_of(actual, expected) if {
|
|
99
|
+
expected & {p | some p in actual} == expected
|
|
100
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
name: Lint Text
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- dev
|
|
7
|
+
- main
|
|
8
|
+
paths:
|
|
9
|
+
- '**/*.js'
|
|
10
|
+
- '**/*.ts'
|
|
11
|
+
- '**/*.vue'
|
|
12
|
+
- '**/*.html'
|
|
13
|
+
- '**/*.css'
|
|
14
|
+
- '**/*.scss'
|
|
15
|
+
- '**/*.less'
|
|
16
|
+
- '**/*.json'
|
|
17
|
+
- '**/*.jsonc'
|
|
18
|
+
- '**/*.yaml'
|
|
19
|
+
- '**/*.yml'
|
|
20
|
+
- '**/*.toml'
|
|
21
|
+
- '**/*.xml'
|
|
22
|
+
- '**/*.md'
|
|
23
|
+
- '**/*.mdc'
|
|
24
|
+
- '**/*.mdс'
|
|
25
|
+
- '**/*.txt'
|
|
26
|
+
- '**/*.go'
|
|
27
|
+
- '**/*.py'
|
|
28
|
+
- '**/*.php'
|
|
29
|
+
- '**/*.sh'
|
|
30
|
+
|
|
31
|
+
pull_request:
|
|
32
|
+
branches:
|
|
33
|
+
- dev
|
|
34
|
+
- main
|
|
35
|
+
|
|
36
|
+
concurrency:
|
|
37
|
+
group: ${{ github.ref }}-${{ github.workflow }}
|
|
38
|
+
cancel-in-progress: true
|
|
39
|
+
|
|
40
|
+
jobs:
|
|
41
|
+
text:
|
|
42
|
+
runs-on: ubuntu-latest
|
|
43
|
+
permissions:
|
|
44
|
+
contents: read
|
|
45
|
+
steps:
|
|
46
|
+
- uses: actions/checkout@v6
|
|
47
|
+
with:
|
|
48
|
+
persist-credentials: false
|
|
49
|
+
|
|
50
|
+
- uses: ./.github/actions/setup-bun-deps
|
|
51
|
+
|
|
52
|
+
- name: Install shellcheck
|
|
53
|
+
run: sudo apt-get update && sudo apt-get install -y shellcheck
|
|
54
|
+
|
|
55
|
+
- name: Install dotenv-linter
|
|
56
|
+
run: >-
|
|
57
|
+
curl -sSfL https://git.io/JLbXn
|
|
58
|
+
| sh -s -- -b /usr/local/bin
|
|
59
|
+
|
|
60
|
+
- name: Lint text
|
|
61
|
+
run: bun run lint-text
|
package/rules/text/text.mdc
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Обробка та перевірка текстових файлів, oxfmt, cspell, shellcheck (sh), dotenv-linter (.env*), markdownlint-cli2, v8r, CI
|
|
3
3
|
alwaysApply: true
|
|
4
|
-
version: '1.
|
|
4
|
+
version: '1.29'
|
|
5
5
|
---
|
|
6
6
|
|
|
7
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`**.
|
|
@@ -172,63 +172,9 @@ version: '1.28'
|
|
|
172
172
|
|
|
173
173
|
Додай workflow `.github/workflows/lint-text.yml`:
|
|
174
174
|
|
|
175
|
-
|
|
176
|
-
name: Lint Text
|
|
177
|
-
|
|
178
|
-
on:
|
|
179
|
-
push:
|
|
180
|
-
branches:
|
|
181
|
-
- dev
|
|
182
|
-
- main
|
|
183
|
-
paths:
|
|
184
|
-
- '**/*.js'
|
|
185
|
-
- '**/*.ts'
|
|
186
|
-
- '**/*.vue'
|
|
187
|
-
- '**/*.html'
|
|
188
|
-
- '**/*.css'
|
|
189
|
-
- '**/*.scss'
|
|
190
|
-
- '**/*.less'
|
|
191
|
-
- '**/*.json'
|
|
192
|
-
- '**/*.jsonc'
|
|
193
|
-
- '**/*.yaml'
|
|
194
|
-
- '**/*.yml'
|
|
195
|
-
- '**/*.toml'
|
|
196
|
-
- '**/*.xml'
|
|
197
|
-
- '**/*.md'
|
|
198
|
-
- '**/*.mdc'
|
|
199
|
-
- '**/*.mdс'
|
|
200
|
-
- '**/*.txt'
|
|
201
|
-
- '**/*.go'
|
|
202
|
-
- '**/*.py'
|
|
203
|
-
- '**/*.php'
|
|
204
|
-
- '**/*.sh'
|
|
205
|
-
|
|
206
|
-
pull_request:
|
|
207
|
-
branches:
|
|
208
|
-
- dev
|
|
209
|
-
- main
|
|
210
|
-
|
|
211
|
-
concurrency:
|
|
212
|
-
group: ${{ github.ref }}-${{ github.workflow }}
|
|
213
|
-
cancel-in-progress: true
|
|
214
|
-
|
|
215
|
-
jobs:
|
|
216
|
-
text:
|
|
217
|
-
runs-on: ubuntu-latest
|
|
218
|
-
permissions:
|
|
219
|
-
contents: read
|
|
220
|
-
steps:
|
|
221
|
-
- uses: actions/checkout@v6
|
|
222
|
-
with:
|
|
223
|
-
persist-credentials: false
|
|
224
|
-
|
|
225
|
-
- uses: ./.github/actions/setup-bun-deps
|
|
226
|
-
|
|
227
|
-
- name: Lint text
|
|
228
|
-
run: bun run lint-text
|
|
229
|
-
```
|
|
175
|
+
- Канон: [lint-text.yml.snippet.yml](./policy/lint_text/template/lint-text.yml.snippet.yml)
|
|
230
176
|
|
|
231
|
-
Перед **`./.github/actions/setup-bun-deps`** — **`actions/checkout@v6`** (див. **ga.mdc**). Composite: Node 24, Bun, кеш, `bun install --frozen-lockfile`.
|
|
177
|
+
Перед **`./.github/actions/setup-bun-deps`** — **`actions/checkout@v6`** (див. **ga.mdc**). Після composite — кроки **`Install shellcheck`** (apt) і **`Install dotenv-linter`** (curl), бо `n-cursor lint-text` вимагає обидва бінарники в PATH; на ubuntu-latest shellcheck часто вже є, dotenv-linter — ні. Composite: Node 24, Bun, кеш, `bun install --frozen-lockfile`.
|
|
232
178
|
|
|
233
179
|
Не дублюй окремий workflow з тими самими кроками cspell/markdownlint.
|
|
234
180
|
|