@nitra/cursor 12.17.0 → 12.18.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/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## [12.18.0] - 2026-06-28
4
+
5
+ ### Changed
6
+
7
+ - Видалено escalation-лог та його тести, оптимізовано pi-agent-fix та orchestrator
8
+
9
+ ### Fixed
10
+
11
+ - CLI lint: не відкидати перший позиційний rule-аргумент, коли `--cwd` не передано
12
+
3
13
  ## [12.17.0] - 2026-06-27
4
14
 
5
15
  ### Changed
package/bin/n-cursor.js CHANGED
@@ -1518,7 +1518,7 @@ try {
1518
1518
  // прогнати лише конформність цих правил, без лінтер-скану (мапить колишній `fix <rule>`).
1519
1519
  const cwdIdx = args.indexOf('--cwd')
1520
1520
  const cwdArg = cwdIdx !== -1 ? resolve(args[cwdIdx + 1]) : undefined
1521
- const rules = args.filter((a, i) => !a.startsWith('-') && i !== cwdIdx + 1)
1521
+ const rules = args.filter((a, i) => !a.startsWith('-') && !(cwdIdx !== -1 && i === cwdIdx + 1))
1522
1522
  process.exitCode = await runLint({
1523
1523
  full: args.includes('--full'),
1524
1524
  readOnly: args.includes('--read-only'),
@@ -3,7 +3,7 @@ type: JS Module
3
3
  title: pi-agent-fix.mjs
4
4
  resource: npm/lib/pi-agent-fix.mjs
5
5
  docgen:
6
- crc: 4cf083e2
6
+ crc: 3e849981
7
7
  model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
8
  score: 100
9
9
  ---
@@ -243,7 +243,7 @@ export async function runPiAgentFix(ruleId, violation, cwd, opts = {}) {
243
243
  rung: tier,
244
244
  model: modelSpec,
245
245
  cwd,
246
- // ВХІД LLM (щоб «що подали» було видно у trace, без розкопок escalation-log):
246
+ // ВХІД LLM (щоб «що подали» було видно прямо у trace):
247
247
  // violation — обрізаний (може бути великим); promptChars — повний розмір промпта.
248
248
  violation: typeof violation === 'string' ? violation.slice(0, 4000) : null,
249
249
  violationChars: typeof violation === 'string' ? violation.length : 0,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nitra/cursor",
3
- "version": "12.17.0",
3
+ "version": "12.18.0",
4
4
  "description": "CLI для завантаження cursor-правил (префікс n-) у локальний репозиторій",
5
5
  "keywords": [
6
6
  "cli",
@@ -12,7 +12,7 @@
12
12
  "e18e/prefer-nullish-coalescing": "deny",
13
13
  "e18e/prefer-spread-syntax": "deny",
14
14
  "e18e/prefer-url-canparse": "deny",
15
- "e18e/ban-dependencies": "deny",
15
+ "e18e/ban-dependencies": ["deny", { "allowed": ["globby"] }],
16
16
  "e18e/prefer-array-from-map": "deny",
17
17
  "e18e/prefer-timer-args": "deny",
18
18
  "e18e/prefer-static-regex": "deny",
@@ -9,7 +9,6 @@ resource: npm/scripts/lib/fix/
9
9
  | Файл | Тип |
10
10
  | ----------------------------------------------------- | --------- |
11
11
  | [discover-t0-patterns.mjs](discover-t0-patterns.md) | JS Module |
12
- | [escalation-log.mjs](escalation-log.md) | JS Module |
13
12
  | [llm-fix-apply.mjs](llm-fix-apply.md) | JS Module |
14
13
  | [llm-lint-fix.mjs](llm-lint-fix.md) | JS Module |
15
14
  | [llm-worker.mjs](llm-worker.md) | JS Module |
@@ -3,7 +3,7 @@ type: JS Module
3
3
  title: orchestrator.mjs
4
4
  resource: npm/scripts/lib/fix/orchestrator.mjs
5
5
  docgen:
6
- crc: 49146418
6
+ crc: c16c34f7
7
7
  model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
8
  score: 100
9
9
  ---
@@ -3,7 +3,6 @@
3
3
  import { env } from 'node:process'
4
4
  import { runConformanceCheck } from './run-conformance-check.mjs'
5
5
  import { runT0AutoCli } from './t0.mjs'
6
- import { logEscalation } from './escalation-log.mjs'
7
6
  import { runPiAgentFix } from '../../../lib/pi-agent-fix.mjs'
8
7
  import { recordFixTelemetry } from '../../../lib/pi-telemetry-store.mjs'
9
8
  import { CLOUD_AVG, CLOUD_MIN, LOCAL_MIN } from '../../../lib/pi-model-tiers.mjs'
@@ -112,7 +111,7 @@ function decideAfterFailure(rung, error) {
112
111
  /**
113
112
  * Проводить ОДНЕ правило по драбині ескалації до першого зеленого re-check.
114
113
  * Кожен рунг: виклик worker (з feedback від попереднього) → re-check цього правила →
115
- * запис у escalation-лог («чи допомогло» + diagnosis). Достроковий вихід — `decideAfterFailure`
114
+ * persist у глобальний telemetry-стор (`recordFixTelemetry`). Достроковий вихід — `decideAfterFailure`
116
115
  * (обрив на no-key, пропуск моделі на systemic) і вичерпаний avg-кеп (залогувати, не мовчки).
117
116
  * @param {{ ruleId: string, output: string }} rule провальне правило з violation-output
118
117
  * @param {string} cwd корінь проєкту
@@ -121,16 +120,13 @@ function decideAfterFailure(rung, error) {
121
120
  * worker: { runFix: (ruleId: string, violation: string, cwd: string, opts: object) => Promise<object> },
122
121
  * check: (rules: string[], cwd: string) => Promise<{rules: Array<{ruleId:string,ok:boolean,output:string}>}>,
123
122
  * avgBudget: number,
124
- * clock?: () => number,
125
123
  * log?: (s: string) => void
126
- * }} deps інжектовані залежності (worker/check/clock — для тестів)
124
+ * }} deps інжектовані залежності (worker/check — для тестів)
127
125
  * @returns {Promise<{ resolved: boolean, avgUsed: number }>} чи закрито правило і скільки avg-викликів витрачено
128
126
  */
129
127
  export async function escalateRule(rule, cwd, deps) {
130
128
  const { ladder, worker, check, avgBudget } = deps
131
- const clock = deps.clock ?? (() => Date.now())
132
129
  const log = deps.log ?? (s => console.log(s))
133
- const record = base => logEscalation({ ts: new Date(clock()).toISOString(), ruleId: rule.ruleId, ...base })
134
130
 
135
131
  let feedback = null
136
132
  let currentViolation = rule.output
@@ -140,43 +136,20 @@ export async function escalateRule(rule, cwd, deps) {
140
136
  // §2-профілактика: violation без actionable ❌ (tool-crash/Usage/шум) → не годуємо
141
137
  // агента (інакше флоундерить рунги до timeout). Рапортуємо як non-actionable, не фіксимо.
142
138
  if (!hasActionableViolation(rule.output)) {
143
- record({
144
- rung: -1,
145
- tier: 'skip',
146
- model: '',
147
- withFeedback: false,
148
- callOk: false,
149
- callError: 'non-actionable violation (нема ❌ — ймовірно check-error/tool-crash)',
150
- recheckOk: false,
151
- remainingViolation: rule.output,
152
- diagnosis: null,
153
- ms: 0
154
- })
155
139
  log(
156
140
  ` ⏭️ ${rule.ruleId}: LLM-фікс пропущено — у violation немає ❌-порушень (check-error/tool-crash, не фіксабельне)`
157
141
  )
158
142
  return { resolved: false, avgUsed: 0 }
159
143
  }
160
144
 
161
- for (const [idx, rung] of ladder.entries()) {
145
+ for (const rung of ladder) {
162
146
  if (skipModels.has(rung.model)) continue
163
147
 
164
- const common = { rung: idx, tier: rung.tier, model: rung.model, withFeedback: rung.feedback }
165
148
  if (rung.isAvg && avgBudget - avgUsed <= 0) {
166
- record({
167
- ...common,
168
- callOk: false,
169
- callError: 'cloud-avg cap reached',
170
- recheckOk: false,
171
- remainingViolation: currentViolation,
172
- diagnosis: null,
173
- ms: 0
174
- })
175
149
  log(` ⏭️ ${rule.ruleId}: ${rung.tier} пропущено (avg-кеп вичерпано)`)
176
150
  continue
177
151
  }
178
152
 
179
- const startedAt = clock()
180
153
  // self_check (advisory §4+5) — той самий verdict-helper, що й зовнішній re-check.
181
154
  const selfCheck = async () => {
182
155
  const r = await check([rule.ruleId], cwd)
@@ -207,16 +180,6 @@ export async function escalateRule(rule, cwd, deps) {
207
180
  })
208
181
  }
209
182
 
210
- record({
211
- ...common,
212
- callOk: !res.error,
213
- callError: res.error ?? null,
214
- recheckOk,
215
- remainingViolation: remaining,
216
- diagnosis: res.telemetry ? `turns=${res.telemetry.turnCount} tools=${res.telemetry.toolCallCount}` : null,
217
- ms: clock() - startedAt
218
- })
219
-
220
183
  if (recheckOk) {
221
184
  log(` ✅ ${rung.tier} (${rung.model || 'pi'}): ${rule.ruleId}`)
222
185
  return { resolved: true, avgUsed }
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- export {}
2
+ export {};
@@ -1,28 +0,0 @@
1
- ---
2
- type: JS Module
3
- title: escalation-log.mjs
4
- resource: npm/scripts/lib/fix/escalation-log.mjs
5
- docgen:
6
- crc: 91898427
7
- model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
- score: 100
9
- ---
10
-
11
- ## Огляд
12
-
13
- Файл створює append-only JSONL-лог ескалації конформність-фіксу (спека 2026-06-19-fix-escalation-cascade-design). Він фіксує кожен запис на рунг драбини, що включає деталі використаної моделі (`model`), подання зворотного зв'язку (`withFeedback`), результат виклику (`callOk`/`callError`), оцінку, чи допомогло це усунути порушення (`recheckOk`), залишковий `violation` та самоаналіз моделі (`diagnosis`). Цей лог доповнює always-on wire-trace (`lib/pi-trace.mjs`) і формує логіку для join за полем `caller` (`fix:<rule>:<rung>`). Запис відбувається за певним шільною: або через kill-switch `N_CURSOR_FIX_ESCALATION_LOG`, або за явним шляхом, дефолтно у `<cwd>/.n-cursor/fix-escalation.jsonl`.
14
-
15
- ## Поведінка
16
-
17
- Поведінка:
18
- escalationLogPath визначає шлях до файлу журналу ескалації конформності. Якщо встановлено змінну середовища N_CURSOR_FIX_ESCALATION_LOG, використовується цей шлях; інакше, за замовчуванням, це .n-cursor/fix-escalation.jsonl у поточній робочій директорії.
19
- logEscalation записує один запис про рунг у JSONL-лог, якщо шлях до логу визначено. Запис містить метадані про спробу фіксування, результати виклику та аналіз. Помилки під час запису логу ігноруються.
20
-
21
- ## Публічний API
22
-
23
- escalationLogPath — вказує на місце зберігання логу ескалацій, якщо функція не вимкнена.
24
- logEscalation — записує один подію виконання в спеціальний лог у форматі JSONL, ігноруючи внутрішні помилки запису.
25
-
26
- ## Гарантії поведінки
27
-
28
- - Перехоплює помилки і не пропускає винятків назовні (fail-safe).
@@ -1,92 +0,0 @@
1
- /**
2
- * Append-only JSONL-лог ескалації конформність-фіксу (спека
3
- * 2026-06-19-fix-escalation-cascade-design). Один запис **на рунг драбини** —
4
- * фіксує `model`, `withFeedback`, чи виклик удався (`callOk`/`callError`), чи
5
- * правило стало зеленим після цього рунга (`recheckOk` = «чи допомогло»),
6
- * залишковий violation і `diagnosis` (само-аналіз моделі «чому не вдалося»).
7
- *
8
- * Це доповнення до always-on wire-trace (`lib/pi-trace.mjs`): trace знає
9
- * `messages`/`reasoning`/`usage` кожного виклику, але **не** знає результату
10
- * re-check — а саме «чи допомогло» й потрібне для пост-аналізу драбини. Join із
11
- * trace — за полем `caller` (`fix:<rule>:<rung>`), яке цей модуль і формує.
12
- *
13
- * Шлях — дзеркало `tracePath()`: `N_CURSOR_FIX_ESCALATION_LOG` (kill-switch
14
- * `0|false|off|no` → не писати; інакше явний шлях) → дефолт
15
- * `<cwd>/.n-cursor/fix-escalation.jsonl`.
16
- */
17
- import { appendFileSync, mkdirSync } from 'node:fs'
18
- import { dirname, join } from 'node:path'
19
- import { cwd, env } from 'node:process'
20
-
21
- /** Значення `N_CURSOR_FIX_ESCALATION_LOG`, що вимикають лог повністю. */
22
- const KILL_VALUES = new Set(['0', 'false', 'off', 'no'])
23
-
24
- /** Межа обрізки `remainingViolation`/`diagnosis` у записі (символів). */
25
- const MAX_FIELD_CHARS = 2000
26
-
27
- /**
28
- * Шлях активного escalation-логу або `null`, якщо вимкнено kill-switch-ем.
29
- * @returns {string|null} шлях до .jsonl або null
30
- */
31
- export function escalationLogPath() {
32
- const override = env.N_CURSOR_FIX_ESCALATION_LOG
33
- if (override !== undefined) {
34
- if (KILL_VALUES.has(override.toLowerCase())) return null
35
- if (override) return override
36
- }
37
- return join(cwd(), '.n-cursor', 'fix-escalation.jsonl')
38
- }
39
-
40
- /**
41
- * Обрізає рядок до `MAX_FIELD_CHARS` (null/undefined → null).
42
- * @param {string|null|undefined} s вхід
43
- * @returns {string|null} обрізаний рядок або null
44
- */
45
- function cap(s) {
46
- if (s === null || s === undefined) return null
47
- return s.length > MAX_FIELD_CHARS ? s.slice(0, MAX_FIELD_CHARS) : s
48
- }
49
-
50
- /**
51
- * Дописує один запис рунга у JSONL-лог (no-op, якщо вимкнено). Помилки запису
52
- * ковтаються — лог діагностичний, не має валити сам фікс.
53
- * @param {object} rec запис рунга
54
- * @param {string} rec.ts ISO-час завершення рунга
55
- * @param {string} rec.ruleId id правила
56
- * @param {number} rec.rung індекс рунга драбини (0-based)
57
- * @param {string} rec.tier мітка тиру (`local-min`|`local-min-retry`|`cloud-min`|`cloud-avg`)
58
- * @param {string} rec.model model-id (порожній → pi-дефолт)
59
- * @param {boolean} rec.withFeedback чи передавався feedback попереднього рунга
60
- * @param {boolean} rec.callOk чи виклик моделі+apply удався
61
- * @param {string|null} rec.callError помилка виклику (null, якщо callOk)
62
- * @param {boolean} rec.recheckOk чи правило стало зеленим після рунга («чи допомогло»)
63
- * @param {string|null} rec.remainingViolation залишковий violation (null, якщо recheckOk)
64
- * @param {string|null} rec.diagnosis само-аналіз моделі «чому попередній рунг не вдався»
65
- * @param {number} rec.ms тривалість рунга (мс)
66
- * @returns {void}
67
- */
68
- export function logEscalation(rec) {
69
- const path = escalationLogPath()
70
- if (!path) return
71
- const line =
72
- JSON.stringify({
73
- ts: rec.ts,
74
- ruleId: rec.ruleId,
75
- rung: rec.rung,
76
- tier: rec.tier,
77
- model: rec.model,
78
- withFeedback: rec.withFeedback,
79
- callOk: rec.callOk,
80
- callError: cap(rec.callError),
81
- recheckOk: rec.recheckOk,
82
- remainingViolation: rec.recheckOk ? null : cap(rec.remainingViolation),
83
- diagnosis: cap(rec.diagnosis),
84
- ms: rec.ms
85
- }) + '\n'
86
- try {
87
- mkdirSync(dirname(path), { recursive: true })
88
- appendFileSync(path, line, 'utf8')
89
- } catch {
90
- /* лог діагностичний — ковтаємо помилки запису */
91
- }
92
- }