@nitra/cursor 12.8.5 → 12.8.7
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 +5 -5
- package/package.json +1 -1
- package/rules/abie/js/http_route_base.mdc +25 -0
- package/rules/abie/js/ua_http_route.mdc +1 -1
- package/rules/abie/main.mdc +12 -0
- package/rules/adr/js/hooks.mdc +32 -0
- package/rules/adr/js/madr_format.mdc +96 -0
- package/rules/adr/js/settings_policy.mdc +34 -0
- package/rules/adr/main.mdc +13 -95
- package/rules/bun/js/bunfig.mdc +12 -0
- package/rules/bun/js/layout.mdc +60 -0
- package/rules/bun/js/lint.mdc +9 -0
- package/rules/bun/js/package_json.mdc +19 -0
- package/rules/bun/main.mdc +9 -61
- package/rules/capacitor/js/ios_spm.mdc +69 -0
- package/rules/capacitor/js/version.mdc +29 -0
- package/rules/capacitor/main.mdc +8 -22
- package/rules/changelog/js/agent-workflow.mdc +15 -0
- package/rules/changelog/js/changelog-format.mdc +33 -0
- package/rules/changelog/js/comparison-models.mdc +40 -0
- package/rules/changelog/main.mdc +4 -98
- package/rules/ci4/js/marksman_config.mdc +31 -0
- package/rules/ci4/js/vscode_extensions.mdc +33 -0
- package/rules/ci4/main.mdc +14 -14
- package/rules/docker/js/compile.mdc +44 -0
- package/rules/docker/js/hadolint.mdc +50 -0
- package/rules/docker/js/mirror.mdc +13 -0
- package/rules/docker/js/multistage.mdc +13 -0
- package/rules/docker/js/native-addon.mdc +43 -0
- package/rules/docker/js/nginx-tag.mdc +7 -0
- package/rules/docker/js/nginx-user.mdc +37 -0
- package/rules/docker/js/non-root.mdc +39 -0
- package/rules/docker/main.mdc +15 -196
- package/rules/ga/js/lint_toolchain.mdc +15 -0
- package/rules/ga/js/required_workflows.mdc +35 -0
- package/rules/ga/js/vscode.mdc +17 -0
- package/rules/ga/js/workflow_common.mdc +108 -0
- package/rules/ga/js/workflows.mdc +32 -0
- package/rules/ga/js/zizmor.mdc +7 -0
- package/rules/ga/main.mdc +17 -125
- package/rules/graphql/js/tooling.mdc +13 -0
- package/rules/graphql/js/vscode_extensions.mdc +13 -0
- package/rules/graphql/main.mdc +3 -22
- package/rules/hasura/js/internal_urls.mdc +27 -0
- package/rules/hasura/js/migrations.mdc +13 -0
- package/rules/hasura/js/svc_hl.mdc +17 -0
- package/rules/hasura/main.mdc +8 -30
- package/rules/image-avif/js/avif_generation.mdc +26 -0
- package/rules/image-avif/js/package_json_optout.mdc +21 -0
- package/rules/image-avif/main.mdc +7 -34
- package/rules/image-compress/js/package_json.mdc +7 -0
- package/rules/image-compress/js/package_setup.mdc +13 -0
- package/rules/image-compress/main.mdc +4 -12
- package/rules/js/docs/index.md +3 -3
- package/rules/js/js/dep-policy.mdc +17 -0
- package/rules/js/js/eslint-config.mdc +28 -0
- package/rules/js/js/extensions.mdc +8 -0
- package/rules/js/js/file-extensions.mdc +12 -0
- package/rules/js/js/for-in.mdc +26 -0
- package/rules/js/js/jscpd.mdc +42 -0
- package/rules/js/js/knip.mdc +15 -0
- package/rules/js/js/lint-js-workflow.mdc +58 -0
- package/rules/js/js/oxlintrc.mdc +20 -0
- package/rules/js/js/package-json.mdc +31 -0
- package/rules/js/js/tests.mdc +9 -0
- package/rules/js/js/utils-lib-structure.mdc +15 -0
- package/rules/js/main.mdc +21 -214
- package/rules/js-bun-db/js/bun-sql-migration.mdc +15 -0
- package/rules/js-bun-db/js/connection.mdc +42 -0
- package/rules/js-bun-db/js/pg-format-identifiers.mdc +102 -0
- package/rules/js-bun-db/js/pg-format-shim.mdc +99 -0
- package/rules/js-bun-db/js/pg-leftover.mdc +27 -0
- package/rules/js-bun-db/js/pg-listen-notify.mdc +51 -0
- package/rules/js-bun-db/js/query-safety.mdc +117 -0
- package/rules/js-bun-db/js/sql-array.mdc +88 -0
- package/rules/js-bun-db/js/unsafe.mdc +65 -0
- package/rules/js-bun-db/main.mdc +15 -605
- package/rules/js-bun-redis/js/imports.mdc +47 -0
- package/rules/js-bun-redis/js/package_json.mdc +44 -0
- package/rules/js-bun-redis/main.mdc +3 -11
- package/rules/js-mssql/js/mssql-in-list.mdc +38 -0
- package/rules/js-mssql/js/mssql-pool.mdc +56 -0
- package/rules/js-mssql/js/mssql-query-template.mdc +33 -0
- package/rules/js-mssql/js/mssql-tvp.mdc +75 -0
- package/rules/js-mssql/js/mssql-version.mdc +7 -0
- package/rules/js-mssql/main.mdc +10 -198
- package/rules/js-run/js/check-env.mdc +35 -0
- package/rules/js-run/js/conn-aliases.mdc +109 -0
- package/rules/js-run/js/jsconfig.mdc +20 -0
- package/rules/js-run/js/otel-configmap.mdc +6 -0
- package/rules/js-run/js/pino.mdc +6 -0
- package/rules/js-run/js/project-structure.mdc +11 -0
- package/rules/js-run/js/runtime.mdc +14 -0
- package/rules/js-run/js/scope.mdc +11 -0
- package/rules/js-run/js/settimeout.mdc +11 -0
- package/rules/js-run/js/temporal.mdc +5 -0
- package/rules/js-run/main.mdc +16 -218
- package/rules/k8s/js/configmap.mdc +41 -0
- package/rules/k8s/js/deployment_resources.mdc +49 -0
- package/rules/k8s/js/hasura_httproute.mdc +91 -0
- package/rules/k8s/js/hpa_apiversion.mdc +27 -0
- package/rules/k8s/js/ingress_gateway.mdc +16 -0
- package/rules/k8s/js/kustomize_structure.mdc +144 -0
- package/rules/k8s/js/lint_k8s.mdc +72 -0
- package/rules/k8s/js/multidoc_yaml.mdc +5 -0
- package/rules/k8s/js/network_policy.mdc +136 -0
- package/rules/k8s/js/schema_modeline.mdc +57 -0
- package/rules/k8s/js/service.mdc +44 -0
- package/rules/k8s/js/topology_hpa_pdb.mdc +181 -0
- package/rules/k8s/main.mdc +30 -843
- package/rules/nginx-default-tpl/js/dockerfile.mdc +36 -0
- package/rules/nginx-default-tpl/js/http-route.mdc +41 -0
- package/rules/nginx-default-tpl/js/ini-keys.mdc +21 -0
- package/rules/nginx-default-tpl/js/template-structure.mdc +86 -0
- package/rules/nginx-default-tpl/js/vscode.mdc +37 -0
- package/rules/nginx-default-tpl/main.mdc +6 -112
- package/rules/npm-module/js/docs/index.md +5 -5
- package/rules/npm-module/js/docs/rule_meta.md +6 -6
- package/rules/npm-module/js/docs/skill_meta.md +8 -8
- package/rules/npm-module/js/header_doc_pointer.mdc +18 -0
- package/rules/npm-module/js/package_structure.mdc +62 -0
- package/rules/npm-module/js/rule_meta.mdc +11 -0
- package/rules/npm-module/js/skill_meta.mdc +11 -0
- package/rules/npm-module/main.mdc +10 -55
- package/rules/php/js/lint_php_yml.mdc +12 -0
- package/rules/php/js/tooling.mdc +66 -0
- package/rules/php/main.mdc +7 -66
- package/rules/python/js/lint_python_yml.mdc +23 -0
- package/rules/python/js/pyproject_toml.mdc +32 -0
- package/rules/python/js/tooling.mdc +23 -0
- package/rules/python/main.mdc +9 -33
- package/rules/rego/js/rego-lint.mdc +31 -0
- package/rules/rego/js/vscode_extensions.mdc +11 -0
- package/rules/rego/js/vscode_settings.mdc +13 -0
- package/rules/rego/main.mdc +8 -24
- package/rules/rust/js/coverage.mdc +28 -0
- package/rules/rust/js/lint.mdc +22 -0
- package/rules/rust/js/tauri_composition.mdc +8 -0
- package/rules/rust/js/vscode_extensions.mdc +12 -0
- package/rules/rust/main.mdc +8 -38
- package/rules/security/js/rego_policies.mdc +15 -0
- package/rules/security/js/sample_secret.mdc +19 -0
- package/rules/security/js/trufflehog.mdc +21 -0
- package/rules/security/main.mdc +7 -35
- package/rules/style/js/admin-table.mdc +88 -0
- package/rules/style/js/colors.mdc +21 -0
- package/rules/style/js/gap.mdc +22 -0
- package/rules/style/js/quasar-fixes.mdc +32 -0
- package/rules/style/js/quasar.mdc +7 -0
- package/rules/style/js/tooling.mdc +85 -0
- package/rules/style/main.mdc +13 -253
- package/rules/tauri/js/cargo_mutants_config.mdc +39 -0
- package/rules/tauri/js/tool_surface.mdc +21 -0
- package/rules/tauri/js/tooling.mdc +25 -0
- package/rules/tauri/main.mdc +8 -78
- package/rules/test/js/cargo_mutants_config.mdc +18 -0
- package/rules/test/js/docs/index.md +7 -7
- package/rules/test/js/location.mdc +52 -0
- package/rules/test/js/no-console-store-restore.mdc +11 -0
- package/rules/test/js/no-process-chdir.mdc +15 -0
- package/rules/test/js/no-relative-fs-path.mdc +22 -0
- package/rules/test/js/sandbox-aware-test.mdc +28 -0
- package/rules/test/js/stryker_config.mdc +26 -0
- package/rules/test/js/vitest-config-pool-forks.mdc +33 -0
- package/rules/test/main.mdc +18 -184
- package/rules/text/js/ci-lint-text.mdc +15 -0
- package/rules/text/js/cspell.mdc +81 -0
- package/rules/text/js/dotenv-linter.mdc +16 -0
- package/rules/text/js/forbidden-prettier.mdc +13 -0
- package/rules/text/js/markdownlint.mdc +25 -0
- package/rules/text/js/oxfmt.mdc +35 -0
- package/rules/text/js/package-json.mdc +26 -0
- package/rules/text/js/shellcheck.mdc +18 -0
- package/rules/text/js/v8r.mdc +23 -0
- package/rules/text/js/vscode.mdc +86 -0
- package/rules/text/main.mdc +20 -237
- package/rules/vue/js/composition-api.mdc +82 -0
- package/rules/vue/js/nheader-layout.mdc +171 -0
- package/rules/vue/js/node-imports.mdc +25 -0
- package/rules/vue/js/quasar-ui.mdc +32 -0
- package/rules/vue/js/structure.mdc +101 -0
- package/rules/vue/js/testing.mdc +32 -0
- package/rules/vue/js/tfm-translations.mdc +26 -0
- package/rules/vue/js/vite-config.mdc +126 -0
- package/rules/vue/js/vite-env.mdc +55 -0
- package/rules/vue/js/vue-imports.mdc +25 -0
- package/rules/vue/main.mdc +16 -640
- package/scripts/auto-rules.mjs +6 -6
- package/scripts/auto-skills.mjs +3 -3
- package/scripts/docs/auto-rules.md +17 -31
- package/scripts/docs/auto-skills.md +18 -163
- package/scripts/docs/index.md +16 -16
- package/scripts/lib/docs/index.md +36 -36
- package/scripts/lib/docs/mirror-parity.md +7 -7
- package/scripts/lib/docs/rule-meta.md +12 -12
- package/scripts/lib/docs/skill-meta.md +9 -9
- package/scripts/lib/docs/worktree-notice.md +10 -8
- package/scripts/lib/rule-meta.mjs +6 -6
- package/scripts/lib/skill-meta.mjs +6 -6
- package/scripts/lib/worktree-notice.mjs +2 -2
- package/scripts/utils/docs/index.md +14 -14
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
## iOS: лише SPM, виняток через Podfile
|
|
2
|
+
|
|
3
|
+
### Правило за замовчуванням
|
|
4
|
+
|
|
5
|
+
Не залишай `Podfile` (поза `Pods/`) у вихідному iOS-шарі, **якщо** уся потрібна
|
|
6
|
+
iOS-функціональність (нативні плагіни/модулі) може працювати **лише** через **SPM** (Swift Package Manager).
|
|
7
|
+
|
|
8
|
+
Перевірка рекурсивно шукає `Podfile` у `ios/`, пропускаючи `Pods/`, `build/`, `DerivedData/`.
|
|
9
|
+
|
|
10
|
+
### Плагіни @nitra/
|
|
11
|
+
|
|
12
|
+
Плагіни зі скоупу `@nitra/` за політикою **підтримують SPM** — перевіряти їх на SPM **не потрібно**
|
|
13
|
+
(check не обходить `package.json` на предмет `@nitra/`).
|
|
14
|
+
|
|
15
|
+
### Коли Podfile дозволений
|
|
16
|
+
|
|
17
|
+
Якщо не вся потрібна iOS-функціональність поза `@nitra/` (сторонні Capacitor-плагіни, інша
|
|
18
|
+
нативна залежність) доступна через SPM — `Podfile` дозволяється, але це **обов'язково** треба
|
|
19
|
+
явно задати в кореневому **`package.json`** або в **`capacitor.config.json` / `capacitor.config.ts` / `capacitor.config.mjs`**:
|
|
20
|
+
|
|
21
|
+
- **`"iosCocoaPodsBecausePluginsLackSpm": true`** — семантика: не вся потрібна нативна частина
|
|
22
|
+
поза `@nitra/` на SPM; `@nitra/` у це не входить;
|
|
23
|
+
- або **`"iosCocoaPodsAllowed": true`** — короткий alias для того самого винятку.
|
|
24
|
+
|
|
25
|
+
Без одного з цих прапорів `true` наявний `Podfile` поза `Pods/` вважається порушенням правила «лише SPM».
|
|
26
|
+
|
|
27
|
+
**Де задати виняток у `package.json`:**
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
{
|
|
31
|
+
"nitra": {
|
|
32
|
+
"iosCocoaPodsBecausePluginsLackSpm": true
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
або коротший alias:
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"nitra": {
|
|
42
|
+
"iosCocoaPodsAllowed": true
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**Де задати виняток у `capacitor.config.json`:**
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"nitra": {
|
|
52
|
+
"iosCocoaPodsAllowed": true
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Де задати виняток у `capacitor.config.ts` / `capacitor.config.mjs`:**
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
const config = {
|
|
61
|
+
// ...
|
|
62
|
+
nitra: {
|
|
63
|
+
iosCocoaPodsAllowed: true,
|
|
64
|
+
},
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Перевірка читає **лише** кореневі файли: `package.json`, потім capacitor-конфіги у корені.
|
|
69
|
+
У `.ts` / `.mjs`: шукається блок `nitra { ... }` і на його тілі перевіряються ці boolean-поля.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
## Версія Capacitor
|
|
2
|
+
|
|
3
|
+
У `package.json` (у **корені** репозиторію чи **workspace**-пакеті) оголошення **`@capacitor/core`**
|
|
4
|
+
має вказувати діапазон, **сумісний лише з мажорною версією 8 і вище** (наприклад `^8.0.0`).
|
|
5
|
+
**`*`**, `latest` і діапазони, де можлива 7-мажор, — неприйнятні.
|
|
6
|
+
|
|
7
|
+
Перевірка обходить усі `package.json` у дереві (крім `node_modules`, `.git`, `dist`, `coverage`,
|
|
8
|
+
`Pods`, `.turbo`, `.next`, `build`) і перевіряє нижню межу діапазону через `capacitorVersionRangeMinMajor`.
|
|
9
|
+
Підтримуються `||`-частини, hyphen-range (`7 - 9`), `^`, `~`, `>=`, `>`, `=`, bare-version;
|
|
10
|
+
`workspace:*` / `*` / `x` / `latest` — пропускаються (не блокують).
|
|
11
|
+
|
|
12
|
+
**Приклади допустимих діапазонів:**
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
"@capacitor/core": "^8.0.0"
|
|
16
|
+
"@capacitor/core": ">=8"
|
|
17
|
+
"@capacitor/core": "8.x"
|
|
18
|
+
"@capacitor/core": "workspace:*"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Приклади неприйнятних діапазонів:**
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
"@capacitor/core": "^7.0.0" // мажор 7 — занадто старий
|
|
25
|
+
"@capacitor/core": "*" // будь-яка — неприйнятна
|
|
26
|
+
"@capacitor/core": "latest" // неприйнятна
|
|
27
|
+
"@capacitor/core": ">=6" // нижня межа 6 — занадто старий
|
|
28
|
+
"@capacitor/core": "6 - 9" // hyphen-range: нижня межа 6 — неприйнятна
|
|
29
|
+
```
|
package/rules/capacitor/main.mdc
CHANGED
|
@@ -5,30 +5,16 @@ alwaysApply: false
|
|
|
5
5
|
version: '1.1'
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Правило перевіряє версію `@capacitor/core` у `package.json` та коректність використання CocoaPods/SPM у iOS-шарі Capacitor-проєкту.
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
має вказувати діапазон, **сумісний лише з мажорною версією 8 і вище** (наприклад `^8.0.0`).
|
|
12
|
-
**`*`**, `latest` і діапазони, де можлива 7-мажор, — неприйнятні.
|
|
10
|
+
[capacitor-version](./js/version.mdc)
|
|
13
11
|
|
|
14
|
-
|
|
12
|
+
[capacitor-ios-spm](./js/ios_spm.mdc)
|
|
15
13
|
|
|
16
|
-
|
|
17
|
-
iOS-функціональність (нативні плагіни/модулі) може працювати **лише** через **SPM** (Swift Package Manager).
|
|
14
|
+
## Швидкий gate через conftest
|
|
18
15
|
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
| namespace | що перевіряє |
|
|
17
|
+
|---|---|
|
|
18
|
+
| `capacitor.package_json` | версія `@capacitor/core` у `dependencies` — мінімум major 8 (спрощений JS-порт для одиничного `package.json`) |
|
|
21
19
|
|
|
22
|
-
|
|
23
|
-
**Capacitor**-плагіни, інша нативна залежність) **доступна** через **SPM** — `Podfile` **дозволяється**,
|
|
24
|
-
але це **обов’язково** треба явно задати в кореневому **`package.json`** або в
|
|
25
|
-
**`capacitor.config.json` / `capacitor.config.ts` / `capacitor.config.mjs`**
|
|
26
|
-
|
|
27
|
-
- **`"iosCocoaPodsBecausePluginsLackSpm": true`** (семантика: **не** **вся** потрібна нативна частина
|
|
28
|
-
**поза** **@nitra/** **на** **SPM**; **@nitra/** у це **не** входить);
|
|
29
|
-
- або **`"iosCocoaPodsAllowed": true`** (короткий **alias** для того самого **винятку**);
|
|
30
|
-
|
|
31
|
-
Без **одного** з цих прапорів `true` наявний **Podfile** поза **`Pods/`** вважається **порушенням** правила **«лише** **SPM**».
|
|
32
|
-
|
|
33
|
-
- Перевірка читає **лише** кореневі файли: **`package.json`**, потім **capacitor-конфіги** у **корені** (див. вище).
|
|
34
|
-
У **`.ts` / `.mjs`**: шукається блок **nitra** `{ ... }` і **на його тілі** перевіряються ці **boolean**-поля.
|
|
20
|
+
JS-перевірка (`platforms.mjs`) — authoritative: підтримує `||`-діапазони, hyphen-range, workspace-monorepo та iOS-специфічну логіку (Podfile).
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
## STOP — перед завершенням відповіді агента
|
|
2
|
+
|
|
3
|
+
> **Якщо в цій сесії ти змінив(ла) файли в пакетному workspace** (код, rego, правила, скіли, скрипти, конфіги, тести — **не** лише `docs/` / `doc/`) — **не завершуй задачу**, поки не виконаєш **усі три** кроки нижче в **тому ж** наборі змін. Це не «опційно після синку» — це частина PR.
|
|
4
|
+
|
|
5
|
+
1. **Поклади change-файл** `<ws>/.changes/YYMMDD-HHMM.md` з frontmatter `bump:` (`major|minor|patch`) + `section:` (`Added|Changed|Fixed|Removed`) і текстом опису. Команда: `npx @nitra/cursor change --bump <…> --section <…> --message "<…>" [--ws <шлях>]`. Якщо файл за ту саму хвилину вже існує, CLI атомарно створює `YYMMDD-HHMM-2.md`, потім `-3` тощо.
|
|
6
|
+
2. **Ніколи** не редагуй `version` і `CHANGELOG.md` вручну — навіть для hotfix. Єдиний артефакт зміни — change-файл; `version`/CHANGELOG формує `n-cursor release` у CI на `main` (агрегує change-файли, ставить git-тег `<name>@<version>`). Будь-яка зміна `version` поза CI (drift від бази чи опублікованої) завалює `check changelog` — навіть якщо поряд є change-файл.
|
|
7
|
+
3. **`npx @nitra/cursor fix changelog`** → exit **`0`** (достатньо наявності change-файлу; `version` лишається незмінним).
|
|
8
|
+
|
|
9
|
+
**Це правило релевантне завжди після будь-якої зміни** коду/конфігу/тестів/воркспейсу — **не** класифікуй його як «лише для релізу». Уже запущені тести чи білд **не** знімають вимогу changelog. Операційно перед фінальною відповіддю: `git status --short` → зіставити змінені шляхи з workspace-ами → change-файл для кожного релевантного workspace → `npx @nitra/cursor fix changelog` (exit `0`). Якщо у фінальній відповіді не можеш заповнити рядок `Changelog: …`, отже ти пропустив(ла) цей крок.
|
|
10
|
+
|
|
11
|
+
**Тригер шляхів (приклади):** `npm/**`, `packages/foo/**`, будь-який каталог з власним `package.json` / `pyproject.toml`, куди потрапили правки.
|
|
12
|
+
|
|
13
|
+
**Інверсія (change-файл не потрібен):** лише `docs/` / `doc/`; синхронізований із `@nitra/cursor` інструментарій (`.cursor/`, `.claude/`); лише `.gitignore`. **Корінь монорепо** (воркспейс `.` за наявності підпакетів) не перевіряється взагалі — отже й кореневі `AGENTS.md` / `CLAUDE.md` та bump `@nitra/cursor` у `devDependencies`. Окремого «релізного кроку» у feature-флоу немає — `version`/`CHANGELOG.md` змінює лише CI.
|
|
14
|
+
|
|
15
|
+
**Pre-commit (людина):** `hk` у цьому репо запускає `fix changelog` при змінах під `npm/**` в **autofix-режимі** (env `N_CURSOR_CHANGELOG_AUTOFIX=1`): за відсутності change-файлу хук **сам** його створює (дефолти `patch`/`Changed`, опис = subject останнього коміту) і ставить у git-індекс, тож коміт не падає. Це лише підстраховка — агент не покладайся на неї: виконуй кроки 1–3 **до** фінальної відповіді, бо автоген ставить осмислений опис лише випадково (subject попереднього коміту), і `bump`/`section`/текст майже завжди треба відредагувати. Autofix-режим також **не робить мережевих викликів** (`npm view` / PyPI fetch пропускаються) — реєстрова drift-перевірка `version` у хуці не виконується (її ловить CI / ручний `fix`). Поза хуком (CI, ручний `fix`/`check`) autofix вимкнено — поведінка лишається fail-on-missing з повною drift-перевіркою.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
## Формат CHANGELOG.md
|
|
2
|
+
|
|
3
|
+
[Keep a Changelog 1.1.0](https://keepachangelog.com/uk/1.1.0/), мова — українська, новіші версії зверху.
|
|
4
|
+
|
|
5
|
+
```md title="<ws>/CHANGELOG.md"
|
|
6
|
+
# Changelog
|
|
7
|
+
|
|
8
|
+
Усі помітні зміни цього пакета документуються тут.
|
|
9
|
+
|
|
10
|
+
Формат — [Keep a Changelog](https://keepachangelog.com/uk/1.1.0/), нумерація — [SemVer](https://semver.org/lang/uk/).
|
|
11
|
+
|
|
12
|
+
## [1.2.3] - 2026-05-05
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- ...
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- ...
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- ...
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Секції — підмножина `### Added`, `### Changed`, `### Fixed`, `### Removed` (одна або кілька).
|
|
28
|
+
|
|
29
|
+
## Post-release інваріант (гарантує CI)
|
|
30
|
+
|
|
31
|
+
Перша (верхня) секція `## [version]` у `CHANGELOG.md` дорівнює полю `version` у маніфесті — але це **post-release** твердження, яке забезпечує `n-cursor release` у CI, агрегуючи change-файли (bump `version` + генерація секції + git-тег `<name>@<version>`). **Локально цю рівність руками не підтримують**: у feature-флоу `version`/`CHANGELOG.md` не чіпають, тож верхня секція може відставати від майбутньої версії — це нормально. Drift `version` поза CI (vs реєстр / vs git-база) ловить `check changelog` як заборонений ручний bump.
|
|
32
|
+
|
|
33
|
+
Інструкції щодо bump `version` і редагування `CHANGELOG.md` живуть **лише** в правилі `changelog` — джерелі істини. Інші правила (зокрема `n-npm-module.mdc`) їй підпорядковані й власних інструкцій bump/CHANGELOG не дублюють.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
## Дві моделі бази порівняння
|
|
2
|
+
|
|
3
|
+
Режим визначається автоматично з маніфесту.
|
|
4
|
+
|
|
5
|
+
### registry-published (npm / PyPI)
|
|
6
|
+
|
|
7
|
+
**npm:** непорожнє `name`, не `private: true`, масив `files`.
|
|
8
|
+
|
|
9
|
+
**Python:** статичні `project.name` і `project.version` у `pyproject.toml` (або Poetry-секція).
|
|
10
|
+
|
|
11
|
+
1. **Локальна `version` ≠ опублікованій** (npm / PyPI): drift поза CI → **fail** (ручний bump заборонено; навіть із change-файлом). Відкоти `version`.
|
|
12
|
+
2. **Версії збігаються**, але в git є **релевантні** зміни без change-файлу → fail. Для npm `"CHANGELOG.md"` має бути в `files` (публікується разом із пакетом).
|
|
13
|
+
3. **Реєстр недосяжний** — fail-safe pass.
|
|
14
|
+
4. **Немає релевантних змін** — pass.
|
|
15
|
+
|
|
16
|
+
### local-only
|
|
17
|
+
|
|
18
|
+
**npm:** `private: true` або без `files`. **Python:** без пари name+version для реєстру. База залежить від гілки:
|
|
19
|
+
|
|
20
|
+
1. На **`dev`** local-only не активний (крім незакомічених registry-published).
|
|
21
|
+
2. На **`main`** — diff від **`origin/main`** (попередній опублікований `main`); без remote — від `HEAD~1`. **`dev` не використовується** як база на `main`.
|
|
22
|
+
3. На **feature-гілці** — `merge-base` з **`dev`**, якщо є; інакше з **`main`** (репо без `dev`).
|
|
23
|
+
4. Drift `version` від бази → **fail** (ручний bump заборонено). Зміни фіксуй change-файлом; bump зробить CI.
|
|
24
|
+
|
|
25
|
+
Якщо немає git або немає `dev`/`main`/`origin/main` — local-only пропускається.
|
|
26
|
+
|
|
27
|
+
## Чеклист агента (деталі)
|
|
28
|
+
|
|
29
|
+
Повний алгоритм — у блоці **STOP** (changelog-agent-workflow); тут лише уточнення.
|
|
30
|
+
|
|
31
|
+
**Інверсія (за замовчуванням не вимагають change-файлу):**
|
|
32
|
+
|
|
33
|
+
- зміни **лише** під `docs/` або `doc/`;
|
|
34
|
+
- синхронізований із `@nitra/cursor` інструментарій під `.cursor/` (канонічні правила й скіли) і `.claude/` (ADR-хуки) — це дзеркало tooling-пакета, а не логіка воркспейсу;
|
|
35
|
+
- будь-які зміни в **корені монорепо** (воркспейс `.` за наявності підпакетів) — корінь веде glue/конфіг/tooling, власного CHANGELOG не має; помітні зміни документують підпакети. Сюди потрапляють і кореневі `AGENTS.md` / `CLAUDE.md`, і bump `@nitra/cursor` у `devDependencies`;
|
|
36
|
+
- файли під **`.gitignore`**.
|
|
37
|
+
|
|
38
|
+
**Вимагають change-файл** — усі інші зміни в каталозі workspace (код, rego, правила, скіли, конфіги, тести тощо). Виняток `.cursor/` / `.claude/` **не** поширюється на джерело правил у репо `@nitra/cursor` — воно лежить під `npm/`, тож зміни в ньому далі вимагають change-файлу.
|
|
39
|
+
|
|
40
|
+
Перевірка програмна (`changelog/js/consistency.mjs`).
|
package/rules/changelog/main.mdc
CHANGED
|
@@ -4,104 +4,10 @@ version: '3.4'
|
|
|
4
4
|
alwaysApply: true
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
У кожному **пакетному** workspace (каталог із `package.json` або `pyproject.toml`) має бути власний **`CHANGELOG.md`**. Спільного на репозиторій змісту змін **не існує** — кожен пакет веде свій. Маніфест версії: **JS/Bun/npm** — `package.json` (`version`); **Python** — `pyproject.toml` (`[project].version` або `[tool.poetry].version`).
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
[changelog-agent-workflow](./js/agent-workflow.mdc)
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
2. **Ніколи** не редагуй `version` і `CHANGELOG.md` вручну — навіть для hotfix. Єдиний артефакт зміни — change-файл; `version`/CHANGELOG формує `n-cursor release` у CI на `main` (агрегує change-файли, ставить git-тег `<name>@<version>`). Будь-яка зміна `version` поза CI (drift від бази чи опублікованої) завалює `check changelog` — навіть якщо поряд є change-файл.
|
|
13
|
-
3. **`npx @nitra/cursor fix changelog`** → exit **`0`** (достатньо наявності change-файлу; `version` лишається незмінним).
|
|
11
|
+
[changelog-comparison-models](./js/comparison-models.mdc)
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
**Тригер шляхів (приклади):** `npm/**`, `packages/foo/**`, будь-який каталог з власним `package.json` / `pyproject.toml`, куди потрапили правки.
|
|
18
|
-
|
|
19
|
-
**Інверсія (change-файл не потрібен):** лише `docs/` / `doc/`; синхронізований із `@nitra/cursor` інструментарій (`.cursor/`, `.claude/`); лише `.gitignore`. **Корінь монорепо** (воркспейс `.` за наявності підпакетів) не перевіряється взагалі — отже й кореневі `AGENTS.md` / `CLAUDE.md` та bump `@nitra/cursor` у `devDependencies`. Окремого «релізного кроку» у feature-флоу немає — `version`/`CHANGELOG.md` змінює лише CI.
|
|
20
|
-
|
|
21
|
-
**Pre-commit (людина):** `hk` у цьому репо запускає `fix changelog` при змінах під `npm/**` в **autofix-режимі** (env `N_CURSOR_CHANGELOG_AUTOFIX=1`): за відсутності change-файлу хук **сам** його створює (дефолти `patch`/`Changed`, опис = subject останнього коміту) і ставить у git-індекс, тож коміт не падає. Це лише підстраховка — агент не покладайся на неї: виконуй кроки 1–3 **до** фінальної відповіді, бо автоген ставить осмислений опис лише випадково (subject попереднього коміту), і `bump`/`section`/текст майже завжди треба відредагувати. Autofix-режим також **не робить мережевих викликів** (`npm view` / PyPI fetch пропускаються) — реєстрова drift-перевірка `version` у хуці не виконується (її ловить CI / ручний `fix`). Поза хуком (CI, ручний `fix`/`check`) autofix вимкнено — поведінка лишається fail-on-missing з повною drift-перевіркою.
|
|
22
|
-
|
|
23
|
-
---
|
|
24
|
-
|
|
25
|
-
У кожному **пакетному** workspace (каталог із `package.json` або `pyproject.toml`) має бути власний **`CHANGELOG.md`**. Спільного на репозиторій змісту змін **не існує** — кожен пакет веде свій.
|
|
26
|
-
|
|
27
|
-
**Маніфест версії:**
|
|
28
|
-
|
|
29
|
-
- **JS / Bun / npm** — `<ws>/package.json` (`version`, для монорепо ще `workspaces` у кореневому `package.json`).
|
|
30
|
-
- **Python** — `<ws>/pyproject.toml`: `[project].name` / `[project].version` (PEP 621) або `[tool.poetry].name` / `[tool.poetry].version`.
|
|
31
|
-
|
|
32
|
-
Каталоги лише з `pyproject.toml` (без `package.json`) теж враховуються; `node_modules/`, `.venv/`, `venv/` при пошуку ігноруються.
|
|
33
|
-
|
|
34
|
-
## Чеклист агента (деталі)
|
|
35
|
-
|
|
36
|
-
Повний алгоритм — у блоці **STOP** вище; тут лише уточнення.
|
|
37
|
-
|
|
38
|
-
**Інверсія (за замовчуванням не вимагають change-файлу):**
|
|
39
|
-
|
|
40
|
-
- зміни **лише** під `docs/` або `doc/`;
|
|
41
|
-
- синхронізований із `@nitra/cursor` інструментарій під `.cursor/` (канонічні правила та скіли) і `.claude/` (ADR-хуки) — це дзеркало tooling-пакета, а не логіка воркспейсу;
|
|
42
|
-
- будь-які зміни в **корені монорепо** (воркспейс `.` за наявності підпакетів) — корінь веде glue/конфіг/tooling, власного CHANGELOG не має; помітні зміни документують підпакети. Сюди потрапляють і кореневі `AGENTS.md` / `CLAUDE.md`, і bump `@nitra/cursor` у `devDependencies`;
|
|
43
|
-
- файли під **`.gitignore`**.
|
|
44
|
-
|
|
45
|
-
**Вимагають change-файл** — усі інші зміни в каталозі workspace (код, rego, правила, скіли, конфіги, тести тощо). Виняток `.cursor/` / `.claude/` **не** поширюється на джерело правил у репо `@nitra/cursor` — воно лежить під `npm/`, тож зміни в ньому далі вимагають change-файлу.
|
|
46
|
-
|
|
47
|
-
Перевірка програмна (`changelog/js/consistency.mjs`).
|
|
48
|
-
|
|
49
|
-
## Дві моделі бази порівняння
|
|
50
|
-
|
|
51
|
-
Режим визначається автоматично з маніфесту.
|
|
52
|
-
|
|
53
|
-
### registry-published (npm / PyPI)
|
|
54
|
-
|
|
55
|
-
**npm:** непорожнє `name`, не `private: true`, масив `files`.
|
|
56
|
-
|
|
57
|
-
**Python:** статичні `project.name` і `project.version` у `pyproject.toml` (або Poetry-секція).
|
|
58
|
-
|
|
59
|
-
1. **Локальна `version` ≠ опублікованій** (npm / PyPI): drift поза CI → **fail** (ручний bump заборонено; навіть із change-файлом). Відкоти `version`.
|
|
60
|
-
2. **Версії збігаються**, але в git є **релевантні** зміни без change-файлу → fail. Для npm `"CHANGELOG.md"` має бути в `files` (публікується разом із пакетом).
|
|
61
|
-
3. **Реєстр недосяжний** — fail-safe pass.
|
|
62
|
-
4. **Немає релевантних змін** — pass.
|
|
63
|
-
|
|
64
|
-
### local-only
|
|
65
|
-
|
|
66
|
-
**npm:** `private: true` або без `files`. **Python:** без пари name+version для реєстру. База залежить від гілки:
|
|
67
|
-
|
|
68
|
-
1. На **`dev`** local-only не активний (крім незакомічених registry-published).
|
|
69
|
-
2. На **`main`** — diff від **`origin/main`** (попередній опублікований `main`); без remote — від `HEAD~1`. **`dev` не використовується** як база на `main`.
|
|
70
|
-
3. На **feature-гілці** — `merge-base` з **`dev`**, якщо є; інакше з **`main`** (репо без `dev`).
|
|
71
|
-
4. Drift `version` від бази → **fail** (ручний bump заборонено). Зміни фіксуй change-файлом; bump зробить CI.
|
|
72
|
-
|
|
73
|
-
Якщо немає git або немає `dev`/`main`/`origin/main` — local-only пропускається.
|
|
74
|
-
|
|
75
|
-
## Формат CHANGELOG.md
|
|
76
|
-
|
|
77
|
-
[Keep a Changelog 1.1.0](https://keepachangelog.com/uk/1.1.0/), мова — українська, новіші версії зверху.
|
|
78
|
-
|
|
79
|
-
```md title="<ws>/CHANGELOG.md"
|
|
80
|
-
# Changelog
|
|
81
|
-
|
|
82
|
-
Усі помітні зміни цього пакета документуються тут.
|
|
83
|
-
|
|
84
|
-
Формат — [Keep a Changelog](https://keepachangelog.com/uk/1.1.0/), нумерація — [SemVer](https://semver.org/lang/uk/).
|
|
85
|
-
|
|
86
|
-
## [1.2.3] - 2026-05-05
|
|
87
|
-
|
|
88
|
-
### Added
|
|
89
|
-
|
|
90
|
-
- ...
|
|
91
|
-
|
|
92
|
-
### Changed
|
|
93
|
-
|
|
94
|
-
- ...
|
|
95
|
-
|
|
96
|
-
### Fixed
|
|
97
|
-
|
|
98
|
-
- ...
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
Секції — підмножина `### Added`, `### Changed`, `### Fixed`, `### Removed` (одна або кілька).
|
|
102
|
-
|
|
103
|
-
## Post-release інваріант (гарантує CI)
|
|
104
|
-
|
|
105
|
-
Перша (верхня) секція `## [version]` у `CHANGELOG.md` дорівнює полю `version` у маніфесті — але це **post-release** твердження, яке забезпечує `n-cursor release` у CI, агрегуючи change-файли (bump `version` + генерація секції + git-тег `<name>@<version>`). **Локально цю рівність руками не підтримують**: у feature-флоу `version`/`CHANGELOG.md` не чіпають, тож верхня секція може відставати від майбутньої версії — це нормально. Drift `version` поза CI (vs реєстр / vs git-база) ловить `check changelog` як заборонений ручний bump.
|
|
106
|
-
|
|
107
|
-
Інструкції щодо bump `version` і редагування `CHANGELOG.md` живуть **лише** в цьому правилі — джерелі істини. Інші правила (зокрема `n-npm-module.mdc`) їй підпорядковані й власних інструкцій bump/CHANGELOG не дублюють.
|
|
13
|
+
[changelog-format](./js/changelog-format.mdc)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
## Конфіг marksman LSP (`.marksman.toml`)
|
|
2
|
+
|
|
3
|
+
Правило перевіряє наявність `.marksman.toml` у корені проєкту. Якщо файл відсутній — автоматично створює його з canonical baseline, що постачається разом із пакетом (`js/data/marksman_config/marksman.baseline.toml`). Повторні прогони ідемпотентні: існуючий файл не перетирається, ручні правки зберігаються.
|
|
4
|
+
|
|
5
|
+
### Baseline-конфіг
|
|
6
|
+
|
|
7
|
+
Canonical baseline ([data/marksman_config/marksman.baseline.toml](./data/marksman_config/marksman.baseline.toml)) містить такі налаштування:
|
|
8
|
+
|
|
9
|
+
```toml
|
|
10
|
+
[core]
|
|
11
|
+
markdown.file_extensions = ["md", "markdown"]
|
|
12
|
+
markdown.glfm = true # GitHub-Flavored Markdown (таблиці, todo, alerts)
|
|
13
|
+
|
|
14
|
+
[completion]
|
|
15
|
+
wiki.style = "file-stem" # [[oidc-pkce-flow]] → docs/adr/oidc-pkce-flow.md
|
|
16
|
+
|
|
17
|
+
[code_action]
|
|
18
|
+
toc.enable = true # «Insert/Update TOC» для довгих arc42-сторінок
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Чому `file-stem`?** ADR-slug збігається з іменем файлу — стабільний ідентифікатор у AUTOGEN `sources`, `manifest.json` і валідаторі. Якщо заголовок ADR змінюється, посилання `[[wiki-link]]` не ламається. Без явного конфіга marksman використовує `title-slug-ref` і вимкнений GLFM — частина задокументованої навігації працювала б інакше.
|
|
22
|
+
|
|
23
|
+
### Поведінка перевірки
|
|
24
|
+
|
|
25
|
+
| Стан | Результат |
|
|
26
|
+
| ----------------------------- | -------------------------------------------------- |
|
|
27
|
+
| baseline-файл пакета відсутній | `fail` — перевстанови `@nitra/cursor` |
|
|
28
|
+
| `.marksman.toml` вже існує | `pass` — файл не чіпається |
|
|
29
|
+
| `.marksman.toml` відсутній | створює файл з baseline, `pass` |
|
|
30
|
+
|
|
31
|
+
Перевірка запускається як `check`-поверхня; `lint`-поверхні правило не має.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
## Рекомендовані розширення VSCode (`.vscode/extensions.json`)
|
|
2
|
+
|
|
3
|
+
Правило перевіряє, що `.vscode/extensions.json` містить усі обовʼязкові записи з канонічного шаблону. Перевірка реалізована через Rego (пакет `ci4.vscode_extensions`) і запускається `conftest` у фазі `check`.
|
|
4
|
+
|
|
5
|
+
### Канонічний шаблон
|
|
6
|
+
|
|
7
|
+
Канон надходить через `--data` як `{ "template": { "snippet": ... } }`. Поточний snippet ([policy/vscode_extensions/template/extensions.json.snippet.json](./policy/vscode_extensions/template/extensions.json.snippet.json)):
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"recommendations": ["arr.marksman"]
|
|
12
|
+
}
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`arr.marksman` — офіційне VSCode-розширення marksman LSP. Дає ту саму навігацію `cmd+click` / `[[wiki-link]]` / find-references / refactor-перейменування, що й Zed built-in marksman, для контрибʼюторів поза Zed.
|
|
16
|
+
|
|
17
|
+
### Rego-логіка
|
|
18
|
+
|
|
19
|
+
Для кожного запису з `data.template.snippet.recommendations` перевіряє, що він присутній у `input.recommendations`. Якщо запис відсутній — deny з повідомленням:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
.vscode/extensions.json: recommendations має містити "arr.marksman" (ci4.mdc)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Приклад коректного файлу
|
|
26
|
+
|
|
27
|
+
```json title=".vscode/extensions.json"
|
|
28
|
+
{
|
|
29
|
+
"recommendations": ["arr.marksman"]
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Інші розширення в масиві `recommendations` дозволені — перевірка лише на наявність обовʼязкових, без виключення додаткових.
|
package/rules/ci4/main.mdc
CHANGED
|
@@ -4,9 +4,7 @@ alwaysApply: true
|
|
|
4
4
|
version: '3.2'
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
Архітектурна документація проєкту живе у Markdown поряд із
|
|
8
|
-
|
|
9
|
-
Формат самих ADR-файлів — MADR v4.0.0 minimal — описаний у правилі **`adr`** (`npm/rules/adr/adr.mdc`). Тут описано, як ADR використовуються як вхід для архітектурних проекцій, а не як вони створюються.
|
|
7
|
+
Архітектурна документація проєкту живе у Markdown поряд із кодом — це **джерело істини**, з якого LLM-агент і людина читають намір системи перед будь-якою зміною коду. Правила нижче — не оформлення, а робочий процес: який стек використовуємо, як зберігаємо рішення, як автоматично перегенеровуємо проекції з ADR і як рендеримо для змішаної аудиторії (менеджери + інженери + ops). Формат самих ADR-файлів — MADR v4.0.0 minimal — описаний у правилі **`adr`** (`npm/rules/adr/adr.mdc`).
|
|
10
8
|
|
|
11
9
|
## Markdown як джерело істини
|
|
12
10
|
|
|
@@ -208,17 +206,7 @@ User Service відповідає за автентифікацію та про
|
|
|
208
206
|
}
|
|
209
207
|
```
|
|
210
208
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
**VSCode-альтернатива.** Контрибʼютори, що працюють у VSCode/Cursor замість Zed, отримують той самий шар навігації через офіційне розширення marksman LSP. Канонічний запис у `.vscode/extensions.json`:
|
|
214
|
-
|
|
215
|
-
```json title=".vscode/extensions.json"
|
|
216
|
-
{
|
|
217
|
-
"recommendations": ["arr.marksman"]
|
|
218
|
-
}
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
Канон `recommendations` (substring requirement): [extensions.json.snippet.json](./policy/vscode_extensions/template/extensions.json.snippet.json). Інші marksman-сумісні редактори (Neovim, Helix, Emacs) налаштовують `marksman` як LSP-сервер за документацією свого редактора — поведінка ідентична (cmd+click по `[link](file.md)`/`[[wiki-link]]`, find-references, refactor-перейменування).
|
|
209
|
+
Деталі конфігурації `.marksman.toml` та VSCode-альтернативи — у відповідних секціях нижче.
|
|
222
210
|
|
|
223
211
|
**Portable-only синтаксис.** Усе, що пишемо в `docs/`, обмежене **CommonMark + GFM + Mermaid у fenced code (` ```mermaid `) + KaTeX (`$...$`) + нативний HTML5 `<details>`**. Заборонено:
|
|
224
212
|
|
|
@@ -375,3 +363,15 @@ ADR (`docs/adr/<slug>.md`) — джерело правди для autogen-про
|
|
|
375
363
|
## Query mode як бонус
|
|
376
364
|
|
|
377
365
|
Поверх проекцій — інтерактивний RAG над clean ADR. Інженер питає: «чому ми обрали Percona замість MariaDB?». LLM шукає по semantic index `Context and Problem Statement + Decision Outcome`, повертає `docs/adr/<slug>.md` з прямою цитатою. Корпус малий (десятки-сотні clean ADR після normalize) і структурований (фіксовані MADR-заголовки) — дешево й точно, без галюцинацій.
|
|
366
|
+
|
|
367
|
+
## Швидкий gate через conftest
|
|
368
|
+
|
|
369
|
+
Rego-перевірки, що запускаються через `conftest` у фазі `check`:
|
|
370
|
+
|
|
371
|
+
| Пакет | Що перевіряє |
|
|
372
|
+
| --------------------------- | -------------------------------------------------------------------- |
|
|
373
|
+
| `ci4.vscode_extensions` | `.vscode/extensions.json` містить `arr.marksman` у `recommendations` |
|
|
374
|
+
|
|
375
|
+
[ci4-marksman_config](./js/marksman_config.mdc)
|
|
376
|
+
|
|
377
|
+
[ci4-vscode_extensions](./js/vscode_extensions.mdc)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
## Компіляція bun-проєкту в бінарник
|
|
2
|
+
|
|
3
|
+
Якщо проект має `bun install` крок, та не є фронтенд проектом (тобто не має `bun build` крок без `--compile`), **і не має нативного `.node`-аддона з динамічним завантаженням** (див. `native-addon.mdc`), то потрібно щоб була компіляція коду, і далі у фінальному образі був тільки бінарник. Цей образ не містить компілятора, npm, Bun — тільки runtime libs.
|
|
4
|
+
|
|
5
|
+
Тригер перевірки:
|
|
6
|
+
- у Dockerfile є крок `bun install` (або `bun i`);
|
|
7
|
+
- фінальний FROM — `mirror.gcr.io/library/alpine:*` (тобто не nginx/openresty frontend).
|
|
8
|
+
|
|
9
|
+
Очікування:
|
|
10
|
+
- у build stage є `bun build --compile`;
|
|
11
|
+
- у фінальному stage немає викликів `bun` (залишків build tooling).
|
|
12
|
+
|
|
13
|
+
### Канон — компільований бінарник на alpine
|
|
14
|
+
|
|
15
|
+
```dockerfile
|
|
16
|
+
FROM mirror.gcr.io/oven/bun:alpine AS build-env
|
|
17
|
+
|
|
18
|
+
WORKDIR /app
|
|
19
|
+
|
|
20
|
+
ENV NODE_ENV=production
|
|
21
|
+
|
|
22
|
+
COPY package.json .
|
|
23
|
+
COPY bunfig.toml .
|
|
24
|
+
|
|
25
|
+
RUN bun install --production
|
|
26
|
+
|
|
27
|
+
COPY ./src ./src
|
|
28
|
+
|
|
29
|
+
# Компілюємо в бінарник
|
|
30
|
+
RUN bun build --compile --outfile app ./src/index.js
|
|
31
|
+
|
|
32
|
+
FROM mirror.gcr.io/library/alpine:latest
|
|
33
|
+
|
|
34
|
+
# (libstdc++ libgcc) для Bun runtime, (tzdata) для часового поясу
|
|
35
|
+
RUN apk add --no-cache libstdc++ libgcc tzdata
|
|
36
|
+
|
|
37
|
+
WORKDIR /app
|
|
38
|
+
|
|
39
|
+
COPY --from=build-env /app/app ./app
|
|
40
|
+
|
|
41
|
+
CMD ["./app"]
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Перевіряє `getBunCompileHint` у **`npm/rules/docker/js/lint.mjs`**.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
## lint-docker: hadolint і CI-workflow
|
|
2
|
+
|
|
3
|
+
### Область lint-docker
|
|
4
|
+
|
|
5
|
+
CLI **`hadolint`** приймає лише **явні шляхи** (`[DOCKERFILE...]` у **`hadolint --help`**); обхід репозиторію робить правило **`n-cursor lint docker`** (реалізація — **`npm/rules/docker/js/lint.mjs`**).
|
|
6
|
+
|
|
7
|
+
**Область lint-docker (вужча, ніж `check docker`):** лише файли з іменем **`Dockerfile`** та **`*.Dockerfile`** (суфікс **`.dockerfile`** без урахування регістру, наприклад **`api.Dockerfile`**). Файли **`Dockerfile.prod`**, **`Containerfile`** тощо **не** входять у **`lint-docker`**; їх ловить **`check docker`** (`rules/docker/fix.mjs`).
|
|
8
|
+
|
|
9
|
+
Обхід: **`walkDir`** з тими самими пропусками каталогів, що й **`rules/docker/fix.mjs`**. Виклик **`hadolint`** як **нативного бінарника** через **`ensureTool`** (PATH → кеш → авто-install brew/scoop/GitHub Release; **без** `docker run`) — спільна логіка **`npm/rules/docker/lib/docker-hadolint.mjs`**.
|
|
10
|
+
|
|
11
|
+
### GitHub Actions workflow
|
|
12
|
+
|
|
13
|
+
Додай workflow **`.github/workflows/lint-docker.yml`** (гілки **`dev`** і **`main`**, лише **`.yml`**, узгоджено з **`ga.mdc`**):
|
|
14
|
+
|
|
15
|
+
- Канон: [lint-docker.yml.snippet.yml](./policy/lint_docker_yml/template/lint-docker.yml.snippet.yml)
|
|
16
|
+
|
|
17
|
+
Локально hadolint авто-встановлюється через **`ensureTool`** (latest, без піну версії). У CI встанови його кроком із workflow-сніпета (curl-download бінарника — без `docker run`).
|
|
18
|
+
|
|
19
|
+
### Конфігурація hadolint
|
|
20
|
+
|
|
21
|
+
Кореневий **`.hadolint.yaml`**: вимкнення правил, trusted registries — [документація](https://github.com/hadolint/hadolint#configure). Щоб не додавати **`# hadolint ignore=DL3007`** у кожному **`FROM`** з **`:latest`**, у корені репозиторію задати глобально:
|
|
22
|
+
|
|
23
|
+
```yaml title=".hadolint.yaml"
|
|
24
|
+
ignored:
|
|
25
|
+
- DL3007
|
|
26
|
+
- DL3008
|
|
27
|
+
- DL3018
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Де DL3007 — «Не використовуй тег latest у FROM»
|
|
31
|
+
Де DL3018 — «Піни версії пакетів у apk add»
|
|
32
|
+
|
|
33
|
+
### Запуск
|
|
34
|
+
|
|
35
|
+
1. **`n-cursor lint docker`** — **`js/lint.mjs`**: **`Dockerfile`** та **`*.Dockerfile`** (lint-docker); у CI використовуй **`n-cursor lint docker --read-only`** і встанови hadolint (приклад у workflow).
|
|
36
|
+
2. **`npx @nitra/cursor fix docker`** — **`rules/docker/fix.mjs`**, виклик hadolint як у **`docker-hadolint.mjs`** (нативний бінарник через **`ensureTool`**; **без** `docker run`).
|
|
37
|
+
|
|
38
|
+
Окремий `package.json`-скрипт `lint-docker` не потрібен і не перевіряється — єдина точка входу для правила: **`n-cursor lint docker`**.
|
|
39
|
+
|
|
40
|
+
Якщо немає файлів у межах відповідного набору (**`lint-docker`** або **`check docker`**) — перевірка пропускається (exit 0).
|
|
41
|
+
|
|
42
|
+
Винятки: **`# hadolint ignore=DL3008`** (або інший код) у Dockerfile або **`ignored`** у **`.hadolint.yaml`** (наприклад **DL3007** для **`:latest`** — div. вище).
|
|
43
|
+
|
|
44
|
+
### Rego-перевірка (conftest)
|
|
45
|
+
|
|
46
|
+
Пакет `docker.lint_docker_yml` перевіряє `.github/workflows/lint-docker.yml` на відповідність канонічному сніпету:
|
|
47
|
+
|
|
48
|
+
- `on.push.paths` містить обов'язкові шляхи з template;
|
|
49
|
+
- присутні всі `uses:` кроки з template;
|
|
50
|
+
- всі `run:` підрядки з template є у workflow.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
## GCR-дзеркало замість Docker Hub
|
|
2
|
+
|
|
3
|
+
Для образів з Docker Hub — **`oven/bun`**, **`alpine`**, **`nginx`**, **`nginxinc/nginx-unprivileged`**, **`node`** — у **`FROM`** треба вказувати дзеркало GCR, а не pull напряму з Hub:
|
|
4
|
+
|
|
5
|
+
| Docker Hub | GCR-дзеркало |
|
|
6
|
+
|---|---|
|
|
7
|
+
| `oven/bun` | `mirror.gcr.io/oven/bun` |
|
|
8
|
+
| `alpine` | `mirror.gcr.io/library/alpine` |
|
|
9
|
+
| `nginx` | `mirror.gcr.io/library/nginx` |
|
|
10
|
+
| `node` | `mirror.gcr.io/library/node` |
|
|
11
|
+
| `nginxinc/nginx-unprivileged` | `mirror.gcr.io/nginxinc/nginx-unprivileged` |
|
|
12
|
+
|
|
13
|
+
Перевіряє **`npm/rules/docker/lib/docker-mirror.mjs`** (через `getMirrorGcrHint`); точка входу обходу — **`npm/rules/docker/fix.mjs`** та **`npm/rules/docker/js/lint.mjs`**.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
## Multistage build і дозволені runtime-образи
|
|
2
|
+
|
|
3
|
+
Dockerfile/Containerfile **має бути multistage build**: окремий build stage (залежності/компіляція) і окремий runtime stage. У фінальному stage дозволені лише мінімальні базові образи:
|
|
4
|
+
|
|
5
|
+
- **backend (типово)**: `mirror.gcr.io/library/alpine:*`
|
|
6
|
+
- **ультра-легкі (glibc / одна статична збірка)**: `scratch` — тільки як `FROM scratch` (офіційний порожній базовий шар), коли весь **runtime** уже в `COPY --from=…`
|
|
7
|
+
- **glibc, Debian (slim)**: `mirror.gcr.io/library/debian:*` **лише** з тегом, у якому є `slim` (наприклад `bookworm-slim`, `trixie-slim`), а не `bookworm` без `slim`. Debian-slim виправданий **лише** коли потрібен саме glibc-рантайм (нативні glibc-залежності, prebuilds без musl-варіанта). **Non-root сам по собі не є підставою** переходити сюди: `mirror.gcr.io/oven/bun:alpine` уже має користувача `bun` (uid/gid 1000), тож `USER bun` дає non-root **без зміни бази**. Перехід Alpine→Debian заради лише non-root — **антипатерн** (більший образ + зайва musl→glibc міграція bun-бінарника)
|
|
8
|
+
- **виняток (інтерпретовані стеки)**: `mirror.gcr.io/library/php:*` або `mirror.gcr.io/library/python:*` — якщо сервіс має крутитися в офіційному runtime PHP чи Python, а не як один бінарник на Alpine; інакше лишай **alpine** у фінальному stage
|
|
9
|
+
- **frontend**: `mirror.gcr.io/nginxinc/nginx-unprivileged:*` або `mirror.gcr.io/openresty/openresty:*`
|
|
10
|
+
|
|
11
|
+
Це стримує зайвий build tooling (Bun, **node_modules** зі збірки) у фінальному образі; для **alpine** / **nginx** / **openresty** у **runtime** лишаються лише відповідні вимоги, для **php** / **python** (виняток) — цільовий інтерпретований **stack**; **scratch** і **debian** з тегом **`*slim*`** — коли glibc і мінімальне оточення Debian важливіші за musl в **alpine**.
|
|
12
|
+
|
|
13
|
+
Перевіряє `getMultistageAndRuntimeHint` у **`npm/rules/docker/js/lint.mjs`**.
|