@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
|
@@ -8,7 +8,11 @@ export const STYLE = [
|
|
|
8
8
|
'Заборонено: сигнатури, типи, параметри функцій; перелік stdlib-модулів; опис regex чи внутрішніх приватних імен.'
|
|
9
9
|
].join(' ')
|
|
10
10
|
|
|
11
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* Окремий блок інструкцій з анкорами — підставляється коли вони є.
|
|
13
|
+
* @param {object|null} anchors анкори файлу (або null)
|
|
14
|
+
* @returns {string} текстовий блок для system-промпта або порожній рядок
|
|
15
|
+
*/
|
|
12
16
|
function anchorsBlock(anchors) {
|
|
13
17
|
if (!anchors) return ''
|
|
14
18
|
const txt = anchorsToPrompt(anchors)
|
|
@@ -35,6 +39,12 @@ function factsSummary(facts) {
|
|
|
35
39
|
return lines.join('\n')
|
|
36
40
|
}
|
|
37
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Пара system+user messages для одного виклику.
|
|
44
|
+
* @param {string} system system-промпт
|
|
45
|
+
* @param {string} user user-промпт
|
|
46
|
+
* @returns {Array<{role:string, content:string}>} messages-масив
|
|
47
|
+
*/
|
|
38
48
|
const msgs = (system, user) => [
|
|
39
49
|
{ role: 'system', content: system },
|
|
40
50
|
{ role: 'user', content: user }
|
|
@@ -45,64 +55,68 @@ const msgs = (system, user) => [
|
|
|
45
55
|
* Код потрапляє лише в `behavior`; решта секцій — на факт-листі.
|
|
46
56
|
* @param {object} facts факт-лист про файл
|
|
47
57
|
* @param {string} src вміст файлу
|
|
58
|
+
* @param {object|null} [anchors] анкори файлу для обовʼязкового включення
|
|
48
59
|
* @returns {Array<{key:string, messages:object[], numPredict:number}>} набір секційних промптів
|
|
49
60
|
*/
|
|
50
61
|
export function sectionMessages(facts, src, anchors = null) {
|
|
51
62
|
const factsTxt = factsSummary(facts)
|
|
52
63
|
const anch = anchorsBlock(anchors)
|
|
53
64
|
const multi = (facts.exports?.length || 0) > 1
|
|
54
|
-
const out = []
|
|
55
65
|
|
|
56
66
|
// Огляд — лише факти (без коду)
|
|
57
|
-
|
|
67
|
+
const overview = {
|
|
58
68
|
key: 'overview',
|
|
59
69
|
numPredict: 220,
|
|
60
70
|
messages: msgs(
|
|
61
71
|
`${STYLE}\n\nВІДОМІ ФАКТИ:\n${factsTxt}${anch}`,
|
|
62
72
|
'Напиши вміст секції «Огляд»: 1-3 речення — що файл робить і навіщо існує (роль у системі). Без заголовка, без переліку функцій. Заборонені generic-фрази типу «забезпечує перевірку», «виконує валідацію» — пиши КОНКРЕТНО що саме і за яким контрактом.'
|
|
63
73
|
)
|
|
64
|
-
}
|
|
74
|
+
}
|
|
65
75
|
|
|
66
76
|
// Поведінка — ЄДИНА секція, якій потрібен код
|
|
67
|
-
|
|
77
|
+
const behaviorTask = multi
|
|
78
|
+
? 'для кожної публічної функції — один короткий пункт «що вона робить»'
|
|
79
|
+
: 'нумерований алгоритм у бізнес-термінах'
|
|
80
|
+
const noInternal = facts.internalSymbols?.length
|
|
81
|
+
? ` НЕ згадуй за іменами службові функції: ${facts.internalSymbols.join(', ')}.`
|
|
82
|
+
: ''
|
|
83
|
+
const behavior = {
|
|
68
84
|
key: 'behavior',
|
|
69
85
|
numPredict: 500,
|
|
70
86
|
messages: msgs(
|
|
71
87
|
`${STYLE}\n\nФАЙЛ ${facts.relPath}:\n\`\`\`\n${src}\n\`\`\`\n\nВІДОМІ ФАКТИ:\n${factsTxt}${anch}`,
|
|
72
|
-
`Напиши вміст секції «Поведінка»: ${
|
|
88
|
+
`Напиши вміст секції «Поведінка»: ${behaviorTask}. Якщо у фактах є свідомі пропуски шляхів — згадай їх там, де доречно (не вигадуй інших «не перевіряє»). НЕ пиши аргументи функцій у дужках, без regex.${noInternal} Без заголовка, без додаткових ## чи # підзаголовків усередині секції.`
|
|
73
89
|
)
|
|
74
|
-
}
|
|
90
|
+
}
|
|
75
91
|
|
|
76
92
|
// API — лише список експортів (без коду)
|
|
77
|
-
if (multi
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
})
|
|
93
|
+
if (!multi && !facts.exports?.some(e => e.desc)) return [overview, behavior]
|
|
94
|
+
const list = facts.exports.map(e => `- ${e.name}: ${e.desc || '(сформулюй стисло з наміру файлу)'}`).join('\n')
|
|
95
|
+
const api = {
|
|
96
|
+
key: 'api',
|
|
97
|
+
numPredict: 320,
|
|
98
|
+
messages: msgs(
|
|
99
|
+
`${STYLE}${anch}`,
|
|
100
|
+
`Перепиши цей список як стислі маркери «назва — що робить», СВОЇМИ словами (не копіюй дослівно), без типів і сигнатур. Використовуй РІВНО ці назви, не додавай і не прибирай:\n${list}\nБез заголовка. Без generic-фраз «застосовує логіку», «перевіряє коректність» — пиши конкретно ЩО саме застосовує/перевіряє.`
|
|
101
|
+
)
|
|
87
102
|
}
|
|
88
|
-
|
|
89
|
-
return out
|
|
103
|
+
return [overview, behavior, api]
|
|
90
104
|
}
|
|
91
105
|
|
|
92
106
|
/**
|
|
93
107
|
* E2-step 1 — критик. Перевіряє чорнетку секції на конкретні дефекти.
|
|
94
108
|
* Повертає messages для LLM-запиту: вихід має бути СПИСКОМ issues або словом NONE.
|
|
95
|
-
* @param {'overview'|'behavior'|'api'} sectionKey
|
|
109
|
+
* @param {'overview'|'behavior'|'api'} sectionKey ключ секції
|
|
96
110
|
* @param {string} draft вже згенерована чорнетка секції
|
|
97
111
|
* @param {object} facts факт-лист
|
|
98
|
-
* @param {ReturnType<import('./docgen-extract-anchors.mjs').extractAnchors>} anchors
|
|
99
|
-
* @returns {Array<{role:string,content:string}>}
|
|
112
|
+
* @param {ReturnType<import('./docgen-extract-anchors.mjs').extractAnchors>} anchors анкори файлу
|
|
113
|
+
* @returns {Array<{role:string,content:string}>} messages-масив для критика
|
|
100
114
|
*/
|
|
101
115
|
export function criticMessages(sectionKey, draft, facts, anchors) {
|
|
102
116
|
const anch = anchorsBlock(anchors)
|
|
103
117
|
const criteria = [
|
|
104
118
|
'generic-фрази без конкретики («забезпечує перевірку», «виконує валідацію», «застосовує логіку»)',
|
|
105
|
-
|
|
119
|
+
"пропущені обов'язкові АНКОРИ з контексту (URLs, magic-string constants, error-маркери, конфіги, code-приклади)",
|
|
106
120
|
'граматичні помилки українською («перед їх застосування», «моделіне», англіцизми як «applys», «moduleline»)',
|
|
107
121
|
'h1/h2/h3 підзаголовки всередині секції — їх не повинно бути',
|
|
108
122
|
'дослівна копія JSDoc-сигнатури або параметрів у дужках',
|
|
@@ -122,12 +136,12 @@ export function criticMessages(sectionKey, draft, facts, anchors) {
|
|
|
122
136
|
|
|
123
137
|
/**
|
|
124
138
|
* E2-step 2 — refine. Переписує чорнетку, виправляючи перелічені issues.
|
|
125
|
-
* @param {'overview'|'behavior'|'api'} sectionKey
|
|
126
|
-
* @param {string} draft
|
|
139
|
+
* @param {'overview'|'behavior'|'api'} sectionKey ключ секції
|
|
140
|
+
* @param {string} draft чорнетка секції
|
|
127
141
|
* @param {string} issues список issues від critic
|
|
128
|
-
* @param {object} facts
|
|
129
|
-
* @param {ReturnType<import('./docgen-extract-anchors.mjs').extractAnchors>} anchors
|
|
130
|
-
* @returns {Array<{role:string,content:string}>}
|
|
142
|
+
* @param {object} facts факт-лист
|
|
143
|
+
* @param {ReturnType<import('./docgen-extract-anchors.mjs').extractAnchors>} anchors анкори файлу
|
|
144
|
+
* @returns {Array<{role:string,content:string}>} messages-масив для переписування
|
|
131
145
|
*/
|
|
132
146
|
export function refineMessages(sectionKey, draft, issues, facts, anchors) {
|
|
133
147
|
const anch = anchorsBlock(anchors)
|
|
@@ -146,7 +160,7 @@ export function refineMessages(sectionKey, draft, issues, facts, anchors) {
|
|
|
146
160
|
/**
|
|
147
161
|
* E3 — детермінований шаблон секції «Гарантії поведінки» з facts.markers.
|
|
148
162
|
* НЕ використовує LLM: 0 запитів, 0 галюцинацій, 0 generic-фраз.
|
|
149
|
-
* @param {object} facts
|
|
163
|
+
* @param {object} facts факт-лист
|
|
150
164
|
* @returns {string} текст секції (без `## Гарантії` — це додає assemble())
|
|
151
165
|
*/
|
|
152
166
|
export function guaranteesFromMarkers(facts) {
|
|
@@ -177,14 +191,3 @@ export function oneShotMessages(facts, src) {
|
|
|
177
191
|
`Напиши документацію для файлу. Секції: ## Огляд (1-3 речення), ## Поведінка (нумерований/маркований алгоритм), ${multi ? '## Публічний API (назва + що робить), ' : ''}## Гарантії поведінки.\n\nФАЙЛ ${facts.relPath}:\n\`\`\`\n${src}\n\`\`\``
|
|
178
192
|
)
|
|
179
193
|
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Лише текст user-промпту для one-shot (для хмарного fallback через Anthropic SDK).
|
|
183
|
-
* @param {object} facts факт-лист про файл
|
|
184
|
-
* @param {string} src вміст файлу
|
|
185
|
-
* @returns {string} plain-text user-prompt
|
|
186
|
-
*/
|
|
187
|
-
export function oneShotPromptText(facts, src) {
|
|
188
|
-
const multi = (facts.exports?.length || 0) > 1
|
|
189
|
-
return `Напиши документацію для файлу. Секції: ## Огляд (1-3 речення), ## Поведінка (нумерований/маркований алгоритм), ${multi ? '## Публічний API (назва + що робить), ' : ''}## Гарантії поведінки.\n\nФАЙЛ ${facts.relPath}:\n\`\`\`\n${src}\n\`\`\``
|
|
190
|
-
}
|
|
@@ -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-викликів — лише будує тексти.
|