@nitra/cursor 3.22.0 → 3.23.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 (228) hide show
  1. package/.pi-template/extensions/n-cursor-adr/docs/index.md +181 -0
  2. package/CHANGELOG.md +31 -3
  3. package/bin/docs/n-cursor.md +636 -0
  4. package/bin/docs/rename-yaml-extensions.md +207 -0
  5. package/bin/n-cursor.js +30 -3
  6. package/package.json +1 -1
  7. package/rules/abie/docs/fix.md +18 -0
  8. package/rules/abie/js/docs/applies.md +26 -0
  9. package/rules/abie/js/docs/env_dns.md +32 -0
  10. package/rules/abie/js/docs/firebase_hosting.md +23 -0
  11. package/rules/abie/js/docs/hc_pairing.md +35 -0
  12. package/rules/abie/js/docs/ua_http_route.md +28 -0
  13. package/rules/abie/js/docs/ua_node_selector.md +28 -0
  14. package/rules/abie/lib/docs/enabled.md +29 -0
  15. package/rules/abie/lib/docs/env-dns.md +35 -0
  16. package/rules/abie/lib/docs/hc-yaml.md +33 -0
  17. package/rules/abie/lib/docs/http-route.md +44 -0
  18. package/rules/abie/lib/docs/k8s-tree.md +40 -0
  19. package/rules/abie/lib/docs/kustomization-patches.md +47 -0
  20. package/rules/abie/lib/docs/overlay-paths.md +38 -0
  21. package/rules/abie/lib/docs/yaml.md +29 -0
  22. package/rules/adr/docs/fix.md +148 -0
  23. package/rules/adr/js/docs/hooks.md +259 -0
  24. package/rules/bun/docs/fix.md +156 -0
  25. package/rules/bun/js/docs/layout.md +393 -0
  26. package/rules/capacitor/docs/fix.md +121 -0
  27. package/rules/capacitor/js/docs/platforms.md +295 -0
  28. package/rules/changelog/changelog.mdc +2 -2
  29. package/rules/changelog/docs/fix.md +174 -0
  30. package/rules/changelog/js/consistency.mjs +114 -13
  31. package/rules/changelog/js/docs/consistency.md +387 -0
  32. package/rules/changelog/lib/docs/package-manifest.md +210 -0
  33. package/rules/ci4/docs/fix.md +179 -0
  34. package/rules/ci4/js/docs/marksman_config.md +128 -0
  35. package/rules/docker/docker.mdc +8 -3
  36. package/rules/docker/docs/fix.md +171 -0
  37. package/rules/docker/js/docs/lint.md +258 -0
  38. package/rules/docker/lib/docs/docker-hadolint.md +184 -0
  39. package/rules/docker/lib/docs/docker-mirror.md +247 -0
  40. package/rules/docker/lib/docs/docker-native-addon.md +170 -0
  41. package/rules/docker/lib/docs/docker-nginx-user.md +219 -0
  42. package/rules/docker/lint/docs/lint.md +193 -0
  43. package/rules/efes/docs/fix.md +203 -0
  44. package/rules/feedback/docs/fix.md +140 -0
  45. package/rules/flow/docs/fix.md +152 -0
  46. package/rules/ga/docs/fix.md +158 -0
  47. package/rules/ga/js/docs/lint.md +100 -0
  48. package/rules/ga/js/docs/workflows.md +217 -0
  49. package/rules/ga/lint/docs/lint.md +209 -0
  50. package/rules/ga/policy/clean_merged_branch/clean_merged_branch.rego +11 -2
  51. package/rules/ga/policy/clean_merged_branch/template/clean-merged-branch.yml.snippet.yml +3 -4
  52. package/rules/graphql/docs/fix.md +126 -0
  53. package/rules/graphql/js/docs/tooling.md +264 -0
  54. package/rules/graphql/lib/docs/graphql-gql-scan.md +219 -0
  55. package/rules/hasura/docs/fix.md +120 -0
  56. package/rules/hasura/hasura.mdc +14 -0
  57. package/rules/hasura/js/docs/internal_urls.md +326 -0
  58. package/rules/image-avif/docs/fix.md +132 -0
  59. package/rules/image-avif/js/docs/avif_generation.md +241 -0
  60. package/rules/image-compress/docs/fix.md +150 -0
  61. package/rules/image-compress/js/docs/package_setup.md +191 -0
  62. package/rules/js-bun-db/docs/fix.md +148 -0
  63. package/rules/js-bun-db/js/docs/safety.md +231 -0
  64. package/rules/js-bun-db/js-bun-db.mdc +42 -13
  65. package/rules/js-bun-db/lib/docs/bun-sql-scan.md +347 -0
  66. package/rules/js-bun-redis/docs/fix.md +123 -0
  67. package/rules/js-bun-redis/js/docs/imports.md +176 -0
  68. package/rules/js-bun-redis/lib/docs/redis-imports.md +223 -0
  69. package/rules/js-lint/docs/fix.md +117 -0
  70. package/rules/js-lint/js/docs/lint.md +250 -0
  71. package/rules/js-lint/js/docs/tooling.md +348 -0
  72. package/rules/js-lint/js/docs/utils_imports.md +207 -0
  73. package/rules/js-lint-ci/docs/fix.md +154 -0
  74. package/rules/js-lint-ci/js/docs/lint.md +144 -0
  75. package/rules/js-mssql/docs/fix.md +128 -0
  76. package/rules/js-mssql/js/docs/deps.md +263 -0
  77. package/rules/js-mssql/lib/docs/mssql-pool-scan.md +367 -0
  78. package/rules/js-run/docs/fix.md +144 -0
  79. package/rules/js-run/js/docs/runtime.md +388 -0
  80. package/rules/js-run/lib/docs/bunyan-imports.md +117 -0
  81. package/rules/js-run/lib/docs/check-env-scan.md +433 -0
  82. package/rules/js-run/lib/docs/conn-file-rules.md +300 -0
  83. package/rules/js-run/lib/docs/conn-imports-scan.md +204 -0
  84. package/rules/js-run/lib/docs/promise-settimeout-scan.md +326 -0
  85. package/rules/k8s/docs/fix.md +129 -0
  86. package/rules/k8s/js/docs/manifests.md +344 -0
  87. package/rules/k8s/js/manifests.mjs +6 -2
  88. package/rules/k8s/k8s.mdc +4 -2
  89. package/rules/k8s/lint/docs/lint.md +411 -0
  90. package/rules/k8s/policy/network_policy/template/deployment.snippet.yaml +2 -0
  91. package/rules/k8s/policy/network_policy/template/stateful-set.snippet.yaml +2 -0
  92. package/rules/nginx-default-tpl/docs/fix.md +124 -0
  93. package/rules/nginx-default-tpl/js/docs/template.md +378 -0
  94. package/rules/npm-module/docs/fix.md +98 -0
  95. package/rules/npm-module/js/docs/package_structure.md +274 -0
  96. package/rules/npm-module/js/docs/rule_meta.md +137 -0
  97. package/rules/npm-module/js/docs/skill_meta.md +190 -0
  98. package/rules/php/docs/fix.md +107 -0
  99. package/rules/php/js/docs/tooling.md +152 -0
  100. package/rules/php/lint/docs/lint.md +215 -0
  101. package/rules/python/docs/fix.md +163 -0
  102. package/rules/python/js/docs/applies.md +108 -0
  103. package/rules/python/js/docs/tooling.md +153 -0
  104. package/rules/python/lint/docs/lint.md +322 -0
  105. package/rules/rego/docs/fix.md +121 -0
  106. package/rules/rego/js/docs/applies.md +174 -0
  107. package/rules/rego/js/docs/lint.md +118 -0
  108. package/rules/rego/lint/docs/lint.md +204 -0
  109. package/rules/release/docs/change.md +185 -0
  110. package/rules/release/docs/fix.md +119 -0
  111. package/rules/release/docs/release.md +222 -0
  112. package/rules/release/lib/docs/aggregate.md +246 -0
  113. package/rules/release/lib/docs/change-file.md +200 -0
  114. package/rules/release/lib/docs/fallback.md +203 -0
  115. package/rules/rust/docs/fix.md +129 -0
  116. package/rules/rust/js/docs/applies.md +140 -0
  117. package/rules/rust/lib/docs/has-cargo-toml.md +130 -0
  118. package/rules/security/docs/fix.md +86 -0
  119. package/rules/security/js/docs/lint.md +171 -0
  120. package/rules/security/js/docs/sample_secret.md +190 -0
  121. package/rules/security/js/docs/trufflehog.md +137 -0
  122. package/rules/security/js/lint.mjs +9 -1
  123. package/rules/style-lint/docs/fix.md +155 -0
  124. package/rules/style-lint/js/docs/lint.md +184 -0
  125. package/rules/style-lint/js/docs/tooling.md +194 -0
  126. package/rules/tauri/docs/fix.md +158 -0
  127. package/rules/tauri/js/docs/cargo_mutants_config.md +168 -0
  128. package/rules/tauri/js/docs/tooling.md +228 -0
  129. package/rules/test/coverage/coverage.mjs +15 -3
  130. package/rules/test/docs/fix.md +132 -0
  131. package/rules/test/js/data/stryker_config/docs/stryker-vue-macros-ignorer.md +138 -0
  132. package/rules/test/js/data/stryker_config/docs/stryker.config.baseline.md +134 -0
  133. package/rules/test/js/data/stryker_config/docs/stryker.config.vue.baseline.md +160 -0
  134. package/rules/test/js/data/vitest_config/docs/vitest.config.baseline.md +195 -0
  135. package/rules/test/js/docs/cargo_mutants_config.md +173 -0
  136. package/rules/test/js/docs/location.md +136 -0
  137. package/rules/test/js/docs/no-process-chdir.md +160 -0
  138. package/rules/test/js/docs/no-relative-fs-path.md +271 -0
  139. package/rules/test/js/docs/stryker_config.md +152 -0
  140. package/rules/test/js/docs/vitest-config-pool-forks.md +174 -0
  141. package/rules/text/docs/fix.md +118 -0
  142. package/rules/text/js/docs/forbidden-prettier.md +143 -0
  143. package/rules/text/js/docs/formatting.md +256 -0
  144. package/rules/text/js/docs/lint.md +122 -0
  145. package/rules/text/lint/docs/lint.md +220 -0
  146. package/rules/text/lint/docs/run-dotenv-linter.md +157 -0
  147. package/rules/text/lint/docs/run-shellcheck.md +212 -0
  148. package/rules/text/lint/docs/run-v8r.md +197 -0
  149. package/rules/vue/docs/fix.md +127 -0
  150. package/rules/vue/js/docs/packages.md +335 -0
  151. package/rules/vue/lib/docs/vue-forbidden-imports.md +261 -0
  152. package/rules/worktree/docs/fix.md +161 -0
  153. package/schemas/rule-meta.json +5 -1
  154. package/scripts/auto-rules.mjs +7 -4
  155. package/scripts/coverage-classify/docs/apply.md +202 -0
  156. package/scripts/coverage-classify/docs/cache.md +203 -0
  157. package/scripts/coverage-classify/docs/index.md +218 -0
  158. package/scripts/coverage-classify/docs/prompt.md +132 -0
  159. package/scripts/coverage-classify/docs/verdict-schema.md +169 -0
  160. package/scripts/coverage-fix-extract.mjs +122 -0
  161. package/scripts/coverage-fix.mjs +1 -1
  162. package/scripts/dispatcher/docs/graph.md +346 -0
  163. package/scripts/dispatcher/docs/index.md +236 -0
  164. package/scripts/dispatcher/docs/trace.md +296 -0
  165. package/scripts/dispatcher/index.mjs +1 -1
  166. package/scripts/dispatcher/lib/active.mjs +4 -8
  167. package/scripts/dispatcher/lib/commands.mjs +7 -11
  168. package/scripts/dispatcher/lib/docs/active.md +348 -0
  169. package/scripts/dispatcher/lib/docs/artifact.md +232 -0
  170. package/scripts/dispatcher/lib/docs/budget.md +167 -0
  171. package/scripts/dispatcher/lib/docs/capability.md +196 -0
  172. package/scripts/dispatcher/lib/docs/commands.md +210 -0
  173. package/scripts/dispatcher/lib/docs/events.md +182 -0
  174. package/scripts/dispatcher/lib/docs/executor.md +190 -0
  175. package/scripts/dispatcher/lib/docs/flow-lock.md +161 -0
  176. package/scripts/dispatcher/lib/docs/flow-resolve.md +267 -0
  177. package/scripts/dispatcher/lib/docs/gate.md +231 -0
  178. package/scripts/dispatcher/lib/docs/level.md +335 -0
  179. package/scripts/dispatcher/lib/docs/plan-panel.md +181 -0
  180. package/scripts/dispatcher/lib/docs/plan.md +200 -0
  181. package/scripts/dispatcher/lib/docs/planner.md +269 -0
  182. package/scripts/dispatcher/lib/docs/review.md +255 -0
  183. package/scripts/dispatcher/lib/docs/reviewer.md +240 -0
  184. package/scripts/dispatcher/lib/docs/snapshot.md +247 -0
  185. package/scripts/dispatcher/lib/docs/spec.md +203 -0
  186. package/scripts/dispatcher/lib/docs/state-store.md +303 -0
  187. package/scripts/dispatcher/lib/docs/subagent-runner.md +173 -0
  188. package/scripts/dispatcher/lib/executor.mjs +6 -1
  189. package/scripts/dispatcher/lib/flow-resolve.mjs +3 -1
  190. package/scripts/dispatcher/lib/level.mjs +29 -3
  191. package/scripts/dispatcher/lib/review.mjs +1 -1
  192. package/scripts/dispatcher/lib/subagent-runner.mjs +5 -3
  193. package/scripts/docs/auto-rules.md +376 -0
  194. package/scripts/docs/auto-skills.md +173 -0
  195. package/scripts/docs/build-agents-commands.md +183 -0
  196. package/scripts/docs/cli-entry.md +153 -0
  197. package/scripts/docs/coverage-fix.md +177 -0
  198. package/scripts/docs/ensure-nitra-cursor-dev-dependencies.md +189 -0
  199. package/scripts/lib/changed-files.mjs +4 -1
  200. package/scripts/lib/docs/changed-files.md +149 -0
  201. package/scripts/lib/docs/check-mdc-template-refs.md +222 -0
  202. package/scripts/lib/docs/check-reporter.md +175 -0
  203. package/scripts/lib/docs/discover-check-rules-from-cursor.md +157 -0
  204. package/scripts/lib/docs/discover-checkable-rules.md +165 -0
  205. package/scripts/lib/docs/ensure-tool.md +254 -0
  206. package/scripts/lib/docs/generated-markdown.md +275 -0
  207. package/scripts/lib/docs/gha-workflow.md +326 -0
  208. package/scripts/lib/docs/inline-template-links.md +303 -0
  209. package/scripts/lib/docs/list-rule-ids.md +156 -0
  210. package/scripts/lib/docs/load-cursor-config.md +147 -0
  211. package/scripts/lib/docs/mirror-parity.md +167 -0
  212. package/scripts/lib/worktree.mjs +26 -0
  213. package/scripts/worktree-cli.mjs +12 -2
  214. package/skills/coverage-fix/SKILL.md +34 -45
  215. package/skills/docgen/SKILL.md +44 -23
  216. package/skills/docgen/bench/etalon/firebase_hosting.md +19 -0
  217. package/skills/docgen/bench/etalon/k8s-tree.md +24 -0
  218. package/skills/docgen/bench/etalon/overlay-paths.md +24 -0
  219. package/skills/docgen/js/docgen-ignore.mjs +54 -0
  220. package/skills/docgen/js/docgen-scan.mjs +37 -21
  221. package/skills/llm-patch/SKILL.md +23 -2
  222. package/skills/start-check/SKILL.md +26 -53
  223. package/skills/start-check/js/check.mjs +211 -0
  224. package/skills/taze/SKILL.md +9 -3
  225. package/skills/taze/js/diff.mjs +154 -0
  226. package/types/bin/n-cursor.d.ts +1 -1
  227. package/skills/fix-tests/SKILL.md +0 -119
  228. package/skills/fix-tests/meta.json +0 -1
@@ -19,8 +19,16 @@
19
19
  * `origin/main` (або `HEAD~1` без remote).
20
20
  *
21
21
  * Усі `git` і зовнішні виклики — через `execFile` / `fetch`, без shell-інтерполяції.
22
+ *
23
+ * **Autofix-режим** (env `N_CURSOR_CHANGELOG_AUTOFIX=1`, виставляється лише кроком
24
+ * `npm-changelog` у `hk.pkl` для pre-commit): замість `fail` на відсутній change-файл
25
+ * правило саме створює його через `writeChange()` з дефолтами (`bump=patch`,
26
+ * `section=Changed`, `message` = subject останнього коміту) і ставить у git-індекс, щоб
27
+ * коміт не падав. Поза хуком (CI, ручний `fix`/`check`, read-only review) режим вимкнено —
28
+ * поведінка лишається fail-on-missing, тож CI не плодить артефактів.
22
29
  */
23
30
  import { execFile } from 'node:child_process'
31
+ import { join } from 'node:path'
24
32
  import { promisify } from 'node:util'
25
33
 
26
34
  import { createCheckReporter } from '../../../scripts/lib/check-reporter.mjs'
@@ -30,10 +38,23 @@ import {
30
38
  parsePyprojectFields,
31
39
  readPackageManifest
32
40
  } from '../lib/package-manifest.mjs'
41
+ import { writeChange } from '../../release/change.mjs'
33
42
  import { readChangeFiles } from '../../release/lib/change-file.mjs'
34
43
 
35
44
  const execFileAsync = promisify(execFile)
36
45
 
46
+ /** Env-прапорець, що вмикає autofix (виставляється кроком `npm-changelog` у `hk.pkl`). */
47
+ const AUTOFIX_ENV_VAR = 'N_CURSOR_CHANGELOG_AUTOFIX'
48
+
49
+ /** Дефолтний `bump` для autofix-створеного change-файлу (вищий bump редагуєш вручну). */
50
+ const AUTOFIX_BUMP = 'patch'
51
+
52
+ /** Дефолтна секція для autofix-створеного change-файлу. */
53
+ const AUTOFIX_SECTION = 'Changed'
54
+
55
+ /** Fallback-опис, коли subject останнього коміту порожній (напр. порожній репозиторій). */
56
+ const AUTOFIX_FALLBACK_MESSAGE = 'оновлення'
57
+
37
58
  /** Кандидати інтеграційними тести гілки для feature-гілок (перша наявна; див. n-changelog.mdc). */
38
59
  const FEATURE_BASE_BRANCH_CANDIDATES = Object.freeze(['dev', 'main'])
39
60
 
@@ -429,16 +450,81 @@ async function hasPendingChangeFiles(ws, cwd) {
429
450
  return files.length > 0
430
451
  }
431
452
 
453
+ /**
454
+ * Опис для autofix-change-файлу: subject останнього коміту (HEAD), а якщо порожній
455
+ * (порожній репозиторій / detached без імені) — назва гілки, інакше fallback-літерал.
456
+ * Опис мусить бути непорожнім — `writeChange`/`parseChangeFile` кидають на порожньому.
457
+ * @param {string} cwd корінь репозиторію
458
+ * @returns {Promise<string>} непорожній опис зміни
459
+ */
460
+ async function resolveAutoChangeMessage(cwd) {
461
+ const lastSubject = await gitOrNull(['log', '-1', '--format=%s'], cwd)
462
+ const subject = lastSubject?.trim()
463
+ if (subject) return subject
464
+ const branch = await currentBranchName(cwd)
465
+ return branch && branch !== 'HEAD' ? branch : AUTOFIX_FALLBACK_MESSAGE
466
+ }
467
+
468
+ /**
469
+ * Реакція на відсутній change-файл: у autofix-режимі — створити його з дефолтами й
470
+ * поставити у git-індекс (щоб коміт не падав); інакше — fail із підказкою.
471
+ * @param {string} ws workspace (`.` — корінь)
472
+ * @param {string} label мітка воркспейсу для повідомлень
473
+ * @param {string} mf шлях до маніфесту (для fail-підказки)
474
+ * @param {boolean} autofix чи створювати файл автоматично
475
+ * @param {(msg: string) => void} pass репортер pass
476
+ * @param {(msg: string) => void} fail репортер fail
477
+ * @param {string} cwd корінь репозиторію
478
+ * @returns {Promise<boolean>} `true` — change-файл створено (autofix); `false` — зафейлено
479
+ */
480
+ async function reportOrFixMissingChangeFile(ws, label, mf, autofix, pass, fail, cwd) {
481
+ if (!autofix) {
482
+ fail(missingChangeFileMessage(label, mf))
483
+ return false
484
+ }
485
+ const message = await resolveAutoChangeMessage(cwd)
486
+ const relFromWs = await writeChange({ bump: AUTOFIX_BUMP, section: AUTOFIX_SECTION, message, ws, cwd })
487
+ const created = ws === '.' ? relFromWs : join(ws, relFromWs)
488
+ // Ставимо новий файл у індекс одразу: pre-commit-хук комітить уже застейджені зміни,
489
+ // а свіжостворений untracked-файл інакше лишився б поза комітом.
490
+ await gitOrNull(['add', '--', created], cwd)
491
+ pass(
492
+ `${label}: автоматично створено change-файл ${created} ` +
493
+ `(${AUTOFIX_BUMP}/${AUTOFIX_SECTION}: "${message}") — відредагуй за потреби; bump зробить CI (n-changelog.mdc)`
494
+ )
495
+ return true
496
+ }
497
+
498
+ /**
499
+ * Published-варіант реакції на відсутній change-файл: створити/зафейлити через
500
+ * `reportOrFixMissingChangeFile`, а коли autofix створив файл — додатково перевірити,
501
+ * що `files` містить `CHANGELOG.md` (реліз наближається — CHANGELOG публікується з пакетом).
502
+ * @param {import('../lib/package-manifest.mjs').PackageManifest} manifest маніфест воркспейсу
503
+ * @param {string} label мітка воркспейсу
504
+ * @param {string} mf шлях до маніфесту
505
+ * @param {boolean} autofix autofix-режим
506
+ * @param {(msg: string) => void} pass репортер pass
507
+ * @param {(msg: string) => void} fail репортер fail
508
+ * @param {string} cwd корінь репозиторію
509
+ * @returns {Promise<void>} результат
510
+ */
511
+ async function fixOrFailPublishedWorkspace(manifest, label, mf, autofix, pass, fail, cwd) {
512
+ if (await reportOrFixMissingChangeFile(manifest.ws, label, mf, autofix, pass, fail, cwd)) {
513
+ checkNpmFilesArrayContainsChangelog(manifest, pass, fail)
514
+ }
515
+ }
516
+
432
517
  /**
433
518
  * @param {import('../lib/package-manifest.mjs').PackageManifest} manifest параметр
434
519
  * @param {string} _Vcurrent параметр (для сумісності сигнатури; bump робить CI)
435
520
  * @param {string[]} subWorkspaces параметр
521
+ * @param {boolean} autofix autofix-режим (створити change-файл замість fail)
436
522
  * @param {(msg: string) => void} pass параметр
437
523
  * @param {(msg: string) => void} fail параметр
438
524
  * @param {string} cwd робочий каталог
439
525
  * @returns {Promise<void>} результат
440
526
  */
441
- async function checkPublishedWorkspacePendingGitChanges(manifest, _Vcurrent, subWorkspaces, pass, fail, cwd) {
527
+ async function checkPublishedWorkspacePendingGitChanges(manifest, _Vcurrent, subWorkspaces, autofix, pass, fail, cwd) {
442
528
  const label = workspaceLabel(manifest)
443
529
  const mf = manifestFilePath(manifest.ws, manifest)
444
530
  if (await hasPendingChangeFiles(manifest.ws, cwd)) {
@@ -455,19 +541,19 @@ async function checkPublishedWorkspacePendingGitChanges(manifest, _Vcurrent, sub
455
541
 
456
542
  if (branch === LOCAL_ONLY_SKIP_BRANCH) {
457
543
  if (await workspaceHasRelevantChangesAgainstBase('HEAD', manifest.ws, subWorkspaces, cwd)) {
458
- fail(missingChangeFileMessage(label, mf))
544
+ await fixOrFailPublishedWorkspace(manifest, label, mf, autofix, pass, fail, cwd)
459
545
  }
460
546
  return
461
547
  }
462
548
 
463
549
  const comparison = await resolveChangelogComparisonPoint(branch, cwd)
464
550
  if (comparison && (await workspaceHasRelevantChangesAgainstBase(comparison.ref, manifest.ws, subWorkspaces, cwd))) {
465
- fail(missingChangeFileMessage(label, mf))
551
+ await fixOrFailPublishedWorkspace(manifest, label, mf, autofix, pass, fail, cwd)
466
552
  return
467
553
  }
468
554
 
469
555
  if (branch === 'main' && (await workspaceHasRelevantChangesAgainstBase('HEAD', manifest.ws, subWorkspaces, cwd))) {
470
- fail(missingChangeFileMessage(label, mf))
556
+ await fixOrFailPublishedWorkspace(manifest, label, mf, autofix, pass, fail, cwd)
471
557
  }
472
558
  }
473
559
 
@@ -475,12 +561,13 @@ async function checkPublishedWorkspacePendingGitChanges(manifest, _Vcurrent, sub
475
561
  * @param {import('../lib/package-manifest.mjs').PackageManifest} manifest параметр
476
562
  * @param {string[]} subWorkspaces параметр
477
563
  * @param {(name: string, kind?: import('../lib/package-manifest.mjs').PackageKind) => Promise<string | null>} getPublishedVersion параметр
564
+ * @param {boolean} autofix autofix-режим (створити change-файл замість fail)
478
565
  * @param {(msg: string) => void} pass параметр
479
566
  * @param {(msg: string) => void} fail параметр
480
567
  * @param {string} cwd робочий каталог
481
568
  * @returns {Promise<void>} результат
482
569
  */
483
- async function checkPublishedWorkspace(manifest, subWorkspaces, getPublishedVersion, pass, fail, cwd) {
570
+ async function checkPublishedWorkspace(manifest, subWorkspaces, getPublishedVersion, autofix, pass, fail, cwd) {
484
571
  const label = workspaceLabel(manifest)
485
572
  const mf = manifestFilePath(manifest.ws, manifest)
486
573
  const Vcurrent = manifest.version
@@ -493,6 +580,16 @@ async function checkPublishedWorkspace(manifest, subWorkspaces, getPublishedVers
493
580
  fail(`${label}: у ${mf} відсутнє ім'я пакета (registry-published воркспейс)`)
494
581
  return
495
582
  }
583
+ // Autofix/hook-режим: жодної мережі. Реєстровий резолв (`npm view` / PyPI fetch) і
584
+ // drift-перевірка vs опублікована версія пропускаються — лишається лише наявність
585
+ // change-файлу (+ autofix) і git-diff. Ручний bump version у хуці не ловиться; його
586
+ // далі ловить CI та ручний `fix changelog` (без env). Запит користувача: «прибери
587
+ // npm view з хуку».
588
+ if (autofix) {
589
+ pass(`${label}: ${name} — autofix-режим, реєстрову перевірку version пропущено (без npm view)`)
590
+ await checkPublishedWorkspacePendingGitChanges(manifest, Vcurrent, subWorkspaces, autofix, pass, fail, cwd)
591
+ return
592
+ }
496
593
  const Vpublished = await resolvePublishedVersion(manifest, getPublishedVersion)
497
594
  if (Vpublished === null) {
498
595
  pass(`${label}: ${name} — опублікована версія недоступна (мережа/реєстр), перевірку пропущено`)
@@ -517,22 +614,23 @@ async function checkPublishedWorkspace(manifest, subWorkspaces, getPublishedVers
517
614
  `${label}: version у ${mf} (${Vcurrent}) позаду опублікованої (${Vpublished}) — ` +
518
615
  `локаль відстала від реєстру (зроби git pull); це не ручний bump`
519
616
  )
520
- await checkPublishedWorkspacePendingGitChanges(manifest, Vcurrent, subWorkspaces, pass, fail, cwd)
617
+ await checkPublishedWorkspacePendingGitChanges(manifest, Vcurrent, subWorkspaces, autofix, pass, fail, cwd)
521
618
  return
522
619
  }
523
620
  pass(`${label}: ${name}@${Vcurrent} збігається з реєстром — перевіряємо git на незрелізні зміни`)
524
- await checkPublishedWorkspacePendingGitChanges(manifest, Vcurrent, subWorkspaces, pass, fail, cwd)
621
+ await checkPublishedWorkspacePendingGitChanges(manifest, Vcurrent, subWorkspaces, autofix, pass, fail, cwd)
525
622
  }
526
623
 
527
624
  /**
528
625
  * @param {string} comparisonRef ref/SHA для `git diff` / `git show`
529
626
  * @param {import('../lib/package-manifest.mjs').PackageManifest} manifest параметр
530
627
  * @param {string} baseLabel параметр
628
+ * @param {boolean} autofix autofix-режим (створити change-файл замість fail)
531
629
  * @param {(msg: string) => void} pass параметр
532
630
  * @param {(msg: string) => void} fail параметр
533
631
  * @param {string} cwd робочий каталог
534
632
  */
535
- async function checkLocalOnlyChangedWorkspace(comparisonRef, manifest, baseLabel, pass, fail, cwd) {
633
+ async function checkLocalOnlyChangedWorkspace(comparisonRef, manifest, baseLabel, autofix, pass, fail, cwd) {
536
634
  const label = workspaceLabel(manifest)
537
635
  const mf = manifestFilePath(manifest.ws, manifest)
538
636
  const Vcurrent = manifest.version
@@ -551,17 +649,18 @@ async function checkLocalOnlyChangedWorkspace(comparisonRef, manifest, baseLabel
551
649
  pass(`${label}: є change-файл(и) у .changes/ — bump зробить CI (n-changelog.mdc)`)
552
650
  return
553
651
  }
554
- fail(missingChangeFileMessage(label, mf))
652
+ await reportOrFixMissingChangeFile(manifest.ws, label, mf, autofix, pass, fail, cwd)
555
653
  }
556
654
 
557
655
  /**
558
656
  * @param {import('../lib/package-manifest.mjs').PackageManifest[]} localOnly параметр
559
657
  * @param {string[]} subWorkspaces параметр
658
+ * @param {boolean} autofix autofix-режим (створити change-файл замість fail)
560
659
  * @param {(msg: string) => void} pass параметр
561
660
  * @param {(msg: string) => void} fail параметр
562
661
  * @param {string} cwd робочий каталог
563
662
  */
564
- async function runLocalOnlyChecks(localOnly, subWorkspaces, pass, fail, cwd) {
663
+ async function runLocalOnlyChecks(localOnly, subWorkspaces, autofix, pass, fail, cwd) {
565
664
  if (localOnly.length === 0) return
566
665
 
567
666
  if (!(await isInsideGitRepo(cwd))) {
@@ -583,7 +682,7 @@ async function runLocalOnlyChecks(localOnly, subWorkspaces, pass, fail, cwd) {
583
682
  for (const manifest of localOnly) {
584
683
  if (!(await workspaceHasRelevantChangesAgainstBase(comparison.ref, manifest.ws, subWorkspaces, cwd))) continue
585
684
  checkedAny = true
586
- await checkLocalOnlyChangedWorkspace(comparison.ref, manifest, comparison.label, pass, fail, cwd)
685
+ await checkLocalOnlyChangedWorkspace(comparison.ref, manifest, comparison.label, autofix, pass, fail, cwd)
587
686
  }
588
687
  if (!checkedAny) {
589
688
  pass(`changelog: local-only воркспейси без змін відносно ${comparison.label}`)
@@ -594,6 +693,7 @@ async function runLocalOnlyChecks(localOnly, subWorkspaces, pass, fail, cwd) {
594
693
  * @param {object} [opts] опції перевірки
595
694
  * @param {(name: string, kind?: import('../lib/package-manifest.mjs').PackageKind) => Promise<string | null>} [opts.getPublishedVersion] перевизначення npm/PyPI у тестах
596
695
  * @param {string} [opts.cwd] корінь репозиторію (за замовчуванням `process.cwd()`)
696
+ * @param {boolean} [opts.autofix] явний autofix-режим (за замовчуванням — з env `N_CURSOR_CHANGELOG_AUTOFIX`)
597
697
  * @returns {Promise<number>} exit-код перевірки
598
698
  */
599
699
  export async function check(opts = {}) {
@@ -601,6 +701,7 @@ export async function check(opts = {}) {
601
701
  const { pass, fail } = reporter
602
702
  const getPublishedVersion = opts.getPublishedVersion ?? createDefaultGetPublishedVersion()
603
703
  const cwd = opts.cwd ?? process.cwd()
704
+ const autofix = opts.autofix ?? process.env[AUTOFIX_ENV_VAR] === '1'
604
705
 
605
706
  const workspaces = await getMonorepoProjectRootDirs(cwd)
606
707
  const subWorkspaces = workspaces.filter(w => w !== '.')
@@ -636,10 +737,10 @@ export async function check(opts = {}) {
636
737
  }
637
738
 
638
739
  for (const manifest of published) {
639
- await checkPublishedWorkspace(manifest, subWorkspaces, getPublishedVersion, pass, fail, cwd)
740
+ await checkPublishedWorkspace(manifest, subWorkspaces, getPublishedVersion, autofix, pass, fail, cwd)
640
741
  }
641
742
 
642
- await runLocalOnlyChecks(localOnly, subWorkspaces, pass, fail, cwd)
743
+ await runLocalOnlyChecks(localOnly, subWorkspaces, autofix, pass, fail, cwd)
643
744
 
644
745
  return reporter.getExitCode()
645
746
  }