@nitra/cursor 1.8.151 → 1.8.152

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.
@@ -18,6 +18,14 @@ The primary development rules are stored in the Cursor rules directory:
18
18
  {{name}}
19
19
  {{/skills}}
20
20
 
21
+ ## Commands
22
+
23
+ Generated from the root `package.json` on each `npx @nitra/cursor` sync. Prefer `bun run <script>` for project scripts.
24
+
25
+ {{#commands}}
26
+ {{name}}
27
+ {{/commands}}
28
+
21
29
  ## Instructions for all agents
22
30
 
23
31
  Before making changes, read the relevant rule files for the area you are working on.
package/README.md CHANGED
@@ -63,7 +63,7 @@ CLI автоматично (команда завантаження правил
63
63
  1. Знайде або створить `.n-cursor.json` у поточній директорії (із полем `$schema` на JSON Schema пакету; якщо файл уже є без коректного `$schema`, поле буде додано або оновлено при зчитуванні конфігу)
64
64
  2. Створить директорію `.cursor/rules/`, якщо її ще немає
65
65
  3. Скопіює кожне з перелічених у конфігу правило з `mdc/` установленого пакету і збереже файли з префіксом `n-`
66
- 4. Після оновлення файлів на диску згенерує в корені проєкту **`AGENTS.md`**: повний вміст береться з шаблону пакету `AGENTS.template.md`, а список правил у шаблоні формується з **усіх наявних файлів `*.mdc`** у `.cursor/rules/` (відсортовано за ім’ям)
66
+ 4. Після оновлення файлів на диску згенерує в корені проєкту **`AGENTS.md`**: повний вміст береться з шаблону пакету `AGENTS.template.md`, а список правил у шаблоні формується з **усіх наявних файлів `*.mdc`** у `.cursor/rules/` (відсортовано за ім’ям); секція команд — з **`package.json`** кореня (див. `{{#commands}}` у шаблоні).
67
67
 
68
68
  ## Приклад виводу
69
69
 
@@ -114,13 +114,18 @@ npm/
114
114
 
115
115
  Під час запуску CLI тіло між `{{#services}}` і `{{/services}}` повторюється для кожного `*.mdc` у `.cursor/rules/`; у `{{name}}` підставляється вже готовий markdown-рядок (наприклад `- .cursor/rules/n-text.mdc`).
116
116
 
117
- 3. Після змін у шаблоні перевірте локально: у тестовому репозиторії з `.n-cursor.json` виконайте `npx`/`bunx` на зібраному пакеті або `node npm/bin/n-cursor.js` з кореня того репозиторію і переконайтеся, що **`AGENTS.md`** виглядає як очікується.
117
+ 3. Для секції **Skills** використовуйте блок **`{{#skills}}` `{{/skills}}`** з тим самим `{{name}}`: рядки формуються з каталогів у `.cursor/skills/` (див. також `buildSkillBulletItems` у `bin/n-cursor.js`).
118
+
119
+ 4. Для секції **Commands** використовуйте **`{{#commands}}` … `{{/commands}}`**: список генерується з кореневого **`package.json`** (поле `scripts` — відомі ключі у фіксованому порядку, плюс додаткові `lint-*`) та завжди доповнюється рядками про **`npx @nitra/cursor`** і **`npx @nitra/cursor check`**. Логіка винесена в **`npm/scripts/build-agents-commands.mjs`**.
120
+
121
+ 5. Після змін у шаблоні перевірте локально: у тестовому репозиторії з `.n-cursor.json` виконайте `npx`/`bunx` на зібраному пакеті або `node npm/bin/n-cursor.js` з кореня того репозиторію і переконайтеся, що **`AGENTS.md`** виглядає як очікується.
118
122
 
119
123
  ### Логіка в коді CLI
120
124
 
121
125
  - Шлях до шаблону: поруч із `mdc/`, тобто `…/node_modules/@nitra/cursor/AGENTS.template.md` після встановлення пакету.
122
126
  - Оновлення **`AGENTS.md`** виконується **після** циклу завантаження правил, щоб список відображав актуальний вміст `.cursor/rules/` на диску.
123
127
  - Якщо каталогу `.cursor/rules/` немає або в ньому немає `*.mdc`, блок `{{#services}}` стає порожнім; решта шаблону все одно записується в **`AGENTS.md`**.
128
+ - Секція **`commands`** залежить лише від **`package.json` у корені cwd**; якщо файлу немає або `scripts` відсутній, у блоці лишаються мінімальні рядки (`bun i`, виклики CLI).
124
129
 
125
130
  ## Мета проекту
126
131
 
package/bin/n-cursor.js CHANGED
@@ -18,6 +18,7 @@
18
18
  *
19
19
  * Файл AGENTS.md у корені: щоразу повністю перезаписується змістом з AGENTS.template.md
20
20
  * пакету; список правил у шаблоні будується з файлів *.mdc у .cursor/rules поточного проєкту.
21
+ * Секція команд — з кореневого package.json (scripts) та фіксовані рядки про CLI синхрону/перевірок.
21
22
  *
22
23
  * Після завантаження: у .cursor/rules видаляються файли *.mdc з префіксом «n-» (керовані
23
24
  * пакетом), яких немає у списку rules у .n-cursor.json. Інші .mdc у цій директорії залишаються.
@@ -45,6 +46,7 @@ import { basename, dirname, join } from 'node:path'
45
46
  import { cwd } from 'node:process'
46
47
  import { fileURLToPath } from 'node:url'
47
48
 
49
+ import { buildAgentsCommandBulletItems } from '../scripts/build-agents-commands.mjs'
48
50
  import { detectAutoRulesAndSkills, mergeConfigWithAutoDetected, normalizeIdList } from '../scripts/auto-rules.mjs'
49
51
  import { ensureNitraCursorInRootDevDependencies } from '../scripts/ensure-nitra-cursor-dev-dependencies.mjs'
50
52
  import { upgradeNitraCursorToLatestAndBunInstall } from '../scripts/upgrade-nitra-cursor-and-install.mjs'
@@ -424,19 +426,21 @@ function expandMustacheSection(template, section, items, prop) {
424
426
  }
425
427
 
426
428
  /**
427
- * Підставляє у вміст AGENTS.template.md список шляхів до файлів правил і skills
429
+ * Підставляє у вміст AGENTS.template.md список шляхів до файлів правил, skills і команд з package.json
428
430
  * @param {string} templateText вміст AGENTS.template.md
429
431
  * @param {string[]} mdcBasenames імена файлів (*.mdc) з .cursor/rules
430
432
  * @param {{ name: string }[]} skillItems рядки для секції Skills
433
+ * @param {{ name: string }[]} commandItems рядки для секції commands
431
434
  * @returns {string} готовий markdown для AGENTS.md
432
435
  */
433
- function renderAgentsTemplate(templateText, mdcBasenames, skillItems) {
436
+ function renderAgentsTemplate(templateText, mdcBasenames, skillItems, commandItems) {
434
437
  let result = templateText
435
438
  const serviceItems = mdcBasenames.map(mdcName => ({
436
439
  name: `- ${RULES_DIR}/${mdcName}`
437
440
  }))
438
441
  result = expandMustacheSection(result, 'services', serviceItems, 'name')
439
442
  result = expandMustacheSection(result, 'skills', skillItems, 'name')
443
+ result = expandMustacheSection(result, 'commands', commandItems, 'name')
440
444
  return result
441
445
  }
442
446
 
@@ -650,7 +654,8 @@ async function syncAgentsMd(agentsTemplatePath = BUNDLED_AGENTS_TEMPLATE_PATH) {
650
654
  const templateText = await readFile(agentsTemplatePath, 'utf8')
651
655
  const mdcFiles = await listProjectRulesMdcFiles()
652
656
  const skillItems = await buildSkillBulletItems()
653
- const body = renderAgentsTemplate(templateText, mdcFiles, skillItems)
657
+ const commandItems = await buildAgentsCommandBulletItems(cwd())
658
+ const body = renderAgentsTemplate(templateText, mdcFiles, skillItems, commandItems)
654
659
  const agentsPath = join(cwd(), AGENTS_FILE)
655
660
  const hadFile = existsSync(agentsPath)
656
661
  const out = body.endsWith('\n') ? body : `${body}\n`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nitra/cursor",
3
- "version": "1.8.151",
3
+ "version": "1.8.152",
4
4
  "description": "CLI для завантаження cursor-правил (префікс n-) у локальний репозиторій",
5
5
  "keywords": [
6
6
  "cli",
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Формує markdown-рядки для секції «Команди» у AGENTS.md.
3
+ *
4
+ * Джерело істини — `package.json` у корені цільового репозиторію: з поля `scripts` беруться відомі ключі
5
+ * у стабільному порядку, додатково — усі `lint-*`, яких не було в основному списку.
6
+ *
7
+ * Наприкінці завжди додаються рядки про CLI `@nitra/cursor` (синхрон правил / programmatic check),
8
+ * на початку — рекомендована команда `bun i` за конвенціями monorepo.
9
+ */
10
+ import { existsSync } from 'node:fs'
11
+ import { readFile } from 'node:fs/promises'
12
+ import { join } from 'node:path'
13
+
14
+ const PACKAGE_NAME = '@nitra/cursor'
15
+ const AGENTS_MD = 'AGENTS.md'
16
+
17
+ /** Порядок виводу скриптів із `package.json` (лише ті, що реально існують). */
18
+ const SCRIPT_KEYS_ORDER = /** @type {const} */ ([
19
+ 'test',
20
+ 'lint',
21
+ 'lint-js',
22
+ 'lint-text',
23
+ 'lint-ga',
24
+ 'lint-k8s',
25
+ 'lint-docker',
26
+ 'start',
27
+ 'dev',
28
+ 'build'
29
+ ])
30
+
31
+ /**
32
+ * Зчитує `scripts` з `package.json` у `projectRoot` або повертає порожній об'єкт.
33
+ * @param {string} projectRoot абсолютний шлях до кореня репозиторію
34
+ * @returns {Promise<Record<string, string>>} об'єкт скриптів
35
+ */
36
+ async function readPackageScripts(projectRoot) {
37
+ const pkgPath = join(projectRoot, 'package.json')
38
+ if (!existsSync(pkgPath)) {
39
+ return {}
40
+ }
41
+ try {
42
+ const raw = await readFile(pkgPath, 'utf8')
43
+ const pkg = JSON.parse(raw)
44
+ if (pkg && typeof pkg === 'object' && pkg.scripts && typeof pkg.scripts === 'object') {
45
+ return /** @type {Record<string, string>} */ (pkg.scripts)
46
+ }
47
+ } catch {
48
+ // некоректний JSON або IO — секція команд лишиться з мінімумом (bun i + npx)
49
+ }
50
+ return {}
51
+ }
52
+
53
+ /**
54
+ * Повертає елементи для Mustache-секції `commands` у AGENTS.template.md.
55
+ * @param {string} projectRoot абсолютний шлях до кореня репозиторію (зазвичай `process.cwd()`)
56
+ * @returns {Promise<{ name: string }[]>} рядки з полем `name` для `expandMustacheSection`
57
+ */
58
+ export async function buildAgentsCommandBulletItems(projectRoot) {
59
+ const scripts = await readPackageScripts(projectRoot)
60
+ const items = /** @type {{ name: string }[]} */ ([])
61
+
62
+ items.push({ name: `- **Залежності**: \`bun i\`` })
63
+
64
+ const added = new Set()
65
+
66
+ for (const key of SCRIPT_KEYS_ORDER) {
67
+ if (typeof scripts[key] === 'string' && scripts[key].length > 0) {
68
+ items.push({ name: `- **${key}**: \`bun run ${key}\`` })
69
+ added.add(key)
70
+ }
71
+ }
72
+
73
+ const lintExtraKeys = Object.keys(scripts)
74
+ .filter(k => k.startsWith('lint-') && !added.has(k) && typeof scripts[k] === 'string')
75
+ .toSorted((a, b) => a.localeCompare(b))
76
+
77
+ for (const key of lintExtraKeys) {
78
+ items.push({ name: `- **${key}**: \`bun run ${key}\`` })
79
+ added.add(key)
80
+ }
81
+
82
+ items.push({
83
+ name: `- **Оновити правила та ${AGENTS_MD}** (після змін у правилах/шаблоні CLI): \`npx ${PACKAGE_NAME}\``
84
+ })
85
+ items.push({ name: `- **Перевірки правил (programmatic)**: \`npx ${PACKAGE_NAME} check\`` })
86
+
87
+ return items
88
+ }