@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.
- package/.claude-template/settings.template.json +22 -0
- package/.pi-template/extensions/n-cursor-adr/docs/index.md +15 -9
- package/CHANGELOG.md +18 -1
- package/bin/n-cursor.js +73 -16
- package/docs/stryker.config.md +6 -0
- package/docs/vitest.config.md +6 -0
- package/lib/docs/llm.md +29 -0
- package/lib/docs/omlx.md +32 -0
- package/lib/llm.mjs +137 -0
- package/lib/models.mjs +9 -1
- package/lib/omlx.mjs +147 -0
- package/package.json +1 -1
- package/rules/abie/docs/fix.md +6 -0
- package/rules/abie/js/docs/applies.md +6 -0
- package/rules/abie/js/docs/env_dns.md +25 -22
- package/rules/abie/js/docs/firebase_hosting.md +6 -0
- package/rules/abie/js/docs/hc_pairing.md +21 -25
- package/rules/abie/js/docs/ua_http_route.md +27 -19
- package/rules/abie/js/docs/ua_node_selector.md +24 -19
- package/rules/abie/lib/docs/enabled.md +13 -7
- package/rules/abie/lib/docs/env-dns.md +9 -3
- package/rules/abie/lib/docs/hc-yaml.md +6 -0
- package/rules/abie/lib/docs/http-route.md +6 -0
- package/rules/abie/lib/docs/k8s-tree.md +6 -0
- package/rules/abie/lib/docs/kustomization-patches.md +6 -0
- package/rules/abie/lib/docs/overlay-paths.md +6 -0
- package/rules/abie/lib/docs/yaml.md +6 -0
- package/rules/adr/docs/fix.md +6 -0
- package/rules/adr/js/docs/hooks.md +29 -244
- package/rules/bun/docs/fix.md +6 -0
- package/rules/bun/js/docs/layout.md +37 -375
- package/rules/capacitor/docs/fix.md +22 -108
- package/rules/capacitor/js/docs/platforms.md +62 -268
- package/rules/changelog/docs/fix.md +6 -0
- package/rules/changelog/lib/docs/package-manifest.md +6 -0
- package/rules/ci4/docs/fix.md +23 -165
- package/rules/ci4/js/docs/marksman_config.md +9 -1
- package/rules/docker/docs/fix.md +6 -0
- package/rules/docker/js/docs/lint.md +55 -239
- package/rules/docker/lib/docs/docker-hadolint.md +6 -0
- package/rules/docker/lib/docs/docker-mirror.md +6 -0
- package/rules/docker/lib/docs/docker-native-addon.md +6 -0
- package/rules/docker/lib/docs/docker-nginx-user.md +6 -0
- package/rules/docker/lint/docs/lint.md +9 -1
- package/rules/efes/docs/fix.md +6 -0
- package/rules/ga/lint/docs/lint.md +6 -0
- package/rules/graphql/docs/fix.md +6 -0
- package/rules/graphql/lib/docs/graphql-gql-scan.md +6 -0
- package/rules/image-avif/docs/fix.md +6 -0
- package/rules/image-avif/js/docs/avif_generation.md +6 -0
- package/rules/js-bun-db/lib/docs/bun-sql-scan.md +9 -3
- package/rules/js-bun-redis/lib/docs/redis-imports.md +6 -0
- package/rules/js-lint/js/docs/utils_imports.md +6 -0
- package/rules/js-lint-ci/docs/fix.md +7 -1
- package/rules/js-mssql/docs/fix.md +6 -0
- package/rules/js-mssql/lib/docs/mssql-pool-scan.md +6 -0
- package/rules/js-run/docs/fix.md +6 -0
- package/rules/js-run/lib/docs/bunyan-imports.md +6 -0
- package/rules/js-run/lib/docs/check-env-scan.md +6 -0
- package/rules/js-run/lib/docs/conn-file-rules.md +6 -0
- package/rules/js-run/lib/docs/conn-imports-scan.md +6 -0
- package/rules/js-run/lib/docs/promise-settimeout-scan.md +6 -0
- package/rules/js-run/lib/docs/temporal-scan.md +6 -0
- package/rules/k8s/docs/fix.md +6 -0
- package/rules/k8s/lint/docs/lint.md +6 -0
- package/rules/nginx-default-tpl/docs/fix.md +6 -0
- package/rules/npm-module/js/docs/header_doc_pointer.md +7 -0
- package/rules/npm-module/js/header_doc_pointer.mjs +2 -8
- package/rules/php/docs/fix.md +6 -0
- package/rules/php/lint/docs/lint.md +6 -0
- package/rules/python/docs/fix.md +6 -0
- package/rules/python/lint/docs/lint.md +6 -0
- package/rules/rego/lint/docs/lint.md +6 -0
- package/rules/release/docs/change.md +6 -0
- package/rules/release/docs/fix.md +6 -0
- package/rules/release/docs/release.md +6 -0
- package/rules/release/lib/docs/aggregate.md +6 -0
- package/rules/release/lib/docs/change-file.md +6 -0
- package/rules/release/lib/docs/fallback.md +6 -0
- package/rules/rust/lib/docs/has-cargo-toml.md +6 -0
- package/rules/security/docs/fix.md +7 -1
- package/rules/security/js/docs/lint.md +6 -0
- package/rules/style-lint/docs/fix.md +6 -0
- package/rules/tauri/docs/fix.md +6 -0
- package/rules/test/docs/fix.md +6 -0
- package/rules/test/js/data/stryker_config/docs/stryker-vue-macros-ignorer.md +6 -0
- package/rules/test/js/data/stryker_config/docs/stryker.config.baseline.md +6 -0
- package/rules/test/js/data/stryker_config/docs/stryker.config.vue.baseline.md +6 -0
- package/rules/test/js/data/vitest_config/docs/vitest.config.baseline.md +6 -0
- package/rules/text/docs/fix.md +6 -0
- package/rules/text/lint/docs/lint.md +6 -0
- package/rules/text/lint/docs/run-dotenv-linter.md +6 -0
- package/rules/text/lint/docs/run-shellcheck.md +6 -0
- package/rules/text/lint/docs/run-v8r.md +6 -0
- package/rules/vue/lib/docs/vue-forbidden-imports.md +6 -0
- package/scripts/coverage-classify/cache.mjs +1 -1
- package/scripts/coverage-classify/docs/apply.md +6 -0
- package/scripts/coverage-classify/docs/cache.md +6 -0
- package/scripts/coverage-classify/docs/prompt.md +6 -0
- package/scripts/coverage-classify/docs/verdict-schema.md +6 -0
- package/scripts/coverage-classify/index.mjs +24 -15
- package/scripts/coverage-classify/prompt.mjs +1 -1
- package/scripts/coverage-fix-extract.mjs +1 -1
- package/scripts/coverage-fix.mjs +2 -1
- package/scripts/docs/auto-skills.md +6 -0
- package/scripts/docs/build-agents-commands.md +7 -1
- package/scripts/docs/cli-entry.md +6 -0
- package/scripts/docs/coverage-fix-extract.md +6 -0
- package/scripts/docs/coverage-fix.md +6 -0
- package/scripts/docs/ensure-nitra-cursor-dev-dependencies.md +6 -0
- package/scripts/docs/lint-cli.md +6 -0
- package/scripts/docs/post-tool-use-fix.md +6 -0
- package/scripts/docs/rename-yaml-extensions.md +6 -0
- package/scripts/docs/skills-cli.md +6 -0
- package/scripts/docs/sync-setup-bun-deps-action.md +6 -0
- package/scripts/docs/upgrade-nitra-cursor-and-install.md +6 -0
- package/scripts/docs/worktree-cli.md +6 -0
- package/scripts/lib/docs/assert-project-root.md +6 -0
- package/scripts/lib/docs/check-mdc-template-refs.md +6 -0
- package/scripts/lib/docs/check-reporter.md +6 -0
- package/scripts/lib/docs/diff-added-lines.md +6 -0
- package/scripts/lib/docs/discover-check-rules-from-cursor.md +6 -0
- package/scripts/lib/docs/discover-checkable-rules.md +6 -0
- package/scripts/lib/docs/ensure-tool.md +6 -0
- package/scripts/lib/docs/generated-markdown.md +6 -0
- package/scripts/lib/docs/gha-workflow.md +6 -0
- package/scripts/lib/docs/inline-template-links.md +6 -0
- package/scripts/lib/docs/list-rule-ids.md +6 -0
- package/scripts/lib/docs/load-cursor-config.md +6 -0
- package/scripts/lib/docs/mirror-parity.md +6 -0
- package/scripts/lib/docs/read-n-cursor-config-lite.md +6 -0
- package/scripts/lib/docs/resolve-target-files.md +6 -0
- package/scripts/lib/docs/root-notice.md +6 -0
- package/scripts/lib/docs/rule-meta-helpers.md +6 -0
- package/scripts/lib/docs/rule-meta.md +6 -0
- package/scripts/lib/docs/run-conftest-batch.md +6 -0
- package/scripts/lib/docs/run-lint-step.md +6 -0
- package/scripts/lib/docs/run-rule-cli.md +6 -0
- package/scripts/lib/docs/run-rule.md +6 -0
- package/scripts/lib/docs/run-standard-lint.md +6 -0
- package/scripts/lib/docs/run-standard-rule.md +6 -0
- package/scripts/lib/docs/skill-meta.md +6 -0
- package/scripts/lib/docs/template.md +6 -0
- package/scripts/lib/docs/timing-summary.md +6 -0
- package/scripts/lib/docs/workspaces.md +6 -0
- package/scripts/lib/docs/worktree-notice.md +6 -0
- package/scripts/lib/docs/worktree.md +6 -0
- package/scripts/lib/mirror-parity.mjs +1 -1
- package/scripts/lib/root-notice.mjs +1 -1
- package/scripts/lib/worktree-notice.mjs +5 -5
- package/scripts/lib/worktree.mjs +1 -1
- package/scripts/sync-claude-config.mjs +3 -0
- package/scripts/utils/docs/ast-scan-utils.md +6 -0
- package/scripts/utils/docs/ensure-gitignore-entries.md +6 -0
- package/scripts/utils/docs/find-package-json-paths.md +6 -0
- package/scripts/utils/docs/lock-cache-dir.md +6 -0
- package/scripts/utils/docs/pass.md +6 -0
- package/scripts/utils/docs/resolve-cargo-manifest.md +6 -0
- package/scripts/utils/docs/resolve-cmd.md +6 -0
- package/scripts/utils/docs/resolve-js-root.md +6 -0
- package/scripts/utils/docs/test-helpers.md +6 -0
- package/scripts/utils/docs/walk-cache.md +6 -0
- package/scripts/utils/docs/walkDir.md +6 -0
- package/scripts/utils/docs/worktree-fingerprint.md +6 -0
- package/scripts/utils/resolve-js-root.mjs +1 -1
- package/skills/doc-aggregate/SKILL.md +129 -0
- package/skills/doc-aggregate/js/docgen-ignore.mjs +9 -0
- package/skills/{docgen → doc-aggregate}/js/docgen-scan.mjs +22 -67
- package/skills/doc-aggregate/js/docs/docgen-ignore.md +21 -0
- package/skills/doc-files/SKILL.md +100 -0
- package/skills/doc-files/js/docgen-crc.mjs +164 -0
- package/skills/{docgen → doc-files}/js/docgen-extract-anchors.mjs +24 -15
- package/skills/{docgen → doc-files}/js/docgen-extract.mjs +15 -9
- package/skills/doc-files/js/docgen-files-batch.mjs +181 -0
- package/skills/doc-files/js/docgen-gen.mjs +291 -0
- package/skills/{docgen → doc-files}/js/docgen-prompts.mjs +43 -40
- package/skills/doc-files/js/docgen-scan.mjs +298 -0
- package/skills/doc-files/js/docs/docgen-crc.md +32 -0
- package/skills/doc-files/js/docs/docgen-extract-anchors.md +27 -0
- package/skills/doc-files/js/docs/docgen-extract.md +29 -0
- package/skills/doc-files/js/docs/docgen-files-batch.md +25 -0
- package/skills/doc-files/js/docs/docgen-gen.md +30 -0
- package/skills/doc-files/js/docs/docgen-prompts.md +32 -0
- package/skills/doc-files/js/docs/docgen-scan.md +25 -0
- package/skills/doc-files/meta.json +1 -0
- package/skills/fix/js/docs/llm-worker.md +6 -0
- package/skills/fix/js/docs/orchestrator.md +6 -0
- package/skills/fix/js/llm-worker.mjs +23 -14
- package/skills/fix/js/orchestrator.mjs +1 -1
- package/skills/start-check/js/check.mjs +5 -3
- package/skills/start-check/js/docs/check.md +6 -0
- package/skills/docgen/SKILL.md +0 -224
- package/skills/docgen/bench/etalon/firebase_hosting.md +0 -19
- package/skills/docgen/bench/etalon/k8s-tree.md +0 -24
- package/skills/docgen/bench/etalon/overlay-paths.md +0 -24
- package/skills/docgen/js/docgen-batch-omlx.mjs +0 -82
- package/skills/docgen/js/docgen-batch.mjs +0 -95
- package/skills/docgen/js/docgen-compare-pi-vs-direct.mjs +0 -95
- package/skills/docgen/js/docgen-gen.mjs +0 -339
- package/skills/docgen/js/docs/docgen-extract.md +0 -28
- package/skills/docgen/js/docs/docgen-gen.md +0 -41
- package/skills/docgen/js/docs/docgen-ignore.md +0 -24
- package/skills/docgen/js/docs/docgen-prompts.md +0 -24
- package/skills/docgen/js/docs/docgen-scan.md +0 -48
- /package/skills/{docgen → doc-aggregate}/meta.json +0 -0
- /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 }
|
|
@@ -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)
|
|
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)(
|
|
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
|
-
*
|
|
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 }}
|
|
93
|
+
* @param {string} model назва моделі (provider/id, `omlx/...` або '')
|
|
94
|
+
* @returns {{ text: string, error?: string }} текст відповіді або повідомлення про помилку
|
|
93
95
|
*/
|
|
94
|
-
function
|
|
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-відповідь від
|
|
121
|
-
*
|
|
122
|
-
* @param {string} text сирий
|
|
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 і викликаємо
|
|
195
|
+
// 3. Будуємо prompt і викликаємо модель
|
|
187
196
|
const prompt = buildPrompt(ruleId, ruleMdc, violationOutput, files)
|
|
188
|
-
const { text, error:
|
|
197
|
+
const { text, error: modelError } = callModel(prompt, model)
|
|
189
198
|
|
|
190
|
-
if (
|
|
191
|
-
if (!text) return { ok: false, error: '
|
|
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 :
|
|
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
|
-
|
|
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,
|
package/skills/docgen/SKILL.md
DELETED
|
@@ -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
|
-
}
|