@nitra/cursor 12.14.0 → 12.15.1

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.
@@ -3,29 +3,38 @@ type: JS Module
3
3
  title: orchestrator.mjs
4
4
  resource: npm/scripts/lib/fix/orchestrator.mjs
5
5
  docgen:
6
- crc: c34d0630
6
+ crc: c6f15470
7
7
  model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
8
  score: 100
9
9
  ---
10
10
 
11
- Модуль відповідає за управління процесом вирішення порушень. Він будує послідовність тирів ескалації за допомогою `buildLadder`. Функція `parseOrchestratorArgs` визначає бюджет LLM та фільтр правил. Далі, `runOrchestratorCli` виконує процес виправлення правил, послідовно застосовуючи `escalateRule` по тирах до досягнення першого успішного вирішення.
11
+ ## Огляд
12
+
13
+ Модуль відповідає за оркестрацію вирішення порушень. Він парсить аргументи для визначення бюджету та фільтрів за допомогою `parseOrchestratorArgs`. Потім він будує послідовність тирів ескалації, використовуючи `buildLadder`, і може ескалувати правила за допомогою `escalateRule`. Нарешті, він виконує повний цикл фіксації порушень через `runOrchestratorCli`.
12
14
 
13
15
  ## Поведінка
14
16
 
15
- buildLadder будує послідовність тирів ескалації для вирішення порушень.
16
- escalateRule проходить по послідовності тирів, намагаючись вирішити одне правило до першого успішного перевірки.
17
- parseOrchestratorArgs парсить аргументи командного рядка для визначення максимального бюджету LLM та фільтра правил.
18
- runOrchestratorCli виконує повний процес виправлення правил, використовуючи послідовність тирів та бюджет LLM.
17
+ buildLadder будує послідовність тирів ескалації для вирішення порушень, від локальних до хмарних моделей.
18
+ escalateRule проводить один прогін по послідовності тирів, намагаючись вирішити порушення, і повертає статус вирішення та використаний бюджет хмарних викликів.
19
+ parseOrchestratorArgs парсить аргументи командного рядка, щоб визначити максимальний бюджет хмарних викликів та фільтр правил.
20
+ runOrchestratorCli виконує повний цикл фіксації порушень: початкова перевірка, детермінований фікс T0-auto, ітеративний LLM-фікс за драбиною ескалації, а потім фінальна перевірка.
19
21
 
20
22
  ## Публічний API
21
23
 
22
- buildLadder — Створює послідовність моделей для ескалації, виходячи з доступних рівнів. Недоступні рівні ігноруються.
24
+ buildLadder — Створює послідовність моделей для ескалації, виходячи з доступних рівнів.
25
+
26
+ local-min — Перший прохід з локальною мінімальною моделлю.
27
+ local-min-retry — Повторний прохід локальною моделлю з урахуванням результатів попереднього кроку.
28
+ cloud-min — Використання мінімальної хмарної моделі з зворотним зв'язком.
29
+ cloud-avg — Використання середньої хмарної моделі з зворотним зв'язком, обмежене середнім бюджетом.
23
30
 
24
- escalateRule — Виконує один етап перевірки за драбиною ескалації. Для кожного кроку викликається модель, відбувається повторна перевірка правила, і результат фіксується в лозі. Процес може зупинитися достроково при певних умовах або після вичерпання ліміту.
31
+ escalateRule — Застосовує одне правило по послідовності ескалації до першого успішного перевірки.
32
+ Кожен рунг — Викликає обробника з попереднім результатом, перевіряє правило, фіксує результат у лозі.
33
+ Достроковий вихід — Зупиняє процес при певних умовах (відсутність ключа, пропуск моделі на системному рівні) або перевищенні середнього бюджету.
25
34
 
26
- parseOrchestratorArgs — Витягує максимальне значення для середнього бюджету з аргументів командного рядка та збирає список фільтрів правил.
35
+ parseOrchestratorArgs — Витягує максимальне значення середнього бюджету з аргументів командного рядка та збирає фільтри правил.
27
36
 
28
- runOrchestratorCli — Запускає основний процес оркестрації, обробляючи аргументи та керуючи виконанням правил.
37
+ runOrchestratorCli — Запускає основний процес оркестрації з командного рядка.
29
38
 
30
39
  ## Гарантії поведінки
31
40
 
@@ -47,54 +47,71 @@ function extractFailPaths(output) {
47
47
  }
48
48
 
49
49
  /**
50
- * Для правил з `policy/<concern>/` підбирає лише ті concern-.mdc, що відповідають
51
- * файлам з ❌-рядків violation output. Читає безпосередньо з пакету (`PACKAGE_RULES_DIR`),
52
- * тому не потребує pre-generation. Fallbacknull (→ повний n-{id}.mdc у caller).
50
+ * Збирає .mdc-контекст правила з двох джерел у пакеті (`PACKAGE_RULES_DIR`):
51
+ * - `js/<check>.mdc` — описи check-логіки (завжди всі, відсортовані за іменем);
52
+ * - `policy/<c>/<c>.mdc`concern-специфічний контент: вибираємо лише ті concern/.mdc,
53
+ * чий `target.json → files.single` збігається з failing paths
54
+ * у violation output; якщо жоден не збігається — включаємо всі.
53
55
  * @param {string} ruleId ID правила
54
56
  * @param {string} violationOutput violation output
55
- * @returns {string|null} конкатенація релевантних .mdc або null
57
+ * @returns {string|null} конкатенація зібраних .mdc або null, якщо нічого не знайдено
56
58
  */
57
- function selectSubCheckMdc(ruleId, violationOutput) {
58
- const policyDir = join(PACKAGE_RULES_DIR, ruleId, 'policy')
59
- if (!existsSync(policyDir)) return null
60
-
61
- const failPaths = extractFailPaths(violationOutput)
62
- if (failPaths.length === 0) return null
63
-
64
- const matched = []
65
- let concerns
66
- try {
67
- concerns = readdirSync(policyDir, { withFileTypes: true })
68
- } catch {
69
- return null
59
+ function readRuleMdc(ruleId, violationOutput) {
60
+ const ruleDir = join(PACKAGE_RULES_DIR, ruleId)
61
+ const parts = []
62
+
63
+ // 1. js/**/*.mdc — завжди всі
64
+ const jsDir = join(ruleDir, 'js')
65
+ if (existsSync(jsDir)) {
66
+ let jsFiles
67
+ try {
68
+ jsFiles = readdirSync(jsDir)
69
+ .filter(f => f.endsWith('.mdc'))
70
+ .sort()
71
+ } catch {
72
+ jsFiles = []
73
+ }
74
+ for (const f of jsFiles) parts.push(readFileSync(join(jsDir, f), 'utf8').trim())
70
75
  }
71
76
 
72
- for (const entry of concerns) {
73
- if (!entry.isDirectory()) continue
74
- const concernDir = join(policyDir, entry.name)
75
- const targetPath = join(concernDir, 'target.json')
76
- if (!existsSync(targetPath)) continue
77
-
78
- let target
77
+ // 2. policy/**/*.mdc matched через target.json; fallback — всі
78
+ const policyDir = join(ruleDir, 'policy')
79
+ if (existsSync(policyDir)) {
80
+ const failPaths = extractFailPaths(violationOutput)
81
+ let concerns
79
82
  try {
80
- target = JSON.parse(readFileSync(targetPath, 'utf8'))
83
+ concerns = readdirSync(policyDir, { withFileTypes: true })
81
84
  } catch {
82
- continue
85
+ concerns = []
83
86
  }
84
87
 
85
- const targetFile = target?.files?.single
86
- if (!targetFile) continue // walkGlob та інші типи → skip, fallback на main.mdc
87
-
88
- // Перевіряємо чи хоч один failing path закінчується на targetFile
89
- const hit = failPaths.some(p => p === targetFile || p.endsWith(`/${targetFile}`))
90
- if (!hit) continue
88
+ const all = []
89
+ const matched = []
90
+ for (const entry of concerns) {
91
+ if (!entry.isDirectory()) continue
92
+ const concernDir = join(policyDir, entry.name)
93
+ const mdcEntry = readdirSync(concernDir).find(f => f.endsWith('.mdc'))
94
+ if (!mdcEntry) continue
95
+ const content = readFileSync(join(concernDir, mdcEntry), 'utf8').trim()
96
+ all.push(content)
97
+
98
+ const targetPath = join(concernDir, 'target.json')
99
+ if (!existsSync(targetPath)) continue
100
+ let target
101
+ try {
102
+ target = JSON.parse(readFileSync(targetPath, 'utf8'))
103
+ } catch {
104
+ continue
105
+ }
106
+ const targetFile = target?.files?.single
107
+ if (!targetFile) continue
108
+ if (failPaths.some(p => p === targetFile || p.endsWith(`/${targetFile}`))) matched.push(content)
109
+ }
91
110
 
92
- const mdcEntry = readdirSync(concernDir).find(f => f.endsWith('.mdc'))
93
- if (!mdcEntry) continue
94
- matched.push(readFileSync(join(concernDir, mdcEntry), 'utf8').trim())
111
+ parts.push(...(matched.length > 0 ? matched : all))
95
112
  }
96
113
 
97
- return matched.length > 0 ? matched.join('\n\n') : null
114
+ return parts.length > 0 ? parts.join('\n\n') : null
98
115
  }
99
116
 
100
117
  /**
@@ -252,7 +269,8 @@ function callModel(prompt, model, caller, timeoutMs, thinkingBudget) {
252
269
  * `model` — перевизначення моделі; `feedback` — контекст попереднього рунга
253
270
  * драбини (retry-with-feedback); `caller` — мітка для wire-trace; `timeoutMs` —
254
271
  * per-tier ліміт виклику (драбина: локалі fail-fast, хмара повний);
255
- * `thinkingBudget` — кількість thinking-токенів для omlx (дефолт `DEFAULT_THINKING_BUDGET`)
272
+ * `thinkingBudget` — кількість thinking-токенів для omlx (дефолт `DEFAULT_THINKING_BUDGET`).
273
+ * `timeoutMs` — per-tier ліміт: локальні 300s (4b повільна, backstop — turn-ceiling), хмарні 120s.
256
274
  * @returns {{ ok: boolean, error?: string, changes: Array<{path:string}>, diagnosis: string|null, reasoning: string|null, reasoningSource: string|null, promptSummary: object }}
257
275
  */
258
276
  export function runLlmWorker(ruleId, violationOutput, projectRoot, opts = {}) {
@@ -262,11 +280,8 @@ export function runLlmWorker(ruleId, violationOutput, projectRoot, opts = {}) {
262
280
  const timeoutMs = opts.timeoutMs
263
281
  const thinkingBudget = opts.thinkingBudget ?? DEFAULT_THINKING_BUDGET
264
282
 
265
- // 1. Читаємо rule .mdc: спробуємо sub-check mdc для конкретної перевірки,
266
- // якщо не вдалося fallback на повний n-{id}.mdc.
267
- const subMdc = selectSubCheckMdc(ruleId, violationOutput)
268
- const mdcPath = join(projectRoot, '.cursor', 'rules', `n-${ruleId}.mdc`)
269
- const ruleMdc = subMdc ?? (existsSync(mdcPath) ? readFileSync(mdcPath, 'utf8') : '(rule file not found)')
283
+ // 1. Читаємо rule .mdc з джерела пакету: js/**/*.mdc + policy/**/*.mdc.
284
+ const ruleMdc = readRuleMdc(ruleId, violationOutput) ?? '(rule file not found)'
270
285
 
271
286
  // 2. Витягуємо файли з violation output і читаємо їх
272
287
  const files = readFilesForFix(extractFilePaths(violationOutput), projectRoot)
@@ -274,7 +289,6 @@ export function runLlmWorker(ruleId, violationOutput, projectRoot, opts = {}) {
274
289
  // 3. Будуємо summary промпту (для verbose-блоку) до виклику моделі
275
290
  const promptSummary = {
276
291
  ruleMdcLen: ruleMdc.length,
277
- subCheckMdc: !!subMdc,
278
292
  violationLen: violationOutput.length,
279
293
  filesCount: files.length,
280
294
  filesTotalBytes: files.reduce((s, f) => s + f.content.length, 0),
@@ -16,11 +16,12 @@ import { CLOUD_AVG, CLOUD_MIN, LOCAL_MIN } from '../../../lib/models.mjs'
16
16
  const DEFAULT_MAX_AVG = 3
17
17
 
18
18
  /**
19
- * Timeout одного LLM-виклику за тиром. Локальні рунги **fail-fast**: не палити
20
- * стіну 120s на повільному 4b (curl exit 28)швидше абортнути й ескалувати.
21
- * Хмарні — повний. Перевизначення: `N_LOCAL_FIX_TIMEOUT_MS` / `N_CLOUD_FIX_TIMEOUT_MS`.
19
+ * Timeout одного LLM-виклику (або всієї агентної сесії) за тиром.
20
+ * Локальні рунги 5 хвилин: 4b модель повільна, основний backstop turn-ceiling (~50).
21
+ * Хмарні — 2 хвилини: API-виклик швидкий, перевищення = transport-помилка.
22
+ * Перевизначення: `N_LOCAL_FIX_TIMEOUT_MS` / `N_CLOUD_FIX_TIMEOUT_MS`.
22
23
  */
23
- const LOCAL_TIMEOUT_MS = Number(env.N_LOCAL_FIX_TIMEOUT_MS) || 45_000
24
+ const LOCAL_TIMEOUT_MS = Number(env.N_LOCAL_FIX_TIMEOUT_MS) || 300_000
24
25
  const CLOUD_TIMEOUT_MS = Number(env.N_CLOUD_FIX_TIMEOUT_MS) || 120_000
25
26
 
26
27
  /** Маркер дружнього повідомлення про відсутній API-ключ (з `llm-worker.callModel`). */
@@ -5,8 +5,8 @@
5
5
  *
6
6
  * Worktree-скіли (`worktree: true`) свій root-assert уже мають у worktree-блоці
7
7
  * (`worktree-notice.mjs`): корінь worktree = його toplevel. Цей модуль — для
8
- * не-worktree-кейсу (напр. `n-start-check`, що прогоняє `start` усіх воркспейсів
9
- * у місці й має стартувати з кореня монорепо).
8
+ * не-worktree-кейсу (напр. `n-taze`, що мутує `package.json` безпосередньо
9
+ * й має стартувати з кореня монорепо).
10
10
  *
11
11
  * Блок — інструкція агенту, що читає `SKILL.md`; вставляється між стабільними
12
12
  * маркерами, ре-синк ідемпотентний: наявний блок замінюється, при `false` —
@@ -166,22 +166,14 @@ async function runPerFileRules(ids, ctx) {
166
166
  }
167
167
 
168
168
  /**
169
- * Конформність-фаза `--full` (поглинула `fix`): escalation-аналітику обрамляє зсувом логу
170
- * (записи саме цього прогону), у fix-режимі по конформності викликає аналіз.
169
+ * Конформність-фаза `--full`.
171
170
  * @param {string} cwd корінь
172
171
  * @param {boolean} readOnly лише детект
173
172
  * @param {(s: string) => void} log логер
174
173
  * @returns {Promise<number>} код конформності
175
174
  */
176
175
  async function runFullConformancePhase(cwd, readOnly, log) {
177
- const { escalationLogSize, maybeAnalyzeEscalation, reportRunStats } = await import('./fix/analyze-escalation.mjs')
178
- const escOffset = readOnly ? 0 : escalationLogSize()
179
- const conformanceCode = await runConformance(cwd, readOnly, log)
180
- if (!readOnly) {
181
- reportRunStats(escOffset, log) // резюме викликів моделей (локальна / cloud-min / cloud-avg)
182
- maybeAnalyzeEscalation(cwd, escOffset, log)
183
- }
184
- return conformanceCode
176
+ return runConformance(cwd, readOnly, log)
185
177
  }
186
178
 
187
179
  /**
@@ -7,7 +7,7 @@
7
7
  * - `requireRoot` — boolean, опційне: чи скіл вимагає запуску з кореня репо.
8
8
  * Worktree-скіли (`worktree:true`) вимагають кореня неявно (корінь worktree =
9
9
  * його toplevel), тож для них поле зайве. Явний `requireRoot:true` — для
10
- * in-place скілів, що мутують CWD без worktree-ізоляції (напр. `n-start-check`).
10
+ * in-place скілів, що мутують CWD без worktree-ізоляції (напр. `n-taze`).
11
11
  *
12
12
  * Цим хелпером користуються `auto-skills.mjs` (автоактивація), `n-cursor.js`
13
13
  * (sync + вшивання worktree/root-блоку) і check-концерн `npm-module/js/skill_meta.mjs`,
@@ -3,34 +3,31 @@ type: JS Module
3
3
  title: walkDir.mjs
4
4
  resource: npm/scripts/utils/walkDir.mjs
5
5
  docgen:
6
- crc: 5e5fec27
6
+ crc: 73503ca2
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 100
7
9
  ---
8
10
 
9
- Файл `n-cursor.js` забезпечує рекурсивний обхід каталогів для скриптів перевірки, дозволяючи виконувати callback-функцію для кожного звичайного файлу. Він обходить дерево каталогів від заданого кореня, ігноруючи певні директорії (наприклад, `.git`, `node_modules`) та шляхи, вказані в `ignorePaths`. Це дозволяє автоматизувати процес аналізу конфігураційних файлів та інших ресурсів у проєкті.
11
+ ## Огляд
12
+
13
+ Публічна функція `walkDir` здійснює рекурсивний пошук файлів у вказаному каталозі. Вона обходить файлову систему, ігноруючи каталоги `.git` та `node_modules`. Знаходячи кожен файл, вона передає його повний шлях у колбек для подальшої обробки. Компонент є read-only, тобто не виконує записів у файлову систему чи бази даних. При роботі з файловою системою він перехоплює помилки, забезпечуючи безпечну роботу без викидання винятків.
10
14
 
11
15
  ## Поведінка
12
16
 
13
- 1. Починається з заданого кореневого каталогу.
14
- 2. Для кожного підкаталогу в кореневому каталозі:
15
- 2.1. Перевіряє, чи є підкаталог у списку `ignorePaths`. Якщо так, пропускає обхід цього підкаталогу та його вмісту.
16
- 2.2. Якщо підкаталог не в списку `ignorePaths`, обробляє вміст підкаталогу:
17
- 2.2.1. Для кожного файлу в підкаталозі, викликає функцію `onFile` з шляхом до файлу.
18
- 2.2.2. Для кожного підкаталогу в підкаталозі, рекурсивно викликає функцію `walkDir` для обходу цього підкаталогу. Під час рекурсивного виклику, також перевіряє, чи є підкаталог у списку `ignorePaths`.
19
- 3. Не обробляє каталоги `node_modules`, `.git`, `dist`, `coverage`, `.turbo` та `.next`.
20
- 4. Якщо при спробі `readdir` для каталогу виникає помилка, обхід цього каталогу припиняється.
21
- 5. Обхід завершується, коли всі підкаталоги та файли в заданому дереві були оброблені.
17
+ 1. Викликається функція walkDir для початку рекурсивного обходу каталогу.
18
+ 2. Система розшифровує вхідний шлях до кореня обходу.
19
+ 3. Система формує додаткові правила ігнорування на основі наданих шляхів.
20
+ 4. Система завжди ігнорує каталоги .git та node_modules.
21
+ 5. Система виконує пошук усіх файлів у каталозі, застосовуючи правила ігнорування, включаючи ті, що визначені в .gitignore.
22
+ 6. У разі виникнення помилки під час пошуку, процес обходу припиняється без генерації винятку.
23
+ 7. Для кожного знайденого файлу система викликає наданий колбек, передаючи йому повний абсолютний шлях до цього файлу.
22
24
 
23
25
  ## Публічний API
24
26
 
25
- - walkDir — Обходить каталог рекурсивно, ігноруючи вказані шляхи.
27
+ walkDir — рекурсивно переглядає файли та папки, ігноруючи ті, що вказані у файлі `.gitignore`.
26
28
 
27
29
  ## Гарантії поведінки
28
30
 
29
- - Функція рекурсивно обходить дерево каталогів, починаючи з заданого кореня.
30
- - Для кожного звичайного файлу викликається переданий callback.
31
- - Не обходить каталоги `node_modules`, `.git`, `dist`, `coverage`, `.turbo`, `.next`.
32
- - Може пропустити каталоги, вказані в `ignorePaths`.
33
- - У разі невдачі `readdir` для каталогу, функція тихо виходить без викидання помилок.
34
- - Функція не викидає винятки назовні.
35
- - У разі невдачі повертає `false` або `null`.
36
- - Не використовує кешування.
31
+ - Read-only: не виконує операцій запису (ФС/БД).
32
+ - Перехоплює помилки і не пропускає винятків назовні (fail-safe).
33
+ - Свідомо пропускає шляхи: `.git`, `node_modules`.