@nitra/cursor 1.7.1 → 1.8.2
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/bin/n-cursor.js +23 -18
- package/github-actions/setup-bun-deps/action.yml +29 -0
- package/mdc/bun.mdc +5 -1
- package/mdc/docker.mdc +6 -8
- package/mdc/ga.mdc +7 -25
- package/mdc/js-lint.mdc +3 -19
- package/mdc/k8s.mdc +25 -7
- package/mdc/npm-module.mdc +4 -4
- package/mdc/style-lint.mdc +1 -1
- package/mdc/text.mdc +6 -26
- package/package.json +2 -1
- package/scripts/check-ga.mjs +11 -1
- package/scripts/check-k8s.mjs +4 -2
- package/scripts/check-npm-module.mjs +1 -1
- package/scripts/check-text.mjs +2 -8
- package/scripts/ensure-nitra-cursor-dev-dependencies.mjs +99 -0
- package/scripts/run-k8s.mjs +1 -1
- package/scripts/sync-setup-bun-deps-action.mjs +36 -0
package/bin/n-cursor.js
CHANGED
|
@@ -20,10 +20,16 @@
|
|
|
20
20
|
* Після завантаження: у .cursor/rules видаляються файли *.mdc з префіксом «n-» (керовані
|
|
21
21
|
* пакетом), яких немає у списку rules у .n-cursor.json. Інші .mdc у цій директорії залишаються.
|
|
22
22
|
*
|
|
23
|
+
* Composite GitHub Action `.github/actions/setup-bun-deps/action.yml` копіюється з каталогу
|
|
24
|
+
* `github-actions/` пакету при кожному успішному синку (workflows з правил ga / js-lint / text).
|
|
25
|
+
*
|
|
23
26
|
* Skills копіюються з npm/skills пакету лише для id з масиву «skills» у .n-cursor.json
|
|
24
27
|
* (у JSON — без префікса, каталоги в проєкті — n-<id>, як і для правил). Якщо ключа skills
|
|
25
28
|
* немає, за замовчуванням підтягуються всі bundled skills з префіксом n- у пакеті.
|
|
26
29
|
* Зайві каталоги n-* у .cursor/skills, яких немає у списку, видаляються.
|
|
30
|
+
*
|
|
31
|
+
* Якщо в корені є package.json і в ньому ще немає \@nitra/cursor у devDependencies (і не оголошено
|
|
32
|
+
* в dependencies), CLI дописує devDependencies з діапазоном ^<version> поточного пакету — зручно після npx.
|
|
27
33
|
*/
|
|
28
34
|
|
|
29
35
|
import { existsSync } from 'node:fs'
|
|
@@ -32,6 +38,12 @@ import { basename, dirname, join } from 'node:path'
|
|
|
32
38
|
import { cwd } from 'node:process'
|
|
33
39
|
import { fileURLToPath } from 'node:url'
|
|
34
40
|
|
|
41
|
+
import {
|
|
42
|
+
ensureNitraCursorInRootDevDependencies,
|
|
43
|
+
readBundledPackageVersion
|
|
44
|
+
} from '../scripts/ensure-nitra-cursor-dev-dependencies.mjs'
|
|
45
|
+
import { syncSetupBunDepsAction } from '../scripts/sync-setup-bun-deps-action.mjs'
|
|
46
|
+
|
|
35
47
|
const PACKAGE_NAME = '@nitra/cursor'
|
|
36
48
|
const CONFIG_FILE = '.n-cursor.json'
|
|
37
49
|
/** Публічний URL JSON Schema для поля `$schema` у `.n-cursor.json` (IDE); вміст правил CLI читає лише з диска пакету */
|
|
@@ -47,6 +59,8 @@ const BUNDLED_MDC_DIR = join(binDir, '..', 'mdc')
|
|
|
47
59
|
const BUNDLED_SCRIPTS_DIR = join(binDir, '..', 'scripts')
|
|
48
60
|
const BUNDLED_SKILLS_DIR = join(binDir, '..', 'skills')
|
|
49
61
|
const BUNDLED_AGENTS_TEMPLATE_PATH = join(binDir, '..', AGENTS_TEMPLATE_FILE)
|
|
62
|
+
/** Корінь установленого пакету (каталог з `mdc/`, `github-actions/`, …) */
|
|
63
|
+
const BUNDLED_PACKAGE_ROOT = join(binDir, '..')
|
|
50
64
|
|
|
51
65
|
/**
|
|
52
66
|
* Імена правил (без .mdc) з каталогу mdc поточної інсталяції пакету
|
|
@@ -205,24 +219,6 @@ function readBundledRuleContent(rule) {
|
|
|
205
219
|
return readFile(bundledPath, 'utf8')
|
|
206
220
|
}
|
|
207
221
|
|
|
208
|
-
/**
|
|
209
|
-
* Версія з `package.json` установленого пакету (каталог поруч із `bin/`).
|
|
210
|
-
* @returns {Promise<string | null>} поле `version` рядком або `null`, якщо файлу немає / помилка парсингу
|
|
211
|
-
*/
|
|
212
|
-
async function readBundledPackageVersion() {
|
|
213
|
-
const pkgPath = join(binDir, '..', 'package.json')
|
|
214
|
-
if (!existsSync(pkgPath)) {
|
|
215
|
-
return null
|
|
216
|
-
}
|
|
217
|
-
try {
|
|
218
|
-
const raw = await readFile(pkgPath, 'utf8')
|
|
219
|
-
const pkg = JSON.parse(raw)
|
|
220
|
-
return typeof pkg.version === 'string' ? pkg.version : null
|
|
221
|
-
} catch {
|
|
222
|
-
return null
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
222
|
/**
|
|
227
223
|
* Нормалізує id skill з конфігу до форми без префікса n- (як «fix»)
|
|
228
224
|
* @param {string} skillName елемент масиву skills або ім'я каталогу
|
|
@@ -651,6 +647,14 @@ async function runSync() {
|
|
|
651
647
|
console.log(`📋 Правил до завантаження: ${rules.length}`)
|
|
652
648
|
console.log(`📋 Skills до синхронізації: ${skills.length}`)
|
|
653
649
|
|
|
650
|
+
try {
|
|
651
|
+
const { destPath } = await syncSetupBunDepsAction(cwd(), BUNDLED_PACKAGE_ROOT)
|
|
652
|
+
console.log(`📝 Оновлено ${destPath} (composite setup-bun-deps з пакету)\n`)
|
|
653
|
+
} catch (error) {
|
|
654
|
+
console.error(`❌ Не вдалося записати setup-bun-deps action: ${error.message}`)
|
|
655
|
+
throw error
|
|
656
|
+
}
|
|
657
|
+
|
|
654
658
|
const rulesDir = join(cwd(), RULES_DIR)
|
|
655
659
|
await mkdir(rulesDir, { recursive: true })
|
|
656
660
|
|
|
@@ -724,6 +728,7 @@ async function runSync() {
|
|
|
724
728
|
const [command, ...args] = process.argv.slice(2)
|
|
725
729
|
|
|
726
730
|
try {
|
|
731
|
+
await ensureNitraCursorInRootDevDependencies(cwd())
|
|
727
732
|
if (command === 'check') {
|
|
728
733
|
await runChecks(args)
|
|
729
734
|
} else {
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: Setup Bun dependencies
|
|
2
|
+
description: Checkout, Node 24, Bun, cache та bun install --frozen-lockfile
|
|
3
|
+
|
|
4
|
+
runs:
|
|
5
|
+
using: composite
|
|
6
|
+
steps:
|
|
7
|
+
- uses: actions/checkout@v6
|
|
8
|
+
with:
|
|
9
|
+
persist-credentials: false
|
|
10
|
+
|
|
11
|
+
- uses: actions/setup-node@v6
|
|
12
|
+
with:
|
|
13
|
+
node-version: '24'
|
|
14
|
+
|
|
15
|
+
- uses: oven-sh/setup-bun@v2
|
|
16
|
+
|
|
17
|
+
- name: Cache Bun dependencies
|
|
18
|
+
uses: actions/cache@v5
|
|
19
|
+
with:
|
|
20
|
+
path: |
|
|
21
|
+
~/.bun/install/cache
|
|
22
|
+
node_modules
|
|
23
|
+
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
|
|
24
|
+
restore-keys: |
|
|
25
|
+
${{ runner.os }}-bun-
|
|
26
|
+
|
|
27
|
+
- name: Install dependencies
|
|
28
|
+
run: bun install --frozen-lockfile
|
|
29
|
+
shell: bash
|
package/mdc/bun.mdc
CHANGED
|
@@ -62,10 +62,14 @@ FROM oven/bun:alpine AS build-env
|
|
|
62
62
|
В Github actions bun повинен налаштований так:
|
|
63
63
|
|
|
64
64
|
```yaml
|
|
65
|
+
- uses: actions/setup-node@v6
|
|
66
|
+
with:
|
|
67
|
+
node-version: '24'
|
|
68
|
+
|
|
65
69
|
- uses: oven-sh/setup-bun@v2
|
|
66
70
|
|
|
67
71
|
- name: Cache Bun dependencies
|
|
68
|
-
uses: actions/cache@
|
|
72
|
+
uses: actions/cache@v5
|
|
69
73
|
with:
|
|
70
74
|
path: |
|
|
71
75
|
~/.bun/install/cache
|
package/mdc/docker.mdc
CHANGED
|
@@ -45,12 +45,6 @@ on:
|
|
|
45
45
|
- '**/Dockerfile'
|
|
46
46
|
- '**/*.Dockerfile'
|
|
47
47
|
- '**/*.dockerfile'
|
|
48
|
-
- '.hadolint.yaml'
|
|
49
|
-
- 'npm/scripts/run-docker.mjs'
|
|
50
|
-
- 'npm/scripts/utils/docker-hadolint.mjs'
|
|
51
|
-
- 'npm/scripts/check-docker.mjs'
|
|
52
|
-
- 'npm/mdc/docker.mdc'
|
|
53
|
-
- 'package.json'
|
|
54
48
|
|
|
55
49
|
pull_request:
|
|
56
50
|
branches:
|
|
@@ -66,7 +60,7 @@ jobs:
|
|
|
66
60
|
permissions:
|
|
67
61
|
contents: read
|
|
68
62
|
steps:
|
|
69
|
-
- uses: actions/checkout@
|
|
63
|
+
- uses: actions/checkout@v6
|
|
70
64
|
with:
|
|
71
65
|
persist-credentials: false
|
|
72
66
|
|
|
@@ -76,10 +70,14 @@ jobs:
|
|
|
76
70
|
chmod +x /tmp/hadolint
|
|
77
71
|
sudo mv /tmp/hadolint /usr/local/bin/hadolint
|
|
78
72
|
|
|
73
|
+
- uses: actions/setup-node@v6
|
|
74
|
+
with:
|
|
75
|
+
node-version: '24'
|
|
76
|
+
|
|
79
77
|
- uses: oven-sh/setup-bun@v2
|
|
80
78
|
|
|
81
79
|
- name: Cache Bun dependencies
|
|
82
|
-
uses: actions/cache@
|
|
80
|
+
uses: actions/cache@v5
|
|
83
81
|
with:
|
|
84
82
|
path: |
|
|
85
83
|
~/.bun/install/cache
|
package/mdc/ga.mdc
CHANGED
|
@@ -26,7 +26,7 @@ jobs:
|
|
|
26
26
|
contents: read
|
|
27
27
|
steps:
|
|
28
28
|
- name: Delete workflow runs
|
|
29
|
-
uses: dmvict/clean-workflow-runs@v1
|
|
29
|
+
uses: dmvict/clean-workflow-runs@v1
|
|
30
30
|
with:
|
|
31
31
|
token: ${{ github.token }}
|
|
32
32
|
save_period: 31
|
|
@@ -55,7 +55,7 @@ jobs:
|
|
|
55
55
|
steps:
|
|
56
56
|
- id: delete_stuff
|
|
57
57
|
name: Delete those pesky dead branches
|
|
58
|
-
uses: phpdocker-io/github-actions-delete-abandoned-branches@v2
|
|
58
|
+
uses: phpdocker-io/github-actions-delete-abandoned-branches@v2.0.3
|
|
59
59
|
with:
|
|
60
60
|
github_token: ${{ github.token }}
|
|
61
61
|
last_commit_age_days: 90
|
|
@@ -80,11 +80,8 @@ on:
|
|
|
80
80
|
branches:
|
|
81
81
|
- dev
|
|
82
82
|
paths:
|
|
83
|
+
- '.github/actions/**'
|
|
83
84
|
- '.github/workflows/**'
|
|
84
|
-
- '.github/zizmor.yml'
|
|
85
|
-
- 'package.json'
|
|
86
|
-
- 'bun.lock'
|
|
87
|
-
|
|
88
85
|
pull_request:
|
|
89
86
|
branches:
|
|
90
87
|
- dev
|
|
@@ -99,31 +96,16 @@ jobs:
|
|
|
99
96
|
permissions:
|
|
100
97
|
contents: read
|
|
101
98
|
steps:
|
|
102
|
-
- uses: actions/
|
|
103
|
-
with:
|
|
104
|
-
persist-credentials: false
|
|
99
|
+
- uses: ./.github/actions/setup-bun-deps
|
|
105
100
|
|
|
106
|
-
- uses:
|
|
107
|
-
|
|
108
|
-
- name: Cache Bun dependencies
|
|
109
|
-
uses: actions/cache@v4
|
|
110
|
-
with:
|
|
111
|
-
path: |
|
|
112
|
-
~/.bun/install/cache
|
|
113
|
-
node_modules
|
|
114
|
-
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
|
|
115
|
-
restore-keys: |
|
|
116
|
-
${{ runner.os }}-bun-
|
|
117
|
-
|
|
118
|
-
- name: Install dependencies
|
|
119
|
-
run: bun install --frozen-lockfile
|
|
120
|
-
|
|
121
|
-
- uses: astral-sh/setup-uv@v6
|
|
101
|
+
- uses: astral-sh/setup-uv@v8.0.0
|
|
122
102
|
|
|
123
103
|
- name: Lint GA
|
|
124
104
|
run: bun run lint-ga
|
|
125
105
|
```
|
|
126
106
|
|
|
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`**.
|
|
108
|
+
|
|
127
109
|
```json title=".vscode/extensions.json"
|
|
128
110
|
{
|
|
129
111
|
"recommendations": ["github.vscode-github-actions"]
|
package/mdc/js-lint.mdc
CHANGED
|
@@ -71,7 +71,6 @@ on:
|
|
|
71
71
|
- '**/*.tsx'
|
|
72
72
|
- '**/*.vue'
|
|
73
73
|
- '**/eslint.config.*'
|
|
74
|
-
- '.jscpd.json'
|
|
75
74
|
|
|
76
75
|
pull_request:
|
|
77
76
|
branches:
|
|
@@ -87,24 +86,7 @@ jobs:
|
|
|
87
86
|
permissions:
|
|
88
87
|
contents: read
|
|
89
88
|
steps:
|
|
90
|
-
- uses: actions/
|
|
91
|
-
with:
|
|
92
|
-
persist-credentials: false
|
|
93
|
-
|
|
94
|
-
- uses: oven-sh/setup-bun@v2
|
|
95
|
-
|
|
96
|
-
- name: Cache Bun dependencies
|
|
97
|
-
uses: actions/cache@v4
|
|
98
|
-
with:
|
|
99
|
-
path: |
|
|
100
|
-
~/.bun/install/cache
|
|
101
|
-
node_modules
|
|
102
|
-
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
|
|
103
|
-
restore-keys: |
|
|
104
|
-
${{ runner.os }}-bun-
|
|
105
|
-
|
|
106
|
-
- name: Install dependencies
|
|
107
|
-
run: bun install --frozen-lockfile
|
|
89
|
+
- uses: ./.github/actions/setup-bun-deps
|
|
108
90
|
|
|
109
91
|
- name: Eslint
|
|
110
92
|
run: |
|
|
@@ -113,6 +95,8 @@ jobs:
|
|
|
113
95
|
bunx jscpd .
|
|
114
96
|
```
|
|
115
97
|
|
|
98
|
+
Composite **`.github/actions/setup-bun-deps/action.yml`** — checkout, Node 24, Bun, кеш і `bun install --frozen-lockfile` (див. **ga.mdc**).
|
|
99
|
+
|
|
116
100
|
Один workflow на лінт JS; зайвий `lint.yml` з тими самими кроками — прибери.
|
|
117
101
|
|
|
118
102
|
```javascript title="eslint.config.js"
|
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.
|
|
3
|
+
version: '1.10'
|
|
4
4
|
globs: "**/k8s/**/*.{yaml,yml}"
|
|
5
5
|
alwaysApply: false
|
|
6
6
|
---
|
|
@@ -72,7 +72,7 @@ jobs:
|
|
|
72
72
|
permissions:
|
|
73
73
|
contents: read
|
|
74
74
|
steps:
|
|
75
|
-
- uses: actions/checkout@
|
|
75
|
+
- uses: actions/checkout@v6
|
|
76
76
|
with:
|
|
77
77
|
persist-credentials: false
|
|
78
78
|
|
|
@@ -86,10 +86,14 @@ jobs:
|
|
|
86
86
|
curl -s https://raw.githubusercontent.com/kubescape/kubescape/master/install.sh | /bin/bash
|
|
87
87
|
echo "$HOME/.kubescape/bin" >> $GITHUB_PATH
|
|
88
88
|
|
|
89
|
+
- uses: actions/setup-node@v6
|
|
90
|
+
with:
|
|
91
|
+
node-version: '24'
|
|
92
|
+
|
|
89
93
|
- uses: oven-sh/setup-bun@v2
|
|
90
94
|
|
|
91
95
|
- name: Cache Bun dependencies
|
|
92
|
-
uses: actions/cache@
|
|
96
|
+
uses: actions/cache@v5
|
|
93
97
|
with:
|
|
94
98
|
path: |
|
|
95
99
|
~/.bun/install/cache
|
|
@@ -117,10 +121,10 @@ jobs:
|
|
|
117
121
|
|
|
118
122
|
## Що закодовано в `check-k8s.mjs`
|
|
119
123
|
|
|
120
|
-
При зміні правил синхронно оновлюй **`YANNH_PIN`**, **`YANNH_REF`** (якщо зміниться гілка за замовчуванням у репо yannh), **`YANNH_GROUPS`**, а в **`run-k8s.mjs`** — константу **`KUBERNETES_VERSION`** (
|
|
124
|
+
При зміні правил синхронно оновлюй **`YANNH_PIN`**, **`YANNH_REF`** (якщо зміниться гілка за замовчуванням у репо yannh), **`YANNH_GROUPS`**, **`DATREE_CRD_BASE`** (GitHub Pages каталогу CRD), а в **`run-k8s.mjs`** — константу **`KUBERNETES_VERSION`** і **`DATREE_CRD_SCHEMA_LOCATION`** (узгоджено з базою datree у цьому правилі).
|
|
121
125
|
|
|
122
126
|
- Обхід з пропуском `node_modules`, `.git`, `dist`, `coverage`, `.turbo`, `.next`.
|
|
123
|
-
- **`file:`** у `$schema` — URL до apiVersion/kind не звіряється; **`https:`** — kustomization за іменем файлу → Schema Store; `v1` → yannh; група з `YANNH_GROUPS` → yannh; інакше → datree.
|
|
127
|
+
- **`file:`** у `$schema` — URL до apiVersion/kind не звіряється; **`https:`** — kustomization за іменем файлу → Schema Store; `v1` → yannh; група з `YANNH_GROUPS` → yannh; інакше → datree (GitHub Pages).
|
|
124
128
|
|
|
125
129
|
## Коли застосовувати (агентам)
|
|
126
130
|
|
|
@@ -138,8 +142,22 @@ jobs:
|
|
|
138
142
|
3. **`apiVersion: group/version`** і **group** у **`YANNH_GROUPS`** у скрипті → yannh:
|
|
139
143
|
`https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/<PIN>/<kind>-<group-з-крапками-як-дефіси>-<version>.json`
|
|
140
144
|
Приклади: `apps/v1` + `Deployment` → `deployment-apps-v1.json`; `networking.k8s.io/v1` + `Ingress` → `ingress-networking-k8s-io-v1.json`.
|
|
141
|
-
4. **Інакше** (CRD тощо) → [datreeio/CRDs-catalog](https://github.com/datreeio/CRDs-catalog):
|
|
142
|
-
`https://
|
|
145
|
+
4. **Інакше** (CRD тощо) → [datreeio/CRDs-catalog](https://github.com/datreeio/CRDs-catalog) через **GitHub Pages** (канон для `$schema` у редакторі):
|
|
146
|
+
`https://datreeio.github.io/CRDs-catalog/<group>/<kind>_<version>.json`
|
|
147
|
+
(`<kind>` — лише літери та цифри в нижньому регістрі, без роздільників між CamelCase, як для yannh.)
|
|
148
|
+
|
|
149
|
+
**Приклад (Gateway API):** `apiVersion: gateway.networking.k8s.io/v1beta1`, `kind: HTTPRoute`:
|
|
150
|
+
|
|
151
|
+
```yaml
|
|
152
|
+
# yaml-language-server: $schema=https://datreeio.github.io/CRDs-catalog/gateway.networking.k8s.io/httproute_v1beta1.json
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**Приклад (GKE):** `apiVersion: networking.gke.io/v1`, `kind: HealthCheckPolicy`:
|
|
156
|
+
|
|
157
|
+
```yaml
|
|
158
|
+
# yaml-language-server: $schema=https://datreeio.github.io/CRDs-catalog/networking.gke.io/healthcheckpolicy_v1.json
|
|
159
|
+
```
|
|
160
|
+
|
|
143
161
|
5. **Немає надійного публічного URL** — не вигадуй: залиш коректний `$schema` або `file:` за узгодженням.
|
|
144
162
|
|
|
145
163
|
## Багатодокументні YAML
|
package/mdc/npm-module.mdc
CHANGED
|
@@ -8,7 +8,7 @@ Bun monorepo: workspace **`npm/`**, кореневий **`package.json`**, **`.g
|
|
|
8
8
|
|
|
9
9
|
## npm publish
|
|
10
10
|
|
|
11
|
-
**`npm-publish.yml`:** push у **`main`**, **`paths
|
|
11
|
+
**`npm-publish.yml`:** push у **`main`**, **`on.push.paths`** з **`npm/**`**, **`JS-DevTools/npm-publish@v4.1.5`**, **`with.package: npm/package.json`**, **`permissions.id-token: write`** (OIDC на npm).
|
|
12
12
|
|
|
13
13
|
```yaml title=".github/workflows/npm-publish.yml"
|
|
14
14
|
name: npm-publish
|
|
@@ -32,17 +32,17 @@ jobs:
|
|
|
32
32
|
id-token: write # КРИТИЧНО для OIDC!
|
|
33
33
|
|
|
34
34
|
steps:
|
|
35
|
-
- uses: actions/checkout@
|
|
35
|
+
- uses: actions/checkout@v6
|
|
36
36
|
with:
|
|
37
37
|
persist-credentials: false
|
|
38
38
|
|
|
39
|
-
- uses: actions/setup-node@
|
|
39
|
+
- uses: actions/setup-node@v6
|
|
40
40
|
with:
|
|
41
41
|
node-version: '24' # includes npm@11.6.0
|
|
42
42
|
registry-url: 'https://registry.npmjs.org'
|
|
43
43
|
|
|
44
44
|
- name: Publish package
|
|
45
|
-
uses: JS-DevTools/npm-publish@v4
|
|
45
|
+
uses: JS-DevTools/npm-publish@v4.1.5
|
|
46
46
|
with:
|
|
47
47
|
package: npm/package.json
|
|
48
48
|
```
|
package/mdc/style-lint.mdc
CHANGED
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.
|
|
4
|
+
version: '1.23'
|
|
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`**.
|
|
@@ -18,7 +18,7 @@ version: '1.22'
|
|
|
18
18
|
}
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
**`package.json`:** скрипт **`lint-text`** і devDependencies **`@nitra/cspell-dict
|
|
21
|
+
**`package.json`:** скрипт **`lint-text`** і devDependencies **`@nitra/cspell-dict`**. Для української додай **`@cspell/dict-uk-ua`**. **`markdownlint-cli2`** викликай у `lint-text` лише через **`bunx markdownlint-cli2`**, не додавай пакет до devDependencies. **`v8r`** лише через **`bun x v8r`** (зазвичай **`bunx v8r`**), не в devDependencies. Окремий пакет **`markdownlint`** не потрібний.
|
|
22
22
|
|
|
23
23
|
У v8r **немає** прапорця тихого режиму; рекомендовано скрипт **`run-v8r.mjs`** з репозиторію пакета `@nitra/cursor` (`npm/scripts/run-v8r.mjs`): один виклик у `lint-text` — під капотом послідовні **`bun x v8r`** для кожного типу (**json**, **json5**, **yml**, **yaml**, **toml**), бо один процес v8r з кількома глобами падає з **98**, якщо хоч один glob порожній, і тоді інші розширення не перевіряються. Вивід при кодах **0** і **98** не показується. Каталог схем **`schemas/v8r-catalog.json`** пакета `@nitra/cursor` скрипт підставляє в v8r сам. За бажання можна передати власні glob-и аргументами скрипта. Шлях до скрипта: `./npm/scripts/…`, `./scripts/…` після копіювання, або `node_modules/@nitra/cursor/scripts/…`.
|
|
24
24
|
|
|
@@ -72,10 +72,6 @@ on:
|
|
|
72
72
|
branches:
|
|
73
73
|
- dev
|
|
74
74
|
paths:
|
|
75
|
-
- '.cspell.json'
|
|
76
|
-
- '.gitignore'
|
|
77
|
-
- '.markdownlint-cli2.jsonc'
|
|
78
|
-
- '.v8rignore'
|
|
79
75
|
- '**/*.js'
|
|
80
76
|
- '**/*.ts'
|
|
81
77
|
- '**/*.vue'
|
|
@@ -111,29 +107,14 @@ jobs:
|
|
|
111
107
|
permissions:
|
|
112
108
|
contents: read
|
|
113
109
|
steps:
|
|
114
|
-
- uses: actions/
|
|
115
|
-
with:
|
|
116
|
-
persist-credentials: false
|
|
117
|
-
|
|
118
|
-
- uses: oven-sh/setup-bun@v2
|
|
119
|
-
|
|
120
|
-
- name: Cache Bun dependencies
|
|
121
|
-
uses: actions/cache@v4
|
|
122
|
-
with:
|
|
123
|
-
path: |
|
|
124
|
-
~/.bun/install/cache
|
|
125
|
-
node_modules
|
|
126
|
-
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
|
|
127
|
-
restore-keys: |
|
|
128
|
-
${{ runner.os }}-bun-
|
|
129
|
-
|
|
130
|
-
- name: Install dependencies
|
|
131
|
-
run: bun install --frozen-lockfile
|
|
110
|
+
- uses: ./.github/actions/setup-bun-deps
|
|
132
111
|
|
|
133
112
|
- name: Lint text
|
|
134
113
|
run: bun run lint-text
|
|
135
114
|
```
|
|
136
115
|
|
|
116
|
+
Composite **`.github/actions/setup-bun-deps/action.yml`** — checkout, Node 24, Bun, кеш і `bun install --frozen-lockfile` (див. **ga.mdc**).
|
|
117
|
+
|
|
137
118
|
Не дублюй окремий workflow з тими самими кроками cspell/markdownlint.
|
|
138
119
|
|
|
139
120
|
**`.cspell.json`**, `version: "0.2"`, **`language`**, **`import`** з `@nitra/cspell-dict`, **`ignorePaths`**, **`words`** лише для назв/термінів, коли не виправити текстом.
|
|
@@ -176,8 +157,7 @@ jobs:
|
|
|
176
157
|
"devDependencies": {
|
|
177
158
|
"@nitra/cspell-dict": "^1.0.185",
|
|
178
159
|
"@cspell/dict-uk-ua": "^4.0.6",
|
|
179
|
-
"@cspell/dict-ru_ru": "^2.3.2"
|
|
180
|
-
"markdownlint-cli2": "^0.22.0"
|
|
160
|
+
"@cspell/dict-ru_ru": "^2.3.2"
|
|
181
161
|
}
|
|
182
162
|
}
|
|
183
163
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nitra/cursor",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.2",
|
|
4
4
|
"description": "CLI для завантаження cursor-правил (префікс n-) у локальний репозиторій",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"files": [
|
|
26
26
|
"mdc",
|
|
27
27
|
"bin",
|
|
28
|
+
"github-actions",
|
|
28
29
|
"schemas",
|
|
29
30
|
"scripts",
|
|
30
31
|
"skills",
|
package/scripts/check-ga.mjs
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* Перевіряє GitHub Actions за правилом ga.mdc.
|
|
3
3
|
*
|
|
4
4
|
* Workflows лише з розширенням `.yml`, наявність clean/lint workflow, конфіг zizmor з ref-pin,
|
|
5
|
-
* відсутність MegaLinter, коректний скрипт `lint-ga` у `package.json
|
|
5
|
+
* відсутність MegaLinter, коректний скрипт `lint-ga` у `package.json`, виклик у `lint-ga.yml`,
|
|
6
|
+
* наявність composite `.github/actions/setup-bun-deps/action.yml` (його записує `npx @nitra/cursor`).
|
|
6
7
|
*/
|
|
7
8
|
import { existsSync } from 'node:fs'
|
|
8
9
|
import { readdir, readFile } from 'node:fs/promises'
|
|
@@ -34,6 +35,15 @@ export async function check() {
|
|
|
34
35
|
return exitCode
|
|
35
36
|
}
|
|
36
37
|
|
|
38
|
+
const setupBunDepsAction = '.github/actions/setup-bun-deps/action.yml'
|
|
39
|
+
if (existsSync(setupBunDepsAction)) {
|
|
40
|
+
pass(`${setupBunDepsAction} існує`)
|
|
41
|
+
} else {
|
|
42
|
+
fail(
|
|
43
|
+
`Відсутній ${setupBunDepsAction} — запустіть npx @nitra/cursor або скопіюйте з пакету (ga.mdc: composite setup-bun-deps)`
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
37
47
|
const files = await readdir(wfDir)
|
|
38
48
|
|
|
39
49
|
const yamlFiles = files.filter(f => f.endsWith('.yaml'))
|
package/scripts/check-k8s.mjs
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* Перевіряє Kubernetes YAML у шляхах з сегментом `k8s` (див. k8s.mdc).
|
|
3
3
|
*
|
|
4
4
|
* Перший рядок `# yaml-language-server: $schema=…`, без дублікатів, розширення `.yaml`
|
|
5
|
-
* (окрім `kustomization.yml`); URL схеми за першим документом — kustomization / yannh / datree
|
|
5
|
+
* (окрім `kustomization.yml`); URL схеми за першим документом — kustomization / yannh / datree
|
|
6
|
+
* (datree: `https://datreeio.github.io/CRDs-catalog/<group>/<kind>_<version>.json`).
|
|
6
7
|
* Dockerfile — правило docker.mdc, скрипт check-docker.mjs.
|
|
7
8
|
*/
|
|
8
9
|
import { readFile } from 'node:fs/promises'
|
|
@@ -21,7 +22,8 @@ const KUSTOMIZATION_SCHEMA = 'https://json.schemastore.org/kustomization.json'
|
|
|
21
22
|
|
|
22
23
|
const YANNH_BASE = `https://raw.githubusercontent.com/yannh/kubernetes-json-schema/${YANNH_REF}/${YANNH_PIN}/`
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
/** Публікація [CRDs-catalog](https://github.com/datreeio/CRDs-catalog) на GitHub Pages (те саме дерево, що й raw на `main`). */
|
|
26
|
+
const DATREE_CRD_BASE = 'https://datreeio.github.io/CRDs-catalog/'
|
|
25
27
|
|
|
26
28
|
/**
|
|
27
29
|
* Групи API Kubernetes, для яких у перевірці очікується схема yannh (не datree CRD catalog).
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Перевіряє структуру npm-модуля в монорепо за правилом npm-module.mdc.
|
|
3
3
|
*
|
|
4
|
-
* Workspace `npm/`, `npm/package.json`, workflow `npm-publish.yml` з OIDC
|
|
4
|
+
* Workspace `npm/`, `npm/package.json`, workflow `npm-publish.yml` з OIDC, `on.push.paths` з glob для каталогу npm (див. npm-module.mdc).
|
|
5
5
|
*/
|
|
6
6
|
import { existsSync } from 'node:fs'
|
|
7
7
|
import { readFile, stat } from 'node:fs/promises'
|
package/scripts/check-text.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Перевіряє текстовий стек за правилом text.mdc.
|
|
3
3
|
*
|
|
4
|
-
* cspell, markdownlint-cli2
|
|
4
|
+
* cspell, markdownlint через `bunx markdownlint-cli2` у `lint-text` (без devDependencies), v8r (`run-v8r.mjs` або чотири `bunx v8r`),
|
|
5
5
|
* `.v8rignore` (vscode JSON),
|
|
6
6
|
* workflow `lint-text.yml`, розширення VSCode для markdownlint.
|
|
7
7
|
*
|
|
@@ -41,7 +41,7 @@ function verifyUkApostropheRuleParagraph(filePath, body, failFn, passFn) {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
|
-
* Перевіряє відповідність проєкту правилам text.mdc (cspell, markdownlint
|
|
44
|
+
* Перевіряє відповідність проєкту правилам text.mdc (cspell, markdownlint через bunx, v8r)
|
|
45
45
|
* @returns {Promise<number>} 0 — все OK, 1 — є проблеми
|
|
46
46
|
*/
|
|
47
47
|
export async function check() {
|
|
@@ -154,12 +154,6 @@ export async function check() {
|
|
|
154
154
|
fail('@nitra/cspell-dict відсутній — bun add -d @nitra/cspell-dict')
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
-
if (devDeps['markdownlint-cli2']) {
|
|
158
|
-
pass('markdownlint-cli2 є в devDependencies')
|
|
159
|
-
} else {
|
|
160
|
-
fail('markdownlint-cli2 відсутній — bun add -d markdownlint-cli2 (n-text.mdc)')
|
|
161
|
-
}
|
|
162
|
-
|
|
163
157
|
const lintText = pkg.scripts?.['lint-text']
|
|
164
158
|
const v8rCalls = typeof lintText === 'string' ? (lintText.match(/bunx v8r/g) || []).length : 0
|
|
165
159
|
const quietCalls = typeof lintText === 'string' ? (lintText.match(/run-v8r?\.mjs/g) || []).length : 0
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Дописує `\@nitra/cursor` у `devDependencies` кореневого `package.json` проєкту, якщо пакет ще не
|
|
3
|
+
* оголошено ні в `devDependencies`, ні в `dependencies`.
|
|
4
|
+
*
|
|
5
|
+
* Використовується CLI `n-cursor` при кожному запуску (`npx \@nitra/cursor`, зокрема `check`), щоб
|
|
6
|
+
* команда `check` і скрипти з `node_modules/\@nitra/cursor/scripts/` були відтворювані після
|
|
7
|
+
* `bun install` / `npm install`, а не лише з кешу npx.
|
|
8
|
+
*
|
|
9
|
+
* Версія діапазону: `^<version>` з поля `version` установленого пакету `\@nitra/cursor`.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { existsSync } from 'node:fs'
|
|
13
|
+
import { readFile, writeFile } from 'node:fs/promises'
|
|
14
|
+
import { dirname, join } from 'node:path'
|
|
15
|
+
import { fileURLToPath } from 'node:url'
|
|
16
|
+
|
|
17
|
+
const PACKAGE_NAME = '@nitra/cursor'
|
|
18
|
+
|
|
19
|
+
const scriptDir = dirname(fileURLToPath(import.meta.url))
|
|
20
|
+
const bundledPkgPath = join(scriptDir, '..', 'package.json')
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Версія з `package.json` пакету `\@nitra/cursor` (каталог на рівень вище за `scripts/`).
|
|
24
|
+
* @returns {Promise<string | null>} поле `version` рядком або `null`, якщо файлу немає / помилка парсингу
|
|
25
|
+
*/
|
|
26
|
+
export async function readBundledPackageVersion() {
|
|
27
|
+
if (!existsSync(bundledPkgPath)) {
|
|
28
|
+
return null
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
const raw = await readFile(bundledPkgPath, 'utf8')
|
|
32
|
+
const pkg = JSON.parse(raw)
|
|
33
|
+
return typeof pkg.version === 'string' ? pkg.version : null
|
|
34
|
+
} catch {
|
|
35
|
+
return null
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Якщо в `root/package.json` немає `\@nitra/cursor` у `devDependencies` і `dependencies`, дописує
|
|
41
|
+
* `devDependencies["\@nitra/cursor"]` зі значенням `^<bundledVersion>`.
|
|
42
|
+
* @param {string} root абсолютний шлях кореня проєкту (зазвичай `process.cwd()`)
|
|
43
|
+
* @param {{ bundledVersion?: string | null, silent?: boolean }} [options] `bundledVersion` — для тестів;
|
|
44
|
+
* `silent` — не писати в консоль при успішному оновленні
|
|
45
|
+
* @returns {Promise<boolean>} `true`, якщо `package.json` змінено на диску
|
|
46
|
+
*/
|
|
47
|
+
export async function ensureNitraCursorInRootDevDependencies(root, options = {}) {
|
|
48
|
+
const pkgPath = join(root, 'package.json')
|
|
49
|
+
if (!existsSync(pkgPath)) {
|
|
50
|
+
return false
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
let raw
|
|
54
|
+
try {
|
|
55
|
+
raw = await readFile(pkgPath, 'utf8')
|
|
56
|
+
} catch {
|
|
57
|
+
return false
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let pkg
|
|
61
|
+
try {
|
|
62
|
+
pkg = JSON.parse(raw)
|
|
63
|
+
} catch {
|
|
64
|
+
return false
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (pkg === null || typeof pkg !== 'object' || Array.isArray(pkg)) {
|
|
68
|
+
return false
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const devDeps = pkg.devDependencies
|
|
72
|
+
const deps = pkg.dependencies
|
|
73
|
+
if (devDeps && typeof devDeps === 'object' && PACKAGE_NAME in devDeps) {
|
|
74
|
+
return false
|
|
75
|
+
}
|
|
76
|
+
if (deps && typeof deps === 'object' && PACKAGE_NAME in deps) {
|
|
77
|
+
return false
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const ver = options.bundledVersion ?? (await readBundledPackageVersion())
|
|
81
|
+
if (!ver) {
|
|
82
|
+
return false
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (!pkg.devDependencies || typeof pkg.devDependencies !== 'object' || Array.isArray(pkg.devDependencies)) {
|
|
86
|
+
pkg.devDependencies = {}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
pkg.devDependencies[PACKAGE_NAME] = `^${ver}`
|
|
90
|
+
|
|
91
|
+
const out = `${JSON.stringify(pkg, null, 2)}\n`
|
|
92
|
+
await writeFile(pkgPath, out, 'utf8')
|
|
93
|
+
|
|
94
|
+
if (!options.silent) {
|
|
95
|
+
console.log(`📝 Додано ${PACKAGE_NAME}@^${ver} у devDependencies у package.json\n`)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return true
|
|
99
|
+
}
|
package/scripts/run-k8s.mjs
CHANGED
|
@@ -23,7 +23,7 @@ const KUBERNETES_VERSION = '1.33.9'
|
|
|
23
23
|
|
|
24
24
|
/** Додатковий реєстр схем для CRD (як у README kubeconform). */
|
|
25
25
|
const DATREE_CRD_SCHEMA_LOCATION =
|
|
26
|
-
'https://
|
|
26
|
+
'https://datreeio.github.io/CRDs-catalog/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json'
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* Чи містить шлях сегмент директорії `k8s`.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Копіює composite GitHub Action `setup-bun-deps` з установленого пакету `@nitra/cursor`
|
|
3
|
+
* у цільовий репозиторій (`.github/actions/setup-bun-deps/action.yml`).
|
|
4
|
+
*
|
|
5
|
+
* Використовується CLI `npx \@nitra/cursor`, щоб workflows з правил `ga` / `js-lint` / `text`
|
|
6
|
+
* могли одразу викликати `uses: ./.github/actions/setup-bun-deps` без ручного копіювання.
|
|
7
|
+
*
|
|
8
|
+
* Джерело: каталог `github-actions/setup-bun-deps/` у корені tarball пакету (поруч із `mdc/`, `bin/`).
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync } from 'node:fs'
|
|
11
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises'
|
|
12
|
+
import { join } from 'node:path'
|
|
13
|
+
|
|
14
|
+
/** Відносний шлях до `action.yml` всередині кореня пакету */
|
|
15
|
+
const RELATIVE_BUNDLED_ACTION = join('github-actions', 'setup-bun-deps', 'action.yml')
|
|
16
|
+
|
|
17
|
+
/** Відносний шлях призначення у проєкті-клієнті */
|
|
18
|
+
const RELATIVE_DEST_ACTION = join('.github', 'actions', 'setup-bun-deps', 'action.yml')
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Записує у `projectRoot` composite action з `bundledPackageRoot` (корінь установленого `@nitra/cursor`).
|
|
22
|
+
* @param {string} projectRoot абсолютний шлях до кореня цільового репозиторію
|
|
23
|
+
* @param {string} bundledPackageRoot абсолютний шлях до кореня пакету (теки з `mdc/`, `github-actions/`)
|
|
24
|
+
* @returns {Promise<{ written: boolean, destPath: string }>} чи був запис і повний шлях файлу
|
|
25
|
+
*/
|
|
26
|
+
export async function syncSetupBunDepsAction(projectRoot, bundledPackageRoot) {
|
|
27
|
+
const srcPath = join(bundledPackageRoot, RELATIVE_BUNDLED_ACTION)
|
|
28
|
+
if (!existsSync(srcPath)) {
|
|
29
|
+
throw new Error(`Не знайдено шаблон composite action.\nОчікуваний шлях: ${srcPath}\nПеревстановіть @nitra/cursor.`)
|
|
30
|
+
}
|
|
31
|
+
const destPath = join(projectRoot, RELATIVE_DEST_ACTION)
|
|
32
|
+
await mkdir(join(projectRoot, '.github', 'actions', 'setup-bun-deps'), { recursive: true })
|
|
33
|
+
const content = await readFile(srcPath, 'utf8')
|
|
34
|
+
await writeFile(destPath, content.endsWith('\n') ? content : `${content}\n`, 'utf8')
|
|
35
|
+
return { written: true, destPath }
|
|
36
|
+
}
|