@nitra/cursor 5.3.2 → 5.3.4

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 (61) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/lib/docs/llm.md +23 -12
  3. package/package.json +1 -1
  4. package/rules/abie/fix.mjs +1 -2
  5. package/rules/adr/fix.mjs +1 -2
  6. package/rules/bun/fix.mjs +1 -2
  7. package/rules/capacitor/fix.mjs +1 -2
  8. package/rules/capacitor/js/platforms.mjs +0 -2
  9. package/rules/changelog/fix.mjs +1 -2
  10. package/rules/ci4/fix.mjs +1 -2
  11. package/rules/docker/fix.mjs +1 -2
  12. package/rules/efes/fix.mjs +1 -2
  13. package/rules/feedback/fix.mjs +1 -2
  14. package/rules/ga/fix.mjs +1 -2
  15. package/rules/graphql/fix.mjs +1 -2
  16. package/rules/hasura/fix.mjs +1 -2
  17. package/rules/image-avif/fix.mjs +1 -2
  18. package/rules/image-compress/fix.mjs +1 -2
  19. package/rules/js-bun-db/fix.mjs +1 -2
  20. package/rules/js-bun-redis/fix.mjs +1 -2
  21. package/rules/js-lint/fix.mjs +1 -2
  22. package/rules/js-lint-ci/fix.mjs +1 -2
  23. package/rules/js-mssql/fix.mjs +1 -2
  24. package/rules/js-run/fix.mjs +1 -2
  25. package/rules/k8s/fix.mjs +1 -2
  26. package/rules/k8s/js/manifests.mjs +1 -5
  27. package/rules/nginx-default-tpl/fix.mjs +1 -2
  28. package/rules/npm-module/fix.mjs +1 -2
  29. package/rules/npm-module/js/package_structure.mjs +0 -1
  30. package/rules/php/fix.mjs +1 -2
  31. package/rules/python/fix.mjs +1 -2
  32. package/rules/rego/fix.mjs +1 -2
  33. package/rules/release/fix.mjs +1 -2
  34. package/rules/rust/fix.mjs +1 -2
  35. package/rules/security/fix.mjs +1 -2
  36. package/rules/style-lint/fix.mjs +1 -2
  37. package/rules/tauri/fix.mjs +1 -2
  38. package/rules/test/coverage/coverage.mjs +0 -2
  39. package/rules/test/fix.mjs +1 -2
  40. package/rules/text/fix.mjs +1 -2
  41. package/rules/vue/fix.mjs +1 -2
  42. package/rules/worktree/fix.mjs +1 -2
  43. package/scripts/lib/run-rule.mjs +0 -2
  44. package/scripts/lint-cli.mjs +0 -1
  45. package/scripts/utils/with-lock.mjs +0 -1
  46. package/skills/doc-aggregate/js/docgen-scan.mjs +17 -18
  47. package/skills/doc-files/.changes/260612-0002.md +5 -0
  48. package/skills/doc-files/.changes/260612-0006.md +5 -0
  49. package/skills/doc-files/.changes/260612-0008.md +5 -0
  50. package/skills/doc-files/.changes/260612-0012.md +5 -0
  51. package/skills/doc-files/js/docgen-extract.mjs +136 -0
  52. package/skills/doc-files/js/docgen-prompts.mjs +2 -2
  53. package/skills/doc-files/js/docgen-scan.mjs +21 -22
  54. package/skills/doc-files/js/docs/docgen-extract-anchors.md +28 -10
  55. package/skills/doc-files/js/docs/docgen-extract.md +22 -12
  56. package/skills/doc-files/js/docs/docgen-files-batch.md +21 -11
  57. package/skills/doc-files/js/docs/docgen-gen.md +29 -13
  58. package/skills/doc-files/js/docs/docgen-ignore.md +37 -0
  59. package/skills/doc-files/js/docs/units-rs.md +35 -0
  60. package/skills/doc-files/js/units-rs.mjs +213 -0
  61. package/skills/doc-files/js/units.mjs +4 -3
@@ -1,30 +1,46 @@
1
1
  ---
2
2
  docgen:
3
3
  source: npm/skills/doc-files/js/docgen-gen.mjs
4
- crc: 2d6e5f79
4
+ crc: e2af04d6
5
+ score: 100
5
6
  ---
6
7
 
7
- # docgen-gen
8
+ # docgen-gen.mjs
8
9
 
9
10
  ## Огляд
10
11
 
11
- Генератор однієї файлової доки local-only конвеєра: файл → українська поведінкова md-документація локальною моделлю, з детермінованим скорингом і позначкою degraded замість будь-яких хмарних ескалацій.
12
+ Огляд
13
+ Публічні функції виконують операції з текстом та оцінками. Вони включають виділення коду, вставлення інформації та генерацію документів на основі визначених параметрів.
12
14
 
13
15
  ## Поведінка
14
16
 
15
- 1. З джерела детерміновано витягуються факти (намір файлу, експорти, маркери поведінки) та анкори (URL, константи, маркери помилок, конфіги, приклади з header-коментаря) — без жодного токена.
16
- 2. Для підтримуваних структур документ збирається посекційно окремими викликами моделі: «Огляд» — лише з фактів, «Поведінка» — єдина секція з кодом у вікні, «Публічний API» — зі списку експортів; «Гарантії поведінки» — детермінований шаблон із маркерів без LLM. Для непідтримуваних структур (`vue`/`py` до появи юніт-шару) — один виклик на весь документ без скорингу.
17
- 3. Чорнетки секцій проходять детермінований пост-лінт (зрізання сигнатур, обгорток, випадкових заголовків); найвразливіші секції — один цикл критика-редактора.
18
- 4. Зібраний документ оцінюється детермінованим скорером (наявність огляду, змістовність поведінки, галюцинація кешу, витік внутрішніх імен). Якщо оцінка нижча за поріг — один повторний прогін з вищою температурою, перемагає кращий за оцінкою (вимикається `N_CURSOR_DOCGEN_BEST_OF=0`).
19
- 5. Результат повертається з оцінкою, списком проблем і прапором degraded; рішення про повторну генерацію приймає batch-обгортка або користувач — конвеєр ніколи не звертається до хмари.
17
+ splitProtected
18
+ Вибирає та видаляє код-фенс-обгортку з секції
19
+
20
+ insertProtected
21
+ Вставляє захищений блок Призначення після заголовка Огляд
22
+
23
+ scoreDoc
24
+ Перевіряє вихід проти фактів і повертає оцінку та список проблем
25
+
26
+ DEFAULT_LOCAL_MODEL
27
+ Повертає дефолтну модель для роботи
28
+
29
+ generateDoc
30
+ Генерує документ з детермінованою оцінкою та метаданими
20
31
 
21
32
  ## Публічний API
22
33
 
23
- - `generateDoc` головна точка: шлях файлу `{ md, ms, score, issues, degraded, model }`.
24
- - `DEFAULT_LOCAL_MODEL` модель конвеєра: `N_CURSOR_DOCGEN_MODEL` каскад локальних тирів локальний omlx-дефолт напряму.
34
+ splitProtectedВідокремлює захищену секцію `## Призначення` (Варіант B). Межа — наступний `## ` і `###` не обриває блок. (abie.mdc)
35
+ insertProtectedВставляє захищений блок `## Призначення` одразу після H1 (фіксована позиція). (abie.mdc)
36
+ scoreDoc — Stage 2.5 — Детермінований скоринг (0 токенів): перевіряє вихід проти фактів. (abie.mdc)
37
+ DEFAULT_LOCAL_MODEL — Дефолтна модель: N_CURSOR_DOCGEN_MODEL → resolveModel → omlx напряму. Останній fallback гарантує локальний виклик без змін середовища (через pi CLI той самий локальний виклик виміряно повільніший на ~46%). (abie.mdc)
38
+ generateDoc — Головний API: файл → md-дока з det-оцінкою. (abie.mdc)
25
39
 
26
40
  ## Гарантії поведінки
27
41
 
28
- - Local-only: жодних хмарних викликів і pre-route за складністю — будь-який файл генерується локальною моделлю.
29
- - Скоринг і пост-лінт детерміновані: однаковий вхід → однакова оцінка.
30
- - Помилка транспорту прокидається назовні не маскується під degraded.
42
+ - Read-only: файл не виконує операцій запису у файлову систему.
43
+ - Перехоплює помилки і не пропускає винятків назовні (fail-safe).
44
+ - За невдачі повертає значення помилки (`false`/`null`/`Err`) замість генерування винятку чи паніки.
45
+ - Кешує результати в межах одного прогону.
46
+ - Не звертається до мережі.
@@ -0,0 +1,37 @@
1
+ ---
2
+ docgen:
3
+ source: npm/skills/doc-files/js/docgen-ignore.mjs
4
+ crc: f9206fe0
5
+ score: 100
6
+ ---
7
+
8
+ # docgen-ignore.mjs
9
+
10
+ ## Огляд
11
+
12
+ DOCGEN_IGNORE_GLOBS
13
+ Список шляхів, які docgen повинен ігнорувати.
14
+
15
+ isDocgenIgnored
16
+ Перевіряє, чи вказаний шлях знаходиться у списку ігнорованих шляхів. Повертає булеве значення.
17
+
18
+ ## Поведінка
19
+
20
+ DOCGEN_IGNORE_GLOBS
21
+ Базовий список glob-ів для docgen ignore
22
+
23
+ isDocgenIgnored
24
+ Перевіряє, чи шлях має бути пропущений docgen
25
+
26
+ ## Публічний API
27
+
28
+ DOCGEN_IGNORE_GLOBS — Базовий список glob-ів для ігнорування у `docgen`.
29
+ isDocgenIgnored — Визначає, чи шлях повинен бути пропущений `docgen`. Для `kind = 'dir'` працює і на підкаталоги, наприклад, `**\\/demo/**` спрацьовує на `demo/x` під час рекурсивного обходу.
30
+
31
+ ## Гарантії поведінки
32
+
33
+ - Read-only: файл не виконує операцій запису у файлову систему.
34
+ - За невдачі повертає значення помилки (`false`/`null`/`Err`) замість генерування винятку чи паніки.
35
+ - Кешує результати в межах одного прогону.
36
+ - Свідомо пропускає шляхи: `.git`, `node_modules`.
37
+ - Не звертається до мережі.
@@ -0,0 +1,35 @@
1
+ ---
2
+ docgen:
3
+ source: npm/skills/doc-files/js/units-rs.mjs
4
+ crc: 11099381
5
+ score: 100
6
+ ---
7
+
8
+ # units-rs.mjs
9
+
10
+ ## Огляд
11
+
12
+ Файл аналізує рядки для визначення структури та елементів модуля. Він ітерує по рядках для визначення глибини, обробляє рядкові літерали для визначення зміщення, змінює глибину при зустрічі відкриваючої чи закриваючої фігу, видаляє відкриті блоки зі стека, перевіряє наявність атрибутів експонування, визначає декларації на верхньому рівні чи в модулях, а також витягує тіло функції та збирає виклики інших юнітів у тілі функції.
13
+
14
+ ## Поведінка
15
+
16
+ 1. Скан файлу по рядках.
17
+ 2. Ітерація по рядках для визначення глибини.
18
+ 3. Обробка рядкових літералів для визначення зміщення.
19
+ 4. Зміна глибини при зустрічі відкриваючої фігу.
20
+ 5. Зміна глибини при зустрічі закриваючої фігу.
21
+ 6. Видалення відкритих блоків з стека.
22
+ 7. Перевірка наявності атрибутів експонування.
23
+ 8. Визначення декларацій на верхньому рівні або в модулях.
24
+ 9. Визначення публічних функцій, структур, перерахувань, трейтів, типів.
25
+ 10. Витягування тіла функції через пошук закриваючої фігу.
26
+ 11. Збір викликів інших юнітів у тілі функції.
27
+
28
+ ## Публічний API
29
+
30
+ extractUnitsRs — Визначає top-level і impl-методи через підрахунок дужок по рядках. Обмеження: рядкові літерали з `{`/`}` всередині `{}` можуть дати хибну глибину.
31
+
32
+ ## Гарантії поведінки
33
+
34
+ - Read-only: файл не виконує операцій запису у файлову систему.
35
+ - Не звертається до мережі.
@@ -0,0 +1,213 @@
1
+ /** @see ./docs/units-rs.md */
2
+
3
+ /**
4
+ * Пропускає рядковий літерал `"..."` (з escape-послідовностями).
5
+ * @param {string} src вміст файлу
6
+ * @param {number} i позиція відкриваючого `"`
7
+ * @returns {number} позиція ПІСЛЯ закриваючого `"`
8
+ */
9
+ function skipString(src, i) {
10
+ i++ // відкриваючий "
11
+ while (i < src.length) {
12
+ if (src[i] === '\\') { i += 2; continue }
13
+ if (src[i] === '"') return i + 1
14
+ i++
15
+ }
16
+ return i
17
+ }
18
+
19
+ /**
20
+ * Знаходить індекс закриваючої `}` для відкриваючої `{` на позиції `start`.
21
+ * Правильно пропускає рядки/блочні коментарі та рядкові літерали.
22
+ * @param {string} src вміст файлу
23
+ * @param {number} start позиція відкриваючої `{`
24
+ * @returns {number} індекс `}` або -1, якщо не знайдено
25
+ */
26
+ function findClosingBrace(src, start) {
27
+ let depth = 0
28
+ let i = start
29
+ while (i < src.length) {
30
+ const ch = src[i]
31
+ if (ch === '/' && src[i + 1] === '/') {
32
+ const nl = src.indexOf('\n', i)
33
+ i = nl === -1 ? src.length : nl + 1
34
+ continue
35
+ }
36
+ if (ch === '/' && src[i + 1] === '*') {
37
+ const end = src.indexOf('*/', i + 2)
38
+ i = end === -1 ? src.length : end + 2
39
+ continue
40
+ }
41
+ if (ch === '"') { i = skipString(src, i); continue }
42
+ if (ch === '{') { depth++; i++; continue }
43
+ if (ch === '}') {
44
+ depth--
45
+ if (depth === 0) return i
46
+ i++
47
+ continue
48
+ }
49
+ i++
50
+ }
51
+ return -1
52
+ }
53
+
54
+ /**
55
+ * Видобуває `///` doc-рядки безпосередньо перед рядком `lineIdx`.
56
+ * Сканує назад через `///`, `#[...]` та пусті рядки.
57
+ * @param {string[]} lines рядки файлу
58
+ * @param {number} lineIdx рядок декларації
59
+ * @returns {string} склеєний опис або ''
60
+ */
61
+ function docBefore(lines, lineIdx) {
62
+ const doc = []
63
+ for (let i = lineIdx - 1; i >= 0; i--) {
64
+ const t = lines[i].trim()
65
+ if (t.startsWith('///')) {
66
+ doc.unshift(t.slice(3).trim())
67
+ } else if (t.startsWith('#[') || t.startsWith('#![') || t === '') {
68
+ // пропустити атрибути та пусті рядки
69
+ } else {
70
+ break
71
+ }
72
+ }
73
+ return doc.join(' ').trim()
74
+ }
75
+
76
+ // Pub-items: pub fn / pub struct / pub enum / pub trait / pub type
77
+ // Також ловить fn без pub (для localSymbols і impl-методів)
78
+ const ITEM_RE = /^[ \t]*(pub(?:\([^)]*\))?\s+)?(?:async\s+)?(?:unsafe\s+)?(fn|struct|enum|trait|type)\s+(\w+)/
79
+
80
+ // impl Type { або impl<T> Trait for Type {
81
+ const IMPL_RE = /^[ \t]*(?:pub\s+)?impl(?:<[^>]*>)?\s+(?:(?:\w[\w:<>, ]*\s+for\s+))?(\w+)/
82
+
83
+ // Підозрілі exposure-атрибути, що роблять непуб-fn фактично публічними
84
+ const EXPOSURE_ATTR_RE = /#\[(?:tauri::command|wasm_bindgen|uniffi::export|pyo3::pyfunction|napi)/
85
+
86
+ // Базовий виклик fn-імені (для call-graph всередині юніта)
87
+ const CALL_RE = /\b([a-z_]\w*)\s*\(/g
88
+
89
+ /**
90
+ * Юніт-екстрактор для `.rs` файлів.
91
+ * Визначає top-level і impl-методи через підрахунок дужок по рядках.
92
+ * Відомі обмеження: рядкові літерали з `{`/`}` всередині `{}` можуть дати
93
+ * хибну глибину (рідкісно в реальному Rust-коді з rustfmt).
94
+ * @param {string} src вміст файлу
95
+ * @param {string} [_relPath] резервний (не використовується)
96
+ * @returns {Array<{name:string, kind:string, exported:boolean, implName:string|null, span:{start:number,end:number}, body:string, calls:string[], doc:string}>|null}
97
+ */
98
+ export function extractUnitsRs(src, _relPath) {
99
+ const lines = src.split('\n')
100
+ const units = []
101
+ let depth = 0
102
+ let lineOffset = 0
103
+ // Стек відкритих impl: { typeName, openDepth }
104
+ const implStack = []
105
+ // Флаг: наступний fn отримує exposure (через #[tauri::command] тощо)
106
+ let nextFnExposed = false
107
+
108
+ for (let li = 0; li < lines.length; li++) {
109
+ const line = lines[li]
110
+ const depthAtStart = depth
111
+
112
+ // Підраховуємо `{` і `}` в рядку (пропускаємо рядкові коментарі та рядки)
113
+ let j = 0
114
+ while (j < line.length) {
115
+ const ch = line[j]
116
+ if (ch === '/' && line[j + 1] === '/') break
117
+ if (ch === '"') {
118
+ j++
119
+ while (j < line.length && line[j] !== '"') {
120
+ if (line[j] === '\\') j++
121
+ j++
122
+ }
123
+ j++
124
+ continue
125
+ }
126
+ if (ch === '{') depth++
127
+ else if (ch === '}') depth--
128
+ j++
129
+ }
130
+
131
+ // Закриті impl-блоки прибираємо зі стека
132
+ while (implStack.length > 0 && implStack[implStack.length - 1].openDepth > depth) {
133
+ implStack.pop()
134
+ }
135
+
136
+ const currentImpl = implStack.at(-1)?.typeName ?? null
137
+
138
+ // Перевіряємо exposure-атрибути
139
+ if (EXPOSURE_ATTR_RE.test(line)) {
140
+ nextFnExposed = true
141
+ }
142
+
143
+ // Impl-декларація (зазвичай глибина 0, але може бути в mod)
144
+ if (depthAtStart <= 1) {
145
+ const implM = line.match(IMPL_RE)
146
+ if (implM && line.includes('{')) {
147
+ implStack.push({ typeName: implM[1], openDepth: depth })
148
+ }
149
+ }
150
+
151
+ // Елементи на глибині 0 (top-level) і 1 (всередині impl)
152
+ if (depthAtStart <= 1) {
153
+ const m = line.match(ITEM_RE)
154
+ if (m) {
155
+ const isPub = Boolean(m[1]) || (m[2] === 'fn' && nextFnExposed)
156
+ if (m[2] === 'fn') nextFnExposed = false
157
+ const kind = m[2]
158
+ const name = m[3]
159
+ const doc = docBefore(lines, li)
160
+
161
+ // Витягуємо тіло через findClosingBrace для fn/struct/enum/trait
162
+ let body = ''
163
+ let itemEnd = lineOffset + line.length
164
+ if (kind !== 'type') {
165
+ const openBraceIdx = src.indexOf('{', lineOffset)
166
+ // Шукаємо `{` не далі ніж через 3 рядки від початку декларації
167
+ const threeLines = lines.slice(li, li + 3).join('\n').length
168
+ if (openBraceIdx !== -1 && openBraceIdx - lineOffset <= threeLines) {
169
+ const closeIdx = findClosingBrace(src, openBraceIdx)
170
+ if (closeIdx !== -1) {
171
+ itemEnd = closeIdx + 1
172
+ body = src.slice(lineOffset, itemEnd)
173
+ }
174
+ }
175
+ }
176
+
177
+ units.push({
178
+ name,
179
+ kind,
180
+ exported: isPub,
181
+ implName: depthAtStart === 1 ? currentImpl : null,
182
+ span: { start: lineOffset, end: itemEnd },
183
+ body,
184
+ calls: [],
185
+ doc
186
+ })
187
+ } else {
188
+ // Рядок не є item — скидаємо exposure-флаг якщо не атрибут
189
+ const t = line.trim()
190
+ if (!t.startsWith('#[') && !t.startsWith('#![') && !t.startsWith('///') && t !== '') {
191
+ nextFnExposed = false
192
+ }
193
+ }
194
+ }
195
+
196
+ lineOffset += line.length + 1 // +1 для '\n'
197
+ }
198
+
199
+ // Базовий call-graph: виклики інших юнітів цього файлу
200
+ const unitNames = new Set(units.map(u => u.name))
201
+ for (const u of units) {
202
+ if (!u.body) continue
203
+ const calls = new Set()
204
+ let cm
205
+ const re = new RegExp(CALL_RE.source, 'g')
206
+ while ((cm = re.exec(u.body)) !== null) {
207
+ if (unitNames.has(cm[1]) && cm[1] !== u.name) calls.add(cm[1])
208
+ }
209
+ u.calls = [...calls]
210
+ }
211
+
212
+ return units.length > 0 ? units : null
213
+ }
@@ -1,13 +1,13 @@
1
1
  /** @see ./docs/units.md */
2
2
 
3
3
  import { extractUnitsJs } from './units-js.mjs'
4
+ import { extractUnitsRs } from './units-rs.mjs'
4
5
 
5
6
  const JS_EXT = new Set(['js', 'mjs', 'ts', 'jsx', 'tsx', 'cts', 'mts'])
6
7
 
7
8
  /**
8
- * Мовно-агностичний фасад юніт-шару (Інкремент 1). Диспатчить за розширенням:
9
- * js/mjs/ts → oxc; vue/py додаються наступними кроками (поки `null` → виклик
10
- * відкочується на whole-file шлях, як і раніше).
9
+ * Мовно-агностичний фасад юніт-шару. Диспатчить за розширенням:
10
+ * js/mjs/ts → oxc AST; rs → regex+brace-counting; vue/py null (whole-file шлях).
11
11
  * @param {string} src вміст файлу
12
12
  * @param {string} relPath шлях файлу
13
13
  * @returns {Array<object>|null} юніти або null, якщо мова ще не підтримана / файл не парситься
@@ -15,5 +15,6 @@ const JS_EXT = new Set(['js', 'mjs', 'ts', 'jsx', 'tsx', 'cts', 'mts'])
15
15
  export function extractUnits(src, relPath) {
16
16
  const ext = (relPath.split('.').pop() || '').toLowerCase()
17
17
  if (JS_EXT.has(ext)) return extractUnitsJs(src, relPath)
18
+ if (ext === 'rs') return extractUnitsRs(src, relPath)
18
19
  return null
19
20
  }