@nitra/cursor 5.1.0 → 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 (204) 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 +12 -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/omlx.mjs +49 -4
  11. package/package.json +1 -1
  12. package/rules/abie/docs/fix.md +6 -0
  13. package/rules/abie/js/docs/applies.md +6 -0
  14. package/rules/abie/js/docs/env_dns.md +25 -22
  15. package/rules/abie/js/docs/firebase_hosting.md +6 -0
  16. package/rules/abie/js/docs/hc_pairing.md +21 -25
  17. package/rules/abie/js/docs/ua_http_route.md +27 -19
  18. package/rules/abie/js/docs/ua_node_selector.md +24 -19
  19. package/rules/abie/lib/docs/enabled.md +13 -7
  20. package/rules/abie/lib/docs/env-dns.md +9 -3
  21. package/rules/abie/lib/docs/hc-yaml.md +6 -0
  22. package/rules/abie/lib/docs/http-route.md +6 -0
  23. package/rules/abie/lib/docs/k8s-tree.md +6 -0
  24. package/rules/abie/lib/docs/kustomization-patches.md +6 -0
  25. package/rules/abie/lib/docs/overlay-paths.md +6 -0
  26. package/rules/abie/lib/docs/yaml.md +6 -0
  27. package/rules/adr/docs/fix.md +6 -0
  28. package/rules/adr/js/docs/hooks.md +29 -244
  29. package/rules/bun/docs/fix.md +6 -0
  30. package/rules/bun/js/docs/layout.md +37 -375
  31. package/rules/capacitor/docs/fix.md +22 -108
  32. package/rules/capacitor/js/docs/platforms.md +62 -268
  33. package/rules/changelog/docs/fix.md +6 -0
  34. package/rules/changelog/lib/docs/package-manifest.md +6 -0
  35. package/rules/ci4/docs/fix.md +23 -165
  36. package/rules/ci4/js/docs/marksman_config.md +9 -1
  37. package/rules/docker/docs/fix.md +6 -0
  38. package/rules/docker/js/docs/lint.md +55 -239
  39. package/rules/docker/lib/docs/docker-hadolint.md +6 -0
  40. package/rules/docker/lib/docs/docker-mirror.md +6 -0
  41. package/rules/docker/lib/docs/docker-native-addon.md +6 -0
  42. package/rules/docker/lib/docs/docker-nginx-user.md +6 -0
  43. package/rules/docker/lint/docs/lint.md +9 -1
  44. package/rules/efes/docs/fix.md +6 -0
  45. package/rules/ga/lint/docs/lint.md +6 -0
  46. package/rules/graphql/docs/fix.md +6 -0
  47. package/rules/graphql/lib/docs/graphql-gql-scan.md +6 -0
  48. package/rules/image-avif/docs/fix.md +6 -0
  49. package/rules/image-avif/js/docs/avif_generation.md +6 -0
  50. package/rules/js-bun-db/lib/docs/bun-sql-scan.md +9 -3
  51. package/rules/js-bun-redis/lib/docs/redis-imports.md +6 -0
  52. package/rules/js-lint/js/docs/utils_imports.md +6 -0
  53. package/rules/js-lint-ci/docs/fix.md +7 -1
  54. package/rules/js-mssql/docs/fix.md +6 -0
  55. package/rules/js-mssql/lib/docs/mssql-pool-scan.md +6 -0
  56. package/rules/js-run/docs/fix.md +6 -0
  57. package/rules/js-run/lib/docs/bunyan-imports.md +6 -0
  58. package/rules/js-run/lib/docs/check-env-scan.md +6 -0
  59. package/rules/js-run/lib/docs/conn-file-rules.md +6 -0
  60. package/rules/js-run/lib/docs/conn-imports-scan.md +6 -0
  61. package/rules/js-run/lib/docs/promise-settimeout-scan.md +6 -0
  62. package/rules/js-run/lib/docs/temporal-scan.md +6 -0
  63. package/rules/k8s/docs/fix.md +6 -0
  64. package/rules/k8s/lint/docs/lint.md +6 -0
  65. package/rules/nginx-default-tpl/docs/fix.md +6 -0
  66. package/rules/npm-module/js/docs/header_doc_pointer.md +7 -0
  67. package/rules/npm-module/js/header_doc_pointer.mjs +2 -8
  68. package/rules/php/docs/fix.md +6 -0
  69. package/rules/php/lint/docs/lint.md +6 -0
  70. package/rules/python/docs/fix.md +6 -0
  71. package/rules/python/lint/docs/lint.md +6 -0
  72. package/rules/rego/lint/docs/lint.md +6 -0
  73. package/rules/release/docs/change.md +6 -0
  74. package/rules/release/docs/fix.md +6 -0
  75. package/rules/release/docs/release.md +6 -0
  76. package/rules/release/lib/docs/aggregate.md +6 -0
  77. package/rules/release/lib/docs/change-file.md +6 -0
  78. package/rules/release/lib/docs/fallback.md +6 -0
  79. package/rules/rust/lib/docs/has-cargo-toml.md +6 -0
  80. package/rules/security/docs/fix.md +7 -1
  81. package/rules/security/js/docs/lint.md +6 -0
  82. package/rules/style-lint/docs/fix.md +6 -0
  83. package/rules/tauri/docs/fix.md +6 -0
  84. package/rules/test/docs/fix.md +6 -0
  85. package/rules/test/js/data/stryker_config/docs/stryker-vue-macros-ignorer.md +6 -0
  86. package/rules/test/js/data/stryker_config/docs/stryker.config.baseline.md +6 -0
  87. package/rules/test/js/data/stryker_config/docs/stryker.config.vue.baseline.md +6 -0
  88. package/rules/test/js/data/vitest_config/docs/vitest.config.baseline.md +6 -0
  89. package/rules/text/docs/fix.md +6 -0
  90. package/rules/text/lint/docs/lint.md +6 -0
  91. package/rules/text/lint/docs/run-dotenv-linter.md +6 -0
  92. package/rules/text/lint/docs/run-shellcheck.md +6 -0
  93. package/rules/text/lint/docs/run-v8r.md +6 -0
  94. package/rules/vue/lib/docs/vue-forbidden-imports.md +6 -0
  95. package/scripts/coverage-classify/cache.mjs +1 -1
  96. package/scripts/coverage-classify/docs/apply.md +6 -0
  97. package/scripts/coverage-classify/docs/cache.md +6 -0
  98. package/scripts/coverage-classify/docs/prompt.md +6 -0
  99. package/scripts/coverage-classify/docs/verdict-schema.md +6 -0
  100. package/scripts/coverage-classify/prompt.mjs +1 -1
  101. package/scripts/coverage-fix-extract.mjs +1 -1
  102. package/scripts/coverage-fix.mjs +2 -1
  103. package/scripts/docs/auto-skills.md +6 -0
  104. package/scripts/docs/build-agents-commands.md +7 -1
  105. package/scripts/docs/cli-entry.md +6 -0
  106. package/scripts/docs/coverage-fix-extract.md +6 -0
  107. package/scripts/docs/coverage-fix.md +6 -0
  108. package/scripts/docs/ensure-nitra-cursor-dev-dependencies.md +6 -0
  109. package/scripts/docs/lint-cli.md +6 -0
  110. package/scripts/docs/post-tool-use-fix.md +6 -0
  111. package/scripts/docs/rename-yaml-extensions.md +6 -0
  112. package/scripts/docs/skills-cli.md +6 -0
  113. package/scripts/docs/sync-setup-bun-deps-action.md +6 -0
  114. package/scripts/docs/upgrade-nitra-cursor-and-install.md +6 -0
  115. package/scripts/docs/worktree-cli.md +6 -0
  116. package/scripts/lib/docs/assert-project-root.md +6 -0
  117. package/scripts/lib/docs/check-mdc-template-refs.md +6 -0
  118. package/scripts/lib/docs/check-reporter.md +6 -0
  119. package/scripts/lib/docs/diff-added-lines.md +6 -0
  120. package/scripts/lib/docs/discover-check-rules-from-cursor.md +6 -0
  121. package/scripts/lib/docs/discover-checkable-rules.md +6 -0
  122. package/scripts/lib/docs/ensure-tool.md +6 -0
  123. package/scripts/lib/docs/generated-markdown.md +6 -0
  124. package/scripts/lib/docs/gha-workflow.md +6 -0
  125. package/scripts/lib/docs/inline-template-links.md +6 -0
  126. package/scripts/lib/docs/list-rule-ids.md +6 -0
  127. package/scripts/lib/docs/load-cursor-config.md +6 -0
  128. package/scripts/lib/docs/mirror-parity.md +6 -0
  129. package/scripts/lib/docs/read-n-cursor-config-lite.md +6 -0
  130. package/scripts/lib/docs/resolve-target-files.md +6 -0
  131. package/scripts/lib/docs/root-notice.md +6 -0
  132. package/scripts/lib/docs/rule-meta-helpers.md +6 -0
  133. package/scripts/lib/docs/rule-meta.md +6 -0
  134. package/scripts/lib/docs/run-conftest-batch.md +6 -0
  135. package/scripts/lib/docs/run-lint-step.md +6 -0
  136. package/scripts/lib/docs/run-rule-cli.md +6 -0
  137. package/scripts/lib/docs/run-rule.md +6 -0
  138. package/scripts/lib/docs/run-standard-lint.md +6 -0
  139. package/scripts/lib/docs/run-standard-rule.md +6 -0
  140. package/scripts/lib/docs/skill-meta.md +6 -0
  141. package/scripts/lib/docs/template.md +6 -0
  142. package/scripts/lib/docs/timing-summary.md +6 -0
  143. package/scripts/lib/docs/workspaces.md +6 -0
  144. package/scripts/lib/docs/worktree-notice.md +6 -0
  145. package/scripts/lib/docs/worktree.md +6 -0
  146. package/scripts/lib/mirror-parity.mjs +1 -1
  147. package/scripts/lib/root-notice.mjs +1 -1
  148. package/scripts/lib/worktree-notice.mjs +5 -5
  149. package/scripts/lib/worktree.mjs +1 -1
  150. package/scripts/sync-claude-config.mjs +3 -0
  151. package/scripts/utils/docs/ast-scan-utils.md +6 -0
  152. package/scripts/utils/docs/ensure-gitignore-entries.md +6 -0
  153. package/scripts/utils/docs/find-package-json-paths.md +6 -0
  154. package/scripts/utils/docs/lock-cache-dir.md +6 -0
  155. package/scripts/utils/docs/pass.md +6 -0
  156. package/scripts/utils/docs/resolve-cargo-manifest.md +6 -0
  157. package/scripts/utils/docs/resolve-cmd.md +6 -0
  158. package/scripts/utils/docs/resolve-js-root.md +6 -0
  159. package/scripts/utils/docs/test-helpers.md +6 -0
  160. package/scripts/utils/docs/walk-cache.md +6 -0
  161. package/scripts/utils/docs/walkDir.md +6 -0
  162. package/scripts/utils/docs/worktree-fingerprint.md +6 -0
  163. package/scripts/utils/resolve-js-root.mjs +1 -1
  164. package/skills/doc-aggregate/SKILL.md +129 -0
  165. package/skills/doc-aggregate/js/docgen-ignore.mjs +9 -0
  166. package/skills/{docgen → doc-aggregate}/js/docgen-scan.mjs +22 -67
  167. package/skills/doc-aggregate/js/docs/docgen-ignore.md +21 -0
  168. package/skills/doc-files/SKILL.md +100 -0
  169. package/skills/doc-files/js/docgen-crc.mjs +164 -0
  170. package/skills/{docgen → doc-files}/js/docgen-extract-anchors.mjs +20 -11
  171. package/skills/{docgen → doc-files}/js/docgen-extract.mjs +15 -9
  172. package/skills/doc-files/js/docgen-files-batch.mjs +181 -0
  173. package/skills/doc-files/js/docgen-gen.mjs +291 -0
  174. package/skills/{docgen → doc-files}/js/docgen-prompts.mjs +43 -40
  175. package/skills/doc-files/js/docgen-scan.mjs +298 -0
  176. package/skills/doc-files/js/docs/docgen-crc.md +32 -0
  177. package/skills/doc-files/js/docs/docgen-extract-anchors.md +27 -0
  178. package/skills/doc-files/js/docs/docgen-extract.md +29 -0
  179. package/skills/doc-files/js/docs/docgen-files-batch.md +25 -0
  180. package/skills/doc-files/js/docs/docgen-gen.md +30 -0
  181. package/skills/doc-files/js/docs/docgen-prompts.md +32 -0
  182. package/skills/doc-files/js/docs/docgen-scan.md +25 -0
  183. package/skills/doc-files/meta.json +1 -0
  184. package/skills/fix/js/docs/llm-worker.md +6 -0
  185. package/skills/fix/js/docs/orchestrator.md +6 -0
  186. package/skills/fix/js/llm-worker.mjs +3 -3
  187. package/skills/fix/js/orchestrator.mjs +1 -1
  188. package/skills/start-check/js/check.mjs +5 -3
  189. package/skills/start-check/js/docs/check.md +6 -0
  190. package/skills/docgen/SKILL.md +0 -224
  191. package/skills/docgen/bench/etalon/firebase_hosting.md +0 -19
  192. package/skills/docgen/bench/etalon/k8s-tree.md +0 -24
  193. package/skills/docgen/bench/etalon/overlay-paths.md +0 -24
  194. package/skills/docgen/js/docgen-batch-omlx.mjs +0 -82
  195. package/skills/docgen/js/docgen-batch.mjs +0 -95
  196. package/skills/docgen/js/docgen-compare-pi-vs-direct.mjs +0 -95
  197. package/skills/docgen/js/docgen-gen.mjs +0 -306
  198. package/skills/docgen/js/docs/docgen-extract.md +0 -28
  199. package/skills/docgen/js/docs/docgen-gen.md +0 -41
  200. package/skills/docgen/js/docs/docgen-ignore.md +0 -24
  201. package/skills/docgen/js/docs/docgen-prompts.md +0 -24
  202. package/skills/docgen/js/docs/docgen-scan.md +0 -48
  203. /package/skills/{docgen → doc-aggregate}/meta.json +0 -0
  204. /package/skills/{docgen → doc-files}/js/docgen-ignore.mjs +0 -0
@@ -0,0 +1,298 @@
1
+ /** @see ./docs/docgen-scan.md */
2
+ // eslint-disable-next-line unicorn/import-style
3
+ import path from 'node:path'
4
+ import { existsSync, readdirSync, statSync } from 'node:fs'
5
+ import { execFileSync } from 'node:child_process'
6
+ import { once } from 'node:events'
7
+ import { env } from 'node:process'
8
+
9
+ import { isRunAsCli } from '../../../scripts/cli-entry.mjs'
10
+ import { isDocgenIgnored } from './docgen-ignore.mjs'
11
+ import { QUALITY_THRESHOLD, readDocQuality, staleness } from './docgen-crc.mjs'
12
+
13
+ /** Кодові розширення, для яких генеруємо документацію. */
14
+ const SOURCE_EXTENSIONS = new Set(['.js', '.mjs', '.ts', '.vue', '.py'])
15
+
16
+ /** `*.test.*`, `*.spec.*` — тести, документувати не треба. */
17
+ const TEST_FILE_RE = /\.(?:test|spec)\.[^.]+$/u
18
+
19
+ /** Поріг великого прогону для Stop-гейта: більше stale-файлів — не блокуємо. */
20
+ const DEFAULT_GATE_MAX = Number(env.N_CURSOR_DOC_FILES_GATE_MAX ?? 50) || 50
21
+
22
+ /**
23
+ * Чи корінь має system-wide docs layout.
24
+ * Такий корінь зарезервований під репозиторні docs/adr, docs/explanation тощо,
25
+ * тому file-level docs у нього не пишемо.
26
+ * @param {string} root абсолютний корінь обходу
27
+ * @returns {boolean} true — корінь system-wide docs
28
+ */
29
+ function isSystemWideDocsRoot(root) {
30
+ return existsSync(path.join(root, 'docs', 'adr')) || existsSync(path.join(root, 'docs', 'explanation'))
31
+ }
32
+
33
+ /**
34
+ * Чи є файл кодовим джерелом для документування.
35
+ * @param {string} fileName базове ім'я файлу
36
+ * @returns {boolean} true — документуємо; false — пропускаємо
37
+ */
38
+ export function isSourceFile(fileName) {
39
+ if (fileName.endsWith('.d.ts')) return false
40
+ if (TEST_FILE_RE.test(fileName)) return false
41
+ return SOURCE_EXTENSIONS.has(path.extname(fileName))
42
+ }
43
+
44
+ /**
45
+ * Обчислює шлях md-документа для кодового файлу: тека `docs/` поряд із джерелом.
46
+ * Якщо `sourcePath` відносний, `docPath` теж відносний; якщо абсолютний — абсолютний.
47
+ * @param {string} sourcePath шлях до джерела (відносний або абсолютний)
48
+ * @returns {string} шлях до `<dir>/docs/<stem>.md` у тому ж просторі шляхів
49
+ */
50
+ export function docPathForSource(sourcePath) {
51
+ const dir = path.dirname(sourcePath)
52
+ const stem = path.basename(sourcePath, path.extname(sourcePath))
53
+ return path.join(dir, 'docs', `${stem}.md`)
54
+ }
55
+
56
+ /**
57
+ * Чи кодовий файл `relPath` (posix, від кореня) підлягає документуванню:
58
+ * правильне розширення, не тест, не в ignore-дереві, не кореневий system-wide docs.
59
+ * @param {string} root абсолютний корінь
60
+ * @param {string} relPath posix-шлях файлу від кореня
61
+ * @returns {boolean} true — кандидат на доку
62
+ */
63
+ export function isDocCandidate(root, relPath) {
64
+ const fileName = path.posix.basename(relPath)
65
+ if (!isSourceFile(fileName)) return false
66
+ if (isSystemWideDocsRoot(root) && path.posix.dirname(relPath) === '.') return false
67
+ return !isDocgenIgnored(relPath)
68
+ }
69
+
70
+ /**
71
+ * Описує один кодовий файл: шлях джерела, шлях доки, стан застарілості за CRC.
72
+ * @param {string} root абсолютний корінь
73
+ * @param {string} sourcePath posix-шлях джерела від кореня
74
+ * @returns {{sourcePath:string, docPath:string, stale:boolean, reason:'missing'|'crc-mismatch'|null}} опис файлу
75
+ */
76
+ export function describeFile(root, sourcePath) {
77
+ const docPath = docPathForSource(sourcePath)
78
+ const { stale, reason } = staleness(path.join(root, sourcePath), path.join(root, docPath))
79
+ return { sourcePath, docPath, stale, reason }
80
+ }
81
+
82
+ /**
83
+ * Рекурсивно обходить дерево від `root`, повертає кодові файли зі станом застарілості.
84
+ * Синхронний `readdirSync` — детермінований порядок без гонок; обсяг дерева це дозволяє.
85
+ * @param {string} root абсолютний корінь обходу
86
+ * @returns {Array<{sourcePath:string, docPath:string, stale:boolean, reason:'missing'|'crc-mismatch'|null}>} кандидати з відносними шляхами
87
+ */
88
+ export function scanForDocFiles(root) {
89
+ const results = []
90
+
91
+ /** @param {string} dir поточний каталог обходу */
92
+ function walk(dir) {
93
+ let entries
94
+ try {
95
+ entries = readdirSync(dir, { withFileTypes: true })
96
+ } catch {
97
+ return
98
+ }
99
+ for (const entry of entries) {
100
+ const fullPath = path.join(dir, entry.name)
101
+ const relPath = path.relative(root, fullPath)
102
+ if (entry.isDirectory()) {
103
+ if (isDocgenIgnored(relPath, 'dir')) continue
104
+ walk(fullPath)
105
+ } else if (entry.isFile() && isSourceFile(entry.name)) {
106
+ if (isSystemWideDocsRoot(root) && path.dirname(relPath) === '.') continue
107
+ const sourcePath = relPath.split(path.sep).join('/')
108
+ if (isDocgenIgnored(sourcePath)) continue
109
+ results.push(describeFile(root, sourcePath))
110
+ }
111
+ }
112
+ }
113
+
114
+ walk(root)
115
+ return results
116
+ }
117
+
118
+ /**
119
+ * Парсить `--root <dir>` з argv; default — cwd.
120
+ * @param {string[]} argv аргументи після підкоманди
121
+ * @returns {string} абсолютний корінь
122
+ */
123
+ export function resolveRoot(argv) {
124
+ const i = argv.indexOf('--root')
125
+ return i !== -1 && argv[i + 1] ? path.resolve(argv[i + 1]) : process.cwd()
126
+ }
127
+
128
+ /**
129
+ * Сканує дерево і друкує JSON-масив усіх кодових файлів зі станом застарілості.
130
+ * Рішення «генерувати лише stale чи всі» приймає скіл, фільтруючи поле `stale`.
131
+ * @param {string[]} argv аргументи після назви субкоманди
132
+ * @returns {number} exit-код: 0 — успіх, 1 — корінь не існує
133
+ */
134
+ export function runDocFilesScanCli(argv) {
135
+ const root = resolveRoot(argv)
136
+ if (!existsSync(root) || !statSync(root).isDirectory()) {
137
+ console.error(`doc-files scan: корінь не існує або не є директорією: ${root}`)
138
+ return 1
139
+ }
140
+ console.log(JSON.stringify(scanForDocFiles(root), null, 2))
141
+ return 0
142
+ }
143
+
144
+ /**
145
+ * Зчитує stdin до EOF як utf8 рядок. На TTY — повертає `''` одразу.
146
+ * @returns {Promise<string>} вміст stdin
147
+ */
148
+ async function readStdin() {
149
+ if (process.stdin.isTTY) return ''
150
+ process.stdin.setEncoding('utf8')
151
+ const chunks = []
152
+ process.stdin.on('data', chunk => chunks.push(chunk))
153
+ try {
154
+ await once(process.stdin, 'end')
155
+ } catch {
156
+ // 'error' на stdin — повертаємо те, що встигли зібрати
157
+ }
158
+ return chunks.join('')
159
+ }
160
+
161
+ /**
162
+ * Дістає `tool_input.file_path` зі stdin JSON Claude Code PostToolUse hook.
163
+ * @param {string} stdinJson сирий вміст stdin
164
+ * @returns {string|null} відносний шлях або null
165
+ */
166
+ function extractHookFilePath(stdinJson) {
167
+ if (!stdinJson) return null
168
+ try {
169
+ const fp = JSON.parse(stdinJson)?.tool_input?.file_path
170
+ return typeof fp === 'string' && fp !== '' ? fp : null
171
+ } catch {
172
+ return null
173
+ }
174
+ }
175
+
176
+ /**
177
+ * Список змінених у задачі джерел — найшвидший спосіб: `git diff --name-only HEAD`
178
+ * (working-tree проти HEAD). Допускаємо неповне покриття (закомічене в межах задачі
179
+ * випадає) — це свідомий компроміс; CRC лишається джерелом правди про застарілість.
180
+ * @param {string} root абсолютний корінь
181
+ * @returns {string[]} posix-шляхи кодових файлів-кандидатів, що існують
182
+ */
183
+ function gitChangedSources(root) {
184
+ let out
185
+ try {
186
+ out = execFileSync('git', ['diff', '--name-only', 'HEAD'], { cwd: root, encoding: 'utf8' })
187
+ } catch {
188
+ return []
189
+ }
190
+ return out
191
+ .split('\n')
192
+ .map(s => s.trim())
193
+ .filter(rel => rel && isDocCandidate(root, rel) && existsSync(path.join(root, rel)))
194
+ }
195
+
196
+ /**
197
+ * Нормалізує абсолютний/відносний шлях до posix-шляху від кореня (або null поза деревом).
198
+ * @param {string} root абсолютний корінь
199
+ * @param {string} candidate шлях-кандидат
200
+ * @returns {string|null} posix-шлях від кореня
201
+ */
202
+ function toRelSource(root, candidate) {
203
+ const rel = path.relative(root, path.resolve(root, candidate))
204
+ if (rel.startsWith('..') || path.isAbsolute(rel)) return null
205
+ return rel.split(path.sep).join('/')
206
+ }
207
+
208
+ /**
209
+ * `doc-files check --degraded` — інформаційний список свіжих за CRC док зі
210
+ * `score < QUALITY_THRESHOLD` (локальний конвеєр не дотягнув; ADR 260610-2228).
211
+ * Не блокує (exit 0): degraded — борг для `gen --retry-degraded`, а не гейт.
212
+ * @param {string} root абсолютний корінь
213
+ * @returns {number} exit-код: завжди 0
214
+ */
215
+ function runDegradedReport(root) {
216
+ const degraded = []
217
+ for (const f of scanForDocFiles(root)) {
218
+ if (f.stale) continue
219
+ const { score, issues } = readDocQuality(path.join(root, f.docPath))
220
+ if (score !== null && score < QUALITY_THRESHOLD) degraded.push({ ...f, score, issues })
221
+ }
222
+ if (degraded.length === 0) {
223
+ console.log(`✓ doc-files: degraded-док немає (поріг ${QUALITY_THRESHOLD}).`)
224
+ return 0
225
+ }
226
+ const list = degraded
227
+ .map(f => {
228
+ const issuesTxt = f.issues.length ? ': ' + f.issues.join(',') : ''
229
+ return ` - ${f.sourcePath} (score=${f.score}${issuesTxt})`
230
+ })
231
+ .join('\n')
232
+ console.log(
233
+ `⚠ doc-files: degraded-док ${degraded.length} (score < ${QUALITY_THRESHOLD}):\n${list}\n→ перегенеруй: npx @nitra/cursor doc-files gen --retry-degraded`
234
+ )
235
+ return 0
236
+ }
237
+
238
+ /**
239
+ * `doc-files check` — детермінований детектор застарілості для hook'ів і CLI.
240
+ *
241
+ * Режими:
242
+ * - `--hook` — PostToolUse: бере `file_path` зі stdin JSON, перевіряє один файл.
243
+ * - `--git` — Stop-гейт: перевіряє `git diff --name-only HEAD`. Поріг `--max N`
244
+ * (default 50): якщо stale більше — не блокуємо (exit 0 + попередження).
245
+ * - `--degraded` — інформаційний звіт по доках зі score нижче порогу (exit 0).
246
+ * - `<paths…>` — явні шляхи-джерела.
247
+ *
248
+ * Exit 2 (стале знайдено) — для hook'а це блок/нагадування Claude; exit 0 — все свіже
249
+ * або великий прогін понад поріг.
250
+ * @param {string[]} argv аргументи після назви субкоманди
251
+ * @returns {Promise<number>} exit-код (0 / 2)
252
+ */
253
+ export async function runDocFilesCheckCli(argv) {
254
+ const root = resolveRoot(argv)
255
+ if (argv.includes('--degraded')) return runDegradedReport(root)
256
+ const hookMode = argv.includes('--hook')
257
+ const gitMode = argv.includes('--git')
258
+ const maxIdx = argv.indexOf('--max')
259
+ const gateMax = maxIdx !== -1 && argv[maxIdx + 1] ? Number(argv[maxIdx + 1]) || DEFAULT_GATE_MAX : DEFAULT_GATE_MAX
260
+
261
+ let sources
262
+ if (hookMode) {
263
+ const fp = extractHookFilePath(await readStdin())
264
+ const rel = fp ? toRelSource(root, fp) : null
265
+ sources = rel && isDocCandidate(root, rel) && existsSync(path.join(root, rel)) ? [rel] : []
266
+ } else if (gitMode) {
267
+ sources = gitChangedSources(root)
268
+ } else {
269
+ sources = argv
270
+ .filter(a => !a.startsWith('--') && a !== argv[maxIdx + 1])
271
+ .map(a => toRelSource(root, a))
272
+ .filter(rel => rel && isDocCandidate(root, rel) && existsSync(path.join(root, rel)))
273
+ }
274
+
275
+ const stale = sources.map(src => describeFile(root, src)).filter(f => f.stale)
276
+ if (stale.length === 0) return 0
277
+
278
+ // Великий прогін: Stop-гейт не блокує, лише попереджає (захист від нескінченного блоку).
279
+ if (gitMode && stale.length > gateMax) {
280
+ console.error(
281
+ `⚠ doc-files: застарілих док ${stale.length} (> ${gateMax}) — гейт не блокує. Запусти масовий прогін:\n npx @nitra/cursor doc-files gen`
282
+ )
283
+ return 0
284
+ }
285
+
286
+ const list = stale.map(f => ` - ${f.sourcePath} (${f.reason})`).join('\n')
287
+ console.error(
288
+ `✗ doc-files: документація застаріла/відсутня для ${stale.length} файл(ів):\n${list}\n→ перегенеруй: /doc-files`
289
+ )
290
+ return 2
291
+ }
292
+
293
+ if (isRunAsCli(import.meta.url)) {
294
+ // Прямий запуск: `node skills/doc-files/js/docgen-scan.mjs [scan|check] [args]`
295
+ const [sub, ...rest] = process.argv.slice(2)
296
+ const argv = sub === 'scan' || sub === 'check' ? rest : process.argv.slice(2)
297
+ process.exitCode = sub === 'check' ? await runDocFilesCheckCli(argv) : runDocFilesScanCli(argv)
298
+ }
@@ -0,0 +1,32 @@
1
+ ---
2
+ docgen:
3
+ source: npm/skills/doc-files/js/docgen-crc.mjs
4
+ crc: 54e8e12b
5
+ ---
6
+
7
+ # docgen-crc
8
+
9
+ ## Огляд
10
+
11
+ Детермінований маркер актуальності файлових док: контрольна сума джерела у frontmatter плюс опційний degraded-маркер якості. Єдине джерело правди про «дока свіжа/застаріла/неякісна» для генерації, перевірок і хуків.
12
+
13
+ ## Поведінка
14
+
15
+ 1. Контрольна сума обчислюється з байтів джерела і записується у машинний frontmatter доки разом зі шляхом джерела; розбіжність суми з поточним джерелом (або відсутність доки) означає застарілість.
16
+ 2. Якщо генерація не дотягнула до порогу якості, frontmatter додатково несе оцінку (`score`) і коди проблем (`issues`); коди нормалізуються до YAML-безпечних (без пробілів, обмежена кількість), а старі доки без цих полів лишаються валідними.
17
+ 3. Поріг degraded — `70`, override через `N_CURSOR_DOC_FILES_THRESHOLD`.
18
+ 4. Перештампування знімає наявний frontmatter і ставить свіжий, не торкаючись тіла документа; якість при цьому передається явно — без неї поля якості зникають.
19
+
20
+ ## Публічний API
21
+
22
+ - `crc32` — контрольна сума вмісту в hex.
23
+ - `staleness` — стан доки відносно джерела: `missing` / `crc-mismatch` / свіжа.
24
+ - `parseDocFrontmatter` / `buildDocFrontmatter` / `stampDoc` — читання і (пере)штампування машинного блока.
25
+ - `readDocCrc` / `readDocQuality` — точкове читання суми та якості з доки.
26
+ - `QUALITY_THRESHOLD` — чинний поріг degraded.
27
+
28
+ ## Гарантії поведінки
29
+
30
+ - Сума не залежить від git-стану: rebase, гілки й незакомічені зміни на неї не впливають.
31
+ - Frontmatter — єдиний машинний виняток із правила «чистий Markdown»; тіло доки модуль не редагує.
32
+ - Відсутні поля якості читаються як «не оцінено» (`score: null`), а не як нуль.
@@ -0,0 +1,27 @@
1
+ ---
2
+ docgen:
3
+ source: npm/skills/doc-files/js/docgen-extract-anchors.mjs
4
+ crc: e80e0827
5
+ ---
6
+
7
+ # docgen-extract-anchors
8
+
9
+ ## Огляд
10
+
11
+ Детермінований витяг «анкорів» — конкретних фрагментів коду, які модель зобов'язана згадати в документації, щоб не зісковзнути на generic-фрази. Анкори підставляються у промпти окремим блоком обов'язкового включення, а їх покриття перевіряється скорером.
12
+
13
+ ## Поведінка
14
+
15
+ 1. З тексту джерела збираються п'ять категорій анкорів: усі URL; експортовані константи-рядки з непорожнім значенням; маркери повідомлень про помилки виду `(rule.mdc)`; посилання на json-конфіги проєкту; code-block-приклади з провідного коментаря файлу (де автор зазвичай показує контракт).
16
+ 2. Кожна категорія дедуплікується зі збереженням порядку появи.
17
+ 3. Для промпта анкори форматуються в компактний текстовий блок з інструкціями, де саме їх згадати; якщо анкорів немає взагалі — блок не додається, щоб не вводити модель в оману «обов'язковими» полями.
18
+
19
+ ## Публічний API
20
+
21
+ - `extractAnchors` — текст джерела → категоризовані анкори.
22
+ - `anchorsToPrompt` — анкори → текстовий блок для system-промпта або порожній рядок.
23
+
24
+ ## Гарантії поведінки
25
+
26
+ - Повністю детермінований і read-only; жодних LLM-викликів і мережі.
27
+ - Працює по сирому тексту без AST: дешево і свідомо толерує надлишок (зайвий анкор — менша проблема, ніж пропущений).
@@ -0,0 +1,29 @@
1
+ ---
2
+ docgen:
3
+ source: npm/skills/doc-files/js/docgen-extract.mjs
4
+ crc: 26bb2901
5
+ ---
6
+
7
+ # docgen-extract
8
+
9
+ ## Огляд
10
+
11
+ Детермінований екстрактор фактів про кодовий файл (нуль токенів): з тексту джерела збирається факт-лист, на якому конвеєр будує промпти, маркери поведінки й список заборонених до згадки внутрішніх імен.
12
+
13
+ ## Поведінка
14
+
15
+ 1. Провідний блок-коментар файлу (до першого коду) стає «наміром файлу»; з документувальних коментарів перед кожним експортом витягуються опис, параметри та опис повернення, відкидаючи беззмістовні заглушки.
16
+ 2. Збираються всі експортовані оголошення з безпосередньо передуючими їм коментарями.
17
+ 3. Імпорти класифікуються на stdlib / npm / внутрішні; імена символів, імпортованих із внутрішніх модулів, складають список internalSymbols — модель не має згадувати їх у доці, а скорер штрафує за витік.
18
+ 4. Маркери поведінки визначаються евристиками по тексту: read-only (немає запису у файлову систему), перехоплення помилок, повернення false/null при невдачі, звертання до мережі, кешування, свідомі пропуски шляхів.
19
+ 5. Для розширень поза js/mjs/ts повертається позначка unsupported — конвеєр переходить на one-shot-шлях.
20
+
21
+ ## Публічний API
22
+
23
+ - `extractFacts` — головна точка: текст джерела + шлях → факт-лист `{header, exports, imports, internalSymbols, markers}` або `{unsupported: true}`.
24
+
25
+ ## Гарантії поведінки
26
+
27
+ - Повністю детермінований: однаковий вхід → однаковий факт-лист; жодних LLM-викликів і мережі.
28
+ - Read-only: файл не виконує операцій запису у файлову систему.
29
+ - Евристики свідомо толерують надлишок (зайвий маркер — менша проблема, ніж пропущений).
@@ -0,0 +1,25 @@
1
+ ---
2
+ docgen:
3
+ source: npm/skills/doc-files/js/docgen-files-batch.mjs
4
+ crc: 20a14675
5
+ ---
6
+
7
+ # docgen-files-batch
8
+
9
+ ## Огляд
10
+
11
+ CLI-оркестратор масової генерації файлових док (`doc-files gen` / `doc-files stamp`): черга, вибір цілей, preflight локального сервера, запис док зі свіжою контрольною сумою і degraded-маркером. Уся важка робота живе тут, а не в контексті агента.
12
+
13
+ ## Поведінка
14
+
15
+ 1. Дерево проєкту сканується, цілі обираються за режимом: за замовчуванням — застарілі доки; `--overwrite` — усі; `--retry-degraded` — свіжі за сумою, але з оцінкою нижче порогу. Зріз великого прогону — `--from N --limit M`.
16
+ 2. Перед генерацією — preflight локального сервера: «сервер лежить», «модель не влазить у пам'ять зайнятої машини» чи «потрібен API-ключ» зупиняють прогін одним зрозумілим повідомленням замість лавини помилок по файлах.
17
+ 3. Кожна ціль генерується локальним конвеєром; дока пишеться поряд із джерелом у `docs/` зі свіжою сумою. Якщо оцінка нижча за поріг — у frontmatter додаються оцінка й коди проблем, файл рахується як degraded.
18
+ 4. Підсумок: кількість успішних, degraded і помилкових файлів; за наявності degraded — підказка про `--retry-degraded`. Помилка хоча б одного файлу → exit-код `1`.
19
+ 5. `stamp` детерміновано перештамповує frontmatter у наявних доках без LLM (міграція док без суми), зберігаючи наявні поля якості.
20
+
21
+ ## Гарантії поведінки
22
+
23
+ - Жодних хмарних викликів: збій локальної генерації стає помилкою чи degraded-маркером, а не ескалацією.
24
+ - Доки пишуться атомарно по файлу: успішні цілі не відкочуються через подальші збої.
25
+ - Прогін ніколи не комітить — рішення про фіксацію приймає користувач.
@@ -0,0 +1,30 @@
1
+ ---
2
+ docgen:
3
+ source: npm/skills/doc-files/js/docgen-gen.mjs
4
+ crc: 2d6e5f79
5
+ ---
6
+
7
+ # docgen-gen
8
+
9
+ ## Огляд
10
+
11
+ Генератор однієї файлової доки local-only конвеєра: файл → українська поведінкова md-документація локальною моделлю, з детермінованим скорингом і позначкою degraded замість будь-яких хмарних ескалацій.
12
+
13
+ ## Поведінка
14
+
15
+ 1. З джерела детерміновано витягуються факти (намір файлу, експорти, маркери поведінки) та анкори (URL, константи, маркери помилок, конфіги, приклади з header-коментаря) — без жодного токена.
16
+ 2. Для підтримуваних структур документ збирається посекційно окремими викликами моделі: «Огляд» — лише з фактів, «Поведінка» — єдина секція з кодом у вікні, «Публічний API» — зі списку експортів; «Гарантії поведінки» — детермінований шаблон із маркерів без LLM. Для непідтримуваних структур (`vue`/`py` до появи юніт-шару) — один виклик на весь документ без скорингу.
17
+ 3. Чорнетки секцій проходять детермінований пост-лінт (зрізання сигнатур, обгорток, випадкових заголовків); найвразливіші секції — один цикл критика-редактора.
18
+ 4. Зібраний документ оцінюється детермінованим скорером (наявність огляду, змістовність поведінки, галюцинація кешу, витік внутрішніх імен). Якщо оцінка нижча за поріг — один повторний прогін з вищою температурою, перемагає кращий за оцінкою (вимикається `N_CURSOR_DOCGEN_BEST_OF=0`).
19
+ 5. Результат повертається з оцінкою, списком проблем і прапором degraded; рішення про повторну генерацію приймає batch-обгортка або користувач — конвеєр ніколи не звертається до хмари.
20
+
21
+ ## Публічний API
22
+
23
+ - `generateDoc` — головна точка: шлях файлу → `{ md, ms, score, issues, degraded, model }`.
24
+ - `DEFAULT_LOCAL_MODEL` — модель конвеєра: `N_CURSOR_DOCGEN_MODEL` → каскад локальних тирів → локальний omlx-дефолт напряму.
25
+
26
+ ## Гарантії поведінки
27
+
28
+ - Local-only: жодних хмарних викликів і pre-route за складністю — будь-який файл генерується локальною моделлю.
29
+ - Скоринг і пост-лінт детерміновані: однаковий вхід → однакова оцінка.
30
+ - Помилка транспорту прокидається назовні — не маскується під degraded.
@@ -0,0 +1,32 @@
1
+ ---
2
+ docgen:
3
+ source: npm/skills/doc-files/js/docgen-prompts.mjs
4
+ crc: c454d2a6
5
+ ---
6
+
7
+ # docgen-prompts
8
+
9
+ ## Огляд
10
+
11
+ Промптовий шар local-only конвеєра файлових док: будує messages-набори для секційної генерації, критики й переписування, а секцію «Гарантії поведінки» формує детерміновано без LLM. Весь стиль документа (українська, поведінковість, заборона сигнатур) зашитий у спільний system-блок.
12
+
13
+ ## Поведінка
14
+
15
+ 1. Для кожної секції збирається мінімальний контекст: «Огляд» — лише людиночитний витяг фактів (без коду), «Поведінка» — єдина секція з повним кодом файлу у вікні, «Публічний API» — лише список експортів з їхніми описами. Анкори (URL, константи, маркери, приклади) додаються окремим блоком, коли вони є.
16
+ 2. Факт-лист перекладається в негативні й позитивні твердження для моделі: свідомі пропуски шляхів, read-only, перехоплення помилок, явне «Кешування: НЕМАЄ — не згадуй кеш» — щоб відсікти типові галюцинації ще в промпті.
17
+ 3. Критик отримує чорнетку секції і закритий список критеріїв дефектів (generic-фрази, пропущені анкори, граматика, підзаголовки, скопійовані сигнатури, вигадані факти); відповідь — список проблем або `NONE`. Переписувач отримує чорнетку разом зі списком проблем і повертає лише оновлений текст.
18
+ 4. «Гарантії поведінки» складаються шаблоном з маркерів факт-листа (read-only, fail-safe, кешування, пропуски шляхів, відсутність мережі) — нуль запитів і нуль generic-фраз; за відсутності маркерів — твердження про детермінованість.
19
+
20
+ ## Публічний API
21
+
22
+ - `sectionMessages` — секційні набори messages з мінімальним контекстом під кожну секцію.
23
+ - `criticMessages` / `refineMessages` — пара критика й переписувача для одного циклу уточнення секції.
24
+ - `guaranteesFromMarkers` — детермінований текст секції гарантій з маркерів.
25
+ - `oneShotMessages` — один запит на весь документ для нестандартних структур файлів.
26
+ - `STYLE` — спільний system-блок стилю.
27
+
28
+ ## Гарантії поведінки
29
+
30
+ - Код файлу потрапляє лише у промпт секції «Поведінка» й у one-shot — решта секцій працюють на факт-листі.
31
+ - Формування промптів детерміноване: однакові факти й код → однакові messages.
32
+ - Не звертається до мережі й не виконує LLM-викликів — лише будує тексти.
@@ -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
  ## Огляд
@@ -12,7 +12,7 @@ import { callOmlx, isOmlxModel } from '../../../lib/omlx.mjs'
12
12
  export const MODEL = env.N_CURSOR_FIX_MODEL ?? resolveModel('min')
13
13
  export const MODEL_HEAVY = env.N_CURSOR_FIX_MODEL_HEAVY ?? resolveModel('avg')
14
14
 
15
- const JSON_CODE_BLOCK_RE = /```(?:json)?\s*([\s\S]*?)```/
15
+ const JSON_CODE_BLOCK_RE = /```(?:json)?[ \t]{0,8}\n?([\s\S]*?)```/
16
16
 
17
17
  /**
18
18
  * Витягує відносні шляхи файлів із violation output.
@@ -35,7 +35,7 @@ function extractFilePaths(output) {
35
35
  }
36
36
 
37
37
  // Патерн без workspace: просто path/to/file.ext або ./file.ext
38
- 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
39
39
  for (const m of output.matchAll(re)) {
40
40
  const p = m[1]
41
41
  if (!seen.has(p)) {
@@ -116,7 +116,7 @@ function callModel(prompt, model) {
116
116
  error: [
117
117
  `pi: немає ключа для ${provider}.`,
118
118
  `Встановіть N_CLOUD_MIN_MODEL=provider/model-id`,
119
- `(напр.: 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)`
120
120
  ].join(' ')
121
121
  }
122
122
  }
@@ -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
  ## Огляд