@nitra/cursor 1.5.1 → 1.5.3
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/mdc/ga.mdc +87 -2
- package/mdc/js-lint.mdc +24 -6
- package/mdc/text.mdc +8 -3
- package/package.json +2 -1
- package/schemas/n-cursor.json +27 -0
- package/scripts/check-ga.mjs +1 -1
- package/scripts/check-js-lint.mjs +36 -1
package/mdc/ga.mdc
CHANGED
|
@@ -41,6 +41,9 @@ on:
|
|
|
41
41
|
jobs:
|
|
42
42
|
cleanup_old_workflows:
|
|
43
43
|
runs-on: ubuntu-latest
|
|
44
|
+
permissions:
|
|
45
|
+
actions: write
|
|
46
|
+
contents: read
|
|
44
47
|
steps:
|
|
45
48
|
- name: Delete workflow runs
|
|
46
49
|
uses: dmvict/clean-workflow-runs@v1.0.0
|
|
@@ -67,6 +70,8 @@ on:
|
|
|
67
70
|
jobs:
|
|
68
71
|
cleanup_old_branches:
|
|
69
72
|
runs-on: ubuntu-latest
|
|
73
|
+
permissions:
|
|
74
|
+
contents: write
|
|
70
75
|
steps:
|
|
71
76
|
- id: delete_stuff
|
|
72
77
|
name: Delete those pesky dead branches
|
|
@@ -78,11 +83,68 @@ jobs:
|
|
|
78
83
|
dry_run: no
|
|
79
84
|
|
|
80
85
|
- name: Get output
|
|
81
|
-
|
|
86
|
+
env:
|
|
87
|
+
DELETED_BRANCHES: ${{ steps.delete_stuff.outputs.deleted_branches }}
|
|
88
|
+
run: |
|
|
89
|
+
echo "Deleted branches: ${DELETED_BRANCHES}"
|
|
82
90
|
```
|
|
83
91
|
|
|
84
92
|
якщо в ignore_branches задані інші бранчі, то це допустимо.
|
|
85
93
|
|
|
94
|
+
Повинен бути файл .github/workflows/lint-ga.yml, зі змістом:
|
|
95
|
+
|
|
96
|
+
```yaml
|
|
97
|
+
name: Lint GA
|
|
98
|
+
|
|
99
|
+
on:
|
|
100
|
+
push:
|
|
101
|
+
branches:
|
|
102
|
+
- dev
|
|
103
|
+
paths:
|
|
104
|
+
- '.github/workflows/**'
|
|
105
|
+
- '.github/zizmor.yml'
|
|
106
|
+
- 'package.json'
|
|
107
|
+
- 'bun.lock'
|
|
108
|
+
|
|
109
|
+
pull_request:
|
|
110
|
+
branches:
|
|
111
|
+
- dev
|
|
112
|
+
|
|
113
|
+
concurrency:
|
|
114
|
+
group: ${{ github.ref }}-${{ github.workflow }}
|
|
115
|
+
cancel-in-progress: true
|
|
116
|
+
|
|
117
|
+
jobs:
|
|
118
|
+
lint-ga:
|
|
119
|
+
runs-on: ubuntu-latest
|
|
120
|
+
permissions:
|
|
121
|
+
contents: read
|
|
122
|
+
steps:
|
|
123
|
+
- uses: actions/checkout@v4
|
|
124
|
+
with:
|
|
125
|
+
persist-credentials: false
|
|
126
|
+
|
|
127
|
+
- uses: oven-sh/setup-bun@v2
|
|
128
|
+
|
|
129
|
+
- name: Cache Bun dependencies
|
|
130
|
+
uses: actions/cache@v4
|
|
131
|
+
with:
|
|
132
|
+
path: |
|
|
133
|
+
~/.bun/install/cache
|
|
134
|
+
node_modules
|
|
135
|
+
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
|
|
136
|
+
restore-keys: |
|
|
137
|
+
${{ runner.os }}-bun-
|
|
138
|
+
|
|
139
|
+
- name: Install dependencies
|
|
140
|
+
run: bun install --frozen-lockfile
|
|
141
|
+
|
|
142
|
+
- uses: astral-sh/setup-uv@v6
|
|
143
|
+
|
|
144
|
+
- name: Lint GA
|
|
145
|
+
run: bun run lint-ga
|
|
146
|
+
```
|
|
147
|
+
|
|
86
148
|
в файлі .vscode/extensions.json є налаштування для GitHub Actions:
|
|
87
149
|
|
|
88
150
|
```json title=".vscode/extensions.json"
|
|
@@ -91,6 +153,29 @@ jobs:
|
|
|
91
153
|
}
|
|
92
154
|
```
|
|
93
155
|
|
|
156
|
+
## actionlint
|
|
157
|
+
|
|
158
|
+
Статична перевірка синтаксису та виразів GitHub Actions: [actionlint](https://github.com/rhysd/actionlint).
|
|
159
|
+
|
|
160
|
+
У кореневому `package.json` у скрипті `lint-ga` викликай **actionlint** через **`bunx node-actionlint`** (пакет [node-actionlint](https://www.npmjs.com/package/node-actionlint) постає бінарник actionlint для Node-екосистеми).
|
|
161
|
+
|
|
162
|
+
## zizmor
|
|
163
|
+
|
|
164
|
+
Статичний аналіз безпеки для GitHub Actions: [zizmor documentation](https://docs.zizmor.sh).
|
|
165
|
+
|
|
166
|
+
У кореневому `package.json` має бути скрипт:
|
|
167
|
+
|
|
168
|
+
```json title="package.json"
|
|
169
|
+
"scripts": {
|
|
170
|
+
"lint-ga": "bunx node-actionlint && uvx zizmor --offline --collect=workflows ."
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Параметр `--offline` обмежує аналіз офлайн-аудитами (без GitHub API);
|
|
175
|
+
|
|
176
|
+
За замовчуванням audit [unpinned-uses](https://docs.zizmor.sh/audits/#unpinned-uses) вимагає повний commit SHA для кожного `uses:`. У всих проєктах прийняті **семантичні теги** (`@v4`, `@v2` тощо), додай `.github/zizmor.yml` з політикою `ref-pin` (приклад у цьому репозиторії).
|
|
177
|
+
|
|
94
178
|
## Перевірка
|
|
95
179
|
|
|
96
|
-
`
|
|
180
|
+
- `bun run lint-ga` — actionlint (node-actionlint) і zizmor
|
|
181
|
+
- `npx @nitra/cursor check ga`
|
package/mdc/js-lint.mdc
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Перевірка JavaScript коду
|
|
3
3
|
alwaysApply: true
|
|
4
|
-
version: '1.
|
|
4
|
+
version: '1.4'
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
Перевірка виконується за допомогою **oxlint** та **
|
|
7
|
+
Перевірка виконується за допомогою **oxlint**, **ESLint** та **jscpd** (дублікати коду).
|
|
8
8
|
|
|
9
9
|
У файлі `.vscode/extensions.json` мають бути рекомендації розширень:
|
|
10
10
|
|
|
@@ -18,18 +18,30 @@ version: '1.2'
|
|
|
18
18
|
}
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
У кореневому `package.json` додай скрипт і
|
|
21
|
+
У кореневому `package.json` додай скрипт і залежності:
|
|
22
22
|
|
|
23
23
|
```json title="package.json"
|
|
24
24
|
"scripts": {
|
|
25
|
-
"lint-js": "oxlint --fix && bunx eslint --fix ."
|
|
25
|
+
"lint-js": "oxlint --fix && bunx eslint --fix . && bunx jscpd ."
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@nitra/eslint-config": "^3.
|
|
28
|
+
"@nitra/eslint-config": "^3.4.0"
|
|
29
29
|
}
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
У `devDependencies` достатньо `@nitra/eslint-config` (залежності ESLint підтягуються разом із ним). **oxlint**
|
|
32
|
+
У `devDependencies` достатньо `@nitra/eslint-config` (залежності ESLint підтягуються разом із ним). **oxlint**, **eslint** та **jscpd** у скриптах викликай через `bunx`; окремо не додавай пакети `oxlint` / `eslint` / `jscpd`, якщо цього не вимагає ваш монорепо.
|
|
33
|
+
|
|
34
|
+
У корені проєкту має бути `.jscpd.json`. Мінімум: увімкнути облік `.gitignore`, ненульовий код виходу при знаходженні клонів, консольний звіт. За потреби додай `ignore` (дзеркальні каталоги, шаблони) та `minLines`, щоб відсікти дрібні збіги:
|
|
35
|
+
|
|
36
|
+
```json title=".jscpd.json"
|
|
37
|
+
{
|
|
38
|
+
"gitignore": true,
|
|
39
|
+
"exitCode": 1,
|
|
40
|
+
"reporters": ["console"],
|
|
41
|
+
"minLines": 25,
|
|
42
|
+
"ignore": []
|
|
43
|
+
}
|
|
44
|
+
```
|
|
33
45
|
|
|
34
46
|
Додай workflow `.github/workflows/lint-js.yml`:
|
|
35
47
|
|
|
@@ -49,6 +61,7 @@ on:
|
|
|
49
61
|
- '**/*.tsx'
|
|
50
62
|
- '**/*.vue'
|
|
51
63
|
- '**/eslint.config.*'
|
|
64
|
+
- '.jscpd.json'
|
|
52
65
|
|
|
53
66
|
pull_request:
|
|
54
67
|
branches:
|
|
@@ -61,8 +74,12 @@ concurrency:
|
|
|
61
74
|
jobs:
|
|
62
75
|
eslint:
|
|
63
76
|
runs-on: ubuntu-latest
|
|
77
|
+
permissions:
|
|
78
|
+
contents: read
|
|
64
79
|
steps:
|
|
65
80
|
- uses: actions/checkout@v4
|
|
81
|
+
with:
|
|
82
|
+
persist-credentials: false
|
|
66
83
|
|
|
67
84
|
- uses: oven-sh/setup-bun@v2
|
|
68
85
|
|
|
@@ -83,6 +100,7 @@ jobs:
|
|
|
83
100
|
run: |
|
|
84
101
|
bunx oxlint
|
|
85
102
|
bunx eslint .
|
|
103
|
+
bunx jscpd .
|
|
86
104
|
```
|
|
87
105
|
|
|
88
106
|
**Без дублювання CI:** якщо в `.github/workflows` уже є `lint.yml` з тими самими кроками `oxlint` або `eslint`, видали зайвий workflow, а саме `lint.yml` — лінт JS має виконуватися в одному місці.
|
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.12'
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
Правило описує роботу з **текстовими файлами** в репозиторії: перевірка правопису через **cspell**, стиль **Markdown** через **markdownlint-cli2**, валідація **JSON/YAML/TOML** через **[v8r](https://chris48s.github.io/v8r/)** ([Schema Store](https://www.schemastore.org/)), розширення **DavidAnson.vscode-markdownlint** у Cursor/VS Code та інтеграція в CI.
|
|
@@ -42,7 +42,9 @@ version: '1.10'
|
|
|
42
42
|
|
|
43
43
|
**Код 98:** якщо для glob **немає жодного файлу**, v8r дає **98**. Це стосується не лише TOML: репозиторій без `.yml`/`.yaml` зламає **один** спільний виклик `v8r` уже на `**/*.yml`. Окремі виклики з дозволом лише **98** покривають і такі репозиторії.
|
|
44
44
|
|
|
45
|
-
За замовчуванням v8r враховує **`.gitignore
|
|
45
|
+
За замовчуванням v8r враховує **`.gitignore`**. **`.v8rignore` не створюй завчасно** — файл потрібен **лише коли** `bunx v8r` падає на JSON/YAML без схеми в каталозі (тоді додай у ignore відповідні glob’и).
|
|
46
|
+
|
|
47
|
+
Пакет **`v8r` у `devDependencies` не додавай** — у скрипті достатньо **`bunx v8r`**.
|
|
46
48
|
|
|
47
49
|
## Конфігурація markdownlint-cli2
|
|
48
50
|
|
|
@@ -84,7 +86,6 @@ on:
|
|
|
84
86
|
- '.cspell.json'
|
|
85
87
|
- '.gitignore'
|
|
86
88
|
- '.markdownlint-cli2.jsonc'
|
|
87
|
-
- '.v8rignore'
|
|
88
89
|
- '**/*.js'
|
|
89
90
|
- '**/*.ts'
|
|
90
91
|
- '**/*.vue'
|
|
@@ -117,8 +118,12 @@ concurrency:
|
|
|
117
118
|
jobs:
|
|
118
119
|
text:
|
|
119
120
|
runs-on: ubuntu-latest
|
|
121
|
+
permissions:
|
|
122
|
+
contents: read
|
|
120
123
|
steps:
|
|
121
124
|
- uses: actions/checkout@v4
|
|
125
|
+
with:
|
|
126
|
+
persist-credentials: false
|
|
122
127
|
|
|
123
128
|
- uses: oven-sh/setup-bun@v2
|
|
124
129
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nitra/cursor",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.3",
|
|
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
|
+
"schemas",
|
|
28
29
|
"scripts",
|
|
29
30
|
"skills",
|
|
30
31
|
"AGENTS.template.md"
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://unpkg.com/@nitra/cursor/schemas/n-cursor.json",
|
|
4
|
+
"title": "n-cursor project config",
|
|
5
|
+
"description": "Конфігурація правил і skills для CLI @nitra/cursor (файл .n-cursor.json у корені репозиторію).",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": true,
|
|
8
|
+
"properties": {
|
|
9
|
+
"rules": {
|
|
10
|
+
"type": "array",
|
|
11
|
+
"description": "Ідентифікатори правил без префікса n- (відповідають файлам n-<id>.mdc).",
|
|
12
|
+
"items": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"minLength": 1
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"skills": {
|
|
18
|
+
"type": "array",
|
|
19
|
+
"description": "Ідентифікатори skills без префікса n- (каталог .cursor/skills).",
|
|
20
|
+
"items": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"minLength": 1
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"required": ["rules", "skills"]
|
|
27
|
+
}
|
package/scripts/check-ga.mjs
CHANGED
|
@@ -30,7 +30,7 @@ export async function check() {
|
|
|
30
30
|
pass('Всі workflows мають розширення .yml')
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
for (const f of ['clean-ga-workflows.yml', 'clean-merged-branch.yml']) {
|
|
33
|
+
for (const f of ['clean-ga-workflows.yml', 'clean-merged-branch.yml', 'lint-ga.yml']) {
|
|
34
34
|
if (files.includes(f)) {
|
|
35
35
|
pass(`${f} існує`)
|
|
36
36
|
} else {
|
|
@@ -27,8 +27,13 @@ export async function check() {
|
|
|
27
27
|
|
|
28
28
|
if (pkg.scripts?.['lint-js']) {
|
|
29
29
|
pass('package.json містить скрипт lint-js')
|
|
30
|
+
if (String(pkg.scripts['lint-js']).includes('jscpd')) {
|
|
31
|
+
pass('lint-js містить jscpd')
|
|
32
|
+
} else {
|
|
33
|
+
fail('lint-js має викликати jscpd — додай "&& bunx jscpd ." у кінець скрипта')
|
|
34
|
+
}
|
|
30
35
|
} else {
|
|
31
|
-
fail('package.json не містить скрипт "lint-js" — додай: "oxlint --fix && bunx eslint --fix ."')
|
|
36
|
+
fail('package.json не містить скрипт "lint-js" — додай: "oxlint --fix && bunx eslint --fix . && bunx jscpd ."')
|
|
32
37
|
}
|
|
33
38
|
|
|
34
39
|
if (pkg.devDependencies?.['@nitra/eslint-config']) {
|
|
@@ -63,10 +68,40 @@ export async function check() {
|
|
|
63
68
|
} else {
|
|
64
69
|
fail('lint-js.yml не містить eslint')
|
|
65
70
|
}
|
|
71
|
+
if (content.includes('jscpd')) {
|
|
72
|
+
pass('lint-js.yml містить jscpd')
|
|
73
|
+
} else {
|
|
74
|
+
fail('lint-js.yml не містить jscpd — додай крок bunx jscpd .')
|
|
75
|
+
}
|
|
66
76
|
} else {
|
|
67
77
|
fail('.github/workflows/lint-js.yml не існує — створи його')
|
|
68
78
|
}
|
|
69
79
|
|
|
80
|
+
if (existsSync('.jscpd.json')) {
|
|
81
|
+
let jscpdCfg
|
|
82
|
+
try {
|
|
83
|
+
jscpdCfg = JSON.parse(await readFile('.jscpd.json', 'utf8'))
|
|
84
|
+
} catch {
|
|
85
|
+
fail('.jscpd.json не є валідним JSON')
|
|
86
|
+
jscpdCfg = null
|
|
87
|
+
}
|
|
88
|
+
if (jscpdCfg) {
|
|
89
|
+
pass('.jscpd.json існує')
|
|
90
|
+
if (jscpdCfg.gitignore === true) {
|
|
91
|
+
pass('.jscpd.json: gitignore увімкнено')
|
|
92
|
+
} else {
|
|
93
|
+
fail('.jscpd.json має містити "gitignore": true')
|
|
94
|
+
}
|
|
95
|
+
if (jscpdCfg.exitCode === 1) {
|
|
96
|
+
pass('.jscpd.json: exitCode 1 при дублікатах')
|
|
97
|
+
} else {
|
|
98
|
+
fail('.jscpd.json має містити "exitCode": 1 (інакше CI не впаде на клонах)')
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
} else {
|
|
102
|
+
fail('.jscpd.json не існує — створи з gitignore, exitCode та reporters згідно js-lint.mdc')
|
|
103
|
+
}
|
|
104
|
+
|
|
70
105
|
for (const dup of ['.eslintrc', '.eslintrc.js', '.eslintrc.json', '.eslintrc.yml']) {
|
|
71
106
|
if (existsSync(dup)) fail(`Знайдено застарілий конфіг ESLint: ${dup} — видали, використовуй eslint.config.js`)
|
|
72
107
|
}
|