@nitra/cursor 5.0.3 → 5.2.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 (206) hide show
  1. package/.claude-template/settings.template.json +22 -0
  2. package/.pi-template/extensions/n-cursor-adr/docs/index.md +15 -9
  3. package/CHANGELOG.md +18 -1
  4. package/bin/n-cursor.js +73 -16
  5. package/docs/stryker.config.md +6 -0
  6. package/docs/vitest.config.md +6 -0
  7. package/lib/docs/llm.md +29 -0
  8. package/lib/docs/omlx.md +32 -0
  9. package/lib/llm.mjs +137 -0
  10. package/lib/models.mjs +9 -1
  11. package/lib/omlx.mjs +147 -0
  12. package/package.json +1 -1
  13. package/rules/abie/docs/fix.md +6 -0
  14. package/rules/abie/js/docs/applies.md +6 -0
  15. package/rules/abie/js/docs/env_dns.md +25 -22
  16. package/rules/abie/js/docs/firebase_hosting.md +6 -0
  17. package/rules/abie/js/docs/hc_pairing.md +21 -25
  18. package/rules/abie/js/docs/ua_http_route.md +27 -19
  19. package/rules/abie/js/docs/ua_node_selector.md +24 -19
  20. package/rules/abie/lib/docs/enabled.md +13 -7
  21. package/rules/abie/lib/docs/env-dns.md +9 -3
  22. package/rules/abie/lib/docs/hc-yaml.md +6 -0
  23. package/rules/abie/lib/docs/http-route.md +6 -0
  24. package/rules/abie/lib/docs/k8s-tree.md +6 -0
  25. package/rules/abie/lib/docs/kustomization-patches.md +6 -0
  26. package/rules/abie/lib/docs/overlay-paths.md +6 -0
  27. package/rules/abie/lib/docs/yaml.md +6 -0
  28. package/rules/adr/docs/fix.md +6 -0
  29. package/rules/adr/js/docs/hooks.md +29 -244
  30. package/rules/bun/docs/fix.md +6 -0
  31. package/rules/bun/js/docs/layout.md +37 -375
  32. package/rules/capacitor/docs/fix.md +22 -108
  33. package/rules/capacitor/js/docs/platforms.md +62 -268
  34. package/rules/changelog/docs/fix.md +6 -0
  35. package/rules/changelog/lib/docs/package-manifest.md +6 -0
  36. package/rules/ci4/docs/fix.md +23 -165
  37. package/rules/ci4/js/docs/marksman_config.md +9 -1
  38. package/rules/docker/docs/fix.md +6 -0
  39. package/rules/docker/js/docs/lint.md +55 -239
  40. package/rules/docker/lib/docs/docker-hadolint.md +6 -0
  41. package/rules/docker/lib/docs/docker-mirror.md +6 -0
  42. package/rules/docker/lib/docs/docker-native-addon.md +6 -0
  43. package/rules/docker/lib/docs/docker-nginx-user.md +6 -0
  44. package/rules/docker/lint/docs/lint.md +9 -1
  45. package/rules/efes/docs/fix.md +6 -0
  46. package/rules/ga/lint/docs/lint.md +6 -0
  47. package/rules/graphql/docs/fix.md +6 -0
  48. package/rules/graphql/lib/docs/graphql-gql-scan.md +6 -0
  49. package/rules/image-avif/docs/fix.md +6 -0
  50. package/rules/image-avif/js/docs/avif_generation.md +6 -0
  51. package/rules/js-bun-db/lib/docs/bun-sql-scan.md +9 -3
  52. package/rules/js-bun-redis/lib/docs/redis-imports.md +6 -0
  53. package/rules/js-lint/js/docs/utils_imports.md +6 -0
  54. package/rules/js-lint-ci/docs/fix.md +7 -1
  55. package/rules/js-mssql/docs/fix.md +6 -0
  56. package/rules/js-mssql/lib/docs/mssql-pool-scan.md +6 -0
  57. package/rules/js-run/docs/fix.md +6 -0
  58. package/rules/js-run/lib/docs/bunyan-imports.md +6 -0
  59. package/rules/js-run/lib/docs/check-env-scan.md +6 -0
  60. package/rules/js-run/lib/docs/conn-file-rules.md +6 -0
  61. package/rules/js-run/lib/docs/conn-imports-scan.md +6 -0
  62. package/rules/js-run/lib/docs/promise-settimeout-scan.md +6 -0
  63. package/rules/js-run/lib/docs/temporal-scan.md +6 -0
  64. package/rules/k8s/docs/fix.md +6 -0
  65. package/rules/k8s/lint/docs/lint.md +6 -0
  66. package/rules/nginx-default-tpl/docs/fix.md +6 -0
  67. package/rules/npm-module/js/docs/header_doc_pointer.md +7 -0
  68. package/rules/npm-module/js/header_doc_pointer.mjs +2 -8
  69. package/rules/php/docs/fix.md +6 -0
  70. package/rules/php/lint/docs/lint.md +6 -0
  71. package/rules/python/docs/fix.md +6 -0
  72. package/rules/python/lint/docs/lint.md +6 -0
  73. package/rules/rego/lint/docs/lint.md +6 -0
  74. package/rules/release/docs/change.md +6 -0
  75. package/rules/release/docs/fix.md +6 -0
  76. package/rules/release/docs/release.md +6 -0
  77. package/rules/release/lib/docs/aggregate.md +6 -0
  78. package/rules/release/lib/docs/change-file.md +6 -0
  79. package/rules/release/lib/docs/fallback.md +6 -0
  80. package/rules/rust/lib/docs/has-cargo-toml.md +6 -0
  81. package/rules/security/docs/fix.md +7 -1
  82. package/rules/security/js/docs/lint.md +6 -0
  83. package/rules/style-lint/docs/fix.md +6 -0
  84. package/rules/tauri/docs/fix.md +6 -0
  85. package/rules/test/docs/fix.md +6 -0
  86. package/rules/test/js/data/stryker_config/docs/stryker-vue-macros-ignorer.md +6 -0
  87. package/rules/test/js/data/stryker_config/docs/stryker.config.baseline.md +6 -0
  88. package/rules/test/js/data/stryker_config/docs/stryker.config.vue.baseline.md +6 -0
  89. package/rules/test/js/data/vitest_config/docs/vitest.config.baseline.md +6 -0
  90. package/rules/text/docs/fix.md +6 -0
  91. package/rules/text/lint/docs/lint.md +6 -0
  92. package/rules/text/lint/docs/run-dotenv-linter.md +6 -0
  93. package/rules/text/lint/docs/run-shellcheck.md +6 -0
  94. package/rules/text/lint/docs/run-v8r.md +6 -0
  95. package/rules/vue/lib/docs/vue-forbidden-imports.md +6 -0
  96. package/scripts/coverage-classify/cache.mjs +1 -1
  97. package/scripts/coverage-classify/docs/apply.md +6 -0
  98. package/scripts/coverage-classify/docs/cache.md +6 -0
  99. package/scripts/coverage-classify/docs/prompt.md +6 -0
  100. package/scripts/coverage-classify/docs/verdict-schema.md +6 -0
  101. package/scripts/coverage-classify/index.mjs +24 -15
  102. package/scripts/coverage-classify/prompt.mjs +1 -1
  103. package/scripts/coverage-fix-extract.mjs +1 -1
  104. package/scripts/coverage-fix.mjs +2 -1
  105. package/scripts/docs/auto-skills.md +6 -0
  106. package/scripts/docs/build-agents-commands.md +7 -1
  107. package/scripts/docs/cli-entry.md +6 -0
  108. package/scripts/docs/coverage-fix-extract.md +6 -0
  109. package/scripts/docs/coverage-fix.md +6 -0
  110. package/scripts/docs/ensure-nitra-cursor-dev-dependencies.md +6 -0
  111. package/scripts/docs/lint-cli.md +6 -0
  112. package/scripts/docs/post-tool-use-fix.md +6 -0
  113. package/scripts/docs/rename-yaml-extensions.md +6 -0
  114. package/scripts/docs/skills-cli.md +6 -0
  115. package/scripts/docs/sync-setup-bun-deps-action.md +6 -0
  116. package/scripts/docs/upgrade-nitra-cursor-and-install.md +6 -0
  117. package/scripts/docs/worktree-cli.md +6 -0
  118. package/scripts/lib/docs/assert-project-root.md +6 -0
  119. package/scripts/lib/docs/check-mdc-template-refs.md +6 -0
  120. package/scripts/lib/docs/check-reporter.md +6 -0
  121. package/scripts/lib/docs/diff-added-lines.md +6 -0
  122. package/scripts/lib/docs/discover-check-rules-from-cursor.md +6 -0
  123. package/scripts/lib/docs/discover-checkable-rules.md +6 -0
  124. package/scripts/lib/docs/ensure-tool.md +6 -0
  125. package/scripts/lib/docs/generated-markdown.md +6 -0
  126. package/scripts/lib/docs/gha-workflow.md +6 -0
  127. package/scripts/lib/docs/inline-template-links.md +6 -0
  128. package/scripts/lib/docs/list-rule-ids.md +6 -0
  129. package/scripts/lib/docs/load-cursor-config.md +6 -0
  130. package/scripts/lib/docs/mirror-parity.md +6 -0
  131. package/scripts/lib/docs/read-n-cursor-config-lite.md +6 -0
  132. package/scripts/lib/docs/resolve-target-files.md +6 -0
  133. package/scripts/lib/docs/root-notice.md +6 -0
  134. package/scripts/lib/docs/rule-meta-helpers.md +6 -0
  135. package/scripts/lib/docs/rule-meta.md +6 -0
  136. package/scripts/lib/docs/run-conftest-batch.md +6 -0
  137. package/scripts/lib/docs/run-lint-step.md +6 -0
  138. package/scripts/lib/docs/run-rule-cli.md +6 -0
  139. package/scripts/lib/docs/run-rule.md +6 -0
  140. package/scripts/lib/docs/run-standard-lint.md +6 -0
  141. package/scripts/lib/docs/run-standard-rule.md +6 -0
  142. package/scripts/lib/docs/skill-meta.md +6 -0
  143. package/scripts/lib/docs/template.md +6 -0
  144. package/scripts/lib/docs/timing-summary.md +6 -0
  145. package/scripts/lib/docs/workspaces.md +6 -0
  146. package/scripts/lib/docs/worktree-notice.md +6 -0
  147. package/scripts/lib/docs/worktree.md +6 -0
  148. package/scripts/lib/mirror-parity.mjs +1 -1
  149. package/scripts/lib/root-notice.mjs +1 -1
  150. package/scripts/lib/worktree-notice.mjs +5 -5
  151. package/scripts/lib/worktree.mjs +1 -1
  152. package/scripts/sync-claude-config.mjs +3 -0
  153. package/scripts/utils/docs/ast-scan-utils.md +6 -0
  154. package/scripts/utils/docs/ensure-gitignore-entries.md +6 -0
  155. package/scripts/utils/docs/find-package-json-paths.md +6 -0
  156. package/scripts/utils/docs/lock-cache-dir.md +6 -0
  157. package/scripts/utils/docs/pass.md +6 -0
  158. package/scripts/utils/docs/resolve-cargo-manifest.md +6 -0
  159. package/scripts/utils/docs/resolve-cmd.md +6 -0
  160. package/scripts/utils/docs/resolve-js-root.md +6 -0
  161. package/scripts/utils/docs/test-helpers.md +6 -0
  162. package/scripts/utils/docs/walk-cache.md +6 -0
  163. package/scripts/utils/docs/walkDir.md +6 -0
  164. package/scripts/utils/docs/worktree-fingerprint.md +6 -0
  165. package/scripts/utils/resolve-js-root.mjs +1 -1
  166. package/skills/doc-aggregate/SKILL.md +129 -0
  167. package/skills/doc-aggregate/js/docgen-ignore.mjs +9 -0
  168. package/skills/{docgen → doc-aggregate}/js/docgen-scan.mjs +22 -67
  169. package/skills/doc-aggregate/js/docs/docgen-ignore.md +21 -0
  170. package/skills/doc-files/SKILL.md +100 -0
  171. package/skills/doc-files/js/docgen-crc.mjs +164 -0
  172. package/skills/{docgen → doc-files}/js/docgen-extract-anchors.mjs +24 -15
  173. package/skills/{docgen → doc-files}/js/docgen-extract.mjs +15 -9
  174. package/skills/doc-files/js/docgen-files-batch.mjs +181 -0
  175. package/skills/doc-files/js/docgen-gen.mjs +291 -0
  176. package/skills/{docgen → doc-files}/js/docgen-prompts.mjs +43 -40
  177. package/skills/doc-files/js/docgen-scan.mjs +298 -0
  178. package/skills/doc-files/js/docs/docgen-crc.md +32 -0
  179. package/skills/doc-files/js/docs/docgen-extract-anchors.md +27 -0
  180. package/skills/doc-files/js/docs/docgen-extract.md +29 -0
  181. package/skills/doc-files/js/docs/docgen-files-batch.md +25 -0
  182. package/skills/doc-files/js/docs/docgen-gen.md +30 -0
  183. package/skills/doc-files/js/docs/docgen-prompts.md +32 -0
  184. package/skills/doc-files/js/docs/docgen-scan.md +25 -0
  185. package/skills/doc-files/meta.json +1 -0
  186. package/skills/fix/js/docs/llm-worker.md +6 -0
  187. package/skills/fix/js/docs/orchestrator.md +6 -0
  188. package/skills/fix/js/llm-worker.mjs +23 -14
  189. package/skills/fix/js/orchestrator.mjs +1 -1
  190. package/skills/start-check/js/check.mjs +5 -3
  191. package/skills/start-check/js/docs/check.md +6 -0
  192. package/skills/docgen/SKILL.md +0 -224
  193. package/skills/docgen/bench/etalon/firebase_hosting.md +0 -19
  194. package/skills/docgen/bench/etalon/k8s-tree.md +0 -24
  195. package/skills/docgen/bench/etalon/overlay-paths.md +0 -24
  196. package/skills/docgen/js/docgen-batch-omlx.mjs +0 -82
  197. package/skills/docgen/js/docgen-batch.mjs +0 -95
  198. package/skills/docgen/js/docgen-compare-pi-vs-direct.mjs +0 -95
  199. package/skills/docgen/js/docgen-gen.mjs +0 -339
  200. package/skills/docgen/js/docs/docgen-extract.md +0 -28
  201. package/skills/docgen/js/docs/docgen-gen.md +0 -41
  202. package/skills/docgen/js/docs/docgen-ignore.md +0 -24
  203. package/skills/docgen/js/docs/docgen-prompts.md +0 -24
  204. package/skills/docgen/js/docs/docgen-scan.md +0 -48
  205. /package/skills/{docgen → doc-aggregate}/meta.json +0 -0
  206. /package/skills/{docgen → doc-files}/js/docgen-ignore.mjs +0 -0
@@ -0,0 +1,25 @@
1
+ ---
2
+ docgen:
3
+ source: npm/skills/doc-files/js/docgen-scan.mjs
4
+ crc: b517ab25
5
+ ---
6
+
7
+ # docgen-scan
8
+
9
+ ## Огляд
10
+
11
+ Сканер кодових файлів і детектор стану файлових док: які джерела підлягають документуванню, де лежить їхня дока, що застаріло, що degraded. Працює і як бібліотека для batch-генерації, і як CLI (`doc-files scan` / `doc-files check`) для хуків.
12
+
13
+ ## Поведінка
14
+
15
+ 1. Рекурсивний обхід від кореня збирає кодові файли (`js`/`mjs`/`ts`/`vue`/`py`), пропускаючи тести, оголошення типів, ignore-дерева і теки `docs/`; для кореня з system-wide docs-layout файлові доки на верхньому рівні не плануються.
16
+ 2. Для кожного джерела обчислюється шлях доки (`<dir>/docs/<stem>.md`) і стан застарілості за контрольною сумою.
17
+ 3. `check` працює в режимах: `--hook` — один файл зі stdin-payload редакторського хука; `--git` — змінені відносно HEAD джерела як Stop-гейт із порогом великого прогону (`--max`, дефолт `50` або `N_CURSOR_DOC_FILES_GATE_MAX`: більше застарілих — попередження без блоку); явні шляхи — точкова перевірка.
18
+ 4. Застарілі доки → exit-код `2` зі списком і підказкою перегенерації; усе свіже або великий прогін — `0`.
19
+ 5. `check --degraded` — інформаційний звіт (exit `0`): свіжі за сумою доки з оцінкою нижче порогу, з кодами проблем і підказкою про `gen --retry-degraded`. Degraded — видимий борг, не гейт.
20
+
21
+ ## Гарантії поведінки
22
+
23
+ - Сканер read-only: жодних записів у дерево.
24
+ - Рішення «застаріла/свіжа» детерміноване і залежить лише від вмісту джерела й frontmatter доки.
25
+ - Stop-гейт ніколи не блокує масовий перший прогін понад поріг — захист від нескінченного блокування задач.
@@ -0,0 +1 @@
1
+ { "auto": "завжди", "worktree": false, "requireRoot": true }
@@ -1,3 +1,9 @@
1
+ ---
2
+ docgen:
3
+ source: npm/skills/fix/js/llm-worker.mjs
4
+ crc: 8317f878
5
+ ---
6
+
1
7
  # llm-worker.mjs
2
8
 
3
9
  ## Огляд
@@ -1,3 +1,9 @@
1
+ ---
2
+ docgen:
3
+ source: npm/skills/fix/js/orchestrator.mjs
4
+ crc: 8b7a7de5
5
+ ---
6
+
1
7
  # orchestrator.mjs
2
8
 
3
9
  ## Огляд
@@ -5,13 +5,14 @@ import { join } from 'node:path'
5
5
  import { spawnSync } from 'node:child_process'
6
6
  import { env } from 'node:process'
7
7
  import { resolveModel } from '../../../lib/models.mjs'
8
+ import { callOmlx, isOmlxModel } from '../../../lib/omlx.mjs'
8
9
 
9
10
  // Тир за замовчуванням: min → avg при ескалації (каскад local→cloud).
10
11
  // Перевизначення через N_CURSOR_FIX_MODEL / N_CURSOR_FIX_MODEL_HEAVY.
11
12
  export const MODEL = env.N_CURSOR_FIX_MODEL ?? resolveModel('min')
12
13
  export const MODEL_HEAVY = env.N_CURSOR_FIX_MODEL_HEAVY ?? resolveModel('avg')
13
14
 
14
- const JSON_CODE_BLOCK_RE = /```(?:json)?\s*([\s\S]*?)```/
15
+ const JSON_CODE_BLOCK_RE = /```(?:json)?[ \t]{0,8}\n?([\s\S]*?)```/
15
16
 
16
17
  /**
17
18
  * Витягує відносні шляхи файлів із violation output.
@@ -34,7 +35,7 @@ function extractFilePaths(output) {
34
35
  }
35
36
 
36
37
  // Патерн без workspace: просто path/to/file.ext або ./file.ext
37
- const re = /(?:^|\s)(\.?[\w][\w./-]*\.(?:json|js|mjs|ts|vue|yml|yaml|toml|mdc|md|sh|py))(?::\d+)?/gm
38
+ const re = /(?:^|\s)(\.?\w[\w./-]*\.(?:json|js|mjs|ts|vue|yml|yaml|toml|mdc|md|sh|py))(?::\d+)?/gm
38
39
  for (const m of output.matchAll(re)) {
39
40
  const p = m[1]
40
41
  if (!seen.has(p)) {
@@ -86,12 +87,20 @@ function buildPrompt(ruleId, ruleMdc, output, files) {
86
87
  }
87
88
 
88
89
  /**
89
- * Запускає pi і повертає stdout як рядок.
90
+ * Викликає LLM за model-id і повертає текст відповіді.
91
+ * `omlx/...` → прямий HTTP до omlx (text-only, локально); решта → pi CLI.
90
92
  * @param {string} prompt текст промпта
91
- * @param {string} model назва моделі (provider/id)
92
- * @returns {{ text: string, error?: string }} stdout pi або повідомлення про помилку
93
+ * @param {string} model назва моделі (provider/id, `omlx/...` або '')
94
+ * @returns {{ text: string, error?: string }} текст відповіді або повідомлення про помилку
93
95
  */
94
- function callPi(prompt, model) {
96
+ function callModel(prompt, model) {
97
+ if (isOmlxModel(model)) {
98
+ try {
99
+ return { text: callOmlx([{ role: 'user', content: prompt }], model, { timeoutMs: 120_000 }) }
100
+ } catch (error) {
101
+ return { text: '', error: error.message }
102
+ }
103
+ }
95
104
  const modelArgs = model ? ['--model', model] : []
96
105
  const r = spawnSync('pi', ['-p', prompt, ...modelArgs, '--no-session', '--mode', 'text', '--no-tools'], {
97
106
  encoding: 'utf8',
@@ -107,7 +116,7 @@ function callPi(prompt, model) {
107
116
  error: [
108
117
  `pi: немає ключа для ${provider}.`,
109
118
  `Встановіть N_CLOUD_MIN_MODEL=provider/model-id`,
110
- `(напр.: openai/gpt-5.4-mini, google/gemini-2.5-flash, ollama/gemma3:4b)`,
119
+ `(напр.: openai/gpt-5.4-mini, google/gemini-2.5-flash, ollama/gemma3:4b)`
111
120
  ].join(' ')
112
121
  }
113
122
  }
@@ -117,9 +126,9 @@ function callPi(prompt, model) {
117
126
  }
118
127
 
119
128
  /**
120
- * Парсить JSON-відповідь від pi.
121
- * pi може обгорнути JSON у ```json ... ```, тому пробуємо витягти.
122
- * @param {string} text сирий stdout pi
129
+ * Парсить JSON-відповідь від моделі.
130
+ * Модель може обгорнути JSON у ```json ... ```, тому пробуємо витягти.
131
+ * @param {string} text сирий текст відповіді
123
132
  * @returns {{ changes: Array<{path:string,content:string}>, error?: string } | null} розпарсений патч або null
124
133
  */
125
134
  function parseResponse(text) {
@@ -183,12 +192,12 @@ export function runLlmWorker(ruleId, violationOutput, projectRoot, opts = {}) {
183
192
  })
184
193
  .filter(Boolean)
185
194
 
186
- // 3. Будуємо prompt і викликаємо pi
195
+ // 3. Будуємо prompt і викликаємо модель
187
196
  const prompt = buildPrompt(ruleId, ruleMdc, violationOutput, files)
188
- const { text, error: piError } = callPi(prompt, model)
197
+ const { text, error: modelError } = callModel(prompt, model)
189
198
 
190
- if (piError) return { ok: false, error: piError }
191
- if (!text) return { ok: false, error: 'pi returned empty response' }
199
+ if (modelError) return { ok: false, error: modelError }
200
+ if (!text) return { ok: false, error: 'model returned empty response' }
192
201
 
193
202
  // 4. Парсимо відповідь
194
203
  const parsed = parseResponse(text)
@@ -20,7 +20,7 @@ export async function runOrchestratorCli(args, cwd) {
20
20
 
21
21
  const maxIterIdx = args.indexOf('--max-iter')
22
22
  const maxIter =
23
- maxIterIdx === -1 ? DEFAULT_MAX_ITER : (Number(args[maxIterIdx + 1] ?? DEFAULT_MAX_ITER) || DEFAULT_MAX_ITER)
23
+ maxIterIdx === -1 ? DEFAULT_MAX_ITER : Number(args[maxIterIdx + 1] ?? DEFAULT_MAX_ITER) || DEFAULT_MAX_ITER
24
24
  const skipIdxs = new Set(maxIterIdx === -1 ? [] : [maxIterIdx, maxIterIdx + 1])
25
25
  const ruleFilter = args.filter((a, i) => !a.startsWith('-') && !skipIdxs.has(i))
26
26
 
@@ -67,8 +67,8 @@ export async function scanStartWorkspaces(cwd) {
67
67
  * @param {string} log обʼєднаний stdout+stderr
68
68
  * @returns {{ready:boolean, firstError:string|null, logTail:string}} витяг
69
69
  */
70
- export function parseStartLog(log) {
71
- const text = log ?? ''
70
+ export function parseStartLog(log = '') {
71
+ const text = log
72
72
  const lines = text.split('\n')
73
73
  const firstError = lines.find(l => ERROR_RE.test(l))?.trim() ?? null
74
74
  const logTail = lines
@@ -137,7 +137,9 @@ export async function runWorkspaceStart(cwd, workspace, opts = {}) {
137
137
 
138
138
  // server: успіх = дожив до кінця grace (timedOut) або встиг віддати рядок готовності.
139
139
  // cli: успіх = чистий вихід 0 у межах grace.
140
- const status = type === 'server' ? (timedOut || ready ? 'OK' : 'FAIL') : exitCode === 0 ? 'OK' : 'FAIL'
140
+ let status
141
+ if (type === 'server') status = timedOut || ready ? 'OK' : 'FAIL'
142
+ else status = exitCode === 0 ? 'OK' : 'FAIL'
141
143
 
142
144
  return {
143
145
  workspace,
@@ -1,3 +1,9 @@
1
+ ---
2
+ docgen:
3
+ source: npm/skills/start-check/js/check.mjs
4
+ crc: 1809127a
5
+ ---
6
+
1
7
  # check.mjs
2
8
 
3
9
  ## Огляд
@@ -1,224 +0,0 @@
1
- ---
2
- name: docgen
3
- description: >-
4
- Обходить проєкт і для кожного кодового файлу (js/mjs/ts/vue/py) пише лаконічну поведінкову українську md-документацію у теку docs/ поряд із кодом — диспатчить окремого субагента на кожен файл, за правилами adr/ci4
5
- ---
6
-
7
- # docgen — генерація документації по файлах
8
-
9
- ## Мета
10
-
11
- Для кожного кодового файлу проєкту створити лаконічну поведінкову `.md`-документацію у теці `docs/`
12
- **поряд із самим файлом** (`<dir>/docs/<stem>.md`). Документацію пише **окремий субагент**
13
- на кожен файл — не один прохід, а батч-диспатч. Джерело правди стилю — правила `adr` і
14
- `ci4` (`docs/explanation`/`docs/adr`-каталоги з тих правил **не застосовуємо** — доку
15
- кладемо локально поряд із кодом).
16
-
17
- Документація — **трирівнева**, рівні виконуються строго послідовно:
18
-
19
- 1. **Tier 1 — файли**: `<dir>/docs/<stem>.md`, субагент на файл (нижче).
20
- 2. **Tier 2 — module-summary**: `<module_root>/docs/ARCHITECTURE.md`, субагент на модуль.
21
- 3. **Tier 3 — доменні доки**: `docs/<домен>.md` у кореневій `docs/`, субагент-синтезатор
22
- виділяє бізнес-домени й пише файл на кожен домен.
23
-
24
- Агрегат ніколи не випереджає джерело: Tier 2 — лише після завершення всього Tier 1,
25
- Tier 3 — лише після завершення всього Tier 2.
26
-
27
- ## ⚠️ Паралелізм
28
-
29
- Диспатч субагентів — **батчами по 5 одночасно**. Не запускати весь список одразу
30
- (перевантаження). Кожен субагент пише свій окремий файл — спільного стану немає, гонок
31
- за файли немає.
32
-
33
- Рівні строго послідовні: Tier 2 стартує лише після завершення всього Tier 1, Tier 3 —
34
- лише після всього Tier 2. Усередині Tier 1 і Tier 2 — батчі по 5. Tier 3 — один субагент.
35
-
36
- ## Передумова
37
-
38
- - Поточна директорія — корінь проєкту, який документуємо.
39
- - Доступний `npx @nitra/cursor` (пакет `@nitra/cursor` встановлено або через npx).
40
-
41
- ## Workflow
42
-
43
- ### Крок 1: Зібрати список файлів
44
-
45
- ```bash
46
- npx @nitra/cursor docgen scan
47
- ```
48
-
49
- Команда друкує JSON-масив об'єктів. Усі шляхи в ньому — відносні до кореня проєкту:
50
-
51
- ```json
52
- [{ "sourcePath": "src/lib/foo.js", "docPath": "src/lib/docs/foo.md", "exists": false }]
53
- ```
54
-
55
- Розпарси JSON.
56
-
57
- ### Крок 2: Відфільтрувати вже описані
58
-
59
- За замовчуванням **пропусти** елементи з `"exists": true`. Перегенеровуй їх лише якщо
60
- користувач явно попросив `--overwrite` (тоді обробляй усі). `--overwrite` — **не** прапор
61
- `docgen scan`: scanner лише лістить файли, а рішення «пропустити чи перегенерувати» приймаєш
62
- ти тут, фільтруючи за полем `exists`.
63
-
64
- Якщо після фільтра список порожній — зупинись:
65
-
66
- ```
67
- ✓ Усі кодові файли вже мають документацію. Нічого робити.
68
- ```
69
-
70
- Запам'ятай `total = довжина відфільтрованого списку`.
71
-
72
- ### Крок 3: Диспатч субагентів батчами по 5
73
-
74
- Розбий список на батчі по 5 елементів. Для кожного батчу запусти **до 5 субагентів
75
- одночасно (в одному повідомленні)**, дочекайся завершення батчу, переходь до наступного.
76
-
77
- Промпт кожного субагента (підстав `sourcePath` і `docPath`):
78
-
79
- ```
80
- Напиши лаконічну технічну документацію для одного файлу коду — орієнтовану на поведінку, не реалізацію.
81
-
82
- ФАЙЛ-ДЖЕРЕЛО: <sourcePath>
83
- ЗАПИСАТИ В: <docPath>
84
-
85
- Кроки:
86
- 1. Прочитай файл <sourcePath> повністю.
87
- 2. Створи теку для <docPath>, якщо її немає.
88
- 3. Запиши markdown-документ у <docPath> за правилами нижче.
89
-
90
- Правила документа (за adr/ci4):
91
- - Мова — УКРАЇНСЬКА для всього тексту (заголовки, абзаци, таблиці). Code identifiers,
92
- шляхи, імена API, команди — лишай як у коді (зазвичай ASCII).
93
- - ЧИСТИЙ Markdown. Жодних HTML-обгорток (<div>/<span>/класів) — токен-ефективність.
94
- - ФОКУС НА ПОВЕДІНЦІ, не реалізації. Пиши ЩО і НАВІЩО, а не як саме це зроблено.
95
- - НЕ перелічуй модулі стандартної бібліотеки (node:fs, node:path, node:crypto, python stdlib
96
- тощо) — вони не несуть бізнес-значення. Зовнішні залежності (npm-пакети, внутрішні модулі)
97
- згадуй лише якщо їхня роль не очевидна з контексту.
98
- - НЕ перелічуй внутрішні назви допоміжних функцій/змінних — описуй їхню роль і поведінку.
99
- Імена публічних exports згадуй лише коли export — справжня точка інтеграції, яку кличуть
100
- ззовні. Для дрібних/листкових модулів з однією відповідальністю опиши роль поведінково,
101
- БЕЗ сигнатур, таблиць типів і переліку параметрів — це деталі реалізації.
102
- - Контекстна незалежність: кожна секція самодостатня. Уникай «як вище», «ця функція», «той сервіс».
103
- - Секції (включай лише доречні — порожніх не вигадуй):
104
- ## Огляд — 1-3 речення: що файл робить і навіщо він існує (роль у системі). Згадай
105
- ключову семантику, якщо вона визначає сенс файлу (opt-in/gate, кеш, ідемпотентність тощо).
106
- ## Поведінка — покроковий алгоритм у бізнес-термінах (не деталі реалізації).
107
- Нумерований список: що відбувається, умови, гілки логіки. Якщо файл керується
108
- конфігом чи форматом даних — наведи короткий приклад (тільки реальний з коду).
109
- ## Публічний API — ЛИШЕ якщо модуль має нетривіальну зовнішню поверхню, яку називають
110
- споживачі. Для кожного export: назва + що робить. Без сигнатур і таблиць типів.
111
- Не дублюй ## Поведінка. Для модуля з однією функцією-предикатом цю секцію пропусти.
112
- ## Де використовується — де в системі цей файл вживається (якщо відомо з коду).
113
- ## Гарантії поведінки — інваріанти й крайові випадки: що гарантовано (read-only,
114
- не кидає винятків, fail-safe-значення за замовчуванням, безпечна обробка поганих даних)
115
- і що стається при відсутніх ресурсах чи некоректному вводі. Пропусти, якщо таких гарантій немає.
116
- - Для .vue додай ## Інтерфейс компонента — props (типи, defaults), emits, slots, реактивний стан.
117
- - НЕ вигадуй деталей, яких немає в коді.
118
- - Мета — Behavior Test: читач розуміє, що робить файл і як він вписується в систему,
119
- без потреби читати реалізацію.
120
-
121
- Поверни лише підтвердження, що файл <docPath> записано.
122
- ```
123
-
124
- ### Крок 4: Tier 2 — module-summary
125
-
126
- Після завершення **всіх** батчів Tier 1 зібрати список модулів:
127
-
128
- ```bash
129
- npx @nitra/cursor docgen modules
130
- ```
131
-
132
- Команда друкує JSON-масив:
133
-
134
- ```json
135
- [
136
- {
137
- "moduleRoot": "/abs/npm/rules/adr",
138
- "relRoot": "npm/rules/adr",
139
- "slug": "npm-rules-adr",
140
- "docPath": "/abs/npm/rules/adr/docs/ARCHITECTURE.md",
141
- "members": ["npm/rules/adr/index.mjs"],
142
- "exists": false
143
- }
144
- ]
145
- ```
146
-
147
- module-summary **завжди регенерується** (це агрегат — поле `exists` ігноруй). Розбий модулі на батчі по 5 і диспатч субагентів. Промпт кожного (підстав `relRoot`, `docPath`, `members`):
148
-
149
- ```
150
- Напиши module-summary для одного логічного модуля.
151
-
152
- МОДУЛЬ: <relRoot>
153
- ЗАПИСАТИ В: <docPath>
154
- ФАЙЛИ МОДУЛЯ (members): <members>
155
-
156
- Кроки:
157
- 1. Прочитай файлові доки членів модуля. <member> — sourcePath відносно кореня проєкту
158
- (= поточний CWD); його файлова дока — <CWD>/<dir>/docs/<stem>.md. За потреби зазирни
159
- в самі файли.
160
- 2. Створи теку для <docPath>, якщо її немає.
161
- 3. Запиши markdown у <docPath> за тими ж правилами стилю, що й файлова дока
162
- (українська, чистий Markdown, контекстна незалежність, без HTML).
163
-
164
- Секції module-summary:
165
- ## Огляд модуля — призначення модуля <relRoot>, його роль у проєкті.
166
- ## Ключові файли — список із кліковими посиланнями (відносними до розташування цього
167
- ARCHITECTURE.md) на члени модуля та їхні файлові доки.
168
- ## Публічний API — що модуль експортує назовні.
169
- ## Внутрішній потік — як компоненти модуля взаємодіють.
170
- ## Підмодулі — вкладені модулі, якщо є.
171
-
172
- Поверни лише підтвердження, що файл <docPath> записано.
173
- ```
174
-
175
- ### Крок 5: Tier 3 — доменні доки
176
-
177
- Після завершення **всіх** module-summary диспатч **одного** субагента-синтезатора.
178
- У промпт підстав конкретний перелік шляхів module-summary (<module_root>/docs/ARCHITECTURE.md
179
- кожного модуля з виводу `docgen modules`), а не інструкцію їх шукати. Промпт:
180
-
181
- ```
182
- Синтезуй доменну документацію бізнес-процесів проєкту.
183
-
184
- ДЖЕРЕЛА (module-summary, читай усі): <перелік шляхів ARCHITECTURE.md, підставлений вище>
185
-
186
- Кроки:
187
- 1. Прочитай усі module-summary.
188
- 2. Виділи бізнес-домени та процеси (можуть перетинати межі модулів). Доменів може бути багато.
189
- 3. Для КОЖНОГО домену запиши окремий файл docs/<домен>.md у кореневій docs/:
190
- - назва файлу — короткий kebab-slug домену;
191
- - не перезаписуй файлові доки кореневих файлів у docs/ (напр. app.md, eslint.config.md):
192
- якщо слаґ домену збігається з іменем такого файлу — додай суфікс -domain
193
- (напр. app-domain.md). Інакше пиши docs/<домен>.md як є;
194
- - опиши бізнес-процес домену з кліковими відносними посиланнями на module-summary, конкретні файли й директорії.
195
-
196
- Правила стилю — ті ж (українська, чистий Markdown, контекстна незалежність, без HTML).
197
-
198
- Поверни перелік створених файлів docs/<домен>.md.
199
- ```
200
-
201
- ### Крок 6: Підсумок
202
-
203
- Після всіх батчів виведи:
204
-
205
- ```
206
- ✓ docgen завершено.
207
- Tier 1 (файли): описано <N>, пропущено <S>, помилок <E>.
208
- Tier 2 (модулі): <M> module-summary.
209
- Tier 3 (домени): <D> доменних доків у docs/.
210
- ```
211
-
212
- Перелічи файли з помилками (субагент впав або не записав `docPath`), якщо такі є.
213
- Помилка одного файлу не зупиняє решту — обробляй усі батчі до кінця.
214
-
215
- ## Нотатки
216
-
217
- - Не комітити автоматично — користувач вирішує, коли комітити згенеровану доку.
218
- - Scanner ігнорує `node_modules`, `dist`, `.git`, `__pycache__`, `coverage`, `.cursor`,
219
- `.claude`, усі теки `docs/`, а також `*.test.*` / `*.spec.*` / `*.d.ts`.
220
- Кореневий repo `docs/` — system-wide only: file-level docs туди не пишуться, і Tier 1
221
- має трактувати цей корінь як повністю нецільовий.
222
- - Список glob-ів для ignore живе в окремому snippet-модулі
223
- `npm/skills/docgen/js/docgen-ignore.mjs` (`DOCGEN_IGNORE_GLOBS`).
224
- Scanner лише читає цей список.
@@ -1,19 +0,0 @@
1
- # firebase_hosting.mjs
2
-
3
- ## Огляд
4
-
5
- Перевірка-концерн правила abie: у підкаталогах першого рівня репозиторію не повинно бути артефактів Firebase Hosting (`.firebaserc`, `firebase.json`, `.firebase/`), бо `abie.mdc` забороняє Firebase Hosting. Сам корінь репозиторію не перевіряється — там ці імена можуть належати суміжним проєктам.
6
-
7
- ## Поведінка
8
-
9
- 1. Прочитати список елементів кореня репозиторію. Якщо каталог не читається — зафіксувати помилку (fail) і завершитися.
10
- 2. Відібрати підкаталоги першого рівня, пропустивши `.git` і `node_modules`.
11
- 3. У кожному такому підкаталозі перевірити наявність заборонених імен: файлів `.firebaserc`, `firebase.json` і каталогу `.firebase/`. Кожна знахідка — окремий fail.
12
- 4. Якщо жодного порушення не знайдено — зафіксувати pass.
13
- 5. Повернути підсумковий exit-код.
14
-
15
- ## Гарантії поведінки
16
-
17
- - Read-only: лише перелічує й перевіряє існування шляхів.
18
- - Помилка читання кореня не валить процес винятком, а стає fail.
19
- - Перевіряється лише перший рівень; корінь і глибші рівні поза охопленням.
@@ -1,24 +0,0 @@
1
- # k8s-tree.mjs
2
-
3
- ## Огляд
4
-
5
- Обхід Kubernetes-дерева для перевірок abie з кешуванням на час одного прогону. Знаходить YAML під сегментом `k8s/` і визначає каталоги з `Deployment`. Перший виклик платить за обхід; наступні концерни прогону беруть із кешу.
6
-
7
- ## Поведінка
8
-
9
- 1. Пошук маніфестів: рекурсивно обійти дерево, відібравши `.yaml`/`.yml` під сегментом `k8s/`; `.github/` свідомо пропускається. Результат відсортований.
10
- 2. Каталоги з Deployment: розпарсити передані YAML, відібрати `kind: Deployment`, зібрати унікальні каталоги.
11
- 3. Кешування: обидві операції кешуються module-level singleton-ом за ключем із входів; повтор без I/O.
12
- 4. Пошкоджені YAML за замовчуванням мовчки пропускаються; репортер передає викликач.
13
-
14
- ## Публічний API
15
-
16
- - `findK8sYamlFiles` — відсортований список YAML під `k8s/` (з кешем, пропуск `.github/`).
17
- - `collectDeploymentDirs` — множина каталогів із Deployment (кеш, опц. репортер помилок).
18
-
19
- ## Гарантії поведінки
20
-
21
- - Read-only щодо проєкту.
22
- - Стійкість до пошкоджених YAML: помилкові документи пропускаються, обхід не переривається.
23
- - Детермінований вивід (стабільне сортування).
24
- - Кеш у межах прогону; повторні виклики безкоштовні.
@@ -1,24 +0,0 @@
1
- # overlay-paths.mjs
2
-
3
- ## Огляд
4
-
5
- Набір чистих path-хелперів для overlay-перевірок правила abie: класифікація шляхів (ua-overlay проти base-шару), виведення каталогу пакета з overlay-шляху, умовні питання правила (чи потрібен HTTPRoute, чи є Deployment). Уся логіка — над рядками/шляхами та перевіркою існування файлів; YAML не парситься.
6
-
7
- ## Поведінка
8
-
9
- - ua-overlay: шлях закінчується на `ua/kustomization.yaml`; base-шар — за сегментом `base/`.
10
- - Каталог пакета: з `…/k8s/ua/kustomization.yaml` виділяється батько `k8s/`; без збігу — немає результату.
11
- - HTTPRoute-gate: вимога лише для Vite-пакетів (є `vite.config.{js,mjs,ts}`).
12
- - Deployment: чи хоч один каталог із Deployment лежить у `k8s/` цього пакета.
13
- - base-шар: yaml під `<пакет>/k8s/` і не в `ua/`.
14
- - Шляхи нормалізуються до posix (`\`→`/`).
15
-
16
- ## Публічний API
17
-
18
- - `isUaKustomizationPath`, `abiePackageDirFromK8sOverlay`, `abieOverlayRequiresHttpRouteByVite`, `abieOverlayK8sTreeHasDeployment`, `isAbieK8sBaseYamlPath`, `isK8sYamlInAbiePackageExcludingUaOverlay`.
19
-
20
- ## Гарантії поведінки
21
-
22
- - Read-only, без побічних ефектів.
23
- - Невідповідність шаблону → негативний/порожній результат, не виняток.
24
- - Незалежність від ОС (розділювачі зводяться до `/`).
@@ -1,82 +0,0 @@
1
- /**
2
- * Тимчасовий A/B-batch: docgen Tier 1 через omlx (gemma-4-e2b 4bit на MLX)
3
- * замість pi/ollama. Перезаписує всі docs/<stem>.md для файлів з sym<4,
4
- * НЕ ескалює в cloud. Призначення — порівняння якості omlx vs попередньої версії.
5
- *
6
- * Запуск: node npm/skills/docgen/js/docgen-batch-omlx.mjs [--limit N] [--from N]
7
- * --limit N — обробити перші N файлів зі списку sym<4
8
- * --from N — почати з індексу N (для дозапуску)
9
- */
10
- import { readFileSync, mkdirSync, writeFileSync } from 'node:fs'
11
- import { dirname, join, resolve } from 'node:path'
12
- import { fileURLToPath } from 'node:url'
13
- import { execSync } from 'node:child_process'
14
- import { env } from 'node:process'
15
- import { generateDoc } from './docgen-gen.mjs'
16
- import { extractFacts } from './docgen-extract.mjs'
17
-
18
- const ROOT = resolve(fileURLToPath(import.meta.url), '../../../../..')
19
-
20
- const args = process.argv.slice(2)
21
- const limitIdx = args.indexOf('--limit')
22
- const limit = limitIdx !== -1 ? Number(args[limitIdx + 1]) : Infinity
23
- const fromIdx = args.indexOf('--from')
24
- const from = fromIdx !== -1 ? Number(args[fromIdx + 1]) : 0
25
-
26
- env.N_CURSOR_DOCGEN_BACKEND = 'omlx'
27
-
28
- const scanOut = execSync('node npm/bin/n-cursor.js docgen scan', { cwd: ROOT, encoding: 'utf8' })
29
- const all = JSON.parse(scanOut)
30
-
31
- const local = []
32
- for (const f of all) {
33
- try {
34
- const src = readFileSync(join(ROOT, f.sourcePath), 'utf8')
35
- const facts = extractFacts(src, join(ROOT, f.sourcePath))
36
- const sym = (facts.internalSymbols ?? []).length
37
- if (sym < 4) local.push({ ...f, sym })
38
- } catch {
39
- /* пропускаємо нечитані */
40
- }
41
- }
42
-
43
- const slice = local.slice(from, from + limit)
44
- console.log(`📋 Файлів sym<4 у проєкті: ${local.length}; обробляємо: ${slice.length} (from=${from}, limit=${limit === Infinity ? 'усе' : limit})`)
45
- console.log(`🤖 Бекенд: omlx → ${env.N_CURSOR_DOCGEN_OMLX_URL ?? 'http://127.0.0.1:8000/v1/chat/completions'}`)
46
-
47
- const stats = { ok: 0, err: 0, totalMs: 0, scores: [], errors: [] }
48
-
49
- for (let i = 0; i < slice.length; i++) {
50
- const f = slice[i]
51
- const t0 = Date.now()
52
- const pct = Math.round(((i + 1) / slice.length) * 100)
53
- process.stdout.write(` [${i + 1}/${slice.length} ${pct}%] sym=${f.sym} ${f.sourcePath} ... `)
54
- try {
55
- const result = await generateDoc(join(ROOT, f.sourcePath), {
56
- symThreshold: 999, // не уходити в cloud за sym
57
- cloudModel: null // повністю вимкнути cloud-fallback навіть при low det-score
58
- })
59
- const docAbs = join(ROOT, f.docPath)
60
- mkdirSync(dirname(docAbs), { recursive: true })
61
- writeFileSync(docAbs, result.md)
62
- const ms = Date.now() - t0
63
- stats.ok++
64
- stats.totalMs += ms
65
- stats.scores.push(result.score ?? 0)
66
- process.stdout.write(`✓ ${Math.round(ms / 1000)}s score=${result.score ?? '?'} tier=${result.tier}\n`)
67
- } catch (error) {
68
- stats.err++
69
- stats.errors.push({ path: f.sourcePath, msg: error.message })
70
- process.stdout.write(`✗ ${error.message}\n`)
71
- }
72
- }
73
-
74
- const avgScore = stats.scores.length ? Math.round(stats.scores.reduce((a, b) => a + b, 0) / stats.scores.length) : 0
75
- console.log(`\n${'─'.repeat(60)}`)
76
- console.log(`✓ OK: ${stats.ok} ✗ Err: ${stats.err}`)
77
- console.log(` Сумарний час: ${Math.round(stats.totalMs / 1000)}s; середній на файл: ${stats.ok ? Math.round(stats.totalMs / stats.ok / 1000) : 0}s`)
78
- console.log(` Середній det-score: ${avgScore}`)
79
- if (stats.errors.length) {
80
- console.log('Помилки:')
81
- for (const e of stats.errors) console.log(` - ${e.path}: ${e.msg}`)
82
- }