@nitra/cursor 3.21.1 → 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 (231) hide show
  1. package/.pi-template/extensions/n-cursor-adr/docs/index.md +181 -0
  2. package/CHANGELOG.md +37 -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/js/lint-findings.mjs +110 -0
  74. package/rules/js-lint/js/lint.mjs +86 -15
  75. package/rules/js-lint-ci/docs/fix.md +154 -0
  76. package/rules/js-lint-ci/js/docs/lint.md +144 -0
  77. package/rules/js-mssql/docs/fix.md +128 -0
  78. package/rules/js-mssql/js/docs/deps.md +263 -0
  79. package/rules/js-mssql/lib/docs/mssql-pool-scan.md +367 -0
  80. package/rules/js-run/docs/fix.md +144 -0
  81. package/rules/js-run/js/docs/runtime.md +388 -0
  82. package/rules/js-run/lib/docs/bunyan-imports.md +117 -0
  83. package/rules/js-run/lib/docs/check-env-scan.md +433 -0
  84. package/rules/js-run/lib/docs/conn-file-rules.md +300 -0
  85. package/rules/js-run/lib/docs/conn-imports-scan.md +204 -0
  86. package/rules/js-run/lib/docs/promise-settimeout-scan.md +326 -0
  87. package/rules/k8s/docs/fix.md +129 -0
  88. package/rules/k8s/js/docs/manifests.md +344 -0
  89. package/rules/k8s/js/manifests.mjs +6 -2
  90. package/rules/k8s/k8s.mdc +4 -2
  91. package/rules/k8s/lint/docs/lint.md +411 -0
  92. package/rules/k8s/policy/network_policy/template/deployment.snippet.yaml +2 -0
  93. package/rules/k8s/policy/network_policy/template/stateful-set.snippet.yaml +2 -0
  94. package/rules/nginx-default-tpl/docs/fix.md +124 -0
  95. package/rules/nginx-default-tpl/js/docs/template.md +378 -0
  96. package/rules/npm-module/docs/fix.md +98 -0
  97. package/rules/npm-module/js/docs/package_structure.md +274 -0
  98. package/rules/npm-module/js/docs/rule_meta.md +137 -0
  99. package/rules/npm-module/js/docs/skill_meta.md +190 -0
  100. package/rules/php/docs/fix.md +107 -0
  101. package/rules/php/js/docs/tooling.md +152 -0
  102. package/rules/php/lint/docs/lint.md +215 -0
  103. package/rules/python/docs/fix.md +163 -0
  104. package/rules/python/js/docs/applies.md +108 -0
  105. package/rules/python/js/docs/tooling.md +153 -0
  106. package/rules/python/lint/docs/lint.md +322 -0
  107. package/rules/rego/docs/fix.md +121 -0
  108. package/rules/rego/js/docs/applies.md +174 -0
  109. package/rules/rego/js/docs/lint.md +118 -0
  110. package/rules/rego/lint/docs/lint.md +204 -0
  111. package/rules/release/docs/change.md +185 -0
  112. package/rules/release/docs/fix.md +119 -0
  113. package/rules/release/docs/release.md +222 -0
  114. package/rules/release/lib/docs/aggregate.md +246 -0
  115. package/rules/release/lib/docs/change-file.md +200 -0
  116. package/rules/release/lib/docs/fallback.md +203 -0
  117. package/rules/rust/docs/fix.md +129 -0
  118. package/rules/rust/js/docs/applies.md +140 -0
  119. package/rules/rust/lib/docs/has-cargo-toml.md +130 -0
  120. package/rules/security/docs/fix.md +86 -0
  121. package/rules/security/js/docs/lint.md +171 -0
  122. package/rules/security/js/docs/sample_secret.md +190 -0
  123. package/rules/security/js/docs/trufflehog.md +137 -0
  124. package/rules/security/js/lint.mjs +9 -1
  125. package/rules/style-lint/docs/fix.md +155 -0
  126. package/rules/style-lint/js/docs/lint.md +184 -0
  127. package/rules/style-lint/js/docs/tooling.md +194 -0
  128. package/rules/tauri/docs/fix.md +158 -0
  129. package/rules/tauri/js/docs/cargo_mutants_config.md +168 -0
  130. package/rules/tauri/js/docs/tooling.md +228 -0
  131. package/rules/test/coverage/coverage.mjs +15 -3
  132. package/rules/test/docs/fix.md +132 -0
  133. package/rules/test/js/data/stryker_config/docs/stryker-vue-macros-ignorer.md +138 -0
  134. package/rules/test/js/data/stryker_config/docs/stryker.config.baseline.md +134 -0
  135. package/rules/test/js/data/stryker_config/docs/stryker.config.vue.baseline.md +160 -0
  136. package/rules/test/js/data/vitest_config/docs/vitest.config.baseline.md +195 -0
  137. package/rules/test/js/docs/cargo_mutants_config.md +173 -0
  138. package/rules/test/js/docs/location.md +136 -0
  139. package/rules/test/js/docs/no-process-chdir.md +160 -0
  140. package/rules/test/js/docs/no-relative-fs-path.md +271 -0
  141. package/rules/test/js/docs/stryker_config.md +152 -0
  142. package/rules/test/js/docs/vitest-config-pool-forks.md +174 -0
  143. package/rules/text/docs/fix.md +118 -0
  144. package/rules/text/js/docs/forbidden-prettier.md +143 -0
  145. package/rules/text/js/docs/formatting.md +256 -0
  146. package/rules/text/js/docs/lint.md +122 -0
  147. package/rules/text/lint/docs/lint.md +220 -0
  148. package/rules/text/lint/docs/run-dotenv-linter.md +157 -0
  149. package/rules/text/lint/docs/run-shellcheck.md +212 -0
  150. package/rules/text/lint/docs/run-v8r.md +197 -0
  151. package/rules/vue/docs/fix.md +127 -0
  152. package/rules/vue/js/docs/packages.md +335 -0
  153. package/rules/vue/lib/docs/vue-forbidden-imports.md +261 -0
  154. package/rules/worktree/docs/fix.md +161 -0
  155. package/schemas/rule-meta.json +5 -1
  156. package/scripts/auto-rules.mjs +7 -4
  157. package/scripts/coverage-classify/docs/apply.md +202 -0
  158. package/scripts/coverage-classify/docs/cache.md +203 -0
  159. package/scripts/coverage-classify/docs/index.md +218 -0
  160. package/scripts/coverage-classify/docs/prompt.md +132 -0
  161. package/scripts/coverage-classify/docs/verdict-schema.md +169 -0
  162. package/scripts/coverage-fix-extract.mjs +122 -0
  163. package/scripts/coverage-fix.mjs +1 -1
  164. package/scripts/dispatcher/docs/graph.md +346 -0
  165. package/scripts/dispatcher/docs/index.md +236 -0
  166. package/scripts/dispatcher/docs/trace.md +296 -0
  167. package/scripts/dispatcher/index.mjs +1 -1
  168. package/scripts/dispatcher/lib/active.mjs +4 -8
  169. package/scripts/dispatcher/lib/commands.mjs +7 -11
  170. package/scripts/dispatcher/lib/docs/active.md +348 -0
  171. package/scripts/dispatcher/lib/docs/artifact.md +232 -0
  172. package/scripts/dispatcher/lib/docs/budget.md +167 -0
  173. package/scripts/dispatcher/lib/docs/capability.md +196 -0
  174. package/scripts/dispatcher/lib/docs/commands.md +210 -0
  175. package/scripts/dispatcher/lib/docs/events.md +182 -0
  176. package/scripts/dispatcher/lib/docs/executor.md +190 -0
  177. package/scripts/dispatcher/lib/docs/flow-lock.md +161 -0
  178. package/scripts/dispatcher/lib/docs/flow-resolve.md +267 -0
  179. package/scripts/dispatcher/lib/docs/gate.md +231 -0
  180. package/scripts/dispatcher/lib/docs/level.md +335 -0
  181. package/scripts/dispatcher/lib/docs/plan-panel.md +181 -0
  182. package/scripts/dispatcher/lib/docs/plan.md +200 -0
  183. package/scripts/dispatcher/lib/docs/planner.md +269 -0
  184. package/scripts/dispatcher/lib/docs/review.md +255 -0
  185. package/scripts/dispatcher/lib/docs/reviewer.md +240 -0
  186. package/scripts/dispatcher/lib/docs/snapshot.md +247 -0
  187. package/scripts/dispatcher/lib/docs/spec.md +203 -0
  188. package/scripts/dispatcher/lib/docs/state-store.md +303 -0
  189. package/scripts/dispatcher/lib/docs/subagent-runner.md +173 -0
  190. package/scripts/dispatcher/lib/executor.mjs +6 -1
  191. package/scripts/dispatcher/lib/flow-resolve.mjs +3 -1
  192. package/scripts/dispatcher/lib/level.mjs +29 -3
  193. package/scripts/dispatcher/lib/review.mjs +1 -1
  194. package/scripts/dispatcher/lib/subagent-runner.mjs +5 -3
  195. package/scripts/docs/auto-rules.md +376 -0
  196. package/scripts/docs/auto-skills.md +173 -0
  197. package/scripts/docs/build-agents-commands.md +183 -0
  198. package/scripts/docs/cli-entry.md +153 -0
  199. package/scripts/docs/coverage-fix.md +177 -0
  200. package/scripts/docs/ensure-nitra-cursor-dev-dependencies.md +189 -0
  201. package/scripts/lib/changed-files.mjs +4 -1
  202. package/scripts/lib/diff-added-lines.mjs +85 -0
  203. package/scripts/lib/docs/changed-files.md +149 -0
  204. package/scripts/lib/docs/check-mdc-template-refs.md +222 -0
  205. package/scripts/lib/docs/check-reporter.md +175 -0
  206. package/scripts/lib/docs/discover-check-rules-from-cursor.md +157 -0
  207. package/scripts/lib/docs/discover-checkable-rules.md +165 -0
  208. package/scripts/lib/docs/ensure-tool.md +254 -0
  209. package/scripts/lib/docs/generated-markdown.md +275 -0
  210. package/scripts/lib/docs/gha-workflow.md +326 -0
  211. package/scripts/lib/docs/inline-template-links.md +303 -0
  212. package/scripts/lib/docs/list-rule-ids.md +156 -0
  213. package/scripts/lib/docs/load-cursor-config.md +147 -0
  214. package/scripts/lib/docs/mirror-parity.md +167 -0
  215. package/scripts/lib/worktree.mjs +26 -0
  216. package/scripts/worktree-cli.mjs +12 -2
  217. package/skills/coverage-fix/SKILL.md +34 -45
  218. package/skills/docgen/SKILL.md +44 -23
  219. package/skills/docgen/bench/etalon/firebase_hosting.md +19 -0
  220. package/skills/docgen/bench/etalon/k8s-tree.md +24 -0
  221. package/skills/docgen/bench/etalon/overlay-paths.md +24 -0
  222. package/skills/docgen/js/docgen-ignore.mjs +54 -0
  223. package/skills/docgen/js/docgen-scan.mjs +37 -21
  224. package/skills/llm-patch/SKILL.md +23 -2
  225. package/skills/start-check/SKILL.md +26 -53
  226. package/skills/start-check/js/check.mjs +211 -0
  227. package/skills/taze/SKILL.md +9 -3
  228. package/skills/taze/js/diff.mjs +154 -0
  229. package/types/bin/n-cursor.d.ts +1 -1
  230. package/skills/fix-tests/SKILL.md +0 -119
  231. package/skills/fix-tests/meta.json +0 -1
@@ -0,0 +1,154 @@
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
+ */
16
+ import { existsSync } from 'node:fs'
17
+ import { readFile } from 'node:fs/promises'
18
+ import { join } from 'node:path'
19
+
20
+ import { getMonorepoPackageRootDirs } from '../../../scripts/lib/workspaces.mjs'
21
+
22
+ /** Поля package.json із залежностями, які порівнюємо. */
23
+ const DEP_FIELDS = ['dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies']
24
+
25
+ /** Дефолтний суфікс бекапу, який створює крок 1 скіла (`cp package.json package.json.taze-bak`). */
26
+ const DEFAULT_BACKUP_SUFFIX = '.taze-bak'
27
+
28
+ // Заякорено на початок (після можливих range-операторів `^~>=<`, пробілів, `v`),
29
+ // щоб НЕ ловити версію всередині protocol-specifier-ів (`workspace:1.0.0`, `npm:x@1.2.3`).
30
+ const SEMVER_RE = /^[\s~^>=<v]*(\d+)\.(\d+)\.(\d+)/
31
+
32
+ /**
33
+ * Парсить semver-ядро зі specifier-а (ігнорує range-префікси `^`/`~`/`>=` тощо).
34
+ * @param {string} spec версійний specifier із package.json
35
+ * @returns {{major:number, minor:number, patch:number}|null} ядро або null для не-semver (`workspace:*`, git-url, `*`)
36
+ */
37
+ export function parseVersion(spec) {
38
+ if (typeof spec !== 'string') return null
39
+ const m = SEMVER_RE.exec(spec)
40
+ if (!m) return null
41
+ return { major: Number(m[1]), minor: Number(m[2]), patch: Number(m[3]) }
42
+ }
43
+
44
+ /**
45
+ * Чи є перехід `from → to` breaking за caret-семантикою (змінилась найлівіша
46
+ * ненульова компонента).
47
+ * @param {{major:number,minor:number,patch:number}} from стара версія
48
+ * @param {{major:number,minor:number,patch:number}} to нова версія
49
+ * @returns {boolean} true — major/breaking
50
+ */
51
+ export function isBreaking(from, to) {
52
+ if (from.major !== to.major) return true
53
+ if (from.major > 0) return false
54
+ if (from.minor !== to.minor) return true
55
+ if (from.minor > 0) return false
56
+ return from.patch !== to.patch
57
+ }
58
+
59
+ /**
60
+ * Порівнює два package.json-обʼєкти й повертає зміни залежностей.
61
+ * @param {object} oldPkg розпарсений старий package.json (бекап)
62
+ * @param {object} newPkg розпарсений новий package.json
63
+ * @param {string} workspace мітка воркспейсу (`.` для кореня)
64
+ * @returns {{major: Array<{workspace:string, pkg:string, from:string, to:string}>, minorPatch:number}} зміни
65
+ */
66
+ export function diffPackageJson(oldPkg, newPkg, workspace) {
67
+ const major = []
68
+ let minorPatch = 0
69
+ for (const field of DEP_FIELDS) {
70
+ const oldDeps = oldPkg?.[field]
71
+ const newDeps = newPkg?.[field]
72
+ if (!oldDeps || !newDeps) continue
73
+ for (const [pkg, from] of Object.entries(oldDeps)) {
74
+ const to = newDeps[pkg]
75
+ if (to === undefined || to === from) continue
76
+ const fromV = parseVersion(from)
77
+ const toV = parseVersion(to)
78
+ if (fromV && toV && isBreaking(fromV, toV)) {
79
+ major.push({ workspace, pkg, from, to })
80
+ } else {
81
+ minorPatch += 1
82
+ }
83
+ }
84
+ }
85
+ return { major, minorPatch }
86
+ }
87
+
88
+ /**
89
+ * Читає JSON-файл або повертає null, якщо файл відсутній / невалідний.
90
+ * @param {string} path абсолютний шлях
91
+ * @returns {Promise<object|null>} розпарсений обʼєкт або null
92
+ */
93
+ async function readJsonOrNull(path) {
94
+ if (!existsSync(path)) return null
95
+ try {
96
+ return JSON.parse(await readFile(path, 'utf8'))
97
+ } catch {
98
+ return null
99
+ }
100
+ }
101
+
102
+ /**
103
+ * Збирає diff по всьому монорепо: для кожного воркспейсу порівнює
104
+ * `<ws>/package.json` з `<ws>/package.json<backupSuffix>`.
105
+ * @param {string} cwd корінь репозиторію
106
+ * @param {string} [backupSuffix] суфікс бекап-файлу
107
+ * @returns {Promise<{major: Array<{workspace:string, pkg:string, from:string, to:string}>, minorPatch:number, totalChanged:number, comparedWorkspaces:number}>} агрегований diff
108
+ */
109
+ export async function collectTazeDiff(cwd, backupSuffix = DEFAULT_BACKUP_SUFFIX) {
110
+ const roots = await getMonorepoPackageRootDirs(cwd)
111
+ const major = []
112
+ let minorPatch = 0
113
+ let comparedWorkspaces = 0
114
+ for (const ws of roots) {
115
+ const dir = join(cwd, ws)
116
+ const oldPkg = await readJsonOrNull(join(dir, `package.json${backupSuffix}`))
117
+ const newPkg = await readJsonOrNull(join(dir, 'package.json'))
118
+ if (!oldPkg || !newPkg) continue
119
+ comparedWorkspaces += 1
120
+ const res = diffPackageJson(oldPkg, newPkg, ws)
121
+ major.push(...res.major)
122
+ minorPatch += res.minorPatch
123
+ }
124
+ return { major, minorPatch, totalChanged: major.length + minorPatch, comparedWorkspaces }
125
+ }
126
+
127
+ const USAGE = 'Usage: n-cursor taze diff [--backup-suffix <suffix>]'
128
+
129
+ /**
130
+ * CLI: `n-cursor taze diff` друкує компактний JSON зі списком major-оновлень і
131
+ * лічбою minor/patch. Read-only.
132
+ * @param {string[]} args аргументи після `taze`
133
+ * @param {string} [cwd] корінь репозиторію (ін'єкція для тестів)
134
+ * @returns {Promise<number>} exit code
135
+ */
136
+ export async function runTazeCli(args, cwd = process.cwd()) {
137
+ if (args[0] !== 'diff') {
138
+ console.error(USAGE)
139
+ return 1
140
+ }
141
+ const flagAt = args.indexOf('--backup-suffix')
142
+ const backupSuffix = flagAt === -1 ? DEFAULT_BACKUP_SUFFIX : args[flagAt + 1]
143
+ if (!backupSuffix) {
144
+ console.error(USAGE)
145
+ return 1
146
+ }
147
+ const diff = await collectTazeDiff(cwd, backupSuffix)
148
+ if (diff.comparedWorkspaces === 0) {
149
+ console.error(`✗ Не знайдено жодного package.json${backupSuffix} — спершу зроби бекап (крок 1 скіла).`)
150
+ return 1
151
+ }
152
+ process.stdout.write(`${JSON.stringify(diff)}\n`)
153
+ return 0
154
+ }
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- export {};
2
+ export {}
@@ -1,119 +0,0 @@
1
- ---
2
- name: n-fix-tests
3
- description: >-
4
- Ітеративно дописати тести щоб підвищити mutation score — читає вцілілі мутанти з COVERAGE.md і запускає агент до конвергенції
5
- ---
6
-
7
- # n-fix-tests — підвищення mutation score
8
-
9
- ## Мета
10
-
11
- Читає структурований JSON-блок вцілілих мутантів з `COVERAGE.md` і ітеративно дописує тести що їх вловлюють. Зупиняється коли score перестає покращуватись (конвергенція).
12
-
13
- ## Передумови
14
-
15
- - У `COVERAGE.md` є секція `## Вцілілі мутанти` з JSON-блоком
16
- - Залежності встановлені (`bun i`)
17
- - `bun run coverage` (або `n-cursor coverage`) доступний
18
-
19
- ## Workflow
20
-
21
- ### Крок 1: Зчитай вцілілих мутантів
22
-
23
- Прочитай `COVERAGE.md`. Знайди секцію `## Вцілілі мутанти`. Знайди огороджений блок ` ```json ` у цій секції і розбери JSON-масив.
24
-
25
- Якщо секція відсутня або масив порожній — зупинись з повідомленням:
26
- `✓ Жодних вцілілих мутантів — mutation score повний`
27
-
28
- Запамʼятай поточну кількість вцілілих: `prevCount = масив.length`
29
-
30
- ### Крок 2: Знайди test-команду і coverage-команду
31
-
32
- Прочитай `package.json` у кореневій директорії.
33
-
34
- **test-команда** (перша що існує):
35
-
36
- 1. `scripts["test"]` з `package.json`
37
- 2. fallback: `bun test`
38
-
39
- **coverage-команда** (перша що існує):
40
-
41
- 1. `scripts["coverage"]` з `package.json` → виклик: `bun run coverage`
42
- 2. fallback: `n-cursor coverage`
43
-
44
- ### Крок 3: Для кожного файлу — запускає Agent
45
-
46
- Згрупуй мутанти по полю `file`. Для кожної групи виконай:
47
-
48
- **3a. Знайди / визнач test файл (завжди у `tests/` директорії):**
49
-
50
- Цільовий файл завжди: `<dir>/tests/<basename>.test.mjs`
51
- (де `<dir>` — директорія source-файлу, `<basename>` — ім'я без розширення)
52
-
53
- - Source: `<cwd>/<file>` (прочитай вміст)
54
- - Test файл:
55
- 1. Якщо `<dir>/tests/<basename>.test.mjs` існує → використай його
56
- 2. Якщо `<dir>/<basename>.test.js` або `<dir>/<basename>.test.mjs` існує (co-located) →
57
- - Перенеси файл до `<dir>/tests/<basename>.test.mjs`
58
- - Оновити відносні `import` шляхи якщо є (тепер треба `../` рівень вгору)
59
- 3. Якщо жоден не знайдено → буде створено `<dir>/tests/<basename>.test.mjs`
60
-
61
- **3b. Сформуй промпт для Agent:**
62
-
63
- ```
64
- Тобі дані вцілілі мутанти зі Stryker для файлу `<file>`.
65
- Ці мутанти вціліли, тому що наявні тести НЕ вловили конкретні зміни коду.
66
-
67
- **Вихідний код** (`<file>`):
68
- \`\`\`
69
- <зміст source-файлу>
70
- \`\`\`
71
-
72
- **Наявні тести** (`<test-file>`):
73
- \`\`\`
74
- <зміст test-файлу або "файл ще не існує">
75
- \`\`\`
76
-
77
- **Вцілілі мутанти** (кожен — зміна коду що НЕ вловлена):
78
- <для кожного мутанта:>
79
- - Рядок <line>, колонка <col>: `<original>` → `<replacement>` (тип мутації: <mutantType>)
80
-
81
- **Завдання:**
82
- Допиши мінімальні test-cases у файл `<test-file>` які б вловили кожен із перелічених мутантів.
83
- Правила:
84
- - НЕ видаляй і НЕ змінюй наявні тести
85
- - Стиль тестів — відповідно до наявного файлу (той самий фреймворк, той самий стиль describe/test)
86
- - Якщо файл ще не існує — створи `<dir>/tests/<basename>.test.mjs` з правильними імпортами.
87
- Приклад: source `src/services/auth-store.js` → test `src/services/tests/auth-store.test.mjs`,
88
- import: `import { ... } from '../auth-store.js'`
89
- - Після написання запусти: `bun test <test-file>` і переконайся що всі тести проходять (виправ якщо падають)
90
- ```
91
-
92
- **3c. Запусти Agent** з цим промптом і дочекайся завершення.
93
-
94
- ### Крок 4: Перевір що всі тести проходять
95
-
96
- ```bash
97
- bun test # або test-команда з кроку 2
98
- ```
99
-
100
- Якщо тести падають — поверни конкретний Agent (для того файлу) з помилкою і попроси виправити.
101
-
102
- ### Крок 5: Запусти coverage і порівняй
103
-
104
- ```bash
105
- bun run coverage # або coverage-команда з кроку 2
106
- ```
107
-
108
- Прочитай новий `COVERAGE.md`, знайди і розбери JSON-масив вцілілих.
109
- `newCount = новий масив.length`
110
-
111
- **Рішення:**
112
-
113
- - Якщо `newCount < prevCount` → повтор з Кроку 1 з оновленим масивом
114
- - Якщо `newCount >= prevCount` → зупинись:
115
- `✓ Конвергенція: mutation score більше не покращується. Вціліло: <newCount> мутантів.`
116
-
117
- ## Зупинка після конвергенції
118
-
119
- Конвергенція — нормальний результат. Деякі мутанти не можна вбити (захищений зовнішнім станом, недетермінована логіка тощо). Не намагайся виправити те що не змінилось після ітерації.
@@ -1 +0,0 @@
1
- { "auto": ["js-lint"], "worktree": true }