@nitra/cursor 12.8.9 → 12.10.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 +1 -23
- package/CHANGELOG.md +14 -1
- package/bin/n-cursor.js +21 -48
- package/docs/stryker.config.md +0 -2
- package/lib/docs/llm.md +16 -21
- package/lib/docs/omlx.md +20 -25
- package/lib/llm.mjs +25 -7
- package/lib/omlx.mjs +10 -3
- package/package.json +5 -5
- package/rules/abie/docs/index.md +0 -1
- package/rules/abie/docs/main.md +0 -2
- package/rules/abie/lib/docs/http-route.md +9 -12
- package/rules/abie/lib/http-route.mjs +3 -0
- package/rules/abie/main.mdc +0 -22
- package/rules/abie/policy/health_check_policy/health_check_policy.mdc +3 -1
- package/rules/abie/policy/health_check_policy/health_check_policy.rego +27 -0
- package/rules/adr/docs/index.md +0 -1
- package/rules/adr/docs/main.md +0 -2
- package/rules/adr/js/madr_format.mdc +13 -1
- package/rules/adr/main.mdc +0 -9
- package/rules/bun/docs/index.md +0 -1
- package/rules/bun/docs/main.md +0 -2
- package/rules/bun/main.mdc +1 -15
- package/rules/bun/policy/package_json/package_json.rego +12 -0
- package/rules/capacitor/docs/index.md +0 -1
- package/rules/capacitor/docs/main.md +0 -2
- package/rules/capacitor/main.mdc +0 -6
- package/rules/changelog/docs/index.md +0 -1
- package/rules/changelog/docs/main.md +0 -2
- package/rules/changelog/js/agent-workflow.mdc +1 -1
- package/rules/changelog/js/consistency.mjs +3 -3
- package/rules/changelog/js/docs/consistency.md +18 -23
- package/rules/changelog/main.mdc +0 -5
- package/rules/ci4/docs/index.md +0 -1
- package/rules/ci4/docs/main.md +0 -2
- package/rules/ci4/main.mdc +0 -5
- package/rules/doc-files/docs/index.md +0 -1
- package/rules/doc-files/docs/main.md +7 -11
- package/rules/doc-files/js/docs/docgen-crc.md +0 -2
- package/rules/doc-files/js/docs/docgen-extract.md +0 -2
- package/rules/doc-files/js/docs/docgen-files-batch.md +0 -2
- package/rules/doc-files/js/docs/docgen-gen.md +0 -2
- package/rules/doc-files/js/docs/docgen-judge-measure.md +0 -2
- package/rules/doc-files/js/docs/docgen-judge.md +0 -2
- package/rules/doc-files/js/docs/docgen-scan.md +0 -2
- package/rules/doc-files/js/docs/run-lint.md +0 -2
- package/rules/doc-files/main.mjs +2 -3
- package/rules/docker/docs/index.md +0 -1
- package/rules/docker/docs/main.md +0 -2
- package/rules/docker/js/docs/lint.md +0 -2
- package/rules/docker/lib/docs/docker-hadolint.md +0 -2
- package/rules/docker/main.mdc +1 -21
- package/rules/efes/docs/index.md +0 -1
- package/rules/efes/docs/main.md +0 -2
- package/rules/efes/main.mdc +0 -1
- package/rules/feedback/docs/index.md +0 -1
- package/rules/feedback/docs/main.md +0 -2
- package/rules/ga/docs/index.md +0 -1
- package/rules/ga/docs/main.md +0 -2
- package/rules/ga/js/docs/index.md +0 -1
- package/rules/ga/main.mdc +1 -31
- package/rules/graphql/docs/index.md +0 -1
- package/rules/graphql/docs/main.md +0 -2
- package/rules/graphql/main.mdc +0 -5
- package/rules/hasura/docs/index.md +0 -1
- package/rules/hasura/docs/main.md +0 -2
- package/rules/hasura/js/docs/index.md +1 -0
- package/rules/hasura/js/docs/migrations.md +28 -0
- package/rules/hasura/js/migrations.mjs +47 -0
- package/rules/hasura/main.mdc +1 -11
- package/rules/image-avif/docs/index.md +0 -1
- package/rules/image-avif/docs/main.md +0 -2
- package/rules/image-avif/main.mdc +1 -9
- package/rules/image-compress/docs/index.md +0 -1
- package/rules/image-compress/docs/main.md +0 -2
- package/rules/image-compress/js/docs/index.md +0 -1
- package/rules/image-compress/main.mdc +1 -9
- package/rules/js/docs/index.md +0 -1
- package/rules/js/docs/main.md +0 -2
- package/rules/js/js/dep-policy.mjs +91 -0
- package/rules/js/js/docs/check.md +0 -2
- package/rules/js/js/docs/dep-policy.md +34 -0
- package/rules/js/js/docs/index.md +5 -4
- package/rules/js/js/docs/tooling.md +0 -2
- package/rules/js/js/docs/utils_imports.md +0 -2
- package/rules/js/main.mdc +0 -31
- package/rules/js/policy/package_json/package_json.rego +16 -0
- package/rules/js-bun-db/docs/index.md +0 -1
- package/rules/js-bun-db/docs/main.md +0 -2
- package/rules/js-bun-db/js/docs/safety.md +18 -23
- package/rules/js-bun-db/js/safety.mjs +31 -3
- package/rules/js-bun-db/lib/bun-sql-scan.mjs +123 -0
- package/rules/js-bun-db/lib/docs/bun-sql-scan.md +37 -331
- package/rules/js-bun-db/main.mdc +1 -23
- package/rules/js-bun-redis/docs/index.md +0 -1
- package/rules/js-bun-redis/docs/main.md +0 -2
- package/rules/js-bun-redis/main.mdc +0 -5
- package/rules/js-mssql/docs/index.md +0 -1
- package/rules/js-mssql/docs/main.md +0 -2
- package/rules/js-mssql/main.mdc +0 -12
- package/rules/js-run/docs/index.md +0 -1
- package/rules/js-run/docs/main.md +0 -2
- package/rules/js-run/js/docs/runtime.md +15 -13
- package/rules/js-run/js/runtime.mjs +48 -4
- package/rules/js-run/main.mdc +0 -25
- package/rules/k8s/docs/index.md +0 -1
- package/rules/k8s/docs/main.md +0 -2
- package/rules/k8s/main.mdc +0 -45
- package/rules/nginx-default-tpl/docs/index.md +0 -1
- package/rules/nginx-default-tpl/docs/main.md +0 -2
- package/rules/nginx-default-tpl/main.mdc +0 -13
- package/rules/npm-module/docs/index.md +0 -1
- package/rules/npm-module/docs/main.md +0 -2
- package/rules/npm-module/js/docs/header_doc_pointer.md +0 -2
- package/rules/npm-module/js/docs/rule_meta.md +0 -2
- package/rules/npm-module/js/docs/skill_meta.md +0 -2
- package/rules/npm-module/main.mdc +1 -15
- package/rules/php/docs/index.md +0 -1
- package/rules/php/docs/main.md +0 -2
- package/rules/php/js/docs/index.md +0 -1
- package/rules/php/main.mdc +1 -9
- package/rules/python/docs/index.md +0 -1
- package/rules/python/docs/main.md +0 -2
- package/rules/python/js/docs/index.md +0 -1
- package/rules/python/main.mdc +1 -13
- package/rules/rego/docs/index.md +0 -1
- package/rules/rego/docs/main.md +0 -2
- package/rules/rego/js/docs/index.md +1 -1
- package/rules/rego/js/docs/tooling.md +26 -0
- package/rules/rego/js/tooling.mdc +14 -0
- package/rules/rego/js/tooling.mjs +24 -0
- package/rules/rego/main.mdc +0 -9
- package/rules/rego/policy/package_json/package_json.mdc +12 -0
- package/rules/rego/policy/package_json/package_json.rego +21 -0
- package/rules/rego/policy/package_json/target.json +4 -0
- package/rules/release/docs/index.md +0 -1
- package/rules/release/docs/main.md +0 -2
- package/rules/release/main.mdc +2 -2
- package/rules/rust/docs/index.md +0 -1
- package/rules/rust/docs/main.md +0 -2
- package/rules/rust/js/docs/index.md +0 -1
- package/rules/rust/main.mdc +1 -11
- package/rules/rust/policy/lint_rust_yml/lint_rust_yml.rego +24 -0
- package/rules/rust/policy/package_json/package_json.mdc +12 -0
- package/rules/rust/policy/package_json/package_json.rego +20 -0
- package/rules/rust/policy/package_json/target.json +4 -0
- package/rules/security/docs/index.md +0 -1
- package/rules/security/docs/main.md +0 -2
- package/rules/security/js/docs/index.md +0 -1
- package/rules/security/main.mdc +0 -13
- package/rules/style/docs/index.md +0 -1
- package/rules/style/docs/main.md +0 -2
- package/rules/style/js/docs/index.md +0 -1
- package/rules/style/js/docs/tooling.md +12 -10
- package/rules/style/js/tooling.mjs +8 -2
- package/rules/style/main.mdc +1 -23
- package/rules/style/policy/lint_style_yml/lint_style_yml.rego +5 -0
- package/rules/tauri/docs/index.md +0 -1
- package/rules/tauri/docs/main.md +0 -2
- package/rules/tauri/main.mdc +1 -11
- package/rules/test/docs/index.md +0 -1
- package/rules/test/docs/main.md +0 -2
- package/rules/test/js/docs/index.md +2 -0
- package/rules/test/js/docs/no-console-store-restore.md +30 -0
- package/rules/test/js/docs/sandbox-aware-test.md +30 -0
- package/rules/test/js/docs/stryker_config.md +0 -2
- package/rules/test/js/docs/vitest-config-pool-forks.md +0 -2
- package/rules/test/js/no-console-store-restore.mjs +88 -0
- package/rules/test/js/sandbox-aware-test.mjs +89 -0
- package/rules/test/main.mdc +1 -21
- package/rules/text/docs/index.md +0 -1
- package/rules/text/docs/main.md +0 -2
- package/rules/text/js/docs/cspell-fix.md +0 -2
- package/rules/text/js/docs/run-dotenv-linter.md +0 -2
- package/rules/text/js/docs/run-shellcheck.md +0 -2
- package/rules/text/js/docs/run-v8r.md +0 -2
- package/rules/text/main.mdc +0 -33
- package/rules/tool-surface/docs/index.md +0 -1
- package/rules/tool-surface/docs/main.md +0 -2
- package/rules/vue/docs/index.md +0 -1
- package/rules/vue/docs/main.md +0 -2
- package/rules/vue/main.mdc +0 -22
- package/rules/worktree/docs/index.md +0 -1
- package/rules/worktree/docs/main.md +0 -2
- package/scripts/docs/auto-rules.md +0 -2
- package/scripts/docs/auto-skills.md +0 -2
- package/scripts/docs/hook.md +30 -0
- package/scripts/docs/index.md +1 -2
- package/scripts/docs/post-tool-use-check.md +0 -2
- package/scripts/docs/sync-claude-config.md +1 -3
- package/scripts/docs/sync-setup-bun-deps-action.md +0 -2
- package/scripts/hook.mjs +71 -0
- package/scripts/lib/docs/check-mdc-template-refs.md +0 -2
- package/scripts/lib/docs/index.md +35 -36
- package/scripts/lib/docs/inline-template-links.md +6 -8
- package/scripts/lib/docs/list-project-rules-mdc.md +0 -2
- package/scripts/lib/docs/list-rule-ids.md +0 -2
- package/scripts/lib/docs/mirror-parity.md +8 -10
- package/scripts/lib/docs/read-n-cursor-config-lite.md +0 -2
- package/scripts/lib/docs/rule-meta.md +0 -2
- package/scripts/lib/docs/run-lint.md +9 -10
- package/scripts/lib/docs/run-rule-cli.md +0 -2
- package/scripts/lib/docs/run-rule.md +7 -9
- package/scripts/lib/docs/run-standard-lint.md +0 -2
- package/scripts/lib/docs/run-standard-rule.md +0 -2
- package/scripts/lib/docs/skill-meta.md +0 -2
- package/scripts/lib/docs/timing-summary.md +0 -2
- package/scripts/lib/docs/worktree-notice.md +0 -2
- package/scripts/lib/fix/docs/analyze-escalation.md +0 -2
- package/scripts/lib/fix/docs/index.md +10 -10
- package/scripts/lib/fix/docs/llm-worker.md +18 -8
- package/scripts/lib/fix/docs/orchestrator.md +44 -20
- package/scripts/lib/fix/docs/run-conformance-check.md +0 -2
- package/scripts/lib/fix/docs/t0.md +0 -2
- package/scripts/lib/fix/docs/verbose-block.md +27 -0
- package/scripts/lib/fix/llm-worker.mjs +75 -22
- package/scripts/lib/fix/orchestrator.mjs +13 -3
- package/scripts/lib/fix/verbose-block.mjs +82 -0
- package/scripts/lib/inline-template-links.mjs +32 -22
- package/scripts/lib/mirror-parity.mjs +2 -2
- package/scripts/lib/run-lint.mjs +15 -2
- package/scripts/lib/run-rule.mjs +1 -2
- package/scripts/sync-claude-config.mjs +7 -4
- package/scripts/utils/docs/resolve-js-root.md +0 -2
- package/skills/adr-normalize/SKILL.md +1 -0
- package/skills/coverage-fix/SKILL.md +1 -0
- package/skills/doc-aggregate/SKILL.md +1 -0
- package/skills/doc-files/SKILL.md +10 -24
- package/skills/lint/SKILL.md +24 -19
- package/skills/llm-patch/SKILL.md +5 -4
- package/skills/publish-telegram/SKILL.md +1 -0
- package/skills/start-check/SKILL.md +1 -0
- package/skills/taze/SKILL.md +3 -2
- package/types/bin/n-cursor.d.ts +1 -1
- package/rules/abie/docs/fix.md +0 -37
- package/rules/adr/docs/fix.md +0 -37
- package/rules/bun/docs/fix.md +0 -30
- package/rules/capacitor/docs/fix.md +0 -36
- package/rules/changelog/docs/fix.md +0 -37
- package/rules/ci4/docs/fix.md +0 -32
- package/rules/doc-files/docs/fix.md +0 -29
- package/rules/docker/docs/fix.md +0 -35
- package/rules/efes/docs/fix.md +0 -37
- package/rules/feedback/docs/fix.md +0 -30
- package/rules/ga/docs/fix.md +0 -30
- package/rules/graphql/docs/fix.md +0 -37
- package/rules/hasura/docs/fix.md +0 -39
- package/rules/image-avif/docs/fix.md +0 -28
- package/rules/image-compress/docs/fix.md +0 -27
- package/rules/js/docs/fix.md +0 -37
- package/rules/js-bun-db/docs/fix.md +0 -30
- package/rules/js-bun-redis/docs/fix.md +0 -32
- package/rules/js-mssql/docs/fix.md +0 -30
- package/rules/js-run/docs/fix.md +0 -36
- package/rules/k8s/docs/fix.md +0 -31
- package/rules/nginx-default-tpl/docs/fix.md +0 -35
- package/rules/npm-module/docs/fix.md +0 -34
- package/rules/php/docs/fix.md +0 -35
- package/rules/python/docs/fix.md +0 -38
- package/rules/rego/docs/fix.md +0 -31
- package/rules/release/docs/fix.md +0 -28
- package/rules/rust/docs/fix.md +0 -32
- package/rules/security/docs/fix.md +0 -33
- package/rules/style/docs/fix.md +0 -28
- package/rules/tauri/docs/fix.md +0 -39
- package/rules/test/docs/fix.md +0 -31
- package/rules/text/docs/fix.md +0 -37
- package/rules/tool-surface/docs/fix.md +0 -32
- package/rules/vue/docs/fix.md +0 -32
- package/rules/worktree/docs/fix.md +0 -40
- package/scripts/docs/post-tool-use-fix.md +0 -32
- package/scripts/docs/worktree-cli.md +0 -27
- package/scripts/lib/docs/worktree.md +0 -42
- package/scripts/lib/fix/docs/run-fix-check.md +0 -33
|
@@ -8,8 +8,6 @@ docgen:
|
|
|
8
8
|
score: 70
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## Огляд
|
|
12
|
-
|
|
13
11
|
Файл надає публічний API для оркестрації правил, який викликається з `rules/<id>/check.mjs`. Він інкапсулює логіку пошуку єдиного правила (`discoverOneRule`) та його виконання (`runRule`). Виконання обертається у `withLock` для дедуплікації паралельних запусків того самого правила на основі стану git-дерева. Локальна логіка в правилах заборонена; розширення поведінки відбувається через `ctx`-опції. Це централізована точка для запуску стандартних правил з кешуванням у межах одного прогону.
|
|
14
12
|
|
|
15
13
|
## Поведінка
|
|
@@ -8,8 +8,6 @@ docgen:
|
|
|
8
8
|
score: 100
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## Огляд
|
|
12
|
-
|
|
13
11
|
Спільний парсер метаданих скіла, що зчитує інформацію з `main.json`. Цей файл є єдиним джерелом правди для скіла. Модуль дозволяє визначати умови автоактивації скіла (через поле `auto`), вказувати, чи виконувати скіл в окремому git-worktree (`worktree`), та чи вимагає він запуску з кореня репозиторію (`requireRoot`). Надає константу `SKILL_ALWAYS` для безумовної активації. Хелпер використовується іншими компонентами для уникнення дублювання парсингу. Функції забезпечують перехоплення помилок (fail-safe), повертаючи порожнє значення замість винятків.
|
|
14
12
|
|
|
15
13
|
## Поведінка
|
|
@@ -8,8 +8,6 @@ docgen:
|
|
|
8
8
|
score: 95
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## Огляд
|
|
12
|
-
|
|
13
11
|
Форматує тривалість у форматі `<ціла>.<десята>s`. Генерує таблицю-резюме часу виконання для оркестратора `fix` або `lint`, яка включає детальні записи та загальний час прогону. Таблиця містить маркер `❌` для позначення невдач. Функція повертає готовий рядок із фінальним `\n`; друк здійснюється на стороні виклику.
|
|
14
12
|
|
|
15
13
|
## Поведінка
|
|
@@ -8,8 +8,6 @@ docgen:
|
|
|
8
8
|
score: 100
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## Огляд
|
|
12
|
-
|
|
13
11
|
Управляє вставкою інструкцій для виконання команд у ізольованому git-worktree у синкнутий `SKILL.md` (рішення D2 зі spec). Коли `main.json.worktree === true`, інструкції вставляються між маркерами `WORKTREE_START` та `WORKTREE_END`. Це забезпечує ре-синк ідемпотентність: наявний блок замінюється, а при `main.json.worktree === false` — видаляється. Механізм адаптований для агента, який читає `SKILL.md`.
|
|
14
12
|
|
|
15
13
|
## Поведінка
|
|
@@ -8,8 +8,6 @@ docgen:
|
|
|
8
8
|
score: 100
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## Огляд
|
|
12
|
-
|
|
13
11
|
Аналізує записи рунгів драбини з `escalation-log.mjs` для виявлення шляхів зменшення LLM-залежності у fix-конформності. Лог обробляється за один прогін (від байтового зсуву) або повністю, ділячись на чанки для аналізу хмарною **avg**-моделлю. Мета аналізу — визначити конкретні правки пакета `@nitra/cursor`: (A) новий ДЕТЕРМІНОВАНИЙ T0-патерн (`t0.mjs`), (B) уточнення `.mdc`-інструкцій правила, або (C) зміна скрипта/чека. Результат зберігається у markdown-звіт `.n-cursor/fix-escalation-analysis.md` (append із timestamp) після виклику CLI `n-cursor analyze-escalation`.
|
|
14
12
|
|
|
15
13
|
## Поведінка
|
|
@@ -6,14 +6,14 @@ resource: npm/scripts/lib/fix/
|
|
|
6
6
|
|
|
7
7
|
# npm/scripts/lib/fix
|
|
8
8
|
|
|
9
|
-
| Файл
|
|
10
|
-
|
|
11
|
-
| [analyze-escalation.mjs](analyze-escalation.md)
|
|
12
|
-
| [escalation-log.mjs](escalation-log.md)
|
|
13
|
-
| [llm-fix-apply.mjs](llm-fix-apply.md)
|
|
14
|
-
| [llm-lint-fix.mjs](llm-lint-fix.md)
|
|
15
|
-
| [llm-worker.mjs](llm-worker.md)
|
|
16
|
-
| [orchestrator.mjs](orchestrator.md)
|
|
9
|
+
| Файл | Тип |
|
|
10
|
+
|---|---|
|
|
11
|
+
| [analyze-escalation.mjs](analyze-escalation.md) | JS Module |
|
|
12
|
+
| [escalation-log.mjs](escalation-log.md) | JS Module |
|
|
13
|
+
| [llm-fix-apply.mjs](llm-fix-apply.md) | JS Module |
|
|
14
|
+
| [llm-lint-fix.mjs](llm-lint-fix.md) | JS Module |
|
|
15
|
+
| [llm-worker.mjs](llm-worker.md) | JS Module |
|
|
16
|
+
| [orchestrator.mjs](orchestrator.md) | JS Module |
|
|
17
17
|
| [run-conformance-check.mjs](run-conformance-check.md) | JS Module |
|
|
18
|
-
| [
|
|
19
|
-
| [
|
|
18
|
+
| [t0.mjs](t0.md) | JS Module |
|
|
19
|
+
| [verbose-block.mjs](verbose-block.md) | JS Module |
|
|
@@ -3,24 +3,34 @@ type: JS Module
|
|
|
3
3
|
title: llm-worker.mjs
|
|
4
4
|
resource: npm/scripts/lib/fix/llm-worker.mjs
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
6
|
+
crc: d6c0b516
|
|
7
7
|
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
8
8
|
score: 100
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
## Огляд
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Модуль взаємодіє з мовною моделлю для обробки правил та файлів. Він формує запит до моделі, отримує пропозиції щодо змін, які не застосовуються до файлової системи. Функція обробки гарантує перехоплення помилок (fail-safe) та не генерує винятків назовні.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
## Поведінка
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
1. Викликає runLlmWorker для виправлення однієї проблеми.
|
|
18
|
+
2. Зчитує вміст відповідного файлу правила.
|
|
19
|
+
3. Витягує шляхи до файлів, які порушені, з вихідних даних про порушення.
|
|
20
|
+
4. Зчитує вміст цих файлів.
|
|
21
|
+
5. Формує повний текстовий запит для моделі, включаючи правило, вихідні дані про порушення, вміст файлів та, за наявності, контекст попередньої спроби.
|
|
22
|
+
6. Відправляє цей запит моделі.
|
|
23
|
+
7. У разі помилки при виклику моделі, повертає статус невдачі з деталями помилки.
|
|
24
|
+
8. Якщо модель відповідає, парсить її відповідь, щоб отримати діагноз та список змін.
|
|
25
|
+
9. У разі неможливості розібрати відповідь або відсутності змін, повертає статус невдачі.
|
|
26
|
+
10. Якщо зміни успішно отримані, застосовує ці зміни до файлової системи проєкту.
|
|
27
|
+
11. Повертає результат, що містить статус успіху, список застосованих змін, діагноз та метадані про запит.
|
|
18
28
|
|
|
19
29
|
## Публічний API
|
|
20
30
|
|
|
21
|
-
|
|
31
|
+
runLlmWorker — виправляє одне порушення правила, використовуючи шаблон C1. Повертає результати виправлення чи діагнозу незалежно від успіху, що дозволяє наступним етапам системи отримувати інформацію про спробу. Поля про міркування та підсумок запиту використовуються для детального виводу в режимі `--full`. Дозволяє перевизначити модель, передати контекст попередніх спроб, позначити джерело виклику та встановити ліміти часу для кожного рівня виконання. Керує обсягом токенів, доступних для процесу мислення.
|
|
22
32
|
|
|
23
33
|
## Гарантії поведінки
|
|
24
34
|
|
|
25
|
-
-
|
|
26
|
-
-
|
|
35
|
+
- Read-only: не виконує операцій запису (ФС/БД).
|
|
36
|
+
- Перехоплює помилки і не пропускає винятків назовні (fail-safe).
|
|
@@ -3,38 +3,62 @@ type: JS Module
|
|
|
3
3
|
title: orchestrator.mjs
|
|
4
4
|
resource: npm/scripts/lib/fix/orchestrator.mjs
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
7
|
-
model:
|
|
6
|
+
crc: 08d96254
|
|
7
|
+
model: claude-sonnet-4-6
|
|
8
8
|
score: 100
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
Модуль відповідає за управління процесом виправлення порушень. Він будує послідовність тирів ескалації за допомогою `buildLadder`, парсить аргументи командного рядка за допомогою `parseOrchestratorArgs` та запускає повний цикл виправлення за допомогою `runOrchestratorCli`. Цей цикл включає автоматичний фікс та ескалацію через LLM-моделі, що реалізується функцією `escalateRule`.
|
|
11
|
+
Оркеструє повний цикл виправлення порушень конформності: детермінований T0-фікс без LLM → LLM-драбина ескалації (local-min → local-min-retry → cloud-min → cloud-avg) → фінальна перевірка. Кожне провальне правило проходить через тири послідовно до першого зеленого re-check або до обриву (no-key, systemic-помилка, cloud transport fail, вичерпаний avg-кеп).
|
|
14
12
|
|
|
15
13
|
## Поведінка
|
|
16
14
|
|
|
17
|
-
buildLadder
|
|
18
|
-
escalateRule виконує один прогін по послідовності тирів, намагаючись вирішити порушення, використовуючи LLM-моделі та фіксуючи результат.
|
|
19
|
-
parseOrchestratorArgs парсить аргументи командного рядка для визначення максимального ліміту викликів хмарної моделі та фільтра правил.
|
|
20
|
-
runOrchestratorCli керує повним процесом виправлення порушень: виконує початкову перевірку, застосовує детермінований фікс (T0-auto), а потім ініціює LLM-драбину ескалації для невирішених правил.
|
|
15
|
+
### `buildLadder`
|
|
21
16
|
|
|
22
|
-
|
|
17
|
+
Будує масив рунгів ескалації з чотирьох тирів:
|
|
18
|
+
|
|
19
|
+
| Тир | Модель | Feedback | Timeout |
|
|
20
|
+
| ----------------- | ----------- | -------- | ------------------------- |
|
|
21
|
+
| `local-min` | `LOCAL_MIN` | ні | `LOCAL_TIMEOUT_MS` (45s) |
|
|
22
|
+
| `local-min-retry` | `LOCAL_MIN` | так | `LOCAL_TIMEOUT_MS` |
|
|
23
|
+
| `cloud-min` | `CLOUD_MIN` | так | `CLOUD_TIMEOUT_MS` (120s) |
|
|
24
|
+
| `cloud-avg` | `CLOUD_AVG` | так | `CLOUD_TIMEOUT_MS` |
|
|
25
|
+
|
|
26
|
+
Рунги з порожньою моделлю (`''`) відфільтровуються — драбина стискається до доступних тирів.
|
|
27
|
+
|
|
28
|
+
### `escalateRule`
|
|
29
|
+
|
|
30
|
+
Проводить одне правило через драбину до першого зеленого re-check. На кожному рунзі:
|
|
23
31
|
|
|
24
|
-
|
|
32
|
+
1. Виклик `worker.runLlmWorker` (синхронно) з feedback від попереднього рунга.
|
|
33
|
+
2. Re-check через `check([ruleId], cwd)`.
|
|
34
|
+
3. Запис у escalation-лог (`logEscalation`).
|
|
35
|
+
4. Якщо re-check зелений → `{ resolved: true }`.
|
|
36
|
+
5. Якщо ні → `decideAfterFailure` визначає дію: `break` (no-key або cloud transport fail), `skip-model` (systemic omlx-помилка), або продовжити.
|
|
37
|
+
6. Avg-рунг пропускається, якщо `avgBudget <= 0` (з фіксацією у лог).
|
|
25
38
|
|
|
26
|
-
|
|
27
|
-
local-min-retry — Повторює локальний прохід, використовуючи результати попереднього рунгу.
|
|
28
|
-
cloud-min — Виконує прохід з хмарною мінімальною моделлю, використовуючи результати попереднього рунгу.
|
|
29
|
-
cloud-avg — Виконує прохід з хмарною середньою моделлю, використовуючи результати попереднього рунгу та обмеження середнього.
|
|
39
|
+
Після кожного рунга виводить verbose-блок (`printVerboseBlock`), якщо `N_CURSOR_FIX_VERBOSE !== 'off'`.
|
|
30
40
|
|
|
31
|
-
|
|
32
|
-
Кожен рунг — Викликає модель з попереднім відгуком, перевіряє правило, фіксує результат у лозі. Зупиняється при певних умовах (відсутність ключа, пропуск моделі, перевищення бюджету).
|
|
41
|
+
### `parseOrchestratorArgs`
|
|
33
42
|
|
|
34
|
-
|
|
43
|
+
Витягує `--max-avg N` (default: 3) і збирає позиційні аргументи як `ruleFilter`.
|
|
44
|
+
|
|
45
|
+
### `runOrchestratorCli`
|
|
46
|
+
|
|
47
|
+
Повний цикл:
|
|
48
|
+
|
|
49
|
+
1. Початкова conformance-перевірка → якщо чисто, exit 0.
|
|
50
|
+
2. `runT0Step` — детермінований фікс без LLM; якщо після нього чисто, exit 0.
|
|
51
|
+
3. Для кожного правила, що лишилося — `escalateRule` з відстеженням `avgBudget`.
|
|
52
|
+
4. Фінальна перевірка → exit 0 якщо чисто, exit 1 якщо є невирішені.
|
|
53
|
+
|
|
54
|
+
## Публічний API
|
|
35
55
|
|
|
36
|
-
|
|
56
|
+
- `buildLadder({ localMin, cloudMin, cloudAvg })` — повертає масив рунгів ескалації.
|
|
57
|
+
- `escalateRule(rule, cwd, deps)` — проводить одне правило через драбину; `deps` дозволяє ін'єкцію worker/check/clock для тестів; повертає `{ resolved, avgUsed }`.
|
|
58
|
+
- `parseOrchestratorArgs(args)` — повертає `{ maxAvg, ruleFilter }`.
|
|
59
|
+
- `runOrchestratorCli(args, cwd)` — CLI-точка входу; повертає `Promise<0|1>`.
|
|
37
60
|
|
|
38
61
|
## Гарантії поведінки
|
|
39
62
|
|
|
40
|
-
-
|
|
63
|
+
- Мутує файли проєкту лише через `worker.runLlmWorker` (apply-changes) і T0-auto.
|
|
64
|
+
- Не кидає винятків назовні: помилки LLM перехоплює worker і повертає як `res.error`.
|
|
@@ -8,8 +8,6 @@ docgen:
|
|
|
8
8
|
score: 90
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## Огляд
|
|
12
|
-
|
|
13
11
|
Модуль реалізує прямий механізм виконання конформності, викликаючи конформність-фазу `lint`, движок (`orchestrator.mjs`, `t0.mjs`) та PostToolUse-хук. Селекція активних правил здійснюється на основі конфігурації `.n-cursor.json`. Для забезпечення ізоляції, кожен обраний `entrypoint rules/<id>/main.mjs` запускається окремим процесом `bun`.
|
|
14
12
|
|
|
15
13
|
## Поведінка
|
|
@@ -8,8 +8,6 @@ docgen:
|
|
|
8
8
|
score: 100
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
## Огляд
|
|
12
|
-
|
|
13
11
|
Модуль керує автоматичним застосуванням паттернів T0-auto до виводів порушень. Він використовує конфігурації з `extensions.json` та `package-lock.json` для визначення правил. Модуль фільтрує правила, які можуть бути автоматично оброблені, застосовує паттерни за допомогою `applyT0Auto`, а потім запускає повний цикл перевірки для всіх провальних правил через `runT0AutoCli`. Усі операції виконуються з механізмом fail-safe, що запобігає виникненню винятків назовні.
|
|
14
12
|
|
|
15
13
|
## Поведінка
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: JS Module
|
|
3
|
+
title: verbose-block.mjs
|
|
4
|
+
resource: npm/scripts/lib/fix/verbose-block.mjs
|
|
5
|
+
docgen:
|
|
6
|
+
crc: 1a921dca
|
|
7
|
+
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
8
|
+
score: 100
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
Цей файл виводить детальний блок інформації після кожного LLM-рунга у режимі `--full`. Він друкує стислий опис промпту, включаючи деталі про правила, порушення та зворотний зв'язок. Також виводиться монолог моделі, якщо він присутній. Вивід блоку вимикається при встановленні `N_CURSOR_FIX_VERBOSE=off`.
|
|
12
|
+
|
|
13
|
+
## Поведінка
|
|
14
|
+
|
|
15
|
+
1. Викликається `printVerboseBlock` для виведення детальної інформації після кожного LLM-рунга у режимі `--full`.
|
|
16
|
+
2. `printVerboseBlock` виводить стислий опис промпту, включаючи ID правила, довжину правила, довжину порушення, кількість та розмір файлів, а також інформацію про зворотний зв'язок (наявність, модель, кількість змін, помилка).
|
|
17
|
+
3. Якщо надано монолог моделі (reasoning), `printVerboseBlock` виводить його, показуючи прев'ю (з можливим зазначенням загальної довжини), і вказує джерело цього монологу.
|
|
18
|
+
4. Якщо монологу моделі немає, `printVerboseBlock` виводить повідомлення про відсутність монологу.
|
|
19
|
+
5. Виведення здійснюється лише якщо змінна середовища `N_CURSOR_FIX_VERBOSE` не встановлена як `off`.
|
|
20
|
+
|
|
21
|
+
## Публічний API
|
|
22
|
+
|
|
23
|
+
printVerboseBlock — виводить детальний опис промпту та внутрішній роздум моделі після символу завершення рядка рунга.
|
|
24
|
+
|
|
25
|
+
## Гарантії поведінки
|
|
26
|
+
|
|
27
|
+
- Read-only: не виконує операцій запису (ФС/БД).
|
|
@@ -4,7 +4,7 @@ import { existsSync, readFileSync } from 'node:fs'
|
|
|
4
4
|
import { join } from 'node:path'
|
|
5
5
|
import { env } from 'node:process'
|
|
6
6
|
import { resolveModel } from '../../../lib/models.mjs'
|
|
7
|
-
import {
|
|
7
|
+
import { callLlmRich } from '../../../lib/llm.mjs'
|
|
8
8
|
import { applyChanges, parseChangesResponse, readFilesForFix } from './llm-fix-apply.mjs'
|
|
9
9
|
|
|
10
10
|
// Дефолтна модель, коли викликач не задав `opts.model` (legacy/прямі виклики).
|
|
@@ -12,6 +12,10 @@ import { applyChanges, parseChangesResponse, readFilesForFix } from './llm-fix-a
|
|
|
12
12
|
// тут лишається тільки fallback на min-тир. Перевизначення — `N_CURSOR_FIX_MODEL`.
|
|
13
13
|
const MODEL = env.N_CURSOR_FIX_MODEL ?? resolveModel('min')
|
|
14
14
|
|
|
15
|
+
// Бюджет thinking-токенів для omlx-моделей (Gemma 4 та ін., що підтримують thinking_budget).
|
|
16
|
+
// Значення 0 вимикає thinking. Перевизначення — `N_CURSOR_OMLX_THINKING_BUDGET`.
|
|
17
|
+
const DEFAULT_THINKING_BUDGET = Number(env.N_CURSOR_OMLX_THINKING_BUDGET ?? 4096)
|
|
18
|
+
|
|
15
19
|
const API_KEY_RE = /api key/i
|
|
16
20
|
|
|
17
21
|
/**
|
|
@@ -112,23 +116,32 @@ function buildPrompt(ruleId, ruleMdc, output, files, feedback = null) {
|
|
|
112
116
|
}
|
|
113
117
|
|
|
114
118
|
/**
|
|
115
|
-
* Викликає LLM через
|
|
119
|
+
* Викликає LLM через `callLlmRich` (маршрут за префіксом model-id; wire-trace).
|
|
120
|
+
* Повертає reasoning поряд із текстом — для verbose-блоку оркестратора.
|
|
116
121
|
* Зберігає дружнє повідомлення про відсутній API-ключ для хмарних провайдерів.
|
|
117
122
|
* @param {string} prompt текст промпта
|
|
118
123
|
* @param {string} model назва моделі (provider/id, `omlx/...` або '')
|
|
119
124
|
* @param {string} caller мітка викликача для wire-trace (`fix:<rule>:<rung>`)
|
|
120
|
-
* @param {number} [timeoutMs] ліміт виклику (драбина задає per-tier; undefined → дефолт
|
|
121
|
-
* @
|
|
125
|
+
* @param {number} [timeoutMs] ліміт виклику (драбина задає per-tier; undefined → дефолт callLlmRich)
|
|
126
|
+
* @param {number} [thinkingBudget] бюджет thinking-токенів (лише omlx; 0 = вимкнено)
|
|
127
|
+
* @returns {{ text: string, reasoning: string|null, reasoningSource: string|null, error?: string }}
|
|
122
128
|
*/
|
|
123
|
-
function callModel(prompt, model, caller, timeoutMs) {
|
|
129
|
+
function callModel(prompt, model, caller, timeoutMs, thinkingBudget) {
|
|
124
130
|
try {
|
|
125
|
-
|
|
131
|
+
const { content, reasoning, reasoningSource } = callLlmRich([{ role: 'user', content: prompt }], model, {
|
|
132
|
+
timeoutMs,
|
|
133
|
+
caller,
|
|
134
|
+
thinkingBudget
|
|
135
|
+
})
|
|
136
|
+
return { text: content, reasoning, reasoningSource }
|
|
126
137
|
} catch (error) {
|
|
127
138
|
const msg = String(error.message)
|
|
128
139
|
if (API_KEY_RE.test(msg)) {
|
|
129
140
|
const provider = model ? model.split('/')[0] : 'дефолтного провайдера'
|
|
130
141
|
return {
|
|
131
142
|
text: '',
|
|
143
|
+
reasoning: null,
|
|
144
|
+
reasoningSource: null,
|
|
132
145
|
error: [
|
|
133
146
|
`pi: немає ключа для ${provider}.`,
|
|
134
147
|
`Встановіть N_CLOUD_MIN_MODEL=provider/model-id`,
|
|
@@ -136,7 +149,7 @@ function callModel(prompt, model, caller, timeoutMs) {
|
|
|
136
149
|
].join(' ')
|
|
137
150
|
}
|
|
138
151
|
}
|
|
139
|
-
return { text: '', error: msg }
|
|
152
|
+
return { text: '', reasoning: null, reasoningSource: null, error: msg }
|
|
140
153
|
}
|
|
141
154
|
}
|
|
142
155
|
|
|
@@ -144,21 +157,24 @@ function callModel(prompt, model, caller, timeoutMs) {
|
|
|
144
157
|
* LLM-worker: виправляє одне rule-порушення через pi (C1 pattern).
|
|
145
158
|
* Повертає `changes`/`diagnosis` навіть при невдачі — драбина ескалації
|
|
146
159
|
* (`orchestrator.mjs`) логує їх і прокидає як feedback у наступний рунг.
|
|
160
|
+
* Поля `reasoning`/`reasoningSource`/`promptSummary` використовує оркестратор
|
|
161
|
+
* для verbose-блоку після кожного рунга (`--full` режим).
|
|
147
162
|
* @param {string} ruleId ID правила
|
|
148
163
|
* @param {string} violationOutput output з fix check для цього rule
|
|
149
164
|
* @param {string} projectRoot абсолютний шлях до кореня проєкту
|
|
150
|
-
* @param {{ model?: string, feedback?: object|null, caller?: string, timeoutMs?: number }} opts опції:
|
|
165
|
+
* @param {{ model?: string, feedback?: object|null, caller?: string, timeoutMs?: number, thinkingBudget?: number }} opts опції:
|
|
151
166
|
* `model` — перевизначення моделі; `feedback` — контекст попереднього рунга
|
|
152
167
|
* драбини (retry-with-feedback); `caller` — мітка для wire-trace; `timeoutMs` —
|
|
153
|
-
* per-tier ліміт виклику (драбина: локалі fail-fast, хмара повний)
|
|
154
|
-
*
|
|
155
|
-
*
|
|
168
|
+
* per-tier ліміт виклику (драбина: локалі fail-fast, хмара повний);
|
|
169
|
+
* `thinkingBudget` — кількість thinking-токенів для omlx (дефолт `DEFAULT_THINKING_BUDGET`)
|
|
170
|
+
* @returns {{ ok: boolean, error?: string, changes: Array<{path:string}>, diagnosis: string|null, reasoning: string|null, reasoningSource: string|null, promptSummary: object }}
|
|
156
171
|
*/
|
|
157
172
|
export function runLlmWorker(ruleId, violationOutput, projectRoot, opts = {}) {
|
|
158
173
|
const model = opts.model ?? MODEL
|
|
159
174
|
const feedback = opts.feedback ?? null
|
|
160
175
|
const caller = opts.caller ?? 'fix'
|
|
161
176
|
const timeoutMs = opts.timeoutMs
|
|
177
|
+
const thinkingBudget = opts.thinkingBudget ?? DEFAULT_THINKING_BUDGET
|
|
162
178
|
|
|
163
179
|
// 1. Читаємо rule .mdc
|
|
164
180
|
const mdcPath = join(projectRoot, '.cursor', 'rules', `n-${ruleId}.mdc`)
|
|
@@ -167,24 +183,61 @@ export function runLlmWorker(ruleId, violationOutput, projectRoot, opts = {}) {
|
|
|
167
183
|
// 2. Витягуємо файли з violation output і читаємо їх
|
|
168
184
|
const files = readFilesForFix(extractFilePaths(violationOutput), projectRoot)
|
|
169
185
|
|
|
170
|
-
// 3. Будуємо
|
|
171
|
-
const
|
|
172
|
-
|
|
186
|
+
// 3. Будуємо summary промпту (для verbose-блоку) до виклику моделі
|
|
187
|
+
const promptSummary = {
|
|
188
|
+
ruleMdcLen: ruleMdc.length,
|
|
189
|
+
violationLen: violationOutput.length,
|
|
190
|
+
filesCount: files.length,
|
|
191
|
+
filesTotalBytes: files.reduce((s, f) => s + f.content.length, 0),
|
|
192
|
+
hasFeedback: !!feedback,
|
|
193
|
+
feedbackModel: feedback?.previousModel ?? null,
|
|
194
|
+
feedbackChangesCount: feedback?.previousChanges?.length ?? 0,
|
|
195
|
+
feedbackError: feedback?.previousError ?? null
|
|
196
|
+
}
|
|
173
197
|
|
|
174
|
-
|
|
175
|
-
|
|
198
|
+
// 4. Будуємо prompt і викликаємо модель
|
|
199
|
+
const prompt = buildPrompt(ruleId, ruleMdc, violationOutput, files, feedback)
|
|
200
|
+
const {
|
|
201
|
+
text,
|
|
202
|
+
error: modelError,
|
|
203
|
+
reasoning,
|
|
204
|
+
reasoningSource
|
|
205
|
+
} = callModel(prompt, model, caller, timeoutMs, thinkingBudget)
|
|
206
|
+
|
|
207
|
+
if (modelError)
|
|
208
|
+
return { ok: false, error: modelError, changes: [], diagnosis: null, reasoning, reasoningSource, promptSummary }
|
|
209
|
+
if (!text)
|
|
210
|
+
return {
|
|
211
|
+
ok: false,
|
|
212
|
+
error: 'model returned empty response',
|
|
213
|
+
changes: [],
|
|
214
|
+
diagnosis: null,
|
|
215
|
+
reasoning,
|
|
216
|
+
reasoningSource,
|
|
217
|
+
promptSummary
|
|
218
|
+
}
|
|
176
219
|
|
|
177
|
-
//
|
|
220
|
+
// 5. Парсимо відповідь
|
|
178
221
|
const parsed = parseChangesResponse(text)
|
|
179
222
|
if (!parsed) {
|
|
180
|
-
return {
|
|
223
|
+
return {
|
|
224
|
+
ok: false,
|
|
225
|
+
error: `cannot parse pi response: ${text.slice(0, 200)}`,
|
|
226
|
+
changes: [],
|
|
227
|
+
diagnosis: null,
|
|
228
|
+
reasoning,
|
|
229
|
+
reasoningSource,
|
|
230
|
+
promptSummary
|
|
231
|
+
}
|
|
181
232
|
}
|
|
182
233
|
const diagnosis = typeof parsed.diagnosis === 'string' && parsed.diagnosis ? parsed.diagnosis : null
|
|
183
234
|
const changes = parsed.changes ?? []
|
|
184
|
-
if (parsed.error)
|
|
185
|
-
|
|
235
|
+
if (parsed.error)
|
|
236
|
+
return { ok: false, error: parsed.error, changes, diagnosis, reasoning, reasoningSource, promptSummary }
|
|
237
|
+
if (changes.length === 0)
|
|
238
|
+
return { ok: false, error: 'pi returned no changes', changes, diagnosis, reasoning, reasoningSource, promptSummary }
|
|
186
239
|
|
|
187
|
-
//
|
|
240
|
+
// 6. Застосовуємо зміни
|
|
188
241
|
const applied = applyChanges(changes, projectRoot)
|
|
189
|
-
return { ...applied, changes, diagnosis }
|
|
242
|
+
return { ...applied, changes, diagnosis, reasoning, reasoningSource, promptSummary }
|
|
190
243
|
}
|
|
@@ -5,6 +5,7 @@ import { runConformanceCheck } from './run-conformance-check.mjs'
|
|
|
5
5
|
import { runT0AutoCli } from './t0.mjs'
|
|
6
6
|
import { logEscalation } from './escalation-log.mjs'
|
|
7
7
|
import { runLlmWorker } from './llm-worker.mjs'
|
|
8
|
+
import { printVerboseBlock } from './verbose-block.mjs'
|
|
8
9
|
import { classifyOmlxError } from '../../../lib/llm.mjs'
|
|
9
10
|
import { CLOUD_AVG, CLOUD_MIN, LOCAL_MIN } from '../../../lib/models.mjs'
|
|
10
11
|
|
|
@@ -147,11 +148,20 @@ export async function escalateRule(rule, cwd, deps) {
|
|
|
147
148
|
|
|
148
149
|
if (recheckOk) {
|
|
149
150
|
log(` ✅ ${rung.tier} (${rung.model || 'pi'}): ${rule.ruleId}`)
|
|
150
|
-
|
|
151
|
+
} else {
|
|
152
|
+
const hint = res.error ? ` ❌ ${res.error.slice(0, 120)}` : ' ❌ досі порушено'
|
|
153
|
+
log(` ⚡ ${rung.tier} (${rung.model || 'pi'}): ${rule.ruleId}${hint}`)
|
|
151
154
|
}
|
|
152
155
|
|
|
153
|
-
|
|
154
|
-
|
|
156
|
+
// DEBUG
|
|
157
|
+
console.error(
|
|
158
|
+
`[DBG] verbose check: VERBOSE=${env.N_CURSOR_FIX_VERBOSE} promptSummary=${JSON.stringify(res.promptSummary)} reasoning=${res.reasoning}`
|
|
159
|
+
)
|
|
160
|
+
if (env.N_CURSOR_FIX_VERBOSE !== 'off' && res.promptSummary) {
|
|
161
|
+
printVerboseBlock(rule.ruleId, res.promptSummary, res.reasoning ?? null, res.reasoningSource ?? null)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (recheckOk) return { resolved: true, avgUsed }
|
|
155
165
|
|
|
156
166
|
// Feedback для наступного рунга + оновлений violation.
|
|
157
167
|
feedback = { previousModel: rung.model, previousChanges: res.changes ?? [], previousError: res.error ?? null }
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verbose-блок після кожного LLM-рунга у `--full` режимі.
|
|
3
|
+
* Друкує стислий опис промпту і thinking-монолог моделі (якщо є).
|
|
4
|
+
* Вимикається через `N_CURSOR_FIX_VERBOSE=off`.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const THINKING_PREVIEW_LEN = 500
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Форматує рядок файлів для prompt-блоку.
|
|
11
|
+
* @param {number} count кількість файлів
|
|
12
|
+
* @param {number} totalBytes сумарний розмір у байтах
|
|
13
|
+
* @returns {string}
|
|
14
|
+
*/
|
|
15
|
+
function formatFiles(count, totalBytes) {
|
|
16
|
+
if (count === 0) return '(none)'
|
|
17
|
+
const kb = (totalBytes / 1024).toFixed(1)
|
|
18
|
+
const word = count === 1 ? 'файл' : count < 5 ? 'файли' : 'файлів'
|
|
19
|
+
return `${count} ${word} (${kb} KB)`
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Форматує рядок feedback для prompt-блоку.
|
|
24
|
+
* @param {boolean} hasFeedback чи є feedback
|
|
25
|
+
* @param {string|null} feedbackModel модель попереднього рунга
|
|
26
|
+
* @param {number} feedbackChangesCount кількість змін попереднього рунга
|
|
27
|
+
* @param {string|null} feedbackError помилка попереднього рунга
|
|
28
|
+
* @returns {string}
|
|
29
|
+
*/
|
|
30
|
+
function formatFeedback(hasFeedback, feedbackModel, feedbackChangesCount, feedbackError) {
|
|
31
|
+
if (!hasFeedback) return '(none)'
|
|
32
|
+
const parts = []
|
|
33
|
+
if (feedbackModel) parts.push(`model=${feedbackModel}`)
|
|
34
|
+
parts.push(`${feedbackChangesCount} changes`)
|
|
35
|
+
if (feedbackError) parts.push(`error="${feedbackError.slice(0, 60)}"`)
|
|
36
|
+
return parts.join(', ')
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Друкує verbose-блок після рядка рунга (`⚡`/`✅`).
|
|
41
|
+
* Містить стислий опис промпту і thinking-монолог моделі (якщо є).
|
|
42
|
+
* Не викликається якщо `N_CURSOR_FIX_VERBOSE=off`.
|
|
43
|
+
* @param {string} ruleId ID правила
|
|
44
|
+
* @param {{ ruleMdcLen: number, violationLen: number, filesCount: number, filesTotalBytes: number, hasFeedback: boolean, feedbackModel: string|null, feedbackChangesCount: number, feedbackError: string|null }} promptSummary стислий опис промпту
|
|
45
|
+
* @param {string|null} reasoning thinking-монолог моделі
|
|
46
|
+
* @param {string|null} reasoningSource джерело reasoning ('field'|'think_tag'|'truncated'|null)
|
|
47
|
+
*/
|
|
48
|
+
export function printVerboseBlock(ruleId, promptSummary, reasoning, reasoningSource) {
|
|
49
|
+
const {
|
|
50
|
+
ruleMdcLen,
|
|
51
|
+
violationLen,
|
|
52
|
+
filesCount,
|
|
53
|
+
filesTotalBytes,
|
|
54
|
+
hasFeedback,
|
|
55
|
+
feedbackModel,
|
|
56
|
+
feedbackChangesCount,
|
|
57
|
+
feedbackError
|
|
58
|
+
} = promptSummary
|
|
59
|
+
|
|
60
|
+
console.log(``)
|
|
61
|
+
console.log(` prompt:`)
|
|
62
|
+
console.log(` rule: n-${ruleId}.mdc (${ruleMdcLen} chars)`)
|
|
63
|
+
console.log(` violation: ${violationLen} chars`)
|
|
64
|
+
console.log(` files: ${formatFiles(filesCount, filesTotalBytes)}`)
|
|
65
|
+
console.log(` feedback: ${formatFeedback(hasFeedback, feedbackModel, feedbackChangesCount, feedbackError)}`)
|
|
66
|
+
|
|
67
|
+
if (reasoning) {
|
|
68
|
+
const preview =
|
|
69
|
+
reasoning.length > THINKING_PREVIEW_LEN
|
|
70
|
+
? reasoning.slice(0, THINKING_PREVIEW_LEN) + ` … (+${reasoning.length - THINKING_PREVIEW_LEN} chars)`
|
|
71
|
+
: reasoning
|
|
72
|
+
console.log(``)
|
|
73
|
+
console.log(` thinking [${reasoningSource}, ${reasoning.length} chars]:`)
|
|
74
|
+
for (const line of preview.split('\n')) {
|
|
75
|
+
console.log(` ${line}`)
|
|
76
|
+
}
|
|
77
|
+
} else {
|
|
78
|
+
console.log(``)
|
|
79
|
+
console.log(` thinking: (none)`)
|
|
80
|
+
}
|
|
81
|
+
console.log(``)
|
|
82
|
+
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs'
|
|
2
|
-
import { readFile } from 'node:fs/promises'
|
|
2
|
+
import { readFile, readdir } from 'node:fs/promises'
|
|
3
3
|
import { basename, extname, join } from 'node:path'
|
|
4
4
|
|
|
5
5
|
const MD_LINK_RE = /\[([^\]]{1,200})\]\((\.\/[^)]{1,500})\)/g
|
|
6
6
|
const TEMPLATE_SEGMENT_RE = /\/templates?\//
|
|
7
|
-
const MDC_EXT_RE = /\.mdc$/
|
|
8
7
|
/** Статичні regexp-літерали `^(.+)\.<slot>\.<ext>$` — без `RegExp(variable)`. */
|
|
9
8
|
const SLOT_SUFFIX_RES = [/^(.+)\.snippet\.[^.]+$/, /^(.+)\.deny\.[^.]+$/, /^(.+)\.contains\.[^.]+$/]
|
|
10
9
|
|
|
@@ -69,31 +68,42 @@ export async function inlineTemplateLinks(text, ruleDir) {
|
|
|
69
68
|
}
|
|
70
69
|
|
|
71
70
|
/**
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* @param {string} text .mdc file contents (after inlineTemplateLinks)
|
|
71
|
+
* Appends all *.mdc files auto-discovered in js/ and policy/<concern>/ subdirectories.
|
|
72
|
+
* js/ direct files come first (alphabetically), then policy concern directories
|
|
73
|
+
* (alphabetically by concern name, then by file name within each concern).
|
|
74
|
+
* @param {string} text rule content (after inlineTemplateLinks)
|
|
77
75
|
* @param {string} ruleDir absolute path to the rule directory
|
|
78
|
-
* @returns {Promise<string>}
|
|
76
|
+
* @returns {Promise<string>} text with discovered concern docs appended
|
|
79
77
|
*/
|
|
80
|
-
export async function
|
|
81
|
-
const
|
|
82
|
-
if (matches.length === 0) return text
|
|
78
|
+
export async function appendDiscoveredMdcFiles(text, ruleDir) {
|
|
79
|
+
const sections = []
|
|
83
80
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
throw new Error(`inlineMarkdownIncludes: file not found: ${absPath} (referenced from .mdc)`)
|
|
81
|
+
const jsDir = join(ruleDir, 'js')
|
|
82
|
+
if (existsSync(jsDir)) {
|
|
83
|
+
const entries = await readdir(jsDir, { withFileTypes: true })
|
|
84
|
+
for (const e of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
85
|
+
if (e.isFile() && e.name.endsWith('.mdc')) {
|
|
86
|
+
sections.push((await readFile(join(jsDir, e.name), 'utf8')).trim())
|
|
87
|
+
}
|
|
92
88
|
}
|
|
89
|
+
}
|
|
93
90
|
|
|
94
|
-
|
|
95
|
-
|
|
91
|
+
const policyDir = join(ruleDir, 'policy')
|
|
92
|
+
if (existsSync(policyDir)) {
|
|
93
|
+
const concerns = (await readdir(policyDir, { withFileTypes: true }))
|
|
94
|
+
.filter(e => e.isDirectory())
|
|
95
|
+
.sort((a, b) => a.name.localeCompare(b.name))
|
|
96
|
+
for (const concern of concerns) {
|
|
97
|
+
const concernDir = join(policyDir, concern.name)
|
|
98
|
+
const files = (await readdir(concernDir, { withFileTypes: true }))
|
|
99
|
+
.filter(e => e.isFile() && e.name.endsWith('.mdc'))
|
|
100
|
+
.sort((a, b) => a.name.localeCompare(b.name))
|
|
101
|
+
for (const f of files) {
|
|
102
|
+
sections.push((await readFile(join(concernDir, f.name), 'utf8')).trim())
|
|
103
|
+
}
|
|
104
|
+
}
|
|
96
105
|
}
|
|
97
106
|
|
|
98
|
-
return
|
|
107
|
+
if (sections.length === 0) return text
|
|
108
|
+
return text.trimEnd() + '\n\n' + sections.join('\n\n') + '\n'
|
|
99
109
|
}
|