@nitra/cursor 1.8.2 → 1.8.5

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.
@@ -1,13 +1,11 @@
1
+ # yaml-language-server: $schema=https://json.schemastore.org/github-action.json
2
+
1
3
  name: Setup Bun dependencies
2
- description: Checkout, Node 24, Bun, cache та bun install --frozen-lockfile
4
+ description: Node 24, Bun, cache та bun install --frozen-lockfile (checkout — окремим кроком у workflow)
3
5
 
4
6
  runs:
5
7
  using: composite
6
8
  steps:
7
- - uses: actions/checkout@v6
8
- with:
9
- persist-credentials: false
10
-
11
9
  - uses: actions/setup-node@v6
12
10
  with:
13
11
  node-version: '24'
package/mdc/ga.mdc CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  description: Правила форматів для .github/workflows
3
3
  alwaysApply: true
4
- version: '1.2'
4
+ version: '1.3'
5
5
  ---
6
6
 
7
7
  У `.github/workflows/` лише **`.yml`**. Мають бути **`clean-ga-workflows.yml`**, **`clean-merged-branch.yml`**, **`lint-ga.yml`**. Якщо є **`apply-k8s.yml`** / **`apply-nats-consumer.yml`** — paths у тригері як у фрагментах.
@@ -96,6 +96,10 @@ jobs:
96
96
  permissions:
97
97
  contents: read
98
98
  steps:
99
+ - uses: actions/checkout@v6
100
+ with:
101
+ persist-credentials: false
102
+
99
103
  - uses: ./.github/actions/setup-bun-deps
100
104
 
101
105
  - uses: astral-sh/setup-uv@v8.0.0
@@ -104,7 +108,7 @@ jobs:
104
108
  run: bun run lint-ga
105
109
  ```
106
110
 
107
- Composite **`.github/actions/setup-bun-deps/action.yml`**: **`actions/checkout@v6`** (`persist-credentials: false`), **`actions/setup-node@v6`** (**Node 24**), **Bun**, **`actions/cache@v5`** і **`bun install --frozen-lockfile`**. У job достатньо **`- uses: ./.github/actions/setup-bun-deps`**.
111
+ **Локальний composite** (`uses: ./.github/actions/setup-bun-deps` або `./npm/github-actions/setup-bun-deps`): **спочатку** обов’язковий крок **`actions/checkout@v6`** (`persist-credentials: false`), інакше runner не знайде `action.yml`. Сам composite: **`actions/setup-node@v6`** (**Node 24**), **Bun**, **`actions/cache@v5`**, **`bun install --frozen-lockfile`**.
108
112
 
109
113
  ```json title=".vscode/extensions.json"
110
114
  {
package/mdc/js-lint.mdc CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  description: Перевірка JavaScript коду
3
3
  alwaysApply: true
4
- version: '1.7'
4
+ version: '1.8'
5
5
  ---
6
6
 
7
7
  **oxlint**, **ESLint**, **jscpd**. У скрипті **`lint-js`:** `oxlint` (без `bunx`), **`bunx eslint`**, **`bunx jscpd`**; у CI — `bunx oxlint` / `bunx eslint` / `bunx jscpd`. Без **prettier** і **@nitra/prettier-config**. Достатньо **`@nitra/eslint-config`** у devDependencies; пакети oxlint/eslint/jscpd не додавай без потреби монорепо.
@@ -86,6 +86,10 @@ jobs:
86
86
  permissions:
87
87
  contents: read
88
88
  steps:
89
+ - uses: actions/checkout@v6
90
+ with:
91
+ persist-credentials: false
92
+
89
93
  - uses: ./.github/actions/setup-bun-deps
90
94
 
91
95
  - name: Eslint
@@ -95,7 +99,7 @@ jobs:
95
99
  bunx jscpd .
96
100
  ```
97
101
 
98
- Composite **`.github/actions/setup-bun-deps/action.yml`** — checkout, Node 24, Bun, кеш і `bun install --frozen-lockfile` (див. **ga.mdc**).
102
+ Перед **`./.github/actions/setup-bun-deps`** — **`actions/checkout@v6`** (див. **ga.mdc**). Composite: Node 24, Bun, кеш, `bun install --frozen-lockfile`.
99
103
 
100
104
  Один workflow на лінт JS; зайвий `lint.yml` з тими самими кроками — прибери.
101
105
 
package/mdc/k8s.mdc CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: K8s YAML — $schema (yaml-language-server); lint-k8s (kubeconform, kubescape); check-k8s
3
- version: '1.10'
3
+ version: '1.12'
4
4
  globs: "**/k8s/**/*.{yaml,yml}"
5
5
  alwaysApply: false
6
6
  ---
@@ -124,7 +124,7 @@ jobs:
124
124
  При зміні правил синхронно оновлюй **`YANNH_PIN`**, **`YANNH_REF`** (якщо зміниться гілка за замовчуванням у репо yannh), **`YANNH_GROUPS`**, **`DATREE_CRD_BASE`** (GitHub Pages каталогу CRD), а в **`run-k8s.mjs`** — константу **`KUBERNETES_VERSION`** і **`DATREE_CRD_SCHEMA_LOCATION`** (узгоджено з базою datree у цьому правилі).
125
125
 
126
126
  - Обхід з пропуском `node_modules`, `.git`, `dist`, `coverage`, `.turbo`, `.next`.
127
- - **`file:`** у `$schema` — URL до apiVersion/kind не звіряється; **`https:`** — kustomization за іменем файлу → Schema Store; `v1` → yannh; група з `YANNH_GROUPS` → yannh; інакше → datree (GitHub Pages).
127
+ - **`file:`** у `$schema` — URL до apiVersion/kind не звіряється; **`https:`** — kustomization за іменем файлу → Schema Store; далі перевіряється **`EXPLICIT_K8S_SCHEMAS`** (`Map`: `apiVersion` + `kind` + `type`, для записів без `type` у маніфесті — третій компонент **`*`**); потім `v1` → yannh; група з `YANNH_GROUPS` → yannh; інакше → datree (GitHub Pages), крім рядків явної таблиці (наприклад **InfisicalSecret** — raw на `main`).
128
128
 
129
129
  ## Коли застосовувати (агентам)
130
130
 
@@ -139,13 +139,25 @@ jobs:
139
139
  2. **`apiVersion: v1`** → yannh, PIN набору схем **`v1.33.9-standalone-strict`**, ref репозиторію для raw URL — **`master`** (каталог версії не є коренем репо на GitHub):
140
140
  `https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/<PIN>/<kind>-v1.json`
141
141
  `<kind>`: літери в нижньому регістрі без роздільників між CamelCase (наприклад `Service` → `service`).
142
+
143
+ **`kind: Secret`** і **`type: kubernetes.io/basic-auth`** — той самий шаблон, **`secret-v1.json`**:
144
+
145
+ ```yaml
146
+ # yaml-language-server: $schema=https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.9-standalone-strict/secret-v1.json
147
+ ```
142
148
  3. **`apiVersion: group/version`** і **group** у **`YANNH_GROUPS`** у скрипті → yannh:
143
149
  `https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/<PIN>/<kind>-<group-з-крапками-як-дефіси>-<version>.json`
144
150
  Приклади: `apps/v1` + `Deployment` → `deployment-apps-v1.json`; `networking.k8s.io/v1` + `Ingress` → `ingress-networking-k8s-io-v1.json`.
145
- 4. **Інакше** (CRD тощо) → [datreeio/CRDs-catalog](https://github.com/datreeio/CRDs-catalog) через **GitHub Pages** (канон для `$schema` у редакторі):
151
+ 4. **Інакше** (CRD тощо) → [datreeio/CRDs-catalog](https://github.com/datreeio/CRDs-catalog). Типово для `$schema` у редакторі — **GitHub Pages**:
146
152
  `https://datreeio.github.io/CRDs-catalog/<group>/<kind>_<version>.json`
147
153
  (`<kind>` — лише літери та цифри в нижньому регістрі, без роздільників між CamelCase, як для yannh.)
148
154
 
155
+ **Виняток — `InfisicalSecret`:** `apiVersion: secrets.infisical.com/v1alpha1`, `kind: InfisicalSecret` — канонічний modeline через **raw** на гілці **`main`** (не GitHub Pages):
156
+
157
+ ```yaml
158
+ # yaml-language-server: $schema=https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/secrets.infisical.com/infisicalsecret_v1alpha1.json
159
+ ```
160
+
149
161
  **Приклад (Gateway API):** `apiVersion: gateway.networking.k8s.io/v1beta1`, `kind: HTTPRoute`:
150
162
 
151
163
  ```yaml
package/mdc/text.mdc CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  description: Обробка та перевірка текстових файлів (cspell, markdownlint-cli2, v8r, CI)
3
3
  alwaysApply: true
4
- version: '1.23'
4
+ version: '1.24'
5
5
  ---
6
6
 
7
7
  **cspell**, **markdownlint-cli2**, **[v8r](https://chris48s.github.io/v8r/)** ([Schema Store](https://www.schemastore.org/)), розширення **DavidAnson.vscode-markdownlint**, workflow **`lint-text`**.
@@ -107,13 +107,17 @@ jobs:
107
107
  permissions:
108
108
  contents: read
109
109
  steps:
110
+ - uses: actions/checkout@v6
111
+ with:
112
+ persist-credentials: false
113
+
110
114
  - uses: ./.github/actions/setup-bun-deps
111
115
 
112
116
  - name: Lint text
113
117
  run: bun run lint-text
114
118
  ```
115
119
 
116
- Composite **`.github/actions/setup-bun-deps/action.yml`** — checkout, Node 24, Bun, кеш і `bun install --frozen-lockfile` (див. **ga.mdc**).
120
+ Перед **`./.github/actions/setup-bun-deps`** — **`actions/checkout@v6`** (див. **ga.mdc**). Composite: Node 24, Bun, кеш, `bun install --frozen-lockfile`.
117
121
 
118
122
  Не дублюй окремий workflow з тими самими кроками cspell/markdownlint.
119
123
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nitra/cursor",
3
- "version": "1.8.2",
3
+ "version": "1.8.5",
4
4
  "description": "CLI для завантаження cursor-правил (префікс n-) у локальний репозиторій",
5
5
  "keywords": [
6
6
  "cli",
@@ -3,7 +3,8 @@
3
3
  *
4
4
  * Workflows лише з розширенням `.yml`, наявність clean/lint workflow, конфіг zizmor з ref-pin,
5
5
  * відсутність MegaLinter, коректний скрипт `lint-ga` у `package.json`, виклик у `lint-ga.yml`,
6
- * наявність composite `.github/actions/setup-bun-deps/action.yml` (його записує `npx @nitra/cursor`).
6
+ * наявність composite `.github/actions/setup-bun-deps/action.yml` (його записує `npx \@nitra/cursor`),
7
+ * перед `uses: ./…/setup-bun-deps` у workflow — `actions/checkout` (runner інакше не бачить локальний action).
7
8
  */
8
9
  import { existsSync } from 'node:fs'
9
10
  import { readdir, readFile } from 'node:fs/promises'
@@ -17,6 +18,36 @@ const MEGALINTER_USE_PATTERNS = [/oxsecurity\/megalinter-action/i, /megalinter\/
17
18
  /** Типові конфіги MegaLinter у корені репо */
18
19
  const MEGALINTER_CONFIG_NAMES = ['.mega-linter.yml', '.megalinter.yaml', '.mega-linter.yaml']
19
20
 
21
+ /**
22
+ * Якщо workflow викликає локальний setup-bun-deps, раніше у файлі має бути `actions/checkout@v…` (ga.mdc).
23
+ * @param {string} relPath шлях для повідомлень
24
+ * @param {string} content вміст YAML
25
+ * @param {(msg: string) => void} failFn реєструє порушення (exit 1)
26
+ * @param {(msg: string) => void} passFn реєструє успішну перевірку
27
+ * @returns {void}
28
+ */
29
+ function verifyCheckoutBeforeLocalSetupBunDeps(relPath, content, failFn, passFn) {
30
+ const patterns = ['./.github/actions/setup-bun-deps', './npm/github-actions/setup-bun-deps']
31
+ let idxSetup = -1
32
+ for (const p of patterns) {
33
+ const i = content.indexOf(p)
34
+ if (i !== -1 && (idxSetup === -1 || i < idxSetup)) {
35
+ idxSetup = i
36
+ }
37
+ }
38
+ if (idxSetup === -1) {
39
+ return
40
+ }
41
+ const idxCheckout = content.indexOf('actions/checkout@v')
42
+ if (idxCheckout === -1 || idxCheckout > idxSetup) {
43
+ failFn(
44
+ `${relPath}: перед локальним setup-bun-deps потрібен крок actions/checkout@v6 — інакше runner не знайде action.yml (ga.mdc)`
45
+ )
46
+ return
47
+ }
48
+ passFn(`${relPath}: перед setup-bun-deps є checkout`)
49
+ }
50
+
20
51
  /**
21
52
  * Перевіряє відповідність проєкту правилам ga.mdc
22
53
  * @returns {Promise<number>} 0 — все OK, 1 — є проблеми
@@ -159,6 +190,15 @@ export async function check() {
159
190
  } else {
160
191
  fail('lint-ga.yml: додай astral-sh/setup-uv для uvx zizmor (ga.mdc)')
161
192
  }
193
+ verifyCheckoutBeforeLocalSetupBunDeps(`${wfDir}/lint-ga.yml`, lgContent, fail, pass)
194
+ }
195
+
196
+ for (const wfName of ['lint-js.yml', 'lint-text.yml']) {
197
+ const p = join(wfDir, wfName)
198
+ if (existsSync(p)) {
199
+ const body = await readFile(p, 'utf8')
200
+ verifyCheckoutBeforeLocalSetupBunDeps(`${wfDir}/${wfName}`, body, fail, pass)
201
+ }
162
202
  }
163
203
 
164
204
  return exitCode
@@ -3,7 +3,11 @@
3
3
  *
4
4
  * Перший рядок `# yaml-language-server: $schema=…`, без дублікатів, розширення `.yaml`
5
5
  * (окрім `kustomization.yml`); URL схеми за першим документом — kustomization / yannh / datree
6
- * (datree: `https://datreeio.github.io/CRDs-catalog/<group>/<kind>_<version>.json`).
6
+ * (datree за замовчуванням: GitHub Pages `https://datreeio.github.io/CRDs-catalog/…`).
7
+ *
8
+ * Явні винятки до загальної логіки yannh/datree — таблиця **`EXPLICIT_K8S_SCHEMAS`** (`Map`): ключ
9
+ * **`apiVersion`, `kind`, `type`** (для CRD без поля `type` у маніфесті — зірочка **`*`** як третій
10
+ * компонент). Спочатку шукається збіг за фактичним `type`, потім за **`*`**.
7
11
  * Dockerfile — правило docker.mdc, скрипт check-docker.mjs.
8
12
  */
9
13
  import { readFile } from 'node:fs/promises'
@@ -25,6 +29,75 @@ const YANNH_BASE = `https://raw.githubusercontent.com/yannh/kubernetes-json-sche
25
29
  /** Публікація [CRDs-catalog](https://github.com/datreeio/CRDs-catalog) на GitHub Pages (те саме дерево, що й raw на `main`). */
26
30
  const DATREE_CRD_BASE = 'https://datreeio.github.io/CRDs-catalog/'
27
31
 
32
+ /** Raw URL для окремих CRD, де в редакторі канон — `raw.githubusercontent.com` (див. k8s.mdc). */
33
+ const DATREE_CRD_RAW_REF = 'main'
34
+
35
+ const DATREE_CRD_RAW_BASE = `https://raw.githubusercontent.com/datreeio/CRDs-catalog/${DATREE_CRD_RAW_REF}/`
36
+
37
+ /** У ключі `Map` означає «будь-який / відсутній `type`» (наприклад CRD без верхньорівневого `type:`). */
38
+ const K8S_EXPLICIT_SCHEMA_TYPE_ANY = '*'
39
+
40
+ /**
41
+ * Ключ запису в **`EXPLICIT_K8S_SCHEMAS`**: `apiVersion`, **`kind` як у YAML** (регістр як у маніфесті),
42
+ * `typeKey` — значення поля **`type:`** або **`K8S_EXPLICIT_SCHEMA_TYPE_ANY`**.
43
+ * @param {string} apiVersion повне значення `apiVersion` з маніфесту
44
+ * @param {string} kind значення `kind` з маніфесту (як у YAML)
45
+ * @param {string} typeKey значення верхньорівневого `type:` або `K8S_EXPLICIT_SCHEMA_TYPE_ANY`
46
+ * @returns {string} внутрішній ключ для `Map`
47
+ */
48
+ function k8sExplicitSchemaMapKey(apiVersion, kind, typeKey) {
49
+ return `${apiVersion}\0${kind}\0${typeKey}`
50
+ }
51
+
52
+ /**
53
+ * Таблиця явних `$schema` для поєднань **`apiVersion` + `kind` + `type`** (див. k8s.mdc).
54
+ * Щоб додати рядок: визнач **`apiVersion`**, **`kind`**, при потребі **`type`**, вкажи **URL** і **reason**.
55
+ *
56
+ * @type {Map<string, { schema: string, reason: string }>}
57
+ */
58
+ const EXPLICIT_K8S_SCHEMAS = new Map([
59
+ [
60
+ k8sExplicitSchemaMapKey('secrets.infisical.com/v1alpha1', 'InfisicalSecret', K8S_EXPLICIT_SCHEMA_TYPE_ANY),
61
+ {
62
+ schema: `${DATREE_CRD_RAW_BASE}secrets.infisical.com/infisicalsecret_v1alpha1.json`,
63
+ reason: 'InfisicalSecret v1alpha1 (явна таблиця схем, datree CRDs-catalog raw)'
64
+ }
65
+ ],
66
+ [
67
+ k8sExplicitSchemaMapKey('v1', 'Secret', 'kubernetes.io/basic-auth'),
68
+ {
69
+ schema: `${YANNH_BASE}secret-v1.json`,
70
+ reason: 'Secret type kubernetes.io/basic-auth (явна таблиця схем, yannh secret-v1.json)'
71
+ }
72
+ ]
73
+ ])
74
+
75
+ /**
76
+ * Витягує верхньорівневе поле **`type:`** з документа (без повного YAML-парсера).
77
+ * @param {string} doc фрагмент YAML одного документа
78
+ * @returns {string | undefined} значення без лапок або undefined, якщо поля немає
79
+ */
80
+ function extractTopLevelManifestType(doc) {
81
+ const m = doc.match(/^\s*type:\s*(\S+)\s*$/mu)
82
+ const raw = m?.[1]?.replaceAll(/^["']|["']$/gu, '')
83
+ return raw === undefined || raw === '' ? undefined : raw
84
+ }
85
+
86
+ /**
87
+ * Шукає схему в **`EXPLICIT_K8S_SCHEMAS`**: спочатку за точним **`type`**, потім за **`*`**.
88
+ * @param {string} apiVersion повне значення `apiVersion` з маніфесту
89
+ * @param {string} kind значення `kind` з маніфесту (як у YAML)
90
+ * @param {string | undefined} manifestType верхньорівневе поле `type` або undefined, якщо відсутнє
91
+ * @returns {{ schema: string, reason: string } | null} запис таблиці або null, якщо збігу немає
92
+ */
93
+ function lookupExplicitK8sSchema(apiVersion, kind, manifestType) {
94
+ if (manifestType !== undefined) {
95
+ const exact = EXPLICIT_K8S_SCHEMAS.get(k8sExplicitSchemaMapKey(apiVersion, kind, manifestType))
96
+ if (exact) return exact
97
+ }
98
+ return EXPLICIT_K8S_SCHEMAS.get(k8sExplicitSchemaMapKey(apiVersion, kind, K8S_EXPLICIT_SCHEMA_TYPE_ANY)) ?? null
99
+ }
100
+
28
101
  /**
29
102
  * Групи API Kubernetes, для яких у перевірці очікується схема yannh (не datree CRD catalog).
30
103
  * `gateway.networking.k8s.io` та інші розширення поза цим списком — datree.
@@ -158,6 +231,12 @@ export function expectedSchemaUrl(filePath, doc) {
158
231
  }
159
232
  }
160
233
 
234
+ const manifestType = extractTopLevelManifestType(doc)
235
+ const explicit = lookupExplicitK8sSchema(apiVersion, kind, manifestType)
236
+ if (explicit) {
237
+ return { expected: explicit.schema, reason: explicit.reason }
238
+ }
239
+
161
240
  if (apiVersion === 'v1') {
162
241
  const k = kindToSchemaFilePart(kind)
163
242
  return { expected: `${YANNH_BASE}${k}-v1.json`, reason: 'core v1 (yannh)' }
@@ -182,6 +261,7 @@ export function expectedSchemaUrl(filePath, doc) {
182
261
  }
183
262
 
184
263
  const datreeKind = kindToSchemaFilePart(kind)
264
+
185
265
  const url = `${DATREE_CRD_BASE}${group}/${datreeKind}_${version}.json`
186
266
  return { expected: url, reason: 'CRD / група поза yannh (datree CRDs-catalog)' }
187
267
  }
@@ -3,7 +3,7 @@
3
3
  * у цільовий репозиторій (`.github/actions/setup-bun-deps/action.yml`).
4
4
  *
5
5
  * Використовується CLI `npx \@nitra/cursor`, щоб workflows з правил `ga` / `js-lint` / `text`
6
- * могли одразу викликати `uses: ./.github/actions/setup-bun-deps` без ручного копіювання.
6
+ * могли одразу викликати `uses: ./.github/actions/setup-bun-deps` після кроку `actions/checkout@v6` (без checkout runner не знайде action.yml).
7
7
  *
8
8
  * Джерело: каталог `github-actions/setup-bun-deps/` у корені tarball пакету (поруч із `mdc/`, `bin/`).
9
9
  */