@7n/rules 1.5.0 → 1.6.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/.claude-template/hooks/.gitignore.snippet +9 -0
- package/CHANGELOG.md +12 -0
- package/bin/n-rules.js +83 -21
- package/package.json +1 -1
- package/rules/abie/main.mdc +0 -6
- package/rules/js/check/docs/main.md +1 -1
- package/rules/js/check/main.mjs +6 -10
- package/rules/js/main.mdc +0 -1
- package/rules/js/vscode_extensions/template/extensions.json.snippet.json +4 -1
- package/rules/npm-module/main.mdc +0 -2
- package/rules/php/tooling/docs/main.md +1 -1
- package/rules/php/tooling/main.mjs +2 -7
- package/rules/python/tooling/docs/main.md +1 -1
- package/rules/python/tooling/main.mjs +2 -7
- package/rules/rego/lib/docs/run-external-tool.md +1 -2
- package/rules/rego/lib/run-external-tool.mjs +4 -1
- package/rules/security/main.mdc +0 -1
- package/rules/style/main.mdc +0 -1
- package/rules/style/tooling/docs/main.md +1 -1
- package/rules/style/tooling/main.mjs +2 -7
- package/rules/tauri/release/release.mdc +1 -1
- package/rules/text/formatting/docs/main.md +1 -1
- package/rules/text/formatting/main.mjs +11 -11
- package/rules/text/main.mdc +0 -1
- package/scripts/docs/skills-cli.md +3 -3
- package/scripts/docs/sync-claude-config.md +1 -1
- package/scripts/lib/acp-runner.mjs +8 -10
- package/scripts/lib/docs/acp-runner.md +5 -5
- package/scripts/lib/docs/mirror-parity.md +1 -1
- package/scripts/lib/mirror-parity.mjs +49 -16
- package/scripts/skills-cli.mjs +1 -1
- package/scripts/sync-claude-config.mjs +2 -2
- package/rules/abie/clean_merged_ignore_branches/clean_merged_ignore_branches.mdc +0 -19
- package/rules/abie/clean_merged_ignore_branches/clean_merged_ignore_branches.rego +0 -81
- package/rules/abie/clean_merged_ignore_branches/concern.json +0 -11
- package/rules/abie/clean_merged_ignore_branches/docs/fix-clean_merged_ignore_branches.md +0 -31
- package/rules/abie/clean_merged_ignore_branches/docs/index.md +0 -9
- package/rules/abie/clean_merged_ignore_branches/fix-clean_merged_ignore_branches.mjs +0 -8
- package/rules/abie/clean_merged_ignore_branches/template/clean-merged-branch.yml.snippet.yml +0 -9
- package/rules/docker/lint_docker_yml/concern.json +0 -12
- package/rules/docker/lint_docker_yml/docs/fix-lint_docker_yml.md +0 -31
- package/rules/docker/lint_docker_yml/docs/index.md +0 -9
- package/rules/docker/lint_docker_yml/fix-lint_docker_yml.mjs +0 -5
- package/rules/docker/lint_docker_yml/lint_docker_yml.mdc +0 -14
- package/rules/docker/lint_docker_yml/lint_docker_yml.rego +0 -79
- package/rules/docker/lint_docker_yml/template/lint-docker.yml.snippet.yml +0 -41
- package/rules/js/lint_js_yml/concern.json +0 -12
- package/rules/js/lint_js_yml/docs/fix-lint_js_yml.md +0 -28
- package/rules/js/lint_js_yml/docs/index.md +0 -9
- package/rules/js/lint_js_yml/fix-lint_js_yml.mjs +0 -5
- package/rules/js/lint_js_yml/lint_js_yml.mdc +0 -14
- package/rules/js/lint_js_yml/lint_js_yml.rego +0 -117
- package/rules/js/lint_js_yml/template/lint-js.yml.snippet.yml +0 -40
- package/rules/k8s/lint_k8s_yml/concern.json +0 -12
- package/rules/k8s/lint_k8s_yml/docs/fix-lint_k8s_yml.md +0 -30
- package/rules/k8s/lint_k8s_yml/docs/index.md +0 -9
- package/rules/k8s/lint_k8s_yml/fix-lint_k8s_yml.mjs +0 -5
- package/rules/k8s/lint_k8s_yml/lint_k8s_yml.rego +0 -57
- package/rules/k8s/lint_k8s_yml/template/lint-k8s.yml.snippet.yml +0 -43
- package/rules/npm-module/npm_publish_yml/concern.json +0 -13
- package/rules/npm-module/npm_publish_yml/docs/fix-npm_publish_yml.md +0 -28
- package/rules/npm-module/npm_publish_yml/docs/index.md +0 -9
- package/rules/npm-module/npm_publish_yml/fix-npm_publish_yml.mjs +0 -8
- package/rules/npm-module/npm_publish_yml/template/npm-publish.yml.snippet.yml +0 -49
- package/rules/php/lint_php_yml/concern.json +0 -12
- package/rules/php/lint_php_yml/docs/fix-lint_php_yml.md +0 -28
- package/rules/php/lint_php_yml/docs/index.md +0 -9
- package/rules/php/lint_php_yml/fix-lint_php_yml.mjs +0 -5
- package/rules/php/lint_php_yml/lint_php_yml.mdc +0 -23
- package/rules/php/lint_php_yml/lint_php_yml.rego +0 -34
- package/rules/php/lint_php_yml/template/lint-php.yml.snippet.yml +0 -47
- package/rules/python/lint_python_yml/concern.json +0 -12
- package/rules/python/lint_python_yml/docs/fix-lint_python_yml.md +0 -27
- package/rules/python/lint_python_yml/docs/index.md +0 -9
- package/rules/python/lint_python_yml/fix-lint_python_yml.mjs +0 -5
- package/rules/python/lint_python_yml/lint_python_yml.mdc +0 -12
- package/rules/python/lint_python_yml/lint_python_yml.rego +0 -68
- package/rules/python/lint_python_yml/template/lint-python.yml.snippet.yml +0 -41
- package/rules/rust/lint_rust_yml/concern.json +0 -14
- package/rules/rust/lint_rust_yml/docs/fix-lint_rust_yml.md +0 -28
- package/rules/rust/lint_rust_yml/docs/index.md +0 -9
- package/rules/rust/lint_rust_yml/fix-lint_rust_yml.mjs +0 -5
- package/rules/rust/lint_rust_yml/lint_rust_yml.mdc +0 -17
- package/rules/rust/lint_rust_yml/lint_rust_yml.rego +0 -79
- package/rules/rust/lint_rust_yml/template/lint-rust.yml.snippet.yml +0 -44
- package/rules/rust/toolchain_cache/concern.json +0 -14
- package/rules/rust/toolchain_cache/docs/fix-toolchain_cache.md +0 -35
- package/rules/rust/toolchain_cache/docs/index.md +0 -12
- package/rules/rust/toolchain_cache/docs/main.md +0 -57
- package/rules/rust/toolchain_cache/fix-toolchain_cache.mjs +0 -117
- package/rules/rust/toolchain_cache/main.mjs +0 -177
- package/rules/rust/toolchain_cache/toolchain_cache.mdc +0 -23
- package/rules/security/lint_security_yml/concern.json +0 -14
- package/rules/security/lint_security_yml/docs/fix-lint_security_yml.md +0 -31
- package/rules/security/lint_security_yml/docs/index.md +0 -9
- package/rules/security/lint_security_yml/fix-lint_security_yml.mjs +0 -8
- package/rules/security/lint_security_yml/lint_security_yml.mdc +0 -7
- package/rules/security/lint_security_yml/lint_security_yml.rego +0 -33
- package/rules/security/lint_security_yml/template/lint-security.yml.snippet.yml +0 -31
- package/rules/style/lint_style_yml/concern.json +0 -12
- package/rules/style/lint_style_yml/docs/fix-lint_style_yml.md +0 -31
- package/rules/style/lint_style_yml/docs/index.md +0 -9
- package/rules/style/lint_style_yml/fix-lint_style_yml.mjs +0 -5
- package/rules/style/lint_style_yml/lint_style_yml.mdc +0 -13
- package/rules/style/lint_style_yml/lint_style_yml.rego +0 -38
- package/rules/style/lint_style_yml/template/lint-style.yml.snippet.yml +0 -39
- package/rules/text/lint_text/concern.json +0 -11
- package/rules/text/lint_text/docs/fix-lint_text.md +0 -28
- package/rules/text/lint_text/docs/index.md +0 -9
- package/rules/text/lint_text/fix-lint_text.mjs +0 -5
- package/rules/text/lint_text/lint_text.mdc +0 -19
- package/rules/text/lint_text/lint_text.rego +0 -104
- package/rules/text/lint_text/template/lint-text.yml.snippet.yml +0 -61
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Parity дзеркала правил: `.cursor/rules/n-<id>.mdc` має дорівнювати канонічному
|
|
3
|
-
* `
|
|
4
|
-
* застосовує синк (`readBundledRuleContent` → `inlineTemplateLinks`).
|
|
5
|
-
* коли канонічний `.mdc` змінюють, не регенерувавши
|
|
3
|
+
* `main.mdc` правила з inlined-шаблонами — тим самим трансформом, що його
|
|
4
|
+
* застосовує синк (`readBundledRuleContent` → `inlineTemplateLinks` → mixin-extras).
|
|
5
|
+
* Дрейф виникає, коли канонічний `.mdc` змінюють, не регенерувавши дзеркало.
|
|
6
|
+
*
|
|
7
|
+
* Multi-dir: власник правила шукається у `npm/rules/<id>` і `plugins/<p>/rules/<id>`
|
|
8
|
+
* (перший з `main.mdc`); решта тек `rules/<id>` інших джерел — mixin-extras, їхні
|
|
9
|
+
* concern-mdc доінлайнюються після концернів власника (як у синку).
|
|
6
10
|
*
|
|
7
11
|
* Використовується і тестом-гардом (drift === []), і разовою регенерацією.
|
|
8
12
|
*/
|
|
@@ -10,41 +14,70 @@ import { existsSync, readdirSync, readFileSync } from 'node:fs'
|
|
|
10
14
|
import { dirname, join } from 'node:path'
|
|
11
15
|
|
|
12
16
|
import { appendDiscoveredMdcFiles, inlineTemplateLinks } from './inline-template-links.mjs'
|
|
17
|
+
import { readNRulesConfigLite } from './read-n-rules-config-lite.mjs'
|
|
18
|
+
import { resolvePlugins } from './resolve-plugins.mjs'
|
|
13
19
|
|
|
14
20
|
const MIRROR_PREFIX = 'n-'
|
|
15
21
|
const MDC_EXT = '.mdc'
|
|
16
22
|
|
|
17
23
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
24
|
+
* Rules-джерела репо у порядку пріоритету: ядро, потім АКТИВНІ плагіни (з `.n-rules.json`,
|
|
25
|
+
* резолв через node_modules — той самий шлях, що у синку; неактивні plugins/* монорепо
|
|
26
|
+
* не враховуються, бо їх нема і в дзеркалах).
|
|
27
|
+
* @param {string} repoRoot корінь репо
|
|
28
|
+
* @returns {Promise<string[]>} абсолютні шляхи rules-каталогів
|
|
29
|
+
*/
|
|
30
|
+
async function repoRulesDirs(repoRoot) {
|
|
31
|
+
const dirs = [join(repoRoot, 'npm/rules')]
|
|
32
|
+
const config = await readNRulesConfigLite(repoRoot)
|
|
33
|
+
for (const plugin of resolvePlugins(repoRoot, { plugins: config.plugins }, { allowInstall: false, quiet: true })) {
|
|
34
|
+
dirs.push(plugin.rulesDir)
|
|
35
|
+
}
|
|
36
|
+
return dirs
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Керовані дзеркала `.cursor/rules/n-<id>.mdc` з канонічним джерелом у ядрі або плагіні.
|
|
41
|
+
* Дзеркала без канону (зовнішні) пропускаються.
|
|
20
42
|
* @param {string} repoRoot корінь репо
|
|
21
|
-
* @returns {{ id: string, mirrorPath: string, canonicalPath: string }[]} список
|
|
43
|
+
* @returns {Promise<{ id: string, mirrorPath: string, canonicalPath: string, extraDirs: string[] }[]>} список
|
|
22
44
|
*/
|
|
23
|
-
export function listManagedMirrors(repoRoot) {
|
|
45
|
+
export async function listManagedMirrors(repoRoot) {
|
|
24
46
|
const rulesDir = join(repoRoot, '.cursor/rules')
|
|
25
47
|
if (!existsSync(rulesDir)) return []
|
|
48
|
+
const sources = await repoRulesDirs(repoRoot)
|
|
26
49
|
return readdirSync(rulesDir)
|
|
27
50
|
.filter(f => f.startsWith(MIRROR_PREFIX) && f.endsWith(MDC_EXT))
|
|
28
51
|
.map(f => {
|
|
29
52
|
const id = f.slice(MIRROR_PREFIX.length, -MDC_EXT.length)
|
|
53
|
+
const candidates = sources.map(s => join(s, id))
|
|
54
|
+
const owner = candidates.find(dir => existsSync(join(dir, `main${MDC_EXT}`)))
|
|
55
|
+
const extraDirs = owner === undefined ? [] : candidates.filter(dir => dir !== owner && existsSync(dir))
|
|
30
56
|
return {
|
|
31
57
|
id,
|
|
32
58
|
mirrorPath: join(rulesDir, f),
|
|
33
|
-
canonicalPath:
|
|
59
|
+
canonicalPath: owner === undefined ? '' : join(owner, `main${MDC_EXT}`),
|
|
60
|
+
extraDirs
|
|
34
61
|
}
|
|
35
62
|
})
|
|
36
|
-
.filter(m =>
|
|
63
|
+
.filter(m => m.canonicalPath !== '')
|
|
37
64
|
}
|
|
38
65
|
|
|
39
66
|
/**
|
|
40
|
-
* Очікуваний вміст дзеркала = канон з inlined-шаблонами
|
|
41
|
-
*
|
|
67
|
+
* Очікуваний вміст дзеркала = канон з inlined-шаблонами + concern-mdc mixin-джерел
|
|
68
|
+
* (той самий трансформ, що у синку).
|
|
69
|
+
* @param {string} canonicalPath абсолютний шлях `rules/<id>/main.mdc` власника
|
|
70
|
+
* @param {string[]} [extraDirs] теки `rules/<id>` mixin-джерел
|
|
42
71
|
* @returns {Promise<string>} очікуваний текст дзеркала
|
|
43
72
|
*/
|
|
44
|
-
export async function expectedMirrorContent(canonicalPath) {
|
|
73
|
+
export async function expectedMirrorContent(canonicalPath, extraDirs = []) {
|
|
45
74
|
const dir = dirname(canonicalPath)
|
|
46
|
-
|
|
47
|
-
|
|
75
|
+
let out = await inlineTemplateLinks(readFileSync(canonicalPath, 'utf8'), dir)
|
|
76
|
+
out = await appendDiscoveredMdcFiles(out, dir)
|
|
77
|
+
for (const extra of extraDirs) {
|
|
78
|
+
out = await appendDiscoveredMdcFiles(out, extra)
|
|
79
|
+
}
|
|
80
|
+
return out
|
|
48
81
|
}
|
|
49
82
|
|
|
50
83
|
/**
|
|
@@ -54,8 +87,8 @@ export async function expectedMirrorContent(canonicalPath) {
|
|
|
54
87
|
*/
|
|
55
88
|
export async function findMirrorDrift(repoRoot) {
|
|
56
89
|
const drift = []
|
|
57
|
-
for (const m of listManagedMirrors(repoRoot)) {
|
|
58
|
-
const expected = await expectedMirrorContent(m.canonicalPath)
|
|
90
|
+
for (const m of await listManagedMirrors(repoRoot)) {
|
|
91
|
+
const expected = await expectedMirrorContent(m.canonicalPath, m.extraDirs)
|
|
59
92
|
if (readFileSync(m.mirrorPath, 'utf8') !== expected) drift.push(m.id)
|
|
60
93
|
}
|
|
61
94
|
return drift.toSorted()
|
package/scripts/skills-cli.mjs
CHANGED
|
@@ -172,7 +172,7 @@ async function runPiRunner(prompt, rawSkillName, skillsRoot, projectDir, logErro
|
|
|
172
172
|
/**
|
|
173
173
|
* Делегує виконання скіла зовнішньому ACP-агенту (`cursor-agent acp`, `codex-acp`,
|
|
174
174
|
* або deprecated `claude`-адаптер) через `runAcpRunner` — JSON-RPC поверх stdio,
|
|
175
|
-
* дозволи на tool-calls
|
|
175
|
+
* дозволи на tool-calls автоматично схвалюються (без інтерактивних питань, паритет із
|
|
176
176
|
* колишнім non-interactive `-p`). `claude` лишається як deprecated fallback для
|
|
177
177
|
* тих, у кого pi-модель ще не налаштована; буде прибрано (мігруй на `skill pi`).
|
|
178
178
|
* @param {'claude' | 'cursor' | 'codex'} kind якого ACP-агента запускати
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* `.pi/extensions/rtk.ts`. Без установленого rtk hooks мовчки пропускають команди,
|
|
27
27
|
* тож конфіг безпечно потрапляє в git — установка зводиться до `brew install rtk-ai/tap/rtk`.
|
|
28
28
|
* - `.gitignore` — **merge** (лише з `adr`): дописує відсутні рядки з канонічного
|
|
29
|
-
* фрагмента
|
|
29
|
+
* фрагмента `.claude-template/hooks/.gitignore.snippet` (`node_modules/`, `dist/`,
|
|
30
30
|
* `*.secret`, логи capture/normalize, `.normalize-state`, `.normalize.lock`,
|
|
31
31
|
* `.claude/scheduled_tasks.lock`); існуючі рядки не перезаписуються.
|
|
32
32
|
*
|
|
@@ -101,7 +101,7 @@ export const PI_EXTENSION_NAME = 'n-rules-adr'
|
|
|
101
101
|
/** @deprecated — ім'я extension-теки до перейменування пакету; лишається для cleanup при ресинку. */
|
|
102
102
|
export const LEGACY_PI_EXTENSION_NAME = 'n-cursor-adr'
|
|
103
103
|
/** Відносний шлях до канонічного фрагмента `.gitignore` для ADR Stop-hook'ів у tarball пакета. */
|
|
104
|
-
export const ADR_GITIGNORE_SNIPPET_REL = '
|
|
104
|
+
export const ADR_GITIGNORE_SNIPPET_REL = '.claude-template/hooks/.gitignore.snippet'
|
|
105
105
|
const GITIGNORE_FILE = '.gitignore'
|
|
106
106
|
const EOL_RE = /\r?\n/u
|
|
107
107
|
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
## Rego: `ignore_branches` у `clean-merged-branch.yml`
|
|
2
|
-
|
|
3
|
-
Rego-пакет: `abie.clean_merged_ignore_branches`
|
|
4
|
-
|
|
5
|
-
Цільовий файл: `.github/workflows/clean-merged-branch.yml`.
|
|
6
|
-
|
|
7
|
-
Перевіряє, що у workflow-файлі є крок з `uses: phpdocker-io/github-actions-delete-abandoned-branches` і що його `with.ignore_branches` містить обидва токени `dev` та `ua` (case-insensitive, пробіли навколо токенів обрізаються). Токени зчитуються з template-файлу `data.template.snippet` — зміна канону автоматично змінює вимоги.
|
|
8
|
-
|
|
9
|
-
Канонічний snippet: [clean-merged-branch.yml.snippet.yml](./template/clean-merged-branch.yml.snippet.yml)
|
|
10
|
-
|
|
11
|
-
```yaml title=".github/workflows/clean-merged-branch.yml (фрагмент)"
|
|
12
|
-
- uses: phpdocker-io/github-actions-delete-abandoned-branches@v2
|
|
13
|
-
with:
|
|
14
|
-
ignore_branches: "dev,ua,main" # ✓ містить dev та ua
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
```yaml
|
|
18
|
-
ignore_branches: "main" # ✗ не вистачає dev,ua
|
|
19
|
-
```
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
# Перевірка `clean-merged-branch.yml` для abie-проєктів (abie.mdc).
|
|
2
|
-
#
|
|
3
|
-
# Канон надходить через --data: { "template": { "snippet": ... } }
|
|
4
|
-
# Структура --data сформована з template/clean-merged-branch.yml.snippet.yml.
|
|
5
|
-
# Action-маркер (`uses:` substring) і required branches (parsed з template's
|
|
6
|
-
# `ignore_branches`) читаються з template. ga.clean_merged_branch перевіряє
|
|
7
|
-
# повний канон workflow окремо; цей пакет — лише abie-specific шар.
|
|
8
|
-
package abie.clean_merged_ignore_branches
|
|
9
|
-
|
|
10
|
-
import rego.v1
|
|
11
|
-
|
|
12
|
-
# Експектації з template's step (першого з steps).
|
|
13
|
-
expected_step := step if some step in data.template.snippet.jobs.cleanup_old_branches.steps
|
|
14
|
-
|
|
15
|
-
target_action_marker := expected_step.uses
|
|
16
|
-
|
|
17
|
-
required_branches := parsed_ignore_tokens(expected_step.with.ignore_branches)
|
|
18
|
-
|
|
19
|
-
step_missing_msg := sprintf(
|
|
20
|
-
"clean-merged-branch.yml: не знайдено крок з uses: %s (abie.mdc)",
|
|
21
|
-
[target_action_marker],
|
|
22
|
-
)
|
|
23
|
-
|
|
24
|
-
ignore_branches_missing_msg := sprintf(
|
|
25
|
-
"clean-merged-branch.yml: не знайдено with.ignore_branches у кроці %s (abie.mdc)",
|
|
26
|
-
[target_action_marker],
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
# ── deny ─────────────────────────────────────────────────────────────────
|
|
30
|
-
|
|
31
|
-
deny contains step_missing_msg if {
|
|
32
|
-
count(target_steps) == 0
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
deny contains ignore_branches_missing_msg if {
|
|
36
|
-
count(target_steps) > 0
|
|
37
|
-
not has_ignore_branches_value
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
deny contains msg if {
|
|
41
|
-
count(target_steps) > 0
|
|
42
|
-
ignore_branches_value != ""
|
|
43
|
-
missing := required_branches - parsed_ignore_tokens(ignore_branches_value)
|
|
44
|
-
count(missing) > 0
|
|
45
|
-
msg := sprintf(
|
|
46
|
-
"clean-merged-branch.yml: ignore_branches має містити %v (зараз: %q; не вистачає: %v) (abie.mdc)",
|
|
47
|
-
[concat(",", sort(required_branches)), ignore_branches_value, concat(",", sort(missing))],
|
|
48
|
-
)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
# ── helpers ──────────────────────────────────────────────────────────────
|
|
52
|
-
|
|
53
|
-
target_steps contains step if {
|
|
54
|
-
some job in object.get(input, "jobs", {})
|
|
55
|
-
some step in object.get(job, "steps", [])
|
|
56
|
-
uses := object.get(step, "uses", "")
|
|
57
|
-
is_string(uses)
|
|
58
|
-
contains(uses, target_action_marker)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
has_ignore_branches_value if {
|
|
62
|
-
some step in target_steps
|
|
63
|
-
v := object.get(object.get(step, "with", {}), "ignore_branches", null)
|
|
64
|
-
is_string(v)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
default ignore_branches_value := ""
|
|
68
|
-
|
|
69
|
-
ignore_branches_value := values[0] if {
|
|
70
|
-
values := [v |
|
|
71
|
-
some step in target_steps
|
|
72
|
-
v := object.get(object.get(step, "with", {}), "ignore_branches", null)
|
|
73
|
-
is_string(v)
|
|
74
|
-
]
|
|
75
|
-
count(values) > 0
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
parsed_ignore_tokens(value) := {lower(trim_space(part)) |
|
|
79
|
-
some part in split(value, ",")
|
|
80
|
-
trim_space(part) != ""
|
|
81
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: JS Module
|
|
3
|
-
title: fix-clean_merged_ignore_branches.mjs
|
|
4
|
-
resource: npm/rules/abie/clean_merged_ignore_branches/fix-clean_merged_ignore_branches.mjs
|
|
5
|
-
docgen:
|
|
6
|
-
crc: 9fe2cc60
|
|
7
|
-
model: openai-codex/gpt-5.5
|
|
8
|
-
tier: cloud-avg
|
|
9
|
-
score: 100
|
|
10
|
-
issues: judge:inaccurate:0.99
|
|
11
|
-
judgeModel: openai-codex/gpt-5.4-mini
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## Огляд
|
|
15
|
-
|
|
16
|
-
`patterns` визначає набір шляхів репозиторію, які правило має враховувати під час перевірки. Воно свідомо не охоплює `.git` і `.github`, щоб не аналізувати службові дані Git та конфігурацію GitHub. Правило працює read-only: лише повідомляє про невідповідність очікуваній структурі, не змінюючи файли чи зовнішні сховища.
|
|
17
|
-
|
|
18
|
-
## Поведінка
|
|
19
|
-
|
|
20
|
-
1. `patterns` визначає правило виправлення, яке забезпечує наявність workflow для очищення merged branches.
|
|
21
|
-
|
|
22
|
-
2. Правило орієнтується на шаблонний стан файлу `.github/workflows/clean-merged-branch.yml`, щоб уніфікувати поведінку репозиторіїв щодо прибирання вже злитих гілок.
|
|
23
|
-
|
|
24
|
-
3. Під час перевірки свідомо не обходить службові шляхи `.github` і `.git`, окрім цільового workflow-файлу, який є предметом виправлення.
|
|
25
|
-
|
|
26
|
-
4. `patterns` лише описує очікуване виправлення й не виконує самостійного запису у файлову систему чи інші сховища.
|
|
27
|
-
|
|
28
|
-
## Гарантії поведінки
|
|
29
|
-
|
|
30
|
-
- Read-only: не виконує операцій запису (ФС/БД).
|
|
31
|
-
- Свідомо пропускає шляхи: `.github`, `.git`.
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: Directory Index
|
|
3
|
-
title: npm/rules/abie/clean_merged_ignore_branches
|
|
4
|
-
resource: npm/rules/abie/clean_merged_ignore_branches/
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
| Файл | Тип |
|
|
8
|
-
| --------------------------------------------------------------------------- | --------- |
|
|
9
|
-
| [fix-clean_merged_ignore_branches.mjs](fix-clean_merged_ignore_branches.md) | JS Module |
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { createTemplateFixPattern } from '../../../scripts/lib/fix/template-deep-merge.mjs'
|
|
2
|
-
|
|
3
|
-
export const patterns = [
|
|
4
|
-
createTemplateFixPattern({
|
|
5
|
-
id: 'abie-clean_merged_ignore_branches-template',
|
|
6
|
-
targetPath: '.github/workflows/clean-merged-branch.yml'
|
|
7
|
-
})
|
|
8
|
-
]
|
package/rules/abie/clean_merged_ignore_branches/template/clean-merged-branch.yml.snippet.yml
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
# abie-specific шар поверх ga.clean_merged_branch:
|
|
2
|
-
# у `clean-merged-branch.yml` крок phpdocker-io/github-actions-delete-abandoned-branches
|
|
3
|
-
# має містити `ignore_branches: dev,ua` (обовʼязкові гілки для abie-проєктів).
|
|
4
|
-
jobs:
|
|
5
|
-
cleanup_old_branches:
|
|
6
|
-
steps:
|
|
7
|
-
- uses: phpdocker-io/github-actions-delete-abandoned-branches
|
|
8
|
-
with:
|
|
9
|
-
ignore_branches: dev,ua
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: JS Module
|
|
3
|
-
title: fix-lint_docker_yml.mjs
|
|
4
|
-
resource: npm/rules/docker/lint_docker_yml/fix-lint_docker_yml.mjs
|
|
5
|
-
docgen:
|
|
6
|
-
crc: 551913c9
|
|
7
|
-
model: openai-codex/gpt-5.5
|
|
8
|
-
tier: cloud-avg
|
|
9
|
-
score: 100
|
|
10
|
-
issues: judge:inaccurate:0.98
|
|
11
|
-
judgeModel: openai-codex/gpt-5.4-mini
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## Огляд
|
|
15
|
-
|
|
16
|
-
`patterns` визначає поведінку правила для обходу проєкту без змін у файловій системі чи зовнішніх сховищах. Службові директорії `.github` і `.git` свідомо не входять до перевірюваних шляхів, щоб правило працювало лише з релевантним кодом проєкту.
|
|
17
|
-
|
|
18
|
-
## Поведінка
|
|
19
|
-
|
|
20
|
-
1. `patterns` визначає правило автоматичного виправлення для workflow перевірки Docker.
|
|
21
|
-
|
|
22
|
-
2. `patterns` забезпечує наявність стандартного файлу `.github/workflows/lint-docker.yml`, щоб проєкт мав єдиний CI-контроль Docker-конфігурації.
|
|
23
|
-
|
|
24
|
-
3. `patterns` працює як read-only опис виправлення: сам модуль не змінює файлову систему чи зовнішні сховища.
|
|
25
|
-
|
|
26
|
-
4. Під час супровідного обходу шляхів свідомо не аналізуються `.github` і `.git`, щоб не змішувати службові директорії з основним кодом проєкту.
|
|
27
|
-
|
|
28
|
-
## Гарантії поведінки
|
|
29
|
-
|
|
30
|
-
- Read-only: не виконує операцій запису (ФС/БД).
|
|
31
|
-
- Свідомо пропускає шляхи: `.github`, `.git`.
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: Directory Index
|
|
3
|
-
title: npm/rules/docker/lint_docker_yml
|
|
4
|
-
resource: npm/rules/docker/lint_docker_yml/
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
| Файл | Тип |
|
|
8
|
-
| ------------------------------------------------- | --------- |
|
|
9
|
-
| [fix-lint_docker_yml.mjs](fix-lint_docker_yml.md) | JS Module |
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
## Перевірка `.github/workflows/lint-docker.yml`
|
|
2
|
-
|
|
3
|
-
Rego-пакет: `docker.lint_docker_yml`
|
|
4
|
-
|
|
5
|
-
Цільовий файл: `.github/workflows/lint-docker.yml`
|
|
6
|
-
|
|
7
|
-
Перевіряє, що CI-workflow lint-docker відповідає канонічному сніпету:
|
|
8
|
-
|
|
9
|
-
- `on.push.paths` містить усі три glob-маски: `**/Dockerfile`, `**/*.Dockerfile`, `**/*.dockerfile`
|
|
10
|
-
- присутні кроки `uses: actions/checkout@v6` та `uses: ./.github/actions/setup-bun-deps`
|
|
11
|
-
- крок install hadolint містить рядок із версією `v2.12.0` (substring-перевірка)
|
|
12
|
-
- крок lint містить `n-rules lint docker --no-fix`
|
|
13
|
-
|
|
14
|
-
Канонічний шаблон: [lint-docker.yml.snippet.yml](./template/lint-docker.yml.snippet.yml)
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
# Перевірка `.github/workflows/lint-docker.yml` (docker.mdc).
|
|
2
|
-
#
|
|
3
|
-
# Канон надходить через --data: { "template": { "snippet": ... } }
|
|
4
|
-
# Структура --data сформована з template/lint-docker.yml.snippet.yml.
|
|
5
|
-
# Path-маркери, hadolint версія (substring "v2.12.0" у run), setup-bun-deps
|
|
6
|
-
# composite, `n-rules lint docker --no-fix` substring — все читається з template's snippet.
|
|
7
|
-
# Універсальні workflow-перевірки — у `ga.workflow_common`.
|
|
8
|
-
package docker.lint_docker_yml
|
|
9
|
-
|
|
10
|
-
import rego.v1
|
|
11
|
-
|
|
12
|
-
# Очікувані літерали з template.
|
|
13
|
-
expected_paths := {p | some p in data.template.snippet.on.push.paths}
|
|
14
|
-
|
|
15
|
-
# Required uses set — з template's steps.
|
|
16
|
-
expected_uses_set contains u if {
|
|
17
|
-
some step in data.template.snippet.jobs["lint-docker"].steps
|
|
18
|
-
u := object.get(step, "uses", "")
|
|
19
|
-
u != ""
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
# Required run substrings — collected per-step з template.
|
|
23
|
-
expected_run_substrings contains r if {
|
|
24
|
-
some step in data.template.snippet.jobs["lint-docker"].steps
|
|
25
|
-
r := object.get(step, "run", "")
|
|
26
|
-
r != ""
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
# Аліаси на input.
|
|
30
|
-
all_step_uses contains u if {
|
|
31
|
-
some job in object.get(input, "jobs", {})
|
|
32
|
-
some step in object.get(job, "steps", [])
|
|
33
|
-
u := object.get(step, "uses", "")
|
|
34
|
-
u != ""
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
all_run_text := concat("\n", [run_text |
|
|
38
|
-
some job in object.get(input, "jobs", {})
|
|
39
|
-
some step in object.get(job, "steps", [])
|
|
40
|
-
run_text := step_run_to_text(step)
|
|
41
|
-
])
|
|
42
|
-
|
|
43
|
-
# conftest парсить YAML 1.1, тож канонічний `on:` без лапок стає булевим ключем
|
|
44
|
-
# `true` (як у `ga.lint_ga`). Тому читаємо через `input["true"]`.
|
|
45
|
-
push_paths_set := {p |
|
|
46
|
-
some p in object.get(object.get(object.get(input, "true", {}), "push", {}), "paths", [])
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
# ── deny: on.push.paths subset-of ──────────────────────────────────────
|
|
50
|
-
|
|
51
|
-
deny contains msg if {
|
|
52
|
-
some required in expected_paths
|
|
53
|
-
not required in push_paths_set
|
|
54
|
-
msg := sprintf("lint-docker.yml: on.push.paths має містити %q (docker.mdc)", [required])
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
# ── deny: required uses present ────────────────────────────────────────
|
|
58
|
-
|
|
59
|
-
deny contains msg if {
|
|
60
|
-
some required_use in expected_uses_set
|
|
61
|
-
not required_use in all_step_uses
|
|
62
|
-
msg := sprintf("lint-docker.yml: відсутній крок `uses: %s` (docker.mdc)", [required_use])
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
# ── deny: required run substrings ──────────────────────────────────────
|
|
66
|
-
|
|
67
|
-
deny contains msg if {
|
|
68
|
-
some required_run in expected_run_substrings
|
|
69
|
-
not contains(all_run_text, required_run)
|
|
70
|
-
msg := sprintf("lint-docker.yml: жоден крок run не містить %q (docker.mdc)", [required_run])
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
# ── helpers ────────────────────────────────────────────────────────────
|
|
74
|
-
|
|
75
|
-
step_run_to_text(step) := step.run if is_string(step.run)
|
|
76
|
-
|
|
77
|
-
else := concat("\n", [s | some s in step.run]) if is_array(step.run)
|
|
78
|
-
|
|
79
|
-
else := ""
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
name: Lint Docker
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches:
|
|
6
|
-
- dev
|
|
7
|
-
- main
|
|
8
|
-
paths:
|
|
9
|
-
- '**/Dockerfile'
|
|
10
|
-
- '**/*.Dockerfile'
|
|
11
|
-
- '**/*.dockerfile'
|
|
12
|
-
|
|
13
|
-
pull_request:
|
|
14
|
-
branches:
|
|
15
|
-
- dev
|
|
16
|
-
- main
|
|
17
|
-
|
|
18
|
-
concurrency:
|
|
19
|
-
group: ${{ github.ref }}-${{ github.workflow }}
|
|
20
|
-
cancel-in-progress: true
|
|
21
|
-
|
|
22
|
-
jobs:
|
|
23
|
-
lint-docker:
|
|
24
|
-
runs-on: ubuntu-latest
|
|
25
|
-
permissions:
|
|
26
|
-
contents: read
|
|
27
|
-
steps:
|
|
28
|
-
- uses: actions/checkout@v6
|
|
29
|
-
with:
|
|
30
|
-
persist-credentials: false
|
|
31
|
-
|
|
32
|
-
- name: Install hadolint
|
|
33
|
-
run: |
|
|
34
|
-
curl -sSL -o /tmp/hadolint https://github.com/hadolint/hadolint/releases/download/v2.12.0/hadolint-Linux-x86_64
|
|
35
|
-
chmod +x /tmp/hadolint
|
|
36
|
-
sudo mv /tmp/hadolint /usr/local/bin/hadolint
|
|
37
|
-
|
|
38
|
-
- uses: ./.github/actions/setup-bun-deps
|
|
39
|
-
|
|
40
|
-
- name: Lint Docker
|
|
41
|
-
run: bunx n-rules lint docker --no-fix
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: JS Module
|
|
3
|
-
title: fix-lint_js_yml.mjs
|
|
4
|
-
resource: npm/rules/js/lint_js_yml/fix-lint_js_yml.mjs
|
|
5
|
-
docgen:
|
|
6
|
-
crc: 39aecc30
|
|
7
|
-
model: openai-codex/gpt-5.4-mini
|
|
8
|
-
tier: cloud-min
|
|
9
|
-
score: 100
|
|
10
|
-
issues: judge:inaccurate:0.99
|
|
11
|
-
judgeModel: openai-codex/gpt-5.4-mini
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## Огляд
|
|
15
|
-
|
|
16
|
-
`patterns` — read-only набір правил для аналізу й уніфікації JavaScript lint-конфігурації в межах доступних шляхів. Він свідомо пропускає `.github` і `.git`, щоб не зачіпати службові та git-специфічні файли.
|
|
17
|
-
|
|
18
|
-
## Поведінка
|
|
19
|
-
|
|
20
|
-
1. `patterns` формує набір правил для виправлення lint-конфігурації JavaScript-проєкту.
|
|
21
|
-
2. Для кожного правила прив’язує оновлення до цільового workflow-файлу `.github/workflows/lint-js.yml`.
|
|
22
|
-
3. У межах своєї роботи свідомо не зачіпає `.github` і `.git`, щоб уникати змін у службових та внутрішніх областях.
|
|
23
|
-
4. Працює в read-only режимі щодо ФС і БД: сам нічого не записує, а лише описує, що треба виправити.
|
|
24
|
-
|
|
25
|
-
## Гарантії поведінки
|
|
26
|
-
|
|
27
|
-
- Read-only: не виконує операцій запису (ФС/БД).
|
|
28
|
-
- Свідомо пропускає шляхи: `.github`, `.git`.
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
## Rego-gate `.github/workflows/lint-js.yml`
|
|
2
|
-
|
|
3
|
-
Rego-пакет: `js_lint.lint_js_yml`
|
|
4
|
-
|
|
5
|
-
Цільовий файл: `.github/workflows/lint-js.yml`.
|
|
6
|
-
|
|
7
|
-
Що перевіряється:
|
|
8
|
-
|
|
9
|
-
- Наявність усіх `uses:`-кроків з канону (subset-of по `jobs.eslint.steps`); SHA-пін того самого action (`owner/action@<40-hex SHA>`, з тег-коментарем `# vX` чи без) задовольняє канонічний тег — НЕ замінюй наявний SHA-пін тегом
|
|
10
|
-
- Наявність усіх рядків `run:` з канону (substring-match по всіх кроках)
|
|
11
|
-
- `actions/checkout` (будь-який ref) має мати `with.persist-credentials: false` (inverse-check)
|
|
12
|
-
- Заборона `--fix` у CI: `bunx oxlint ... --fix` або `eslint --fix` у будь-якому `run:` → deny
|
|
13
|
-
|
|
14
|
-
Канон-snippet: [lint-js.yml.snippet.yml](./template/lint-js.yml.snippet.yml)
|