@7n/rules 1.20.1 → 1.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/package.json +1 -1
- package/scripts/lib/docs/resolve-plugins.md +1 -1
- package/rules/python/applies/concern.json +0 -4
- package/rules/python/applies/docs/main.md +0 -29
- package/rules/python/applies/main.mjs +0 -24
- package/rules/python/docs/index.md +0 -11
- package/rules/python/lib/docs/index.md +0 -9
- package/rules/python/lib/docs/uv-run.md +0 -31
- package/rules/python/lib/uv-run.mjs +0 -52
- package/rules/python/main.json +0 -1
- package/rules/python/main.mdc +0 -8
- package/rules/python/mypy/concern.json +0 -7
- package/rules/python/mypy/docs/main.md +0 -32
- package/rules/python/mypy/main.mjs +0 -37
- package/rules/python/project/concern.json +0 -6
- package/rules/python/project/docs/main.md +0 -42
- package/rules/python/project/main.mjs +0 -125
- package/rules/python/pyproject_toml/concern.json +0 -9
- package/rules/python/pyproject_toml/pyproject_toml.mdc +0 -29
- package/rules/python/pyproject_toml/pyproject_toml.rego +0 -53
- package/rules/python/pyproject_toml/template/pyproject.toml.deny.toml +0 -2
- package/rules/python/pyproject_toml/template/pyproject.toml.snippet.toml +0 -12
- package/rules/python/ruff/concern.json +0 -7
- package/rules/python/ruff/docs/fix-ruff.md +0 -33
- package/rules/python/ruff/docs/main.md +0 -35
- package/rules/python/ruff/fix-ruff.mjs +0 -65
- package/rules/python/ruff/main.mjs +0 -53
- package/rules/python/tooling/concern.json +0 -15
- package/rules/python/tooling/docs/index.md +0 -11
- package/rules/python/tooling/docs/main.md +0 -35
- package/rules/python/tooling/main.mjs +0 -45
- package/rules/python/tooling/tooling.mdc +0 -22
- package/rules/rust/applies/concern.json +0 -4
- package/rules/rust/applies/docs/index.md +0 -11
- package/rules/rust/applies/docs/main.md +0 -30
- package/rules/rust/applies/main.mjs +0 -28
- package/rules/rust/check/check.mdc +0 -16
- package/rules/rust/check/concern.json +0 -7
- package/rules/rust/check/docs/fix-check.md +0 -30
- package/rules/rust/check/docs/index.md +0 -11
- package/rules/rust/check/docs/main.md +0 -37
- package/rules/rust/check/fix-check.mjs +0 -80
- package/rules/rust/check/main.mjs +0 -87
- package/rules/rust/docs/index.md +0 -11
- package/rules/rust/lib/docs/has-cargo-toml.md +0 -134
- package/rules/rust/lib/docs/index.md +0 -11
- package/rules/rust/lib/has-cargo-toml.mjs +0 -37
- package/rules/rust/main.json +0 -1
- package/rules/rust/main.mdc +0 -8
- package/rules/rust/package_json/concern.json +0 -10
- package/rules/rust/package_json/package_json.mdc +0 -12
- package/rules/rust/package_json/package_json.rego +0 -20
- package/rules/rust/vscode_extensions/concern.json +0 -11
- package/rules/rust/vscode_extensions/docs/fix-vscode_extensions.md +0 -25
- package/rules/rust/vscode_extensions/docs/index.md +0 -11
- package/rules/rust/vscode_extensions/fix-vscode_extensions.mjs +0 -1
- package/rules/rust/vscode_extensions/template/extensions.json.snippet.json +0 -1
- package/rules/rust/vscode_extensions/vscode_extensions.mdc +0 -9
- package/rules/rust/vscode_extensions/vscode_extensions.rego +0 -15
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.21.0] - 2026-07-18
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- Фаза 3 spec lang-plugins-extraction: lint-правила `rust` і `python` (main.mdc, концерни, rego, шаблони) виїхали з ядра у плагіни `@7n/rules-lang-rust`/`@7n/rules-lang-python` (contributes.rules) — резолвляться через resolveRulesDirs, автодетект/дзеркала/auto-rules працюють без змін для репо з активними плагінами. Mixin-теки CI-плагінів (Rego-gate lint-rust.yml/lint-python.yml) доповнюють правила плагінів-власників, як і раніше
|
|
8
|
+
|
|
3
9
|
## [1.20.1] - 2026-07-18
|
|
4
10
|
|
|
5
11
|
### Changed
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@ type: JS Module
|
|
|
3
3
|
title: resolve-plugins.mjs
|
|
4
4
|
resource: npm/scripts/lib/resolve-plugins.mjs
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
6
|
+
crc: 17248373
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
Резолв плагінів @7n/rules: визначає, які пакети-плагіни активні у проєкті, де їхні `rules/`-каталоги, які capabilities вони надають і які handlers надають.
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: JS Module
|
|
3
|
-
title: main.mjs
|
|
4
|
-
resource: npm/rules/python/applies/main.mjs
|
|
5
|
-
docgen:
|
|
6
|
-
crc: 871eb5c6
|
|
7
|
-
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
8
|
-
score: 100
|
|
9
|
-
issues: judge:inaccurate:0.97
|
|
10
|
-
judgeModel: openai-codex/gpt-5.4-mini
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Огляд
|
|
14
|
-
|
|
15
|
-
Перевіряє наявність файлу `pyproject.toml` у корені репозиторію для визначення, чи має застосовуватися правило до проєктів, що використовують Python. Публічні функції `applies` та `main` реалізують цю логіку.
|
|
16
|
-
|
|
17
|
-
## Поведінка
|
|
18
|
-
|
|
19
|
-
applies визначає, чи застосовне правило, перевіряючи наявність файлу `pyproject.toml` у корені репозиторію.
|
|
20
|
-
main повідомляє про успішне знаходження файлу `pyproject.toml`, що підтверджує застосування правила для Python.
|
|
21
|
-
|
|
22
|
-
## Публічний API
|
|
23
|
-
|
|
24
|
-
- applies — визначає загальні налаштування та конфігурацію.
|
|
25
|
-
- main — виводить загальний контекст, тоді як спеціалізовані блоки виконують конкретні перевірки.
|
|
26
|
-
|
|
27
|
-
## Гарантії поведінки
|
|
28
|
-
|
|
29
|
-
- Read-only: не виконує операцій запису (ФС/БД).
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/** @see ./docs/applies.md */
|
|
2
|
-
import { existsSync } from 'node:fs'
|
|
3
|
-
import { join } from 'node:path'
|
|
4
|
-
|
|
5
|
-
import { createViolationReporter } from '../../../scripts/lib/lint-surface/violation-reporter.mjs'
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* @param {string} [cwd] корінь репозиторію (`process.cwd()` у звичайному прогоні)
|
|
9
|
-
* @returns {Promise<boolean>} `true` — правило застосовне; `false` — пропустити
|
|
10
|
-
*/
|
|
11
|
-
export function applies(cwd = process.cwd()) {
|
|
12
|
-
return Promise.resolve(existsSync(join(cwd, 'pyproject.toml')))
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Друкує короткий context-pass — самі перевірки виконують інші concerns.
|
|
17
|
-
* @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст лінту.
|
|
18
|
-
* @returns {Promise<import('../../../scripts/lib/lint-surface/types.mjs').LintResult>} результат context-pass
|
|
19
|
-
*/
|
|
20
|
-
export function lint(ctx) {
|
|
21
|
-
const reporter = createViolationReporter(ctx)
|
|
22
|
-
reporter.pass('pyproject.toml знайдено в корені — застосовую python.mdc')
|
|
23
|
-
return Promise.resolve(reporter.result())
|
|
24
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: JS Module
|
|
3
|
-
title: uv-run.mjs
|
|
4
|
-
resource: npm/rules/python/lib/uv-run.mjs
|
|
5
|
-
docgen:
|
|
6
|
-
crc: 1d697d71
|
|
7
|
-
model: openai-codex/gpt-5.4-mini
|
|
8
|
-
score: 100
|
|
9
|
-
issues: judge:inaccurate:0.97
|
|
10
|
-
judgeModel: openai-codex/gpt-5.4-mini
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Огляд
|
|
14
|
-
|
|
15
|
-
Спільний preflight для Python-детекторів `mypy` і `ruff`, виділений зі спільного дубльованого коду з `main.mjs`. Використовує `PY_EXT_RE`, щоб залишати лише Python-цілі; для `ctx.files` запускає перевірку по вибраних файлах, а без них — по всьому проєкту через `.`. За наявності `uvToolAvailable` готує запуск обох детекторів через `uv run --frozen`; `preparePythonRun` формує однаковий контракт підготовки для обох інструментів.
|
|
16
|
-
|
|
17
|
-
## Поведінка
|
|
18
|
-
|
|
19
|
-
- `PY_EXT_RE` — визначає, чи файл належить до Python-цілей для delta-лінту.
|
|
20
|
-
- `uvToolAvailable` — перевіряє, чи доступний Python-інструмент у середовищі `uv`.
|
|
21
|
-
- `preparePythonRun` — готує спільний preflight для Python-лінтерів: пропускає без `pyproject.toml`, відсікає нерелевантні файли, перевіряє наявність `uv` і доступність інструменту, після чого повертає готові цілі для запуску через `uv run --frozen`.
|
|
22
|
-
|
|
23
|
-
## Публічний API
|
|
24
|
-
|
|
25
|
-
- PY_EXT_RE — Відібрає лише Python-файли з delta-списку для `lint`.
|
|
26
|
-
- uvToolAvailable — Підтверджує, що `uv` доступний у середовищі.
|
|
27
|
-
- preparePythonRun — Готує запуск Python-цілі: звіряє `pyproject.toml`, визначає delta або full-обсяг, знаходить `uv` і перевіряє, чи є потрібний `tool`; якщо підготовка не вдалася, викликач завершує `reporter.result` раніше.
|
|
28
|
-
|
|
29
|
-
## Гарантії поведінки
|
|
30
|
-
|
|
31
|
-
- Read-only: не виконує операцій запису (ФС/БД).
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Спільний preflight обох python-детекторів (`mypy`, `ruff`) — обидва per-file: приймають
|
|
3
|
-
* `ctx.files`, інакше `.` (весь проєкт), обидва йдуть через `uv run --frozen`. Виділено зі
|
|
4
|
-
* спільного дубльованого коду (jscpd) обох `main.mjs`.
|
|
5
|
-
*/
|
|
6
|
-
import { existsSync } from 'node:fs'
|
|
7
|
-
import { join } from 'node:path'
|
|
8
|
-
|
|
9
|
-
import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
|
|
10
|
-
import { spawnAsync } from '../../../scripts/utils/spawn-async.mjs'
|
|
11
|
-
|
|
12
|
-
/** Розширення `.py` — фільтр delta-списку файлів у `lint(ctx)`. */
|
|
13
|
-
export const PY_EXT_RE = /\.py$/u
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Async (не блокує event loop) — детектор може виконуватись у parallel lane `detectAll()`
|
|
17
|
-
* (ADR 260716-1354).
|
|
18
|
-
* @param {string} uv шлях до бінарника uv.
|
|
19
|
-
* @param {string} tool ім'я інструменту в uv-середовищі.
|
|
20
|
-
* @returns {Promise<boolean>} true якщо інструмент доступний
|
|
21
|
-
*/
|
|
22
|
-
export async function uvToolAvailable(uv, tool) {
|
|
23
|
-
const r = await spawnAsync(uv, ['run', '--frozen', tool, '--version'])
|
|
24
|
-
return r.exitCode === 0
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Спільний preflight: pyproject.toml, delta/full-цілі, резолв `uv`, доступність `tool` у
|
|
29
|
-
* uv-середовищі. Викликач рано виходить (`reporter.result()`), коли повертається `null` —
|
|
30
|
-
* `fail()` для випадку відсутнього `uv` уже викликаний усередині.
|
|
31
|
-
* Async (не блокує event loop) — детектор може виконуватись у parallel lane `detectAll()`
|
|
32
|
-
* (ADR 260716-1354).
|
|
33
|
-
* @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст лінту.
|
|
34
|
-
* @param {(msg: string, opts: object) => void} fail колбек реєстрації порушення.
|
|
35
|
-
* @param {string} tool ім'я інструменту (`mypy`|`ruff`) для перевірки доступності.
|
|
36
|
-
* @returns {Promise<{uv: string, targets: string[]}|null>} preflight-результат, або null (рано вийти).
|
|
37
|
-
*/
|
|
38
|
-
export async function preparePythonRun(ctx, fail, tool) {
|
|
39
|
-
if (!existsSync(join(ctx.cwd, 'pyproject.toml'))) return null
|
|
40
|
-
|
|
41
|
-
const targets = ctx.files === undefined ? ['.'] : ctx.files.filter(f => PY_EXT_RE.test(f))
|
|
42
|
-
if (targets.length === 0) return null
|
|
43
|
-
|
|
44
|
-
const uv = resolveCmd('uv')
|
|
45
|
-
if (!uv) {
|
|
46
|
-
fail('lint-python: `uv` не знайдено в PATH (потрібен при наявному pyproject.toml, python.mdc)', 'uv-missing')
|
|
47
|
-
return null
|
|
48
|
-
}
|
|
49
|
-
if (!(await uvToolAvailable(uv, tool))) return null // tool недоступний у uv-середовищі → пропущено
|
|
50
|
-
|
|
51
|
-
return { uv, targets }
|
|
52
|
-
}
|
package/rules/python/main.json
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{ "auto": { "glob": "pyproject.toml" } }
|
package/rules/python/main.mdc
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Python — пакет-менеджер uv (без Poetry), PEP 621, lint-python
|
|
3
|
-
globs: "**/*.py,pyproject.toml,uv.lock,.github/workflows/lint-python.yml"
|
|
4
|
-
alwaysApply: false
|
|
5
|
-
version: '1.0'
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
Python-проєкти ведуться **виключно** на [uv](https://docs.astral.sh/uv/) — єдиний пакет-менеджер і резолвер. **Poetry заборонено.** Середовище: `uv sync --frozen` (строго з `uv.lock`).
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: JS Module
|
|
3
|
-
title: main.mjs
|
|
4
|
-
resource: npm/rules/python/mypy/main.mjs
|
|
5
|
-
docgen:
|
|
6
|
-
crc: 189c5b15
|
|
7
|
-
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
8
|
-
score: 100
|
|
9
|
-
issues: judge:inaccurate:0.99
|
|
10
|
-
judgeModel: openai-codex/gpt-5.4-mini
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Огляд
|
|
14
|
-
|
|
15
|
-
Please provide the draft section "overview" that needs revision, according to the context and requirements.
|
|
16
|
-
|
|
17
|
-
## Поведінка
|
|
18
|
-
|
|
19
|
-
1. Перевіряє наявність файлу `pyproject.toml` у кореневій директорії проєкту. Якщо його немає, перевірка не виконується.
|
|
20
|
-
2. Визначає цільові файли для перевірки: або всі `.py` файли у проєкті, або лише ті, що передані в контекст.
|
|
21
|
-
3. Перевіряє наявність у системному шляху інструмента `uv` та доступності `mypy` у середовищі `uv`. Якщо `uv` або `mypy` недоступні, перевірка пропускається.
|
|
22
|
-
4. Запускає `mypy` через `uv run --frozen` для визначених цільових файлів, передаючи поточну робочу директорію проєкту як робочу директорію для виконання.
|
|
23
|
-
5. Якщо `mypy` завершується з ненульовим кодом, фіксується порушення з виводом команди та кодом помилки.
|
|
24
|
-
6. Якщо `mypy` завершується успішно, результати перевірки вважаються позитивними.
|
|
25
|
-
|
|
26
|
-
## Публічний API
|
|
27
|
-
|
|
28
|
-
lint — виявляє помилки в коді Python за допомогою mypy.
|
|
29
|
-
|
|
30
|
-
## Гарантії поведінки
|
|
31
|
-
|
|
32
|
-
- Read-only: не виконує операцій запису (ФС/БД).
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* lint-поверхня python/mypy: read-only detector (`mypy`, через `uv run --frozen`). Per-file:
|
|
3
|
-
* приймає `ctx.files`, інакше `.` (весь проєкт). Виділено з колишнього bundled `python/check`
|
|
4
|
-
* (spec docs/specs/2026-07-02-text-check-per-file-split-design.md "Рішення python/php/rego") —
|
|
5
|
-
* mypy сам транзитивно підвантажує імпортовані модулі (follow-imports), тож дає коректні
|
|
6
|
-
* діагнози й на підмножині переданих файлів. Немає fix capability (mypy — detect-only).
|
|
7
|
-
*/
|
|
8
|
-
import { createViolationReporter } from '../../../scripts/lib/lint-surface/violation-reporter.mjs'
|
|
9
|
-
import { spawnAsync } from '../../../scripts/utils/spawn-async.mjs'
|
|
10
|
-
import { preparePythonRun } from '../lib/uv-run.mjs'
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Detector python/mypy (read-only).
|
|
14
|
-
* Async (не блокує event loop) — детектор може виконуватись у parallel lane `detectAll()`
|
|
15
|
-
* (ADR 260716-1354).
|
|
16
|
-
* @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст лінту.
|
|
17
|
-
* @returns {Promise<import('../../../scripts/lib/lint-surface/types.mjs').LintResult>} результат із порушеннями
|
|
18
|
-
*/
|
|
19
|
-
export async function lint(ctx) {
|
|
20
|
-
const reporter = createViolationReporter(ctx)
|
|
21
|
-
const { fail } = reporter
|
|
22
|
-
const cwd = ctx.cwd
|
|
23
|
-
|
|
24
|
-
const prepared = await preparePythonRun(ctx, fail, 'mypy')
|
|
25
|
-
if (!prepared) return reporter.result()
|
|
26
|
-
const { uv, targets } = prepared
|
|
27
|
-
|
|
28
|
-
const r = await spawnAsync(uv, ['run', '--frozen', 'mypy', ...targets], { cwd })
|
|
29
|
-
if (r.exitCode !== 0) {
|
|
30
|
-
const code = typeof r.exitCode === 'number' ? r.exitCode : 1
|
|
31
|
-
const out = `${r.stdout ?? ''}${r.stderr ?? ''}`.trim().slice(0, 2000)
|
|
32
|
-
const outSuffix = out ? `\n${out}` : ''
|
|
33
|
-
fail(`lint-python: mypy — помилка (код ${code}, python.mdc)${outSuffix}`, 'mypy-violation')
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return reporter.result()
|
|
37
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: JS Module
|
|
3
|
-
title: main.mjs
|
|
4
|
-
resource: npm/rules/python/project/main.mjs
|
|
5
|
-
docgen:
|
|
6
|
-
crc: 2426a5fa
|
|
7
|
-
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
8
|
-
score: 100
|
|
9
|
-
judgeModel: openai-codex/gpt-5.4-mini
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## Огляд
|
|
13
|
-
|
|
14
|
-
Огляд
|
|
15
|
-
Цей детектор забезпечує перевірку цілісності оточення Python на рівні всього проекту. Він діагностує відповідність файлів блокування та ліцензій, виконуючи аудит на основі повного набору залежностей, а не лише змін у межах дельти.
|
|
16
|
-
|
|
17
|
-
Поведінка
|
|
18
|
-
Система перевіряє наявність файлу `pyproject.toml` у робочому каталозі; відсутність файлу призводить до успішного завершення.
|
|
19
|
-
Визначає виконуваний файл `uv`; у разі відсутності він повідомляє про це (python.mdc).
|
|
20
|
-
Виконує аудит цілісності файлу блокування за допомогою `uv lock --check`. Виявлені порушення фіксуються (python.mdc), і виконання негайно припиняється.
|
|
21
|
-
Виконує збірку оточення через `uv sync --frozen`. Будь-які помилки фіксуються (python.mdc), зупиняючи процес.
|
|
22
|
-
Сканує ліцензії усіх залежностей за допомогою `pip-licenses`. Якщо інструмент недоступний, перевірка пропускається. При помилці інструменту фіксується порушення (python.mdc). Якщо знайдено пакети, ліцензії яких не відповідають критеріям Blue Oak Bronze+, фіксується порушення (python.mdc) із переліком відповідних пакетів.
|
|
23
|
-
Процес роботи є read-only, він не змінює файлової системи чи бази даних. Усі помилки перехоплюються з механізмом fail-safe, і винятки назовні не генеруються. На етапі виконання жодного кешування не відбувається.
|
|
24
|
-
|
|
25
|
-
## Поведінка
|
|
26
|
-
|
|
27
|
-
Поведінка:
|
|
28
|
-
1. Перевіряє наявність файлу `pyproject.toml` у робочому каталозі. Якщо його немає, операція завершується успішно.
|
|
29
|
-
2. Знаходить виконуваний файл `uv`. Якщо він не знайдений, операція завершується з повідомленням про відсутність `uv` (python.mdc).
|
|
30
|
-
3. Виконує перевірку цілісності блокування за допомогою `uv lock --check`. Якщо виникає помилка, фіксує порушення (python.mdc) та завершує роботу.
|
|
31
|
-
4. Виконує збірку оточення за допомогою `uv sync --frozen`. Якщо виникає помилка, фіксує порушення (python.mdc) та завершує роботу.
|
|
32
|
-
5. Виконує перевірку ліцензій залежностей за допомогою `pip-licenses`. Якщо інструмент недоступний, перевірка пропускається. Якщо виникає помилка виконання, фіксує порушення (python.mdc). Якщо знайдено пакети з ліцензіями, що не відповідають критеріям Blue Oak Bronze+, фіксує порушення (python.mdc), перелічуючи знахідки.
|
|
33
|
-
6. Повертає результат виконання перевірок.
|
|
34
|
-
|
|
35
|
-
## Публічний API
|
|
36
|
-
|
|
37
|
-
lint — знаходить проблеми в коді Python для даного проєкту.
|
|
38
|
-
|
|
39
|
-
## Гарантії поведінки
|
|
40
|
-
|
|
41
|
-
- Read-only: не виконує операцій запису (ФС/БД).
|
|
42
|
-
- Перехоплює помилки і не пропускає винятків назовні (fail-safe).
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* lint-поверхня python/project: read-only detector (`uv lock --check` + `uv sync --frozen` +
|
|
3
|
-
* `pip-licenses`), перейменовано з колишнього bundled `python/check` (spec
|
|
4
|
-
* docs/specs/2026-07-02-text-check-per-file-split-design.md §5-A). `full`, без `lint.glob` —
|
|
5
|
-
* lockfile-аудит і ліцензійна перевірка project-wide за природою, не входять у delta-план
|
|
6
|
-
* (§5): спрацьовують лише через `n-rules lint --full` або scoped `n-rules lint python`.
|
|
7
|
-
*/
|
|
8
|
-
import { existsSync } from 'node:fs'
|
|
9
|
-
import { join } from 'node:path'
|
|
10
|
-
|
|
11
|
-
import { createViolationReporter } from '../../../scripts/lib/lint-surface/violation-reporter.mjs'
|
|
12
|
-
import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
|
|
13
|
-
import { spawnAsync } from '../../../scripts/utils/spawn-async.mjs'
|
|
14
|
-
import { getBronzeAndAbove, isSpdxAllowed } from '../../../scripts/lib/blue-oak.mjs'
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Async (не блокує event loop) — детектор може виконуватись у parallel lane `detectAll()`
|
|
18
|
-
* (ADR 260716-1354).
|
|
19
|
-
* @param {string} label назва кроку.
|
|
20
|
-
* @param {string} cmd команда для запуску.
|
|
21
|
-
* @param {string[]} args аргументи команди.
|
|
22
|
-
* @param {string} cwd робочий каталог.
|
|
23
|
-
* @param {(msg: string, reason: string) => void} fail колбек реєстрації порушення.
|
|
24
|
-
* @param {string} reason машиночитна причина порушення.
|
|
25
|
-
* @returns {Promise<boolean>} true якщо OK
|
|
26
|
-
*/
|
|
27
|
-
async function runTool(label, cmd, args, cwd, fail, reason) {
|
|
28
|
-
const r = await spawnAsync(cmd, args, { cwd })
|
|
29
|
-
if (r.exitCode === 0) return true
|
|
30
|
-
const code = typeof r.exitCode === 'number' ? r.exitCode : 1
|
|
31
|
-
const out = `${r.stdout ?? ''}${r.stderr ?? ''}`.trim().slice(0, 2000)
|
|
32
|
-
const outSuffix = out ? `\n${out}` : ''
|
|
33
|
-
fail(`lint-python: ${label} — помилка (код ${code}, python.mdc)${outSuffix}`, reason)
|
|
34
|
-
return false
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Async (не блокує event loop) — детектор може виконуватись у parallel lane `detectAll()`
|
|
39
|
-
* (ADR 260716-1354).
|
|
40
|
-
* @param {string} uv шлях до бінарника uv.
|
|
41
|
-
* @param {string} tool ім'я інструменту в uv-середовищі.
|
|
42
|
-
* @returns {Promise<boolean>} true якщо інструмент доступний
|
|
43
|
-
*/
|
|
44
|
-
async function uvToolAvailable(uv, tool) {
|
|
45
|
-
const r = await spawnAsync(uv, ['run', '--frozen', tool, '--version'])
|
|
46
|
-
return r.exitCode === 0
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Перевірка ліцензій залежностей через pip-licenses (read-only).
|
|
51
|
-
* Async (не блокує event loop) — детектор може виконуватись у parallel lane `detectAll()`
|
|
52
|
-
* (ADR 260716-1354).
|
|
53
|
-
* @param {string} uv шлях до бінарника uv.
|
|
54
|
-
* @param {string} cwd робочий каталог.
|
|
55
|
-
* @param {(msg: string, reason: string) => void} fail колбек реєстрації порушення.
|
|
56
|
-
* @returns {Promise<boolean>} true якщо OK / пропущено
|
|
57
|
-
*/
|
|
58
|
-
async function checkPipLicenses(uv, cwd, fail) {
|
|
59
|
-
if (!(await uvToolAvailable(uv, 'pip-licenses'))) return true // недоступний → пропущено
|
|
60
|
-
const r = await spawnAsync(uv, ['run', '--frozen', 'pip-licenses', '--from=mixed', '--format=spdx-json'], {
|
|
61
|
-
cwd
|
|
62
|
-
})
|
|
63
|
-
if (r.exitCode !== 0) {
|
|
64
|
-
fail('lint-python: pip-licenses — помилка виконання', 'pip-licenses-error')
|
|
65
|
-
return false
|
|
66
|
-
}
|
|
67
|
-
const allowed = getBronzeAndAbove()
|
|
68
|
-
let doc
|
|
69
|
-
try {
|
|
70
|
-
doc = JSON.parse(r.stdout)
|
|
71
|
-
} catch {
|
|
72
|
-
doc = null
|
|
73
|
-
}
|
|
74
|
-
const packages = doc?.packages ?? []
|
|
75
|
-
const violations = packages.filter(pkg => {
|
|
76
|
-
const lic = pkg.licenseDeclared ?? pkg.licenseConcluded ?? 'NOASSERTION'
|
|
77
|
-
return !isSpdxAllowed(lic, allowed)
|
|
78
|
-
})
|
|
79
|
-
if (violations.length > 0) {
|
|
80
|
-
const list = violations
|
|
81
|
-
.map(
|
|
82
|
-
pkg =>
|
|
83
|
-
` ✗ ${pkg.name}@${pkg.versionInfo ?? '?'}: ${pkg.licenseDeclared ?? pkg.licenseConcluded ?? 'NOASSERTION'}`
|
|
84
|
-
)
|
|
85
|
-
.join('\n')
|
|
86
|
-
fail(
|
|
87
|
-
`lint-python: pip-licenses — ${violations.length} пакет(ів) поза Blue Oak Bronze+ (python.mdc)\n${list}`,
|
|
88
|
-
'license-violation'
|
|
89
|
-
)
|
|
90
|
-
return false
|
|
91
|
-
}
|
|
92
|
-
return true
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Detector python/project (read-only).
|
|
97
|
-
* Async (не блокує event loop) — детектор може виконуватись у parallel lane `detectAll()`
|
|
98
|
-
* (ADR 260716-1354).
|
|
99
|
-
* @param {import('../../../scripts/lib/lint-surface/types.mjs').LintContext} ctx контекст лінту.
|
|
100
|
-
* @returns {Promise<import('../../../scripts/lib/lint-surface/types.mjs').LintResult>} результат із порушеннями
|
|
101
|
-
*/
|
|
102
|
-
export async function lint(ctx) {
|
|
103
|
-
const reporter = createViolationReporter(ctx)
|
|
104
|
-
const { fail } = reporter
|
|
105
|
-
const cwd = ctx.cwd
|
|
106
|
-
|
|
107
|
-
if (!existsSync(join(cwd, 'pyproject.toml'))) return reporter.result()
|
|
108
|
-
|
|
109
|
-
const uv = resolveCmd('uv')
|
|
110
|
-
if (!uv) {
|
|
111
|
-
fail('lint-python: `uv` не знайдено в PATH (потрібен при наявному pyproject.toml, python.mdc)', 'uv-missing')
|
|
112
|
-
return reporter.result()
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (!(await runTool('uv lock --check', uv, ['lock', '--check'], cwd, fail, 'uv-lock-violation'))) {
|
|
116
|
-
return reporter.result()
|
|
117
|
-
}
|
|
118
|
-
if (!(await runTool('uv sync --frozen', uv, ['sync', '--frozen'], cwd, fail, 'uv-sync-violation'))) {
|
|
119
|
-
return reporter.result()
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
await checkPipLicenses(uv, cwd, fail)
|
|
123
|
-
|
|
124
|
-
return reporter.result()
|
|
125
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
## Rego-gate: перевірка `pyproject.toml`
|
|
2
|
-
|
|
3
|
-
Rego-пакет: `python.pyproject_toml`
|
|
4
|
-
|
|
5
|
-
Цільовий файл: `pyproject.toml`
|
|
6
|
-
|
|
7
|
-
Дві групи правил:
|
|
8
|
-
|
|
9
|
-
**1. Заборона Poetry** — перевіряє заборонені під-таблиці `[tool.*]` за deny-template (drift-safe через `--data template`): [pyproject.toml.deny.toml](./template/pyproject.toml.deny.toml)
|
|
10
|
-
|
|
11
|
-
**2. PEP 621** — метадані проєкту мають бути у секції **`[project]`** (PEP 621), а **не** в `[tool.poetry]`. Обовʼязкові поля:
|
|
12
|
-
|
|
13
|
-
- `[project].name` — назва пакета (непорожній рядок);
|
|
14
|
-
- `[project].version` — статична версія (непорожній рядок);
|
|
15
|
-
- `[project].requires-python` — мінімальна версія Python (наприклад `>=3.12`);
|
|
16
|
-
- `[project].dependencies` — залежності (навіть порожній список `[]`).
|
|
17
|
-
|
|
18
|
-
Канонічний цільовий вигляд: [pyproject.toml.snippet.toml](./template/pyproject.toml.snippet.toml)
|
|
19
|
-
|
|
20
|
-
## Залежності та lock-файл (uv)
|
|
21
|
-
|
|
22
|
-
Залежності додаються командою `uv add <pkg>`; dev-залежності — `uv add --dev <pkg>`. Lock-файл — **`uv.lock`** (іде в коміт, оновлюється командою `uv lock`).
|
|
23
|
-
|
|
24
|
-
## Міграція з Poetry на uv
|
|
25
|
-
|
|
26
|
-
1. Прибери `[tool.poetry]` і `poetry.lock` / `poetry.toml`.
|
|
27
|
-
2. Перенеси метадані в `[project]` (name, version, requires-python, dependencies) за PEP 621.
|
|
28
|
-
3. Згенеруй lock: `uv lock` → `uv.lock`.
|
|
29
|
-
4. Dev-залежності: `uv add --dev ruff mypy …`.
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
# Перевірка `pyproject.toml` (python.mdc).
|
|
2
|
-
#
|
|
3
|
-
# Канон надходить через --data: { "template": { "deny": ... } }
|
|
4
|
-
# Структура --data сформована з template/pyproject.toml.deny.toml.
|
|
5
|
-
# FS-перевірки (`poetry.lock`, `poetry.toml`, `uv.lock`, `package.json`) — у JS.
|
|
6
|
-
#
|
|
7
|
-
# Дві групи правил:
|
|
8
|
-
# 1. Заборона Poetry — `[tool.poetry]` (та інші заборонені під-таблиці `tool`)
|
|
9
|
-
# керується deny-template, drift-safe.
|
|
10
|
-
# 2. PEP 621 — `[project].name` і `[project].version` обовʼязкові (структурна
|
|
11
|
-
# вимога без канонічного літералу, тому inline).
|
|
12
|
-
package python.pyproject_toml
|
|
13
|
-
|
|
14
|
-
import rego.v1
|
|
15
|
-
|
|
16
|
-
# ── Заборона Poetry (deny-template керує переліком) ──────────────────────────
|
|
17
|
-
|
|
18
|
-
deny contains msg if {
|
|
19
|
-
some key, reason in object.get(data.template.deny, "tool", {})
|
|
20
|
-
key in object.keys(object.get(input, "tool", {}))
|
|
21
|
-
msg := sprintf("pyproject.toml: [tool.%s] — %s", [key, reason])
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
# ── PEP 621: обовʼязкові [project].* ─────────────────────────────────────────
|
|
25
|
-
|
|
26
|
-
deny contains msg if {
|
|
27
|
-
not project_field_set("name")
|
|
28
|
-
msg := "pyproject.toml: відсутній [project].name (PEP 621 — мігруй з [tool.poetry], python.mdc)"
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
deny contains msg if {
|
|
32
|
-
not project_field_set("version")
|
|
33
|
-
msg := "pyproject.toml: відсутній статичний [project].version (PEP 621, python.mdc)"
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
deny contains msg if {
|
|
37
|
-
not project_field_set("requires-python")
|
|
38
|
-
msg := "pyproject.toml: відсутній [project].requires-python (наприклад '>=3.12') (PEP 621, python.mdc)"
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
deny contains msg if {
|
|
42
|
-
not project_key_exists("dependencies")
|
|
43
|
-
msg := "pyproject.toml: відсутній [project].dependencies (навіть порожній список `[]`) (PEP 621, python.mdc)"
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
project_field_set(key) if {
|
|
47
|
-
value := object.get(object.get(input, "project", {}), key, "")
|
|
48
|
-
value != ""
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
project_key_exists(key) if {
|
|
52
|
-
key in object.keys(object.get(input, "project", {}))
|
|
53
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
# Канонічний цільовий вигляд після міграції з Poetry на uv (PEP 621).
|
|
2
|
-
# Метадані — у [project] (а не [tool.poetry]); dev-залежності додавай через
|
|
3
|
-
# `uv add --dev <pkg>` (uv тримає їх у [dependency-groups].dev або [tool.uv]).
|
|
4
|
-
[project]
|
|
5
|
-
name = "your-package"
|
|
6
|
-
version = "0.1.0"
|
|
7
|
-
requires-python = ">=3.12"
|
|
8
|
-
dependencies = []
|
|
9
|
-
|
|
10
|
-
[build-system]
|
|
11
|
-
requires = ["hatchling"]
|
|
12
|
-
build-backend = "hatchling.build"
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
type: JS Module
|
|
3
|
-
title: fix-ruff.mjs
|
|
4
|
-
resource: npm/rules/python/ruff/fix-ruff.mjs
|
|
5
|
-
docgen:
|
|
6
|
-
crc: e0a79f8d
|
|
7
|
-
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
8
|
-
score: 100
|
|
9
|
-
issues: judge:inaccurate:0.99
|
|
10
|
-
judgeModel: openai-codex/gpt-5.4-mini
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Огляд
|
|
14
|
-
|
|
15
|
-
T0-autofix для `python/ruff` забезпечує детерміновані виправлення та форматування файлів проєкту (`ruff check --fix` та `ruff format`), якщо інструмент `uv` доступний. Його призначення — стандартизувати код, порівнюючи зміни, внесені через автоматичні інструменти, з початковим вмістом.
|
|
16
|
-
|
|
17
|
-
## Поведінка
|
|
18
|
-
|
|
19
|
-
Поведінка
|
|
20
|
-
1. Перевіряє, чи доступна команда `uv`. Якщо ні, жодних дій не виконує.
|
|
21
|
-
2. Визначає список усіх файлів `.py` у проєкті, використовуючи інструмент `git`.
|
|
22
|
-
3. Зберігає поточний вміст усіх знайдених `.py` файлів.
|
|
23
|
-
4. Виконує команду `ruff check --fix` у всіх файлах проєкту, щоб автоматично виправити порушення.
|
|
24
|
-
5. Виконує команду `ruff format` у всіх файлах проєкту, щоб застосувати стандарт форматування.
|
|
25
|
-
6. Порівнює поточний вміст файлів із вмістом до виправлення.
|
|
26
|
-
7. Якщо вміст файлу змінився, цей файл позначається як змінений.
|
|
27
|
-
8. Якщо були змінені файли, результат повідомляється, а ці файли реєструються як змінені.
|
|
28
|
-
|
|
29
|
-
## Гарантії поведінки
|
|
30
|
-
|
|
31
|
-
- Read-only: не виконує операцій запису (ФС/БД).
|
|
32
|
-
- Перехоплює помилки і не пропускає винятків назовні (fail-safe).
|
|
33
|
-
- За певних помилок повертає порожнє значення (напр. `null`) замість винятку.
|