@nitra/cursor 12.3.2 → 12.4.0

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.
Files changed (57) hide show
  1. package/.claude-template/hooks/capture-decisions.sh +36 -19
  2. package/.claude-template/hooks/lib/tooling-only.sh +16 -0
  3. package/CHANGELOG.md +12 -0
  4. package/package.json +1 -1
  5. package/rules/bun/bun.mdc +5 -5
  6. package/rules/bun/policy/package_json/package_json.rego +0 -31
  7. package/rules/ga/ga.mdc +2 -4
  8. package/rules/ga/policy/lint_ga/lint_ga.rego +2 -2
  9. package/rules/ga/policy/lint_ga/template/lint-ga.yml.snippet.yml +1 -1
  10. package/rules/js-lint/js-lint.mdc +2 -5
  11. package/rules/js-lint/policy/lint_js_yml/template/lint-js.yml.snippet.yml +1 -5
  12. package/rules/js-lint/policy/package_json/template/package.json.snippet.json +0 -3
  13. package/rules/lint/js/docs/orchestrate.md +11 -12
  14. package/rules/lint/js/orchestrate.mjs +82 -5
  15. package/rules/php/js/docs/index.md +1 -0
  16. package/rules/php/js/docs/lint.md +20 -0
  17. package/rules/php/js/lint.mjs +13 -0
  18. package/rules/php/php.mdc +1 -3
  19. package/rules/php/policy/lint_php_yml/template/lint-php.yml.snippet.yml +1 -1
  20. package/rules/python/js/docs/index.md +1 -0
  21. package/rules/python/js/docs/lint.md +21 -0
  22. package/rules/python/js/lint.mjs +14 -0
  23. package/rules/python/lint/docs/lint.md +15 -312
  24. package/rules/python/lint/lint.mjs +11 -5
  25. package/rules/python/meta.json +1 -1
  26. package/rules/python/policy/lint_python_yml/template/lint-python.yml.snippet.yml +1 -1
  27. package/rules/python/python.mdc +1 -3
  28. package/rules/rego/rego.mdc +2 -6
  29. package/rules/rust/js/docs/index.md +1 -0
  30. package/rules/rust/js/docs/lint.md +21 -0
  31. package/rules/rust/js/lint.mjs +67 -0
  32. package/rules/rust/rust.mdc +2 -4
  33. package/rules/security/policy/package_json/package_json.rego +0 -19
  34. package/rules/security/security.mdc +5 -6
  35. package/rules/style-lint/policy/lint_style_yml/template/lint-style.yml.snippet.yml +1 -1
  36. package/rules/style-lint/policy/package_json/package_json.rego +0 -10
  37. package/rules/style-lint/style-lint.mdc +4 -6
  38. package/rules/text/js/formatting.mjs +7 -31
  39. package/rules/text/policy/lint_text/template/lint-text.yml.snippet.yml +1 -1
  40. package/rules/ga/policy/package_json/package_json.rego +0 -20
  41. package/rules/ga/policy/package_json/target.json +0 -8
  42. package/rules/ga/policy/package_json/template/package.json.contains.json +0 -1
  43. package/rules/php/policy/package_json/package_json.rego +0 -16
  44. package/rules/php/policy/package_json/target.json +0 -4
  45. package/rules/php/policy/package_json/template/package.json.contains.json +0 -5
  46. package/rules/python/policy/package_json/package_json.rego +0 -16
  47. package/rules/python/policy/package_json/target.json +0 -4
  48. package/rules/python/policy/package_json/template/package.json.contains.json +0 -5
  49. package/rules/rego/policy/package_json/package_json.rego +0 -16
  50. package/rules/rego/policy/package_json/target.json +0 -5
  51. package/rules/rego/policy/package_json/template/package.json.snippet.json +0 -1
  52. package/rules/rust/policy/package_json/package_json.rego +0 -18
  53. package/rules/rust/policy/package_json/target.json +0 -5
  54. package/rules/rust/policy/package_json/template/package.json.contains.json +0 -9
  55. package/rules/security/policy/package_json/template/package.json.contains.json +0 -1
  56. package/rules/security/policy/package_json/template/package.json.snippet.json +0 -5
  57. package/rules/style-lint/policy/package_json/template/package.json.contains.json +0 -5
@@ -10,16 +10,6 @@ package style_lint.package_json
10
10
 
11
11
  import rego.v1
12
12
 
13
- # ── deny: substring requirements у scripts (contains) ────────────────────
14
-
15
- deny contains msg if {
16
- some script_name, needles in data.template.contains.scripts
17
- actual := object.get(object.get(input, "scripts", {}), script_name, "")
18
- some needle in needles
19
- not contains(actual, needle)
20
- msg := sprintf("package.json: scripts.%s має містити %q (style-lint.mdc)", [script_name, needle])
21
- }
22
-
23
13
  # ── deny: 2-level snippet walker (для stylelint.extends, якщо поле є) ────
24
14
 
25
15
  deny contains msg if {
@@ -95,16 +95,17 @@ $white-a1: color.adjust(white, $alpha: -0.85);
95
95
 
96
96
  - **Джерело правил:** перед тим як писати або суттєво змінювати **`.css`**, **`.scss`** або стилі в **`.vue`**, переглянь у корені проєкту (і в релевантних пакетах монорепо, якщо є) поле **`stylelint`** у **`package.json`** (зокрема `extends`), наявні **`.stylelintrc.*`**, **`stylelint.config.*`** та **`.stylelintignore`**. Не покладайся на «типові» правила stylelint з пам’яті — дотримуйся **проєктного** **`@nitra/stylelint-config`** і будь-яких локальних доповнень у репозиторії.
97
97
  - **Форматування** узгоджуй з **`n-text.mdc`** (oxfmt / `.oxfmtrc.json` для css, scss тощо), щоб форматер і stylelint не суперечили один одному.
98
- - **Запуск stylelint:** лише **`npx stylelint`**. Локально — через скрипт **`lint-style`** (`bun run lint-style`, з `--fix`); у **GitHub Actions** у кроці **`run`** викликай `npx stylelint '**/*.{css,scss,vue}'` напряму **без `--fix`** (CI — read-only, нуль мутацій; не через **`bun run lint-style`**). Не використовуй **`bunx stylelint`**. Після змін запускай **`bun run lint-style`** і виправляй усе, що лишилось після auto-fix; за потреби — повний `bun run lint` (навичка **`/n-lint`**).
98
+ - **Запуск stylelint:** лише через **`n-cursor lint style-lint`** (локально з auto-fix; у CI — `--read-only`, нуль мутацій). Під капотом `npx stylelint`; **не** використовуй **`bunx stylelint`**. Після змін запускай **`n-cursor lint style-lint`** і виправляй усе, що лишилось після auto-fix; за потреби — повний прогін `n-cursor lint --full`.
99
99
  - **Не розширюй винятки:** не додавай зайві **`stylelint-disable`** без потреби; краще підлаштувати стилі під правила проєкту.
100
100
 
101
101
  ## Канон
102
102
 
103
103
  ### `package.json`
104
104
 
105
- - `lint-style` (substring requirement): [package.json.contains.json](./policy/package_json/template/package.json.contains.json)
106
105
  - `stylelint.extends`: [package.json.snippet.json](./policy/package_json/template/package.json.snippet.json)
107
106
 
107
+ Окремого `lint-style` скрипта немає — запуск через **`n-cursor lint style-lint`** (CI — `--read-only`).
108
+
108
109
  ### `.vscode/extensions.json`
109
110
 
110
111
  - Канон `recommendations`: [extensions.json.snippet.json](./policy/vscode_extensions/template/extensions.json.snippet.json)
@@ -120,9 +121,6 @@ $white-a1: color.adjust(white, $alpha: -0.85);
120
121
  **`package.json`:**
121
122
 
122
123
  ```json title="package.json"
123
- "scripts": {
124
- "lint-style": "npx stylelint '**/*.{css,scss,vue}' --fix",
125
- },
126
124
  "devDependencies": {
127
125
  "@nitra/stylelint-config": "^1.4.0"
128
126
  },
@@ -131,7 +129,7 @@ $white-a1: color.adjust(white, $alpha: -0.85);
131
129
  },
132
130
  ```
133
131
 
134
- Додай **`.github/workflows/lint-style.yml`** (лише **`.yml`**, **`ga.mdc`**): після **`checkout`** — локальний composite **`setup-bun-deps`**, далі `npx stylelint '**/*.{css,scss,vue}'` (CI — без `--fix`) у кроці **`run`**. **Не** дублюй окремі кроки **`setup-node`** / **`oven-sh/setup-bun`** / кеш / **`npm install`**.
132
+ Додай **`.github/workflows/lint-style.yml`** (лише **`.yml`**, **`ga.mdc`**): після **`checkout`** — локальний composite **`setup-bun-deps`**, далі `n-cursor lint style-lint --read-only` у кроці **`run`**. **Не** дублюй окремі кроки **`setup-node`** / **`oven-sh/setup-bun`** / кеш / **`npm install`**.
135
133
 
136
134
  ```yaml title=".github/workflows/lint-style.yml"
137
135
  name: StyleLint
@@ -94,25 +94,20 @@ function checkTextConfigsExistence(passFn, failFn, cwd) {
94
94
  }
95
95
 
96
96
  /**
97
- * Перевіряє package.json для текстового стека: складний `lint-text` скрипт і
98
- * виклик `n-cursor lint-text --read-only` у відповідному workflow (CI — нуль мутацій). Решта (Prettier-заборона,
99
- * `@nitra/cspell-dict ^2.0.0+`, заборона `markdownlint-cli2` у залежностях,
100
- * `@nitra/*` гейт) — у Rego (`text.package_json`, `bun.package_json`).
97
+ * Перевіряє CI-workflow текстового стека: крок `n-cursor lint text --read-only` у
98
+ * `.github/workflows/lint-text.yml` (CI — нуль мутацій). Окремого `lint-text` скрипта в
99
+ * `package.json` немає — лінт через `n-cursor lint text`. Решта package.json-перевірок
100
+ * (Prettier-заборона, `@nitra/cspell-dict`, `@nitra/*` гейт) — у Rego (`text.package_json`, `bun.package_json`).
101
101
  * @param {(msg: string) => void} passFn callback при успішній перевірці
102
102
  * @param {(msg: string) => void} failFn callback при помилці
103
103
  * @param {string} cwd корінь репозиторію
104
104
  */
105
- async function checkPackageJsonText(passFn, failFn, cwd) {
106
- const pkgPath = join(cwd, 'package.json')
107
- if (!existsSync(pkgPath)) return
108
- const pkg = JSON.parse(await readFile(pkgPath, 'utf8'))
109
- checkLintTextScript(pkg.scripts?.['lint-text'], passFn, failFn)
110
-
105
+ async function checkLintTextWorkflow(passFn, failFn, cwd) {
111
106
  const lintTextWf = join(cwd, '.github/workflows/lint-text.yml')
112
107
  if (existsSync(lintTextWf)) {
113
108
  const wf = await readFile(lintTextWf, 'utf8')
114
109
  const root = parseWorkflowYaml(wf)
115
- const canonRun = 'n-cursor lint-text --read-only'
110
+ const canonRun = 'n-cursor lint text --read-only'
116
111
  const ok = root ? anyRunStepIncludes(root, canonRun) : wf.includes(canonRun)
117
112
  if (ok) {
118
113
  passFn(`lint-text.yml викликає ${canonRun}`)
@@ -124,25 +119,6 @@ async function checkPackageJsonText(passFn, failFn, cwd) {
124
119
  }
125
120
  }
126
121
 
127
- /**
128
- * Перевіряє скрипт lint-text: канонічний — `n-cursor lint-text` (CLI пакета `@nitra/cursor` робить
129
- * `cspell` → `runShellcheckText()` → `bunx markdownlint-cli2 --fix` → `runV8rWithGlobs()`).
130
- * Дозволено whitespace навколо команди.
131
- * @param {unknown} lintText значення `scripts.lint-text` з package.json
132
- * @param {(msg: string) => void} passFn callback при успішній перевірці
133
- * @param {(msg: string) => void} failFn callback при помилці
134
- */
135
- function checkLintTextScript(lintText, passFn, failFn) {
136
- const lt = typeof lintText === 'string' ? lintText.trim() : ''
137
- if (lt === 'n-cursor lint-text') {
138
- passFn('lint-text делегує CLI n-cursor lint-text (cspell + shellcheck + markdownlint + v8r)')
139
- } else {
140
- failFn(
141
- 'package.json: lint-text має бути "n-cursor lint-text" — CLI пакета @nitra/cursor виконує cspell → shellcheck → markdownlint-cli2 → v8r (text.mdc)'
142
- )
143
- }
144
- }
145
-
146
122
  /**
147
123
  * Перевіряє відповідність проєкту правилам text.mdc.
148
124
  * @param {string} [cwd] корінь репозиторію
@@ -166,7 +142,7 @@ export async function check(cwd = process.cwd()) {
166
142
  }
167
143
  }
168
144
 
169
- await checkPackageJsonText(pass, fail, cwd)
145
+ await checkLintTextWorkflow(pass, fail, cwd)
170
146
 
171
147
  return reporter.getExitCode()
172
148
  }
@@ -58,4 +58,4 @@ jobs:
58
58
  | sh -s -- -b /usr/local/bin
59
59
 
60
60
  - name: Lint text
61
- run: n-cursor lint-text --read-only
61
+ run: n-cursor lint text --read-only
@@ -1,20 +0,0 @@
1
- # Перевірка кореневого `package.json` для GitHub Actions tooling (ga.mdc).
2
- #
3
- # Канон надходить через --data: { "template": { "contains": ... } }
4
- # Структура --data сформована з template/package.json.contains.json.
5
- #
6
- # Конвенція проєкту — `import rego.v1` + multi-value `deny contains msg if { … }`
7
- # (.cursor/rules/conftest.mdc). Лінт — `bun run lint-rego` (regal).
8
- package ga.package_json
9
-
10
- import rego.v1
11
-
12
- # Кожне рядкове поле з contains має містити кожен substring.
13
- # Відсутність ключа → `""` → contains() = false → deny.
14
- deny contains msg if {
15
- some script_name, needles in data.template.contains.scripts
16
- actual := object.get(object.get(input, "scripts", {}), script_name, "")
17
- some needle in needles
18
- not contains(actual, needle)
19
- msg := sprintf("package.json: scripts.%s має містити %q (ga.mdc)", [script_name, needle])
20
- }
@@ -1,8 +0,0 @@
1
- {
2
- "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
- "files": {
4
- "single": "package.json",
5
- "required": true
6
- },
7
- "missingMessage": "package.json не існує — потрібен lint-ga у scripts (ga.mdc)"
8
- }
@@ -1 +0,0 @@
1
- { "scripts": { "lint-ga": ["n-cursor lint-ga"] } }
@@ -1,16 +0,0 @@
1
- # Перевірка `package.json` (php.mdc).
2
- #
3
- # Канон надходить через --data: { "template": { "contains": ... } }
4
- # Структура --data сформована з template/package.json.contains.json.
5
- # FS-перевірки (`composer.json`, наявність `package.json` як такого) — у JS.
6
- package php.package_json
7
-
8
- import rego.v1
9
-
10
- deny contains msg if {
11
- some script_name, needles in data.template.contains.scripts
12
- actual := object.get(object.get(input, "scripts", {}), script_name, "")
13
- some needle in needles
14
- not contains(actual, needle)
15
- msg := sprintf("package.json: scripts.%s має містити %q (php.mdc)", [script_name, needle])
16
- }
@@ -1,4 +0,0 @@
1
- {
2
- "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
- "files": { "single": "package.json" }
4
- }
@@ -1,5 +0,0 @@
1
- {
2
- "scripts": {
3
- "lint-php": ["bun"]
4
- }
5
- }
@@ -1,16 +0,0 @@
1
- # Перевірка `package.json` (python.mdc).
2
- #
3
- # Канон надходить через --data: { "template": { "contains": ... } }
4
- # Структура --data сформована з template/package.json.contains.json.
5
- # FS-перевірки (наявність `package.json` як такого) — у JS.
6
- package python.package_json
7
-
8
- import rego.v1
9
-
10
- deny contains msg if {
11
- some script_name, needles in data.template.contains.scripts
12
- actual := object.get(object.get(input, "scripts", {}), script_name, "")
13
- some needle in needles
14
- not contains(actual, needle)
15
- msg := sprintf("package.json: scripts.%s має містити %q (python.mdc)", [script_name, needle])
16
- }
@@ -1,4 +0,0 @@
1
- {
2
- "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
- "files": { "single": "package.json" }
4
- }
@@ -1,5 +0,0 @@
1
- {
2
- "scripts": {
3
- "lint-python": ["bun"]
4
- }
5
- }
@@ -1,16 +0,0 @@
1
- # Перевірка `package.json` для rego (rego.mdc).
2
- #
3
- # Канон надходить через --data: { "template": { "snippet": ... } }
4
- # Структура --data сформована з template/package.json.snippet.json.
5
- # Дозволяємо whitespace навколо значення (trim_space) — допуск, який мав
6
- # попередній inline-варіант.
7
- package rego.package_json
8
-
9
- import rego.v1
10
-
11
- deny contains msg if {
12
- some script_name, expected in data.template.snippet.scripts
13
- actual := object.get(object.get(input, "scripts", {}), script_name, "")
14
- trim_space(actual) != expected
15
- msg := sprintf("package.json: scripts.%s має бути %q (rego.mdc)", [script_name, expected])
16
- }
@@ -1,5 +0,0 @@
1
- {
2
- "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
- "files": { "single": "package.json", "required": true },
4
- "missingMessage": "package.json не існує — створи згідно rego.mdc (rego.package_json)"
5
- }
@@ -1 +0,0 @@
1
- { "scripts": { "lint-rego": "n-cursor lint-rego" } }
@@ -1,18 +0,0 @@
1
- # Перевірка `package.json` для правила rust (rust.mdc).
2
- #
3
- # Канон надходить через --data: { "template": { "contains": ... } }
4
- # Структура --data сформована з template/package.json.contains.json.
5
- # Перевіряємо substring-вимоги до scripts.lint-rust: усі три кроки
6
- # (`cargo fmt`, `cargo clippy --fix`, фінальний `cargo clippy ... -D warnings`)
7
- # мають бути присутніми у значенні скрипта.
8
- package rust.package_json
9
-
10
- import rego.v1
11
-
12
- deny contains msg if {
13
- some script_name, needles in data.template.contains.scripts
14
- actual := object.get(object.get(input, "scripts", {}), script_name, "")
15
- some needle in needles
16
- not contains(actual, needle)
17
- msg := sprintf("package.json: scripts.%s має містити %q (rust.mdc)", [script_name, needle])
18
- }
@@ -1,5 +0,0 @@
1
- {
2
- "$schema": "https://unpkg.com/@nitra/cursor/schemas/target.json",
3
- "files": { "single": "package.json", "required": true },
4
- "missingMessage": "package.json не існує — створи зі scripts.lint-rust (rust.mdc)"
5
- }
@@ -1,9 +0,0 @@
1
- {
2
- "scripts": {
3
- "lint-rust": [
4
- "cargo fmt --all",
5
- "cargo clippy --fix --allow-staged --allow-dirty",
6
- "cargo clippy --all-targets --all-features -- -D warnings"
7
- ]
8
- }
9
- }
@@ -1 +0,0 @@
1
- { "scripts": { "lint": ["bun run lint-security"] } }
@@ -1,5 +0,0 @@
1
- {
2
- "scripts": {
3
- "lint-security": "trufflehog filesystem . --no-update --exclude-paths .trufflehog-exclude --results=verified,unknown --fail"
4
- }
5
- }
@@ -1,5 +0,0 @@
1
- {
2
- "scripts": {
3
- "lint-style": ["npx stylelint"]
4
- }
5
- }