@nitra/cursor 3.26.0 → 3.28.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 (128) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/bin/n-cursor.js +29 -9
  3. package/package.json +1 -1
  4. package/rules/abie/js/applies.mjs +1 -5
  5. package/rules/abie/js/env_dns.mjs +1 -9
  6. package/rules/abie/js/firebase_hosting.mjs +1 -5
  7. package/rules/abie/js/hc_pairing.mjs +1 -8
  8. package/rules/abie/js/ua_http_route.mjs +1 -10
  9. package/rules/abie/js/ua_node_selector.mjs +1 -8
  10. package/rules/adr/js/hooks.mjs +1 -20
  11. package/rules/bun/js/layout.mjs +1 -19
  12. package/rules/capacitor/js/platforms.mjs +1 -23
  13. package/rules/changelog/js/consistency.mjs +1 -29
  14. package/rules/ci4/js/marksman_config.mjs +1 -19
  15. package/rules/docker/js/lint.mjs +1 -34
  16. package/rules/ga/docs/fix.md +16 -149
  17. package/rules/ga/js/docs/lint.md +12 -93
  18. package/rules/ga/js/docs/workflows.md +28 -213
  19. package/rules/ga/js/workflows.mjs +1 -16
  20. package/rules/ga/lint/docs/lint.md +24 -206
  21. package/rules/graphql/js/tooling.mjs +1 -9
  22. package/rules/hasura/js/internal_urls.mjs +1 -24
  23. package/rules/image-avif/js/avif_generation.mjs +1 -27
  24. package/rules/image-compress/js/package_setup.mjs +1 -18
  25. package/rules/js-bun-db/js/safety.mjs +1 -31
  26. package/rules/js-bun-redis/js/imports.mjs +1 -12
  27. package/rules/js-lint/js/docs/lint-findings.md +30 -0
  28. package/rules/js-lint/js/lint-findings.mjs +1 -7
  29. package/rules/js-lint/js/lint.mjs +1 -10
  30. package/rules/js-lint/js/tooling.mjs +1 -13
  31. package/rules/js-lint/js/utils_imports.mjs +1 -18
  32. package/rules/js-lint-ci/js/lint.mjs +1 -6
  33. package/rules/js-mssql/js/deps.mjs +1 -10
  34. package/rules/js-run/js/runtime.mjs +1 -37
  35. package/rules/js-run/lib/docs/temporal-scan.md +25 -0
  36. package/rules/k8s/js/manifests.mjs +1 -137
  37. package/rules/nginx-default-tpl/js/template.mjs +1 -18
  38. package/rules/npm-module/js/docs/header_doc_pointer.md +25 -0
  39. package/rules/npm-module/js/header_doc_pointer.mjs +82 -0
  40. package/rules/npm-module/js/package_structure.mjs +1 -28
  41. package/rules/npm-module/js/rule_meta.mjs +1 -10
  42. package/rules/npm-module/js/skill_meta.mjs +1 -13
  43. package/rules/php/js/tooling.mjs +1 -11
  44. package/rules/python/js/applies.mjs +1 -8
  45. package/rules/python/js/tooling.mjs +1 -21
  46. package/rules/rego/js/applies.mjs +1 -11
  47. package/rules/rust/js/applies.mjs +1 -7
  48. package/rules/security/js/sample_secret.mjs +1 -28
  49. package/rules/security/js/trufflehog.mjs +1 -8
  50. package/rules/style-lint/js/lint.mjs +1 -5
  51. package/rules/style-lint/js/tooling.mjs +1 -19
  52. package/rules/tauri/js/cargo_mutants_config.mjs +1 -20
  53. package/rules/tauri/js/tooling.mjs +1 -21
  54. package/rules/test/js/cargo_mutants_config.mjs +1 -12
  55. package/rules/test/js/location.mjs +1 -9
  56. package/rules/test/js/no-process-chdir.mjs +1 -21
  57. package/rules/test/js/no-relative-fs-path.mjs +1 -23
  58. package/rules/test/js/stryker_config.mjs +4 -25
  59. package/rules/test/js/vitest-config-pool-forks.mjs +1 -17
  60. package/rules/text/js/forbidden-prettier.mjs +1 -10
  61. package/rules/text/js/formatting.mjs +1 -31
  62. package/rules/vue/js/packages.mjs +1 -24
  63. package/scripts/docs/coverage-fix-extract.md +32 -0
  64. package/scripts/docs/lint-cli.md +25 -0
  65. package/scripts/docs/post-tool-use-fix.md +27 -0
  66. package/scripts/docs/rename-yaml-extensions.md +36 -0
  67. package/scripts/docs/skills-cli.md +35 -0
  68. package/scripts/docs/sync-claude-config.md +52 -0
  69. package/scripts/docs/sync-setup-bun-deps-action.md +26 -0
  70. package/scripts/docs/upgrade-nitra-cursor-and-install.md +29 -0
  71. package/scripts/docs/worktree-cli.md +46 -0
  72. package/scripts/lib/docs/assert-project-root.md +28 -0
  73. package/scripts/lib/docs/diff-added-lines.md +34 -0
  74. package/scripts/lib/docs/read-n-cursor-config-lite.md +28 -0
  75. package/scripts/lib/docs/resolve-target-files.md +34 -0
  76. package/scripts/lib/docs/root-notice.md +28 -0
  77. package/scripts/lib/docs/rule-meta-helpers.md +34 -0
  78. package/scripts/lib/docs/rule-meta.md +34 -0
  79. package/scripts/lib/docs/rule-predicates.md +30 -0
  80. package/scripts/lib/docs/run-conftest-batch.md +26 -0
  81. package/scripts/lib/docs/run-lint-step.md +25 -0
  82. package/scripts/lib/docs/run-rule-cli.md +27 -0
  83. package/scripts/lib/docs/run-rule.md +32 -0
  84. package/scripts/lib/docs/run-standard-lint.md +22 -0
  85. package/scripts/lib/docs/run-standard-rule.md +24 -0
  86. package/scripts/lib/docs/skill-meta.md +31 -0
  87. package/scripts/lib/docs/sync-gitignore-worktree.md +31 -0
  88. package/scripts/lib/docs/template.md +40 -0
  89. package/scripts/lib/docs/timing-summary.md +24 -0
  90. package/scripts/lib/docs/workspaces.md +30 -0
  91. package/scripts/lib/docs/worktree-notice.md +27 -0
  92. package/scripts/lib/docs/worktree.md +38 -0
  93. package/scripts/utils/docs/ast-scan-utils.md +50 -0
  94. package/scripts/utils/docs/ensure-gitignore-entries.md +28 -0
  95. package/scripts/utils/docs/find-package-json-paths.md +26 -0
  96. package/scripts/utils/docs/lock-cache-dir.md +25 -0
  97. package/scripts/utils/docs/pass.md +25 -0
  98. package/scripts/utils/docs/resolve-cargo-manifest.md +23 -0
  99. package/scripts/utils/docs/resolve-cmd.md +29 -0
  100. package/scripts/utils/docs/resolve-js-root.md +25 -0
  101. package/scripts/utils/docs/test-helpers.md +36 -0
  102. package/scripts/utils/docs/walk-cache.md +27 -0
  103. package/scripts/utils/docs/walkDir.md +32 -0
  104. package/scripts/utils/docs/with-lock.md +25 -0
  105. package/scripts/utils/docs/worktree-fingerprint.md +27 -0
  106. package/skills/docgen/js/docgen-batch.mjs +95 -0
  107. package/skills/docgen/js/docgen-extract.mjs +33 -18
  108. package/skills/docgen/js/docgen-gen.mjs +258 -30
  109. package/skills/docgen/js/docgen-ignore.mjs +4 -7
  110. package/skills/docgen/js/docgen-prompts.mjs +40 -23
  111. package/skills/docgen/js/docgen-scan.mjs +1 -8
  112. package/skills/docgen/js/docs/docgen-extract.md +28 -0
  113. package/skills/docgen/js/docs/docgen-gen.md +41 -0
  114. package/skills/docgen/js/docs/docgen-ignore.md +24 -0
  115. package/skills/docgen/js/docs/docgen-prompts.md +24 -0
  116. package/skills/docgen/js/docs/docgen-scan.md +48 -0
  117. package/skills/fix/SKILL.md +5 -31
  118. package/skills/fix/js/docs/llm-worker.md +27 -0
  119. package/skills/fix/js/docs/orchestrator.md +32 -0
  120. package/skills/fix/js/docs/t0.md +29 -0
  121. package/skills/fix/js/llm-worker.mjs +216 -0
  122. package/skills/fix/js/orchestrator.mjs +119 -0
  123. package/skills/fix/js/t0.mjs +213 -0
  124. package/skills/fix/meta.json +1 -1
  125. package/skills/start-check/js/check.mjs +1 -16
  126. package/skills/start-check/js/docs/check.md +34 -0
  127. package/skills/taze/js/diff.mjs +1 -15
  128. package/skills/taze/js/docs/diff.md +33 -0
@@ -0,0 +1,213 @@
1
+ /** @see ./docs/t0.md */
2
+ import { existsSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
3
+ import { join } from 'node:path'
4
+ import { spawnSync } from 'node:child_process'
5
+ import { dirname } from 'node:path'
6
+ import { fileURLToPath } from 'node:url'
7
+
8
+ /**
9
+ * Патерни T0-auto.
10
+ * Кожен паттерн: {
11
+ * id: string — унікальна назва паттерну (для логу)
12
+ * test: (output)=>bool — чи підходить цей output до паттерну
13
+ * apply: (match, cwd)=>{ ok: bool, action: string } — застосувати фікс
14
+ * }
15
+ */
16
+ const PATTERNS = [
17
+ // ── vscode-ext-add ──────────────────────────────────────────────────────────
18
+ // Violation: «recommendations має містити "tsandall.opa"»
19
+ // Fix: додати рядок у .vscode/extensions.json#recommendations
20
+ {
21
+ id: 'vscode-ext-add',
22
+ test: out => /recommendations має містити "[^"]+"/.test(out),
23
+ apply: (out, cwd) => {
24
+ const matches = [...out.matchAll(/recommendations має містити "([^"]+)"/g)]
25
+ if (matches.length === 0) return { ok: false, action: 'no match' }
26
+
27
+ const extPath = join(cwd, '.vscode/extensions.json')
28
+ if (!existsSync(extPath)) {
29
+ return { ok: false, action: '.vscode/extensions.json не знайдено' }
30
+ }
31
+
32
+ let parsed
33
+ try {
34
+ parsed = JSON.parse(readFileSync(extPath, 'utf8'))
35
+ } catch {
36
+ return { ok: false, action: '.vscode/extensions.json: невалідний JSON' }
37
+ }
38
+
39
+ const recs = Array.isArray(parsed.recommendations) ? parsed.recommendations : []
40
+ const toAdd = matches.map(m => m[1]).filter(e => !recs.includes(e))
41
+ if (toAdd.length === 0) return { ok: false, action: 'вже є' }
42
+
43
+ parsed.recommendations = [...recs, ...toAdd]
44
+ writeFileSync(extPath, JSON.stringify(parsed, null, 2) + '\n', 'utf8')
45
+ return { ok: true, action: `додано до extensions.json: ${toAdd.join(', ')}` }
46
+ }
47
+ },
48
+
49
+ // ── rm-forbidden-file ────────────────────────────────────────────────────────
50
+ // Violation: «Знайдено заборонений файл: package-lock.json»
51
+ // Fix: видалити файл
52
+ {
53
+ id: 'rm-forbidden-file',
54
+ test: out => /Знайдено заборонений файл: \S+/.test(out),
55
+ apply: (out, cwd) => {
56
+ const matches = [...out.matchAll(/Знайдено заборонений файл: (\S+)/g)]
57
+ if (matches.length === 0) return { ok: false, action: 'no match' }
58
+
59
+ const removed = []
60
+ for (const m of matches) {
61
+ const filePath = join(cwd, m[1])
62
+ if (existsSync(filePath)) {
63
+ rmSync(filePath, { force: true })
64
+ removed.push(m[1])
65
+ }
66
+ }
67
+ if (removed.length === 0) return { ok: false, action: 'файлів не знайдено' }
68
+ return { ok: true, action: `видалено: ${removed.join(', ')}` }
69
+ }
70
+ }
71
+ ]
72
+
73
+ /**
74
+ * Застосовує всі T0-auto паттерни до одного violation-output.
75
+ *
76
+ * @param {string} ruleId id правила (для логу)
77
+ * @param {string} violationOutput рядок з поля `output` у `fix --json`
78
+ * @param {string} cwd корінь проєкту
79
+ * @returns {{ applied: boolean, actions: string[] }}
80
+ */
81
+ export function applyT0Auto(ruleId, violationOutput, cwd) {
82
+ const actions = []
83
+ let applied = false
84
+
85
+ for (const p of PATTERNS) {
86
+ if (!p.test(violationOutput)) continue
87
+ const result = p.apply(violationOutput, cwd)
88
+ actions.push(`[${p.id}] ${result.action}`)
89
+ if (result.ok) {
90
+ applied = true
91
+ }
92
+ }
93
+
94
+ return { applied, actions }
95
+ }
96
+
97
+ /**
98
+ * Повертає список id правил, для яких є хоча б один T0-auto паттерн
99
+ * (визначається по violation-output із `fix --json`).
100
+ *
101
+ * @param {{ ruleId: string, output: string }[]} failedRules
102
+ * @returns {string[]}
103
+ */
104
+ export function filterT0AutoRules(failedRules) {
105
+ return failedRules.filter(r => PATTERNS.some(p => p.test(r.output))).map(r => r.ruleId)
106
+ }
107
+
108
+ // ─── CLI entry-point ──────────────────────────────────────────────────────────
109
+
110
+ const HERE = dirname(fileURLToPath(import.meta.url))
111
+ /** Абсолютний шлях до npm/bin/n-cursor.js відносно цього файлу */
112
+ const N_CURSOR_BIN = join(HERE, '../../../bin/n-cursor.js')
113
+
114
+ /**
115
+ * CLI підкоманда `n-cursor fix-t0 [rule...]`.
116
+ * Запускає `fix --json`, застосовує T0-auto для кожного violation,
117
+ * повторно перевіряє check-gate, виводить підсумок.
118
+ *
119
+ * @param {string[]} args аргументи підкоманди (опційний список rule-ids)
120
+ * @param {string} cwd корінь проєкту
121
+ * @returns {Promise<number>} 0 — T0-auto закрив всі або немає порушень; 1 — лишились
122
+ */
123
+ export async function runT0AutoCli(args, cwd) {
124
+ const ruleFilter = args.filter(a => !a.startsWith('--'))
125
+ const verbose = args.includes('--verbose') || args.includes('-v')
126
+
127
+ // 1. Запустити fix --json
128
+ const fixResult = spawnSync('bun', [N_CURSOR_BIN, '_fix-check', ...ruleFilter], {
129
+ cwd,
130
+ encoding: 'utf8',
131
+ timeout: 120_000
132
+ })
133
+ const raw = fixResult.stdout?.trim()
134
+ if (!raw) {
135
+ console.error(`n-cursor fix-t0: fix --json повернув порожній stdout`)
136
+ console.error(fixResult.stderr?.slice(0, 300) ?? '')
137
+ return 1
138
+ }
139
+
140
+ let fixJson
141
+ try {
142
+ fixJson = JSON.parse(raw)
143
+ } catch {
144
+ console.error(`n-cursor fix-t0: fix --json повернув невалідний JSON`)
145
+ return 1
146
+ }
147
+
148
+ const failed = fixJson.rules.filter(r => !r.ok)
149
+ if (failed.length === 0) {
150
+ console.log(`✅ fix-t0: всі правила чисті — T0 не потрібен`)
151
+ return 0
152
+ }
153
+
154
+ // 2. Застосувати T0-auto
155
+ const applied = []
156
+ const skipped = []
157
+ for (const r of failed) {
158
+ const result = applyT0Auto(r.ruleId, r.output, cwd)
159
+ if (result.applied) {
160
+ applied.push({ ruleId: r.ruleId, actions: result.actions })
161
+ } else {
162
+ skipped.push(r.ruleId)
163
+ }
164
+ }
165
+
166
+ if (applied.length === 0) {
167
+ console.log(`⏭️ fix-t0: T0-auto паттерн не підходить для: ${failed.map(r => r.ruleId).join(', ')}`)
168
+ return 1
169
+ }
170
+
171
+ // 3. Вивести що зробили
172
+ for (const { ruleId, actions } of applied) {
173
+ console.log(`⚙️ ${ruleId}:`)
174
+ for (const a of actions) console.log(` ${a}`)
175
+ }
176
+
177
+ // 4. Check-gate: перевірити лише ті правила, що ми чіпали
178
+ const recheck = spawnSync('bun', [N_CURSOR_BIN, '_fix-check', ...applied.map(a => a.ruleId)], {
179
+ cwd,
180
+ encoding: 'utf8',
181
+ timeout: 120_000
182
+ })
183
+ const recheckRaw = recheck.stdout?.trim()
184
+ if (!recheckRaw) {
185
+ console.error(`fix-t0: check-gate: fix --json повернув порожній stdout`)
186
+ return 1
187
+ }
188
+
189
+ const recheckJson = JSON.parse(recheckRaw)
190
+ const stillFailed = recheckJson.rules.filter(r => !r.ok)
191
+
192
+ if (verbose) {
193
+ for (const r of recheckJson.rules) {
194
+ console.log(` ${r.ok ? '✅' : '❌'} ${r.ruleId}`)
195
+ }
196
+ }
197
+
198
+ if (stillFailed.length > 0) {
199
+ console.log(`❌ fix-t0 check-gate: ${stillFailed.map(r => r.ruleId).join(', ')} — лишились`)
200
+ if (skipped.length > 0) {
201
+ console.log(`⏭️ без T0 паттерну: ${skipped.join(', ')} → потрібен LLM`)
202
+ }
203
+ return 1
204
+ }
205
+
206
+ const totalFixed = applied.length
207
+ const total = failed.length
208
+ console.log(
209
+ `✅ fix-t0: ${totalFixed}/${total} правил закрито T0-auto` +
210
+ (skipped.length > 0 ? `; ${skipped.join(', ')} → T1 (LLM)` : '')
211
+ )
212
+ return 0
213
+ }
@@ -1 +1 @@
1
- { "auto": "завжди", "worktree": true }
1
+ { "auto": "завжди", "worktree": true, "orchestrator": true }
@@ -1,19 +1,4 @@
1
- /**
2
- * `n-cursor start-check scan|run` — детермінована частина smoke-перевірки
3
- * bun-монорепо для скілу `n-start-check`.
4
- *
5
- * Мотивація: скіл раніше казав LLM-агенту вручну розгортати glob-воркспейси,
6
- * читати кожен `package.json`, класифікувати `start` (сервер vs CLI), запускати
7
- * процес із таймаутом через `perl alarm`, інтерпретувати exit-коди й парсити лог
8
- * на рядки готовності/помилки. Усе це детерміновано — скрипт робить це надійно й
9
- * крос-платформно (`spawnSync` з `timeout`), а агент лишається тільки з
10
- * діагностикою: **чому** саме воркспейс упав.
11
- *
12
- * `scan` — `[{workspace, name, hasStart, startCmd, type}]`.
13
- * `run <ws>` — `{workspace, type, exitCode, timedOut, status, ready, firstError,
14
- * logTail, sideEffects}` (sideEffects — read-only git-diff проти стану до запуску;
15
- * власне відкат лишається явним кроком скіла).
16
- */
1
+ /** @see ./docs/check.md */
17
2
  import { spawnSync } from 'node:child_process'
18
3
  import { existsSync } from 'node:fs'
19
4
  import { readFile } from 'node:fs/promises'
@@ -0,0 +1,34 @@
1
+ # check.mjs
2
+
3
+ ## Огляд
4
+
5
+ Файл `n-cursor start-check scan|run` є частиною smoke-перевірки для скілу `n-start-check`. Він автоматично аналізує та запускає воркспейси, визначаючи тип стартового скрипта (сервер чи CLI) та перевіряючи успішність його виконання з обмеженням часу. Результати аналізу та запуску записуються у форматі JSON для подальшого аналізу та діагностики проблем.
6
+
7
+ ## Поведінка
8
+
9
+ - `classifyStartType` визначає, чи є команда `start` CLI чи довгим процесом (сервером).
10
+ - `scanStartWorkspaces` сканує монорепо, визначаючи воркспейси з `start`, їхні команди та типи.
11
+ - `parseStartLog` витягує готовність, першу помилку та хвіст логу з процесу.
12
+ - `runWorkspaceStart` запускає команду `start` воркспейсу з grace-таймаутом, класифікує результат та повертає інформацію про процес.
13
+ - `runStartCheckCli` виконує `scan` або `run` воркспейсу, приймаючи аргументи командного рядка.
14
+
15
+ ## Публічний API
16
+
17
+ - classifyStartType — Визначає, чи є команда `start` сервером або CLI.
18
+ - scanStartWorkspaces — Перевіряє монорепо на наявність команди `start` та її типу у кожному воркспейсі.
19
+ - parseStartLog — Аналізує лог процесу `start` для виявлення статусу, помилок та кінця.
20
+ - runWorkspaceStart — Запускає команду `start` у воркспейсі з обмеженим часом та визначає результат.
21
+ - runStartCheckCli — Запускає CLI для сканування воркспейсів з `start` та індивідуального запуску воркспейсу з подальшим виводом результатів у JSON.
22
+
23
+ ## Гарантії поведінки
24
+
25
+ - Скрипт детерміновано виконує перевірку запуску воркспейса.
26
+ - Скрипт використовує `spawnSync` з таймаутом для запуску процесів.
27
+ - Скрипт інтерпретує exit-коди та парсить логи.
28
+ - Результат перевірки воркспейса представлений у форматі `[{workspace, name, hasStart, startCmd, type}]`.
29
+ - У разі невдачі перевірки, скрипт повертає `false` або `null`.
30
+ - Скрипт не кидає винятків.
31
+ - Скрипт не використовує кешування.
32
+ - Скрипт не взаємодіє з мережею.
33
+ - Результат запуску воркспейса представлений у форматі `{workspace, type, exitCode, timedOut, status, ready, firstError, logTail, sideEffects}`.
34
+ - `sideEffects` містить відкат стану воркспейса до його початкового стану перед запуском.
@@ -1,18 +1,4 @@
1
- /**
2
- * `n-cursor taze diff` — read-only детермінований diff версій залежностей між
3
- * `package.json` і його бекапом `package.json.taze-bak` (root + усі воркспейси
4
- * монорепо), із класифікацією кожної зміни за semver.
5
- *
6
- * Мотивація: скіл `n-taze` раніше казав LLM-агенту вручну порівнювати backup із
7
- * новим `package.json` по всіх воркспейсах і вирішувати, де «змінилась перша
8
- * значуща цифра semver» (major). Це детермінований JSON-diff + semver-логіка —
9
- * скрипт робить це за мілісекунди й без помилок, а агент отримує готовий список
10
- * major-оновлень для справді когнітивної роботи (читання CHANGELOG, рефакторинг).
11
- *
12
- * «Breaking» (major) рахуємо за caret-семантикою — змінилась найлівіша ненульова
13
- * компонента: `1.x→2.x`, `0.4.x→0.5.x`, `0.0.3→0.0.4`. Minor/patch вважаємо
14
- * сумісними.
15
- */
1
+ /** @see ./docs/diff.md */
16
2
  import { existsSync } from 'node:fs'
17
3
  import { readFile } from 'node:fs/promises'
18
4
  import { join } from 'node:path'
@@ -0,0 +1,33 @@
1
+ # diff.mjs
2
+
3
+ ## Огляд
4
+
5
+ Файл `n-cursor taze diff` порівнює поточну версію `package.json` з її резервною копією (`package.json.taze-bak`) для виявлення змін залежностей. Він класифікує ці зміни за семантикою версій (major, minor, patch) та надає список оновлень, які потребують уваги. Це автоматизує процес, який раніше виконувався вручну, забезпечуючи швидкий та точний аналіз змін у залежностях монорепо.
6
+
7
+ ## Поведінка
8
+
9
+ `parseVersion` парсує версійний specifier, ігноруючи range-префікси, і повертає об'єкт з major, minor та patch компонентами, або null, якщо spec не є semver.
10
+ `isBreaking` визначає, чи є перехід від старої до нової версії "breaking" за caret-семантикою.
11
+ `diffPackageJson` порівнює два об'єкти `package.json`, виявляє major-оновлення та підраховує minor/patch зміни для залежностей.
12
+ `collectTazeDiff` збирає diff по всіх воркспейсах монорепо, порівнюючи `package.json` з бекапом, та повертає список major-оновлень, кількість minor/patch змін, загальну кількість порівняних воркспейсів та кількість воркспейсів, які були порівняні.
13
+ `runTazeCli` запускає CLI `n-cursor taze diff`, збирає diff по воркспейсах, та виводить результат у форматі JSON.
14
+
15
+ ## Публічний API
16
+
17
+ - parseVersion — Розбирає semver-версію з специфікатора.
18
+ - isBreaking — Визначає, чи є перехід breaking за caret-семантикою.
19
+ - diffPackageJson — Порівнює два package.json-об'єкти та визначає зміни залежностей.
20
+ - collectTazeDiff — Збирає diff для монорепо, порівнюючи package.json з резервною копією.
21
+ - runTazeCli — Запускає CLI для виведення компактного JSON з інформацією про major-оновлення та кількість minor/patch.
22
+
23
+ ## Гарантії поведінки
24
+
25
+ - Скрипт повертає `true`, якщо всі воркспейси монорепо успішно порівняні.
26
+ - Скрипт повертає `false` та `null`, якщо виникла будь-яка помилка під час порівняння.
27
+ - Результат порівняння завжди є `null`, якщо `package.json` або `package.json.taze-bak` не є валідним JSON.
28
+ - Результат порівняння містить список major-оновлень, визначених за caret-семантикою.
29
+ - Minor та patch оновлення не включаються в результат.
30
+ - Результат завжди детермінований, тобто при однаковому вході скрипт завжди повертає однаковий результат.
31
+ - Скрипт не використовує кешування.
32
+ - Скрипт не кидає винятків.
33
+ - Скрипт перехоплює помилки та повертає `false` та `null`.