@nitra/cursor 12.6.1 → 12.8.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 -1
- package/.pi-template/extensions/n-cursor-adr/docs/index.md +2 -2
- package/CHANGELOG.md +25 -5
- package/bin/docs/n-cursor.md +4 -20
- package/bin/n-cursor.js +8 -54
- package/docs/index.md +3 -3
- package/docs/stryker.config.md +20 -28
- package/lib/docs/index.md +5 -5
- package/lib/docs/llm.md +4 -4
- package/package.json +2 -2
- package/rules/abie/docs/fix.md +8 -8
- package/rules/abie/docs/index.md +4 -3
- package/rules/abie/docs/main.md +29 -0
- package/rules/abie/js/docs/index.md +6 -6
- package/rules/abie/lib/docs/index.md +9 -9
- package/rules/abie/{fix.mjs → main.mjs} +5 -3
- package/rules/adr/docs/index.md +1 -0
- package/rules/adr/docs/main.md +29 -0
- package/rules/adr/{fix.mjs → main.mjs} +5 -3
- package/rules/bun/docs/fix.md +5 -5
- package/rules/bun/docs/index.md +4 -3
- package/rules/bun/docs/main.md +30 -0
- package/rules/bun/js/docs/index.md +2 -2
- package/rules/bun/js/docs/layout.md +11 -36
- package/rules/bun/{fix.mjs → main.mjs} +5 -3
- package/rules/capacitor/docs/fix.md +10 -10
- package/rules/capacitor/docs/index.md +4 -3
- package/rules/capacitor/docs/main.md +29 -0
- package/rules/capacitor/js/docs/index.md +2 -2
- package/rules/capacitor/{fix.mjs → main.mjs} +5 -3
- package/rules/changelog/docs/fix.md +11 -11
- package/rules/changelog/docs/index.md +4 -3
- package/rules/changelog/docs/main.md +27 -0
- package/rules/changelog/js/docs/consistency.md +12 -12
- package/rules/changelog/js/docs/index.md +2 -2
- package/rules/changelog/lib/docs/index.md +2 -2
- package/rules/changelog/main.mjs +20 -0
- package/rules/ci4/docs/fix.md +4 -4
- package/rules/ci4/docs/index.md +4 -3
- package/rules/ci4/docs/main.md +30 -0
- package/rules/ci4/js/docs/index.md +2 -2
- package/rules/ci4/main.mjs +20 -0
- package/rules/doc-files/docs/index.md +4 -3
- package/rules/doc-files/docs/main.md +31 -0
- package/rules/doc-files/js/docgen-crc.mjs +2 -8
- package/rules/doc-files/js/docgen-extract.mjs +5 -3
- package/rules/doc-files/js/docgen-files-batch.mjs +63 -4
- package/rules/doc-files/js/docgen-gen.mjs +11 -3
- package/rules/doc-files/js/docgen-judge-measure.mjs +67 -18
- package/rules/doc-files/js/docgen-judge.mjs +8 -1
- package/rules/doc-files/js/docgen-scan.mjs +99 -11
- package/rules/doc-files/js/docs/docgen-crc.md +25 -14
- package/rules/doc-files/js/docs/docgen-extract.md +15 -13
- package/rules/doc-files/js/docs/docgen-files-batch.md +15 -15
- package/rules/doc-files/js/docs/docgen-gen.md +15 -26
- package/rules/doc-files/js/docs/docgen-judge-measure.md +14 -12
- package/rules/doc-files/js/docs/docgen-scan.md +34 -34
- package/rules/doc-files/js/docs/index.md +16 -15
- package/rules/doc-files/js/docs/run-lint.md +27 -0
- package/rules/doc-files/{lint/lint.mjs → js/run-lint.mjs} +23 -9
- package/rules/doc-files/{js/lint.mjs → main.mjs} +60 -10
- package/rules/docker/docs/fix.md +6 -6
- package/rules/docker/docs/index.md +4 -3
- package/rules/docker/docs/main.md +28 -0
- package/rules/docker/js/docs/index.md +2 -2
- package/rules/docker/js/docs/lint.md +26 -54
- package/rules/docker/js/lint.mjs +11 -0
- package/rules/docker/lib/docker-hadolint.mjs +1 -1
- package/rules/docker/lib/docs/docker-hadolint.md +16 -173
- package/rules/docker/lib/docs/index.md +5 -5
- package/rules/docker/main.mjs +20 -0
- package/rules/efes/docs/fix.md +8 -8
- package/rules/efes/docs/index.md +4 -3
- package/rules/efes/docs/main.md +29 -0
- package/rules/efes/main.mjs +20 -0
- package/rules/feedback/docs/fix.md +5 -5
- package/rules/feedback/docs/index.md +4 -3
- package/rules/feedback/docs/main.md +30 -0
- package/rules/feedback/main.mjs +20 -0
- package/rules/ga/docs/fix.md +5 -5
- package/rules/ga/docs/index.md +4 -3
- package/rules/ga/docs/main.md +29 -0
- package/rules/ga/js/docs/index.md +3 -3
- package/rules/ga/{lint/lint.mjs → main.mjs} +36 -10
- package/rules/graphql/docs/fix.md +8 -8
- package/rules/graphql/docs/index.md +4 -3
- package/rules/graphql/docs/main.md +36 -0
- package/rules/graphql/js/docs/index.md +2 -2
- package/rules/graphql/lib/docs/index.md +2 -2
- package/rules/graphql/main.mjs +20 -0
- package/rules/hasura/docs/fix.md +11 -11
- package/rules/hasura/docs/index.md +4 -3
- package/rules/hasura/docs/main.md +30 -0
- package/rules/hasura/js/docs/index.md +2 -2
- package/rules/hasura/main.mjs +20 -0
- package/rules/image-avif/docs/fix.md +3 -3
- package/rules/image-avif/docs/index.md +4 -3
- package/rules/image-avif/docs/main.md +30 -0
- package/rules/image-avif/js/docs/avif_generation.md +20 -233
- package/rules/image-avif/js/docs/index.md +2 -2
- package/rules/image-avif/main.mjs +20 -0
- package/rules/image-compress/docs/fix.md +2 -2
- package/rules/image-compress/docs/index.md +4 -3
- package/rules/image-compress/docs/main.md +29 -0
- package/rules/image-compress/js/docs/index.md +3 -3
- package/rules/image-compress/js/docs/package_setup.md +12 -11
- package/rules/image-compress/{js/lint.mjs → main.mjs} +21 -5
- package/rules/js-bun-db/docs/fix.md +5 -5
- package/rules/js-bun-db/docs/index.md +4 -3
- package/rules/js-bun-db/docs/main.md +30 -0
- package/rules/js-bun-db/js/docs/index.md +2 -2
- package/rules/js-bun-db/lib/docs/index.md +2 -2
- package/rules/js-bun-db/main.mjs +20 -0
- package/rules/js-bun-redis/docs/fix.md +6 -6
- package/rules/js-bun-redis/docs/index.md +4 -3
- package/rules/js-bun-redis/docs/main.md +29 -0
- package/rules/js-bun-redis/js/docs/index.md +2 -2
- package/rules/js-bun-redis/lib/docs/index.md +2 -2
- package/rules/js-bun-redis/main.mjs +20 -0
- package/rules/js-lint/docs/fix.md +9 -9
- package/rules/js-lint/docs/index.md +4 -3
- package/rules/js-lint/docs/main.md +29 -0
- package/rules/js-lint/js/check.mjs +268 -0
- package/rules/js-lint/js/docs/check.md +39 -0
- package/rules/js-lint/js/docs/index.md +4 -4
- package/rules/js-lint/js/docs/tooling.md +12 -32
- package/rules/js-lint/js/tooling.mjs +1 -265
- package/rules/js-lint/{js/lint.mjs → main.mjs} +19 -2
- package/rules/js-lint-ci/docs/fix.md +3 -3
- package/rules/js-lint-ci/docs/index.md +4 -3
- package/rules/js-lint-ci/docs/main.md +27 -0
- package/rules/js-lint-ci/js/docs/index.md +2 -2
- package/rules/js-lint-ci/main.mjs +33 -0
- package/rules/js-mssql/docs/fix.md +5 -5
- package/rules/js-mssql/docs/index.md +4 -3
- package/rules/js-mssql/docs/main.md +30 -0
- package/rules/js-mssql/js/docs/index.md +2 -2
- package/rules/js-mssql/lib/docs/index.md +2 -2
- package/rules/js-mssql/main.mjs +20 -0
- package/rules/js-run/docs/fix.md +8 -8
- package/rules/js-run/docs/index.md +4 -3
- package/rules/js-run/docs/main.md +30 -0
- package/rules/js-run/js/docs/index.md +2 -2
- package/rules/js-run/lib/docs/index.md +7 -7
- package/rules/js-run/main.mjs +20 -0
- package/rules/k8s/docs/fix.md +4 -4
- package/rules/k8s/docs/index.md +4 -3
- package/rules/k8s/docs/main.md +40 -0
- package/rules/k8s/js/docs/index.md +12 -0
- package/rules/k8s/{lint/lint.mjs → main.mjs} +32 -10
- package/rules/nginx-default-tpl/docs/fix.md +7 -7
- package/rules/nginx-default-tpl/docs/index.md +4 -3
- package/rules/nginx-default-tpl/docs/main.md +30 -0
- package/rules/nginx-default-tpl/js/docs/index.md +2 -2
- package/rules/nginx-default-tpl/js/docs/template.md +2 -2
- package/rules/nginx-default-tpl/main.mjs +20 -0
- package/rules/npm-module/docs/fix.md +8 -8
- package/rules/npm-module/docs/index.md +4 -3
- package/rules/npm-module/docs/main.md +29 -0
- package/rules/npm-module/js/docs/index.md +5 -5
- package/rules/npm-module/js/docs/rule_meta.md +17 -16
- package/rules/npm-module/js/header_doc_pointer.mjs +1 -3
- package/rules/npm-module/js/rule_meta.mjs +13 -3
- package/rules/npm-module/main.mjs +20 -0
- package/rules/php/docs/fix.md +6 -6
- package/rules/php/docs/index.md +4 -3
- package/rules/php/docs/main.md +33 -0
- package/rules/php/js/docs/index.md +3 -3
- package/rules/php/js/docs/tooling.md +10 -10
- package/rules/php/{lint/lint.mjs → main.mjs} +32 -6
- package/rules/python/docs/fix.md +11 -11
- package/rules/python/docs/index.md +4 -3
- package/rules/python/docs/main.md +31 -0
- package/rules/python/js/docs/index.md +3 -3
- package/rules/python/js/docs/tooling.md +17 -17
- package/rules/python/{lint/lint.mjs → main.mjs} +31 -6
- package/rules/rego/docs/fix.md +5 -5
- package/rules/rego/docs/index.md +4 -3
- package/rules/rego/docs/main.md +37 -0
- package/rules/rego/js/docs/index.md +3 -3
- package/rules/rego/{lint/lint.mjs → main.mjs} +27 -5
- package/rules/release/docs/index.md +5 -4
- package/rules/release/docs/main.md +29 -0
- package/rules/release/docs/release.md +0 -3
- package/rules/release/lib/docs/index.md +4 -4
- package/rules/release/release.mdc +10 -0
- package/rules/rust/docs/fix.md +4 -4
- package/rules/rust/docs/index.md +4 -3
- package/rules/rust/docs/main.md +27 -0
- package/rules/rust/js/docs/index.md +3 -3
- package/rules/rust/lib/docs/index.md +2 -2
- package/rules/rust/{js/lint.mjs → main.mjs} +27 -4
- package/rules/security/docs/fix.md +6 -6
- package/rules/security/docs/index.md +4 -3
- package/rules/security/docs/main.md +28 -0
- package/rules/security/js/docs/index.md +4 -4
- package/rules/security/main.mjs +45 -0
- package/rules/style-lint/docs/fix.md +3 -3
- package/rules/style-lint/docs/index.md +4 -3
- package/rules/style-lint/docs/main.md +29 -0
- package/rules/style-lint/js/docs/index.md +3 -3
- package/rules/style-lint/{js/lint.mjs → main.mjs} +19 -1
- package/rules/tauri/docs/fix.md +11 -11
- package/rules/tauri/docs/index.md +4 -3
- package/rules/tauri/docs/main.md +29 -0
- package/rules/tauri/js/docs/index.md +3 -3
- package/rules/tauri/main.mjs +20 -0
- package/rules/test/docs/fix.md +5 -5
- package/rules/test/docs/index.md +4 -3
- package/rules/test/docs/main.md +30 -0
- package/rules/test/js/data/stryker_config/docs/index.md +4 -4
- package/rules/test/js/data/vitest_config/docs/index.md +2 -2
- package/rules/test/js/docs/index.md +7 -7
- package/rules/test/main.mjs +20 -0
- package/rules/text/docs/fix.md +11 -11
- package/rules/text/docs/index.md +4 -3
- package/rules/text/docs/main.md +29 -0
- package/rules/text/{lint → js}/cspell-fix.mjs +7 -2
- package/rules/text/js/docs/cspell-fix.md +30 -0
- package/rules/text/js/docs/formatting.md +12 -45
- package/rules/text/js/docs/index.md +8 -4
- package/rules/text/js/docs/run-dotenv-linter.md +31 -0
- package/rules/text/js/docs/run-shellcheck.md +28 -0
- package/rules/text/js/docs/run-v8r.md +29 -0
- package/rules/text/{lint/lint.mjs → main.mjs} +41 -10
- package/rules/tool-surface/docs/index.md +4 -3
- package/rules/tool-surface/docs/main.md +29 -0
- package/rules/tool-surface/main.mjs +20 -0
- package/rules/tool-surface/meta.json +6 -1
- package/rules/vue/docs/fix.md +6 -6
- package/rules/vue/docs/index.md +4 -3
- package/rules/vue/docs/main.md +29 -0
- package/rules/vue/js/docs/index.md +2 -2
- package/rules/vue/lib/docs/index.md +2 -2
- package/rules/vue/main.mjs +20 -0
- package/rules/worktree/docs/fix.md +11 -11
- package/rules/worktree/docs/index.md +4 -3
- package/rules/worktree/docs/main.md +28 -0
- package/rules/worktree/main.mjs +20 -0
- package/scripts/coverage-classify/docs/index.md +6 -6
- package/scripts/dispatcher/docs/index.md +2 -2
- package/scripts/docs/index.md +16 -15
- package/scripts/docs/post-tool-use-check.md +29 -0
- package/scripts/docs/sync-claude-config.md +64 -92
- package/scripts/lib/adr/docs/normalize-cli.md +0 -3
- package/scripts/lib/adr/docs/normalize-pipeline.md +0 -3
- package/scripts/lib/docs/gha-workflow.md +25 -317
- package/scripts/lib/docs/index.md +36 -35
- package/scripts/lib/docs/list-project-rules-mdc.md +5 -4
- package/scripts/lib/docs/list-rule-ids.md +15 -148
- package/scripts/lib/docs/read-n-cursor-config-lite.md +12 -16
- package/scripts/lib/docs/run-lint-step.md +13 -13
- package/scripts/lib/docs/run-lint.md +30 -0
- package/scripts/lib/docs/run-rule-cli.md +14 -10
- package/scripts/lib/docs/run-standard-lint.md +29 -10
- package/scripts/lib/docs/run-standard-rule.md +12 -11
- package/scripts/lib/docs/timing-summary.md +11 -12
- package/scripts/lib/docs/worktree-notice.md +0 -3
- package/scripts/lib/fix/analyze-escalation.mjs +4 -1
- package/scripts/lib/fix/docs/index.md +11 -10
- package/scripts/lib/fix/docs/orchestrator.md +23 -18
- package/scripts/lib/fix/docs/run-conformance-check.md +33 -0
- package/scripts/lib/fix/docs/run-fix-check.md +3 -3
- package/scripts/lib/fix/docs/t0.md +10 -9
- package/scripts/lib/fix/orchestrator.mjs +31 -8
- package/scripts/lib/fix/{run-fix-check.mjs → run-conformance-check.mjs} +13 -13
- package/scripts/lib/fix/t0.mjs +6 -3
- package/scripts/lib/list-project-rules-mdc.mjs +1 -1
- package/scripts/lib/list-rule-ids.mjs +12 -3
- package/scripts/lib/read-n-cursor-config-lite.mjs +2 -2
- package/{rules/lint/js/orchestrate.mjs → scripts/lib/run-lint.mjs} +42 -22
- package/scripts/lib/run-rule-cli.mjs +4 -4
- package/scripts/lib/run-standard-lint.mjs +19 -6
- package/scripts/lib/run-standard-rule.mjs +4 -4
- package/scripts/lib/timing-summary.mjs +1 -1
- package/scripts/{post-tool-use-fix.mjs → post-tool-use-check.mjs} +9 -9
- package/scripts/sync-claude-config.mjs +2 -2
- package/scripts/utils/docs/index.md +14 -14
- package/skills/doc-aggregate/js/docs/index.md +3 -3
- package/skills/doc-files/.changes/260612-0002.md +1 -0
- package/skills/doc-files/.changes/260612-0006.md +1 -0
- package/skills/doc-files/.changes/260612-0008.md +1 -0
- package/skills/doc-files/.changes/260612-0012.md +1 -0
- package/skills/doc-files/.changes/260612-0031.md +1 -0
- package/skills/doc-files/.changes/260612-0036.md +1 -0
- package/skills/doc-files/.changes/260612-0114.md +1 -0
- package/skills/start-check/js/docs/index.md +2 -2
- package/skills/taze/js/docs/index.md +2 -2
- package/types/bin/n-cursor.d.ts +1 -1
- package/rules/changelog/fix.mjs +0 -18
- package/rules/ci4/fix.mjs +0 -18
- package/rules/doc-files/fix.mjs +0 -19
- package/rules/doc-files/js/docs/lint.md +0 -34
- package/rules/doc-files/lint/docs/index.md +0 -11
- package/rules/doc-files/lint/docs/lint.md +0 -35
- package/rules/docker/fix.mjs +0 -18
- package/rules/docker/lint/docs/index.md +0 -11
- package/rules/docker/lint/docs/lint.md +0 -200
- package/rules/docker/lint/lint.mjs +0 -95
- package/rules/efes/fix.mjs +0 -18
- package/rules/feedback/fix.mjs +0 -18
- package/rules/ga/fix.mjs +0 -18
- package/rules/ga/js/docs/lint.md +0 -20
- package/rules/ga/js/lint.mjs +0 -12
- package/rules/ga/lint/docs/index.md +0 -11
- package/rules/ga/lint/docs/lint.md +0 -31
- package/rules/graphql/fix.mjs +0 -18
- package/rules/hasura/fix.mjs +0 -18
- package/rules/image-avif/fix.mjs +0 -18
- package/rules/image-compress/fix.mjs +0 -18
- package/rules/image-compress/js/docs/lint.md +0 -24
- package/rules/js-bun-db/fix.mjs +0 -18
- package/rules/js-bun-redis/fix.mjs +0 -18
- package/rules/js-lint/fix.mjs +0 -18
- package/rules/js-lint/js/docs/lint.md +0 -32
- package/rules/js-lint-ci/fix.mjs +0 -18
- package/rules/js-lint-ci/js/docs/lint.md +0 -22
- package/rules/js-lint-ci/js/lint.mjs +0 -15
- package/rules/js-mssql/fix.mjs +0 -18
- package/rules/js-run/fix.mjs +0 -18
- package/rules/k8s/fix.mjs +0 -18
- package/rules/k8s/js/lint.mjs +0 -14
- package/rules/k8s/lint/docs/index.md +0 -11
- package/rules/k8s/lint/docs/lint.md +0 -413
- package/rules/lint/docs/fix.md +0 -25
- package/rules/lint/docs/index.md +0 -11
- package/rules/lint/fix.mjs +0 -18
- package/rules/lint/js/docs/index.md +0 -11
- package/rules/lint/js/docs/orchestrate.md +0 -31
- package/rules/lint/meta.json +0 -1
- package/rules/nginx-default-tpl/fix.mjs +0 -18
- package/rules/npm-module/fix.mjs +0 -18
- package/rules/php/fix.mjs +0 -18
- package/rules/php/js/docs/lint.md +0 -20
- package/rules/php/js/lint.mjs +0 -15
- package/rules/php/lint/docs/index.md +0 -11
- package/rules/php/lint/docs/lint.md +0 -219
- package/rules/python/fix.mjs +0 -18
- package/rules/python/js/docs/lint.md +0 -21
- package/rules/python/js/lint.mjs +0 -14
- package/rules/python/lint/docs/index.md +0 -11
- package/rules/python/lint/docs/lint.md +0 -29
- package/rules/rego/fix.mjs +0 -18
- package/rules/rego/js/docs/lint.md +0 -21
- package/rules/rego/js/lint.mjs +0 -12
- package/rules/rego/lint/docs/index.md +0 -11
- package/rules/rego/lint/docs/lint.md +0 -208
- package/rules/rust/fix.mjs +0 -18
- package/rules/rust/js/docs/lint.md +0 -21
- package/rules/security/fix.mjs +0 -18
- package/rules/security/js/docs/lint.md +0 -175
- package/rules/security/js/lint.mjs +0 -26
- package/rules/style-lint/fix.mjs +0 -18
- package/rules/style-lint/js/docs/lint.md +0 -31
- package/rules/tauri/fix.mjs +0 -18
- package/rules/test/fix.mjs +0 -18
- package/rules/text/fix.mjs +0 -18
- package/rules/text/js/docs/lint.md +0 -23
- package/rules/text/js/lint.mjs +0 -15
- package/rules/text/lint/docs/cspell-fix.md +0 -32
- package/rules/text/lint/docs/index.md +0 -15
- package/rules/text/lint/docs/lint.md +0 -36
- package/rules/text/lint/docs/run-dotenv-linter.md +0 -161
- package/rules/text/lint/docs/run-shellcheck.md +0 -216
- package/rules/text/lint/docs/run-v8r.md +0 -201
- package/rules/tool-surface/fix.mjs +0 -18
- package/rules/vue/fix.mjs +0 -18
- package/rules/worktree/fix.mjs +0 -18
- /package/rules/release/{fix.mjs → main.mjs} +0 -0
- /package/rules/text/{lint → js}/run-dotenv-linter.mjs +0 -0
- /package/rules/text/{lint → js}/run-shellcheck.mjs +0 -0
- /package/rules/text/{lint → js}/run-v8r.mjs +0 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: JS Module
|
|
3
|
+
title: run-conformance-check.mjs
|
|
4
|
+
resource: npm/scripts/lib/fix/run-conformance-check.mjs
|
|
5
|
+
docgen:
|
|
6
|
+
crc: 7a026c26
|
|
7
|
+
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
8
|
+
score: 90
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Огляд
|
|
12
|
+
|
|
13
|
+
Модуль реалізує прямий механізм виконання конформності, викликаючи конформність-фазу `lint`, движок (`orchestrator.mjs`, `t0.mjs`) та PostToolUse-хук. Селекція активних правил здійснюється на основі конфігурації `.n-cursor.json`. Для забезпечення ізоляції, кожен обраний `entrypoint rules/<id>/main.mjs` запускається окремим процесом `bun`.
|
|
14
|
+
|
|
15
|
+
## Поведінка
|
|
16
|
+
|
|
17
|
+
resolveCheckRuleIds визначає набір ID правил для прогону, використовуючи `.n-cursor.json` як єдине джерело правди для селекції. Якщо запитані правила надані, вони фільтруються за активністю; інакше, він вибирає активні правила з конфігурації, або, за відсутності конфігурації, використовує зматеріалізовані файли `.cursor/rules/*.mdc` для режиму відладки.
|
|
18
|
+
|
|
19
|
+
runConformanceCheck виконує перевірку конформності для кожного правила, яке було визначено як активне. Він запускає кожен `check.mjs` окремим процесом `bun` для ізоляції та повертає загальну кількість виконаних, успішних та невдалих перевірок.
|
|
20
|
+
|
|
21
|
+
## Публічний API
|
|
22
|
+
|
|
23
|
+
resolveCheckRuleIds — Визначає, які правила будуть застосовані для перевірки, використовуючи `.n-cursor.json` як основне джерело:
|
|
24
|
+
|
|
25
|
+
- Якщо вказані правила, вони фільтруються до активних у конфігурації.
|
|
26
|
+
- Якщо правила не вказані, беруться всі активні правила з конфігу.
|
|
27
|
+
- Якщо правила не вказані і конфіг відсутній, використовується список правил, що були збережені локально.
|
|
28
|
+
|
|
29
|
+
runConformanceCheck — Виконує перевірку відповідності для кожного окремого правила без внесення змін.
|
|
30
|
+
|
|
31
|
+
## Гарантії поведінки
|
|
32
|
+
|
|
33
|
+
- Read-only: не виконує операцій запису (ФС/БД).
|
|
@@ -15,9 +15,9 @@ docgen:
|
|
|
15
15
|
1. Визначається наявність інструменту `conftest`.
|
|
16
16
|
2. Отримується список усіх доступних ідентифікаторів правил з каталогу правил.
|
|
17
17
|
3. Визначається список ідентифікаторів правил для прогону (`resolveCheckRuleIds`), де `.n-cursor.json` — єдине джерело правди:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
а. Якщо надано явний список правил — він валідується проти доступних і звужується до активних (вимкнене правило не вмикається навіть на явний запит).
|
|
19
|
+
б. Якщо явного списку нема й конфіг є — беруться активні правила конфіга (`available ∩ enabled`); `.cursor/rules/*.mdc` ігнорується (фікс дрейфу «enabled, але .mdc нема»).
|
|
20
|
+
в. Якщо конфіга нема (open-by-default debug) — fallback на скан `.cursor/rules/*.mdc`.
|
|
21
21
|
4. Якщо визначено ідентифікатори правил для прогону, для кожного ідентифікатора запускається окремий процес `bun` з файлом `fix.mjs` відповідного правила.
|
|
22
22
|
5. Захоплюється вивід кожного процесу.
|
|
23
23
|
6. Підраховується загальна кількість правил, що не пройшли перевірку.
|
|
@@ -3,26 +3,27 @@ type: JS Module
|
|
|
3
3
|
title: t0.mjs
|
|
4
4
|
resource: npm/scripts/lib/fix/t0.mjs
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
6
|
+
crc: 49c0669b
|
|
7
7
|
model: omlx/gemma-4-e4b-it-OptiQ-4bit
|
|
8
8
|
score: 100
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
## Огляд
|
|
12
|
+
|
|
13
|
+
Модуль керує автоматичним застосуванням T0-auto паттернів до виводів порушень. Він визначає, які правила можуть бути оброблені автоматично, використовуючи конфігурації з `extensions.json` та `package-lock.json`. Функціонал реалізовано через публічні функції: `filterT0AutoRules` для визначення правил, `applyT0Auto` для автоматичного застосування паттернів до виводів, та `runT0AutoCli` для запуску процесу. Модуль працює у режимі fail-safe, перехоплюючи помилки та не кидаючи винятків назовні, надаючи звіт про застосовані автоматичні виправлення.
|
|
12
14
|
|
|
13
15
|
## Поведінка
|
|
14
16
|
|
|
15
|
-
applyT0Auto застосовує
|
|
16
|
-
filterT0AutoRules повертає
|
|
17
|
-
runT0AutoCli запускає T0-auto для
|
|
17
|
+
applyT0Auto застосовує всі визначені T0-auto паттерни до одного виводу порушення, повертаючи результат застосування.
|
|
18
|
+
filterT0AutoRules повертає список ID правил, для яких існує хоча б один T0-auto паттерн, виходячи з виводів порушень.
|
|
19
|
+
runT0AutoCli запускає T0-auto для кожного провального правила, повторно перевіряє конформність та виводить підсумок.
|
|
18
20
|
|
|
19
21
|
## Публічний API
|
|
20
22
|
|
|
21
|
-
applyT0Auto —
|
|
22
|
-
filterT0AutoRules —
|
|
23
|
-
runT0AutoCli —
|
|
23
|
+
applyT0Auto — вносить зміни до виводу порушень, використовуючи всі визначені T0-auto шаблони.
|
|
24
|
+
filterT0AutoRules — визначає, які правила мають принаймні один T0-auto шаблон, ґрунтуючись на виводі порушень у форматі JSON.
|
|
25
|
+
runT0AutoCli — виконує команду `n-cursor fix-t0 [rule...]`, яка застосовує T0-auto до кожного порушення, повторно перевіряє check-gate та надає звіт.
|
|
24
26
|
|
|
25
27
|
## Гарантії поведінки
|
|
26
28
|
|
|
27
29
|
- Перехоплює помилки і не пропускає винятків назовні (fail-safe).
|
|
28
|
-
- Не звертається до мережі.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @see ./docs/orchestrator.md */
|
|
2
2
|
|
|
3
3
|
import { env } from 'node:process'
|
|
4
|
-
import {
|
|
4
|
+
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'
|
|
@@ -45,7 +45,14 @@ const CLOUD_TRANSPORT_RE = /etimedout|timed out|pi error/i
|
|
|
45
45
|
export function buildLadder({ localMin, cloudMin, cloudAvg }) {
|
|
46
46
|
return [
|
|
47
47
|
{ tier: 'local-min', model: localMin, feedback: false, local: true, isAvg: false, timeoutMs: LOCAL_TIMEOUT_MS },
|
|
48
|
-
{
|
|
48
|
+
{
|
|
49
|
+
tier: 'local-min-retry',
|
|
50
|
+
model: localMin,
|
|
51
|
+
feedback: true,
|
|
52
|
+
local: true,
|
|
53
|
+
isAvg: false,
|
|
54
|
+
timeoutMs: LOCAL_TIMEOUT_MS
|
|
55
|
+
},
|
|
49
56
|
{ tier: 'cloud-min', model: cloudMin, feedback: true, local: false, isAvg: false, timeoutMs: CLOUD_TIMEOUT_MS },
|
|
50
57
|
{ tier: 'cloud-avg', model: cloudAvg, feedback: true, local: false, isAvg: true, timeoutMs: CLOUD_TIMEOUT_MS }
|
|
51
58
|
].filter(r => r.model)
|
|
@@ -103,7 +110,15 @@ export async function escalateRule(rule, cwd, deps) {
|
|
|
103
110
|
|
|
104
111
|
const common = { rung: idx, tier: rung.tier, model: rung.model, withFeedback: rung.feedback }
|
|
105
112
|
if (rung.isAvg && avgBudget - avgUsed <= 0) {
|
|
106
|
-
record({
|
|
113
|
+
record({
|
|
114
|
+
...common,
|
|
115
|
+
callOk: false,
|
|
116
|
+
callError: 'cloud-avg cap reached',
|
|
117
|
+
recheckOk: false,
|
|
118
|
+
remainingViolation: currentViolation,
|
|
119
|
+
diagnosis: null,
|
|
120
|
+
ms: 0
|
|
121
|
+
})
|
|
107
122
|
log(` ⏭️ ${rule.ruleId}: ${rung.tier} пропущено (avg-кеп вичерпано)`)
|
|
108
123
|
continue
|
|
109
124
|
}
|
|
@@ -120,7 +135,15 @@ export async function escalateRule(rule, cwd, deps) {
|
|
|
120
135
|
const recheck = await check([rule.ruleId], cwd)
|
|
121
136
|
const recheckOk = recheck.rules.every(r => r.ok)
|
|
122
137
|
const remaining = recheckOk ? '' : (recheck.rules.find(r => !r.ok)?.output ?? '')
|
|
123
|
-
record({
|
|
138
|
+
record({
|
|
139
|
+
...common,
|
|
140
|
+
callOk: res.ok,
|
|
141
|
+
callError: res.error ?? null,
|
|
142
|
+
recheckOk,
|
|
143
|
+
remainingViolation: remaining,
|
|
144
|
+
diagnosis: res.diagnosis ?? null,
|
|
145
|
+
ms: clock() - startedAt
|
|
146
|
+
})
|
|
124
147
|
|
|
125
148
|
if (recheckOk) {
|
|
126
149
|
log(` ✅ ${rung.tier} (${rung.model || 'pi'}): ${rule.ruleId}`)
|
|
@@ -165,7 +188,7 @@ export function parseOrchestratorArgs(args) {
|
|
|
165
188
|
async function runT0Step(cwd, ruleFilter, failed) {
|
|
166
189
|
await runT0AutoCli([...ruleFilter], cwd)
|
|
167
190
|
|
|
168
|
-
const afterT0 = await
|
|
191
|
+
const afterT0 = await runConformanceCheck(ruleFilter, cwd)
|
|
169
192
|
const failedAfterT0 = afterT0.rules.filter(r => !r.ok)
|
|
170
193
|
const t0Fixed = failed.filter(r => !failedAfterT0.some(f => f.ruleId === r.ruleId))
|
|
171
194
|
|
|
@@ -186,7 +209,7 @@ export async function runOrchestratorCli(args, cwd) {
|
|
|
186
209
|
const ladder = buildLadder({ localMin: LOCAL_MIN, cloudMin: CLOUD_MIN, cloudAvg: CLOUD_AVG })
|
|
187
210
|
|
|
188
211
|
// ── Перша перевірка (тихо) ──
|
|
189
|
-
const initial = await
|
|
212
|
+
const initial = await runConformanceCheck(ruleFilter, cwd)
|
|
190
213
|
let failed = initial.rules.filter(r => !r.ok)
|
|
191
214
|
const total = initial.total
|
|
192
215
|
|
|
@@ -220,14 +243,14 @@ export async function runOrchestratorCli(args, cwd) {
|
|
|
220
243
|
const { avgUsed } = await escalateRule(rule, cwd, {
|
|
221
244
|
ladder,
|
|
222
245
|
worker,
|
|
223
|
-
check:
|
|
246
|
+
check: runConformanceCheck,
|
|
224
247
|
avgBudget
|
|
225
248
|
})
|
|
226
249
|
avgBudget -= avgUsed
|
|
227
250
|
}
|
|
228
251
|
|
|
229
252
|
// ── Фінальна перевірка ──
|
|
230
|
-
const finalCheck = await
|
|
253
|
+
const finalCheck = await runConformanceCheck(ruleFilter, cwd)
|
|
231
254
|
const stillFailed = finalCheck.rules.filter(r => !r.ok)
|
|
232
255
|
if (stillFailed.length === 0) {
|
|
233
256
|
console.log(`✅ fix: ${total} правил — все чисто`)
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Конформність-детект
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Конформність-детект як ПРЯМА функція — без subprocess-обгортки.
|
|
3
|
+
* Викликають конформність-фаза `lint` (read-only), движок (`orchestrator.mjs`, `t0.mjs`)
|
|
4
|
+
* і PostToolUse-хук.
|
|
5
5
|
*
|
|
6
|
-
* Per-rule ізоляція зберігається:
|
|
7
|
-
* процесом `bun` (crash-isolation).
|
|
8
|
-
*
|
|
6
|
+
* Per-rule ізоляція зберігається: entrypoint `rules/<id>/main.mjs` кожного правила
|
|
7
|
+
* запускається окремим процесом `bun` (crash-isolation). Канон — єдиний `main.mjs`
|
|
8
|
+
* (ADR 2026-06-21); його CLI-блок кличе `runRuleCli(import.meta.dirname)`.
|
|
9
9
|
*
|
|
10
10
|
* Селекція активних правил — виключно тут (`resolveCheckRuleIds` за `.n-cursor.json`);
|
|
11
11
|
* per-rule whitelist у спавнених процесах прибрано як дубль (див. `runRuleCli`).
|
|
@@ -21,7 +21,7 @@ import { discoverCheckRulesFromCursorRules } from '../discover-check-rules-from-
|
|
|
21
21
|
import { listProjectRulesMdcFiles } from '../list-project-rules-mdc.mjs'
|
|
22
22
|
import { isRuleEnabled, readNCursorConfigLite } from '../read-n-cursor-config-lite.mjs'
|
|
23
23
|
|
|
24
|
-
// Цей файл: npm/scripts/lib/fix/run-
|
|
24
|
+
// Цей файл: npm/scripts/lib/fix/run-conformance-check.mjs → npm/rules (чотири dirname угору + rules).
|
|
25
25
|
const BUNDLED_RULES_DIR = join(dirname(dirname(dirname(dirname(fileURLToPath(import.meta.url))))), 'rules')
|
|
26
26
|
|
|
27
27
|
/**
|
|
@@ -61,16 +61,16 @@ export async function resolveCheckRuleIds(requestedRules, available, cwd) {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
|
-
* Прогоняє
|
|
64
|
+
* Прогоняє check-entrypoint кожного правила окремим процесом, захоплюючи output.
|
|
65
65
|
* @param {string[]} idsToRun правила
|
|
66
66
|
* @param {string} cwd корінь
|
|
67
67
|
* @returns {{ totalFailed:number, rules:Array<{ruleId:string, ok:boolean, output:string}> }} результат
|
|
68
68
|
*/
|
|
69
|
-
function
|
|
69
|
+
function runRuleCheckProcesses(idsToRun, cwd) {
|
|
70
70
|
let totalFailed = 0
|
|
71
71
|
const rules = []
|
|
72
72
|
for (const id of idsToRun) {
|
|
73
|
-
const r = spawnSync('bun', [join(BUNDLED_RULES_DIR, id, '
|
|
73
|
+
const r = spawnSync('bun', [join(BUNDLED_RULES_DIR, id, 'main.mjs')], { cwd, encoding: 'utf8' })
|
|
74
74
|
const ok = r.status === 0
|
|
75
75
|
rules.push({ ruleId: id, ok, output: `${r.stdout ?? ''}${r.stderr ?? ''}`.trim() })
|
|
76
76
|
if (!ok) totalFailed++
|
|
@@ -79,12 +79,12 @@ function runRuleFixProcesses(idsToRun, cwd) {
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
/**
|
|
82
|
-
* Конформність-детект: per-rule `
|
|
82
|
+
* Конформність-детект: per-rule `check.mjs run()` (= перевірка, без мутацій).
|
|
83
83
|
* @param {string[]} [requestedRules] фільтр (порожній → discovery з `.cursor/rules/`)
|
|
84
84
|
* @param {string} [cwd] корінь
|
|
85
85
|
* @returns {Promise<{ total:number, failed:number, rules:Array<{ruleId:string, ok:boolean, output:string}> }>} результат
|
|
86
86
|
*/
|
|
87
|
-
export async function
|
|
87
|
+
export async function runConformanceCheck(requestedRules = [], cwd = processCwd()) {
|
|
88
88
|
ensureTool('conftest')
|
|
89
89
|
const available = await listRuleIds(BUNDLED_RULES_DIR)
|
|
90
90
|
if (available.length === 0) return { total: 0, failed: 0, rules: [] }
|
|
@@ -92,6 +92,6 @@ export async function runFixCheck(requestedRules = [], cwd = processCwd()) {
|
|
|
92
92
|
const idsToRun = await resolveCheckRuleIds(requestedRules, available, cwd)
|
|
93
93
|
if (idsToRun.length === 0) return { total: 0, failed: 0, rules: [] }
|
|
94
94
|
|
|
95
|
-
const { totalFailed, rules } =
|
|
95
|
+
const { totalFailed, rules } = runRuleCheckProcesses(idsToRun, cwd)
|
|
96
96
|
return { total: idsToRun.length, failed: totalFailed, rules }
|
|
97
97
|
}
|
package/scripts/lib/fix/t0.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { spawnSync } from 'node:child_process'
|
|
|
3
3
|
import { existsSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
|
4
4
|
import { join } from 'node:path'
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { runConformanceCheck } from './run-conformance-check.mjs'
|
|
7
7
|
import { writeChange } from '../../../rules/release/change.mjs'
|
|
8
8
|
|
|
9
9
|
const REC_REQUIRE_RE = /recommendations має містити "[^"]+"/
|
|
@@ -188,7 +188,7 @@ export async function runT0AutoCli(args, cwd) {
|
|
|
188
188
|
const verbose = args.includes('--verbose') || args.includes('-v')
|
|
189
189
|
|
|
190
190
|
// 1. Конформність-детект (пряма функція, без subprocess)
|
|
191
|
-
const fixJson = await
|
|
191
|
+
const fixJson = await runConformanceCheck(ruleFilter, cwd)
|
|
192
192
|
const failed = fixJson.rules.filter(r => !r.ok)
|
|
193
193
|
if (failed.length === 0) {
|
|
194
194
|
console.log(`✅ fix-t0: всі правила чисті — T0 не потрібен`)
|
|
@@ -210,7 +210,10 @@ export async function runT0AutoCli(args, cwd) {
|
|
|
210
210
|
}
|
|
211
211
|
|
|
212
212
|
// 4. Check-gate: перевірити лише ті правила, що ми чіпали
|
|
213
|
-
const recheckJson = await
|
|
213
|
+
const recheckJson = await runConformanceCheck(
|
|
214
|
+
applied.map(a => a.ruleId),
|
|
215
|
+
cwd
|
|
216
|
+
)
|
|
214
217
|
const stillFailed = recheckJson.rules.filter(r => !r.ok)
|
|
215
218
|
|
|
216
219
|
if (verbose) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Список `.mdc`-файлів правил у `.cursor/rules/` проєкту-споживача (відсортований).
|
|
3
|
-
* Винесено зі `bin/n-cursor.js`, щоб ділити між CLI-dispatch і `run-
|
|
3
|
+
* Винесено зі `bin/n-cursor.js`, щоб ділити між CLI-dispatch і `run-conformance-check` (конформність-детект).
|
|
4
4
|
*/
|
|
5
5
|
import { existsSync } from 'node:fs'
|
|
6
6
|
import { readdir } from 'node:fs/promises'
|
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Перебір `rules/<id>/` директорій з фільтром на наявність
|
|
3
|
-
*
|
|
2
|
+
* Перебір `rules/<id>/` директорій з фільтром на наявність entrypoint-а.
|
|
3
|
+
* Канон (ADR 2026-06-21): єдиний entrypoint `rules/<id>/main.mjs`. Каталог без нього —
|
|
4
4
|
* пропускається (це not-a-rule або заглушка).
|
|
5
5
|
*/
|
|
6
6
|
import { existsSync } from 'node:fs'
|
|
7
7
|
import { readdir } from 'node:fs/promises'
|
|
8
8
|
import { join } from 'node:path'
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Чи має каталог правила entrypoint `main.mjs`.
|
|
12
|
+
* @param {string} ruleDir абсолютний шлях `rules/<id>/`
|
|
13
|
+
* @returns {boolean} true, якщо `main.mjs` існує
|
|
14
|
+
*/
|
|
15
|
+
function hasEntrypoint(ruleDir) {
|
|
16
|
+
return existsSync(join(ruleDir, 'main.mjs'))
|
|
17
|
+
}
|
|
18
|
+
|
|
10
19
|
/**
|
|
11
20
|
* @param {string} bundledRulesDir абсолютний шлях до `npm/rules/`
|
|
12
21
|
* @param {string} [filter] id одного правила (через `--rule abie`)
|
|
@@ -17,7 +26,7 @@ export async function listRuleIds(bundledRulesDir, filter) {
|
|
|
17
26
|
const ids = entries
|
|
18
27
|
.filter(e => e.isDirectory() && !e.name.startsWith('.'))
|
|
19
28
|
.map(e => e.name)
|
|
20
|
-
.filter(id =>
|
|
29
|
+
.filter(id => hasEntrypoint(join(bundledRulesDir, id)))
|
|
21
30
|
.filter(id => filter === undefined || id === filter)
|
|
22
31
|
return ids.toSorted((a, b) => a.localeCompare(b))
|
|
23
32
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Light read-only `.n-cursor.json` reader для standalone `
|
|
2
|
+
* Light read-only `.n-cursor.json` reader для standalone `check.mjs` invocation.
|
|
3
3
|
*
|
|
4
4
|
* НЕ робить auto-rules detection, merge, schema sync — це справа повного `readConfig` у CLI.
|
|
5
5
|
* Тут лише: прочитати файл (якщо є), повернути `{ rules: string[], disableRules: string[] }`.
|
|
6
6
|
*
|
|
7
7
|
* Спостереження whitelist:
|
|
8
8
|
* - якщо `.n-cursor.json` НЕМАЄ → правило вважається enabled (поведінка "open by default"),
|
|
9
|
-
* щоб `bun rules/<id>/
|
|
9
|
+
* щоб `bun rules/<id>/check.mjs` з будь-якої тимчасової директорії працювало для debug.
|
|
10
10
|
* - якщо файл є з `rules:[…]`, але правила там немає → правило не enabled.
|
|
11
11
|
* - якщо правило в `disable-rules` → не enabled, навіть якщо у `rules:[…]`.
|
|
12
12
|
*/
|
|
@@ -1,19 +1,40 @@
|
|
|
1
|
-
/** @see ./docs/
|
|
1
|
+
/** @see ./docs/run-lint.md */
|
|
2
2
|
import { existsSync, readdirSync } from 'node:fs'
|
|
3
3
|
import { dirname, join } from 'node:path'
|
|
4
4
|
import { fileURLToPath } from 'node:url'
|
|
5
5
|
import { cwd as processCwd } from 'node:process'
|
|
6
6
|
import { spawnSync } from 'node:child_process'
|
|
7
7
|
|
|
8
|
-
import { parseRuleLintSpec, readRuleMetaRaw } from '
|
|
9
|
-
import { collectChangedFilesSince, resolveChangedBase } from '
|
|
10
|
-
import { resolveCmd } from '
|
|
11
|
-
import { isRuleEnabled, readNCursorConfigLite } from '
|
|
8
|
+
import { parseRuleLintSpec, readRuleMetaRaw } from './rule-meta.mjs'
|
|
9
|
+
import { collectChangedFilesSince, resolveChangedBase } from './changed-files.mjs'
|
|
10
|
+
import { resolveCmd } from '../utils/resolve-cmd.mjs'
|
|
11
|
+
import { isRuleEnabled, readNCursorConfigLite } from './read-n-cursor-config-lite.mjs'
|
|
12
12
|
|
|
13
|
-
// Цей файл: npm/
|
|
14
|
-
const PACKAGE_ROOT = dirname(dirname(
|
|
13
|
+
// Цей файл: npm/scripts/lib/run-lint.mjs → PACKAGE_ROOT = npm (два dirname угору).
|
|
14
|
+
const PACKAGE_ROOT = dirname(dirname(fileURLToPath(import.meta.url)))
|
|
15
15
|
const RULES_DIR = join(PACKAGE_ROOT, 'rules')
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Чи має правило лінт-поверхню — `meta.json#lint` задано (`per-file`/`full`).
|
|
19
|
+
* Канонічний сигнал (ADR 2026-06-21): gate за meta, не за наявністю файлу.
|
|
20
|
+
* @param {Record<string, unknown> | undefined} raw meta-обʼєкт правила
|
|
21
|
+
* @returns {boolean} true — правило лінтить
|
|
22
|
+
*/
|
|
23
|
+
function hasLintSurface(raw) {
|
|
24
|
+
return parseRuleLintSpec(raw?.lint) !== null
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Резолвить лінт-entrypoint правила: `main.mjs` з експортом `lint` (канон, ADR 2026-06-21).
|
|
29
|
+
* @param {string} rulesDir каталог rules
|
|
30
|
+
* @param {string} id rule-id
|
|
31
|
+
* @returns {string | null} шлях до `main.mjs`, або null якщо файлу нема
|
|
32
|
+
*/
|
|
33
|
+
function resolveLintEntrypoint(rulesDir, id) {
|
|
34
|
+
const main = join(rulesDir, id, 'main.mjs')
|
|
35
|
+
return existsSync(main) ? main : null
|
|
36
|
+
}
|
|
37
|
+
|
|
17
38
|
/**
|
|
18
39
|
* Конформність-фаза lint (whole-repo: config/file/workflow conformance — те, що раніше робив `fix`).
|
|
19
40
|
* Per-file декомпозиції немає, тож виконується лише у `--full`.
|
|
@@ -27,11 +48,11 @@ const RULES_DIR = join(PACKAGE_ROOT, 'rules')
|
|
|
27
48
|
*/
|
|
28
49
|
async function runConformance(cwd, readOnly, log, filter = []) {
|
|
29
50
|
if (!readOnly) {
|
|
30
|
-
const { runOrchestratorCli } = await import('
|
|
51
|
+
const { runOrchestratorCli } = await import('./fix/orchestrator.mjs')
|
|
31
52
|
return runOrchestratorCli(filter, cwd)
|
|
32
53
|
}
|
|
33
|
-
const {
|
|
34
|
-
const { rules } = await
|
|
54
|
+
const { runConformanceCheck } = await import('./fix/run-conformance-check.mjs')
|
|
55
|
+
const { rules } = await runConformanceCheck(filter, cwd)
|
|
35
56
|
const failed = rules.filter(x => !x.ok)
|
|
36
57
|
if (failed.length === 0) return 0
|
|
37
58
|
log(`❌ lint: конформність — ${failed.length} порушень: ${failed.map(x => x.ruleId).join(', ')}\n`)
|
|
@@ -97,9 +118,9 @@ async function runPerFileRules(ids, ctx) {
|
|
|
97
118
|
const { rulesDir, changed, cwd, readOnly, metaById, log } = ctx
|
|
98
119
|
let worst = 0
|
|
99
120
|
for (const id of ids) {
|
|
100
|
-
const lintPath =
|
|
101
|
-
if (!
|
|
102
|
-
log(`⚠️ lint: правило ${id} має lint
|
|
121
|
+
const lintPath = resolveLintEntrypoint(rulesDir, id)
|
|
122
|
+
if (!lintPath) {
|
|
123
|
+
log(`⚠️ lint: правило ${id} має lint-фазу (meta.lint), але немає main.mjs — пропускаю.\n`)
|
|
103
124
|
continue
|
|
104
125
|
}
|
|
105
126
|
// lintPath = join(rulesDir, id, …) — суто package-internal (rulesDir пакета + id зі
|
|
@@ -127,9 +148,7 @@ async function runPerFileRules(ids, ctx) {
|
|
|
127
148
|
* @returns {Promise<number>} код конформності
|
|
128
149
|
*/
|
|
129
150
|
async function runFullConformancePhase(cwd, readOnly, log) {
|
|
130
|
-
const { escalationLogSize, maybeAnalyzeEscalation, reportRunStats } = await import(
|
|
131
|
-
'../../../scripts/lib/fix/analyze-escalation.mjs'
|
|
132
|
-
)
|
|
151
|
+
const { escalationLogSize, maybeAnalyzeEscalation, reportRunStats } = await import('./fix/analyze-escalation.mjs')
|
|
133
152
|
const escOffset = readOnly ? 0 : escalationLogSize()
|
|
134
153
|
const conformanceCode = await runConformance(cwd, readOnly, log)
|
|
135
154
|
if (!readOnly) {
|
|
@@ -160,11 +179,12 @@ function runFormat(cwd, log) {
|
|
|
160
179
|
}
|
|
161
180
|
|
|
162
181
|
/**
|
|
163
|
-
* Scoped-режим (`lint <rule…>`): повний прогін НАЗВАНИХ правил — їх лінтер (
|
|
164
|
-
* whole-repo) для тих, що
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
182
|
+
* Scoped-режим (`lint <rule…>`): повний прогін НАЗВАНИХ правил — їх лінтер (entrypoint
|
|
183
|
+
* `main.mjs::lint`, whole-repo) для тих, що мають лінт-поверхню
|
|
184
|
+
* (`meta.json#lint`), + конформність для всіх названих. Дзеркалить `--full`, але звужено
|
|
185
|
+
* до правил, тож `lint ga` ≡ standalone `lint-ga`. Конформність-only правила (напр.
|
|
186
|
+
* `changelog` із hk) без `meta.lint` → проганяється лише їх конформність (зворотна
|
|
187
|
+
* сумісність із колишнім `fix <rule>`). oxfmt у scoped НЕ запускається — це
|
|
168
188
|
* таргетований прогін правил, а не глобальне форматування.
|
|
169
189
|
* @param {string[]} rules id названих правил
|
|
170
190
|
* @param {{ cwd: string, readOnly: boolean, rulesDir: string, conformance: boolean, log: (s: string) => void }} ctx контекст (`conformance` — чи запускати конформність; false для юніт-тестів із кастомним rulesDir, де реальний пакет недоступний)
|
|
@@ -173,7 +193,7 @@ function runFormat(cwd, log) {
|
|
|
173
193
|
async function runScopedRules(rules, ctx) {
|
|
174
194
|
const { cwd, readOnly, rulesDir, conformance, log } = ctx
|
|
175
195
|
const metaById = readAllMeta(rulesDir)
|
|
176
|
-
const linterIds = rules.filter(id =>
|
|
196
|
+
const linterIds = rules.filter(id => hasLintSurface(metaById[id]))
|
|
177
197
|
let worst = 0
|
|
178
198
|
if (linterIds.length > 0) {
|
|
179
199
|
const perFile = await runPerFileRules(linterIds, { rulesDir, changed: undefined, cwd, readOnly, metaById, log })
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Standalone CLI runner для одного правила. Викликається з `rules/<id>/
|
|
3
|
-
* у блоці `if (import.meta.main)` — це робить `bun rules/<id>/
|
|
2
|
+
* Standalone CLI runner для одного правила. Викликається з `rules/<id>/check.mjs`
|
|
3
|
+
* у блоці `if (import.meta.main)` — це робить `bun rules/<id>/check.mjs` повним
|
|
4
4
|
* еквівалентом `npx \@nitra/cursor fix <id>`: друкує summary, повертає aggregated exit-code.
|
|
5
5
|
*
|
|
6
6
|
* **Без whitelist-гейту.** Гейтинг активних правил — єдине джерело: `resolveCheckRuleIds`
|
|
7
|
-
* (`scripts/lib/fix/run-
|
|
7
|
+
* (`scripts/lib/fix/run-conformance-check.mjs`) за `.n-cursor.json`. Прямий `bun rules/<id>/check.mjs` —
|
|
8
8
|
* свідомий запуск саме цього правила (debug / override), тож виконується беззастережно;
|
|
9
9
|
* усі автоматичні шляхи (lint-конформність, orchestrator, t0, hook) уже спавнять лише активні.
|
|
10
10
|
*
|
|
@@ -15,7 +15,7 @@ import { basename } from 'node:path'
|
|
|
15
15
|
import { runStandardRule } from './run-standard-rule.mjs'
|
|
16
16
|
import { getOrCreateWalkCache } from '../utils/walk-cache.mjs'
|
|
17
17
|
|
|
18
|
-
// Re-export для зворотної сумісності: уся `rules/<id>/
|
|
18
|
+
// Re-export для зворотної сумісності: уся `rules/<id>/check.mjs` уже імпортує `isRunAsCli`
|
|
19
19
|
// саме звідси. Канонічна реалізація — у `scripts/cli-entry.mjs`. Caller передає
|
|
20
20
|
// `import.meta.url`: `if (isRunAsCli(import.meta.url)) …`.
|
|
21
21
|
export { isRunAsCli } from '../cli-entry.mjs'
|
|
@@ -7,29 +7,42 @@
|
|
|
7
7
|
* патчилися в кожному `rules/<rule>/lint/lint.mjs`.
|
|
8
8
|
*
|
|
9
9
|
* Зараз робить рівно одне: серіалізує + дедуплікує запуски через `withLock('lint-<ruleId>')`.
|
|
10
|
-
* `ruleId` виводиться зі
|
|
10
|
+
* `ruleId` виводиться зі шляху незалежно від глибини виклику: `rules/<id>` (з `main.mjs`),
|
|
11
|
+
* `rules/<id>/js` або `rules/<id>/lint` → `<id>` (сегмент одразу після `rules/`).
|
|
11
12
|
*
|
|
12
13
|
* Інтеграція з боку правила:
|
|
13
14
|
*
|
|
14
15
|
* ```js
|
|
15
|
-
* import { runStandardLint } from '
|
|
16
|
+
* import { runStandardLint } from '../../scripts/lib/run-standard-lint.mjs'
|
|
16
17
|
*
|
|
17
18
|
* async function runLintFooSteps() { ... }
|
|
18
19
|
*
|
|
19
|
-
* export
|
|
20
|
+
* export function lint(_files) { return runStandardLint(import.meta.dirname, runLintFooSteps) }
|
|
20
21
|
* ```
|
|
21
22
|
*/
|
|
22
|
-
import { basename
|
|
23
|
+
import { basename } from 'node:path'
|
|
23
24
|
|
|
24
25
|
import { withLock } from '../utils/with-lock.mjs'
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
|
-
*
|
|
28
|
+
* Виводить `<id>` зі шляху каталогу правила незалежно від глибини: сегмент одразу після
|
|
29
|
+
* останнього `rules/`. Fallback — `basename(dir)`, якщо `rules/` у шляху немає.
|
|
30
|
+
* @param {string} dir абсолютний шлях каталогу (`rules/<id>`, `rules/<id>/js`, …)
|
|
31
|
+
* @returns {string} rule-id
|
|
32
|
+
*/
|
|
33
|
+
function ruleIdFromDir(dir) {
|
|
34
|
+
const parts = dir.split(/[/\\]/u)
|
|
35
|
+
const i = parts.lastIndexOf('rules')
|
|
36
|
+
return i !== -1 && parts[i + 1] ? parts[i + 1] : basename(dir)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @param {string} lintDir абсолютний шлях до каталогу правила (передавай `import.meta.dirname`)
|
|
28
41
|
* @param {() => number | Promise<number>} stepsFn реальна робота лінту; повертає код виходу
|
|
29
42
|
* @param {{ttl?:number, staleThreshold?:number, waitTimeout?:number, pollInterval?:number, cacheDir?:string, getFingerprint?:() => string | null}} [opts] прокидаються у `withLock`
|
|
30
43
|
* @returns {Promise<number>} код виходу
|
|
31
44
|
*/
|
|
32
45
|
export function runStandardLint(lintDir, stepsFn, opts) {
|
|
33
|
-
const ruleId =
|
|
46
|
+
const ruleId = ruleIdFromDir(lintDir)
|
|
34
47
|
return withLock(`lint-${ruleId}`, stepsFn, opts)
|
|
35
48
|
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Public API per-rule orchestration. Викликається з `rules/<id>/
|
|
2
|
+
* Public API per-rule orchestration. Викликається з `rules/<id>/check.mjs`.
|
|
3
3
|
*
|
|
4
4
|
* Інкапсулює: `discoverOneRule` → `runRule(applies → JS → policy → mdc-refs)`.
|
|
5
5
|
* Локальна логіка в правилах заборонена; розширення поведінки — через `ctx`-опції.
|
|
6
6
|
*
|
|
7
7
|
* Серіалізація: загортає виконання у `withLock('fix-<ruleId>')` — паралельні запуски
|
|
8
|
-
* того самого правила (через `npx \@nitra/cursor fix`, прямий `bun rules/<id>/
|
|
8
|
+
* того самого правила (через `npx \@nitra/cursor fix`, прямий `bun rules/<id>/check.mjs`
|
|
9
9
|
* чи `run(ctx)`-композицію) дедупляться за станом git-дерева; різні правила можуть
|
|
10
10
|
* виконуватись паралельно. Точка інтеграції — тут, щоб не дублювати лок у кожному
|
|
11
|
-
* `
|
|
11
|
+
* `check.mjs`.
|
|
12
12
|
*/
|
|
13
13
|
import { basename, dirname } from 'node:path'
|
|
14
14
|
|
|
@@ -24,7 +24,7 @@ import { withLock } from '../utils/with-lock.mjs'
|
|
|
24
24
|
* Зарезервовано на майбутнє (поки не реалізовано — додається, коли з'явиться потреба):
|
|
25
25
|
* - `skipMdcRefs`, `skipApplies`, `onlyConcerns`.
|
|
26
26
|
* Розширення поведінки правила робиться лише через нові поля тут, не через локальну
|
|
27
|
-
* логіку в `rules/<id>/
|
|
27
|
+
* логіку в `rules/<id>/check.mjs`.
|
|
28
28
|
*/
|
|
29
29
|
|
|
30
30
|
/**
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Формат таблиці-резюме часу виконання для orchestrator `fix` / `lint`.
|
|
3
3
|
*
|
|
4
4
|
* Дві спільні точки використання:
|
|
5
|
-
* - `runFixCommand` у `bin/n-cursor.js` — після прогону всіх `rules/<id>/
|
|
5
|
+
* - `runFixCommand` у `bin/n-cursor.js` — після прогону всіх `rules/<id>/check.mjs`.
|
|
6
6
|
* - `runLintCli` у `scripts/lib/run-lint-cli.mjs` — після прогону `lint-*` скриптів з кореневого `package.json`.
|
|
7
7
|
*
|
|
8
8
|
* Чиста функція без I/O — повертає готовий рядок (з фінальним `\n`), друк — на стороні виклику.
|
|
@@ -4,17 +4,17 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Раніше хук маршрутизував змінений файл у релевантні правила й ганяв повний `fix` (автофікс
|
|
6
6
|
* + LLM) — дорого, тож звужували. Тепер хук — **детект** (нуль мутацій, нуль LLM), тож роутинг
|
|
7
|
-
* зайвий: один виклик `_fix-check` (per-rule `
|
|
7
|
+
* зайвий: один виклик `_fix-check` (per-rule `check.mjs run()` = перевірка) по всіх правилах.
|
|
8
8
|
*
|
|
9
9
|
* Контракт:
|
|
10
10
|
* - stdin Claude Code: JSON із `tool_input.file_path`; якщо файлу немає (напр. Bash) — exit 0 (skip);
|
|
11
|
-
* - інакше пряма `
|
|
11
|
+
* - інакше пряма `runConformanceCheck` (детект усіх правил, без subprocess-обгортки), exit-код прозоро:
|
|
12
12
|
* 1 — є порушення конформності (PostToolUse не блокує turn, але код лишаємо інформативним).
|
|
13
13
|
*/
|
|
14
14
|
import { once } from 'node:events'
|
|
15
15
|
import { cwd as processCwd } from 'node:process'
|
|
16
16
|
|
|
17
|
-
import {
|
|
17
|
+
import { runConformanceCheck } from './lib/fix/run-conformance-check.mjs'
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Зчитує stdin до EOF як utf8 рядок. На TTY — повертає `''` одразу.
|
|
@@ -57,20 +57,20 @@ export function extractFilePath(stdinJson) {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
/**
|
|
60
|
-
* Точка входу. Викликається з `bin/n-cursor.js` коли argv[0] === `post-tool-use-
|
|
60
|
+
* Точка входу. Викликається з `bin/n-cursor.js` коли argv[0] === `post-tool-use-check`.
|
|
61
61
|
* Параметри доступні для інʼєкції для тестів: `stdinJson` обходить read від `process.stdin`,
|
|
62
|
-
* `
|
|
63
|
-
* @param {{ stdinJson?: string,
|
|
62
|
+
* `runConformanceCheckFn` — заміна `runConformanceCheck`.
|
|
63
|
+
* @param {{ stdinJson?: string, runConformanceCheckFn?: typeof runConformanceCheck }} [options] параметри для тестів
|
|
64
64
|
* @returns {Promise<number>} exit code (0 — пропущено / конформність ОК; 1 — є порушення)
|
|
65
65
|
*/
|
|
66
|
-
export async function
|
|
66
|
+
export async function runPostToolUseCheckCli(options = {}) {
|
|
67
67
|
const stdinJson = options.stdinJson ?? (await readStdin())
|
|
68
68
|
const filePath = extractFilePath(stdinJson)
|
|
69
69
|
// Тільки після редагування файлу (Edit/Write/MultiEdit мають file_path); Bash тощо — skip.
|
|
70
70
|
if (filePath === null) {
|
|
71
71
|
return 0
|
|
72
72
|
}
|
|
73
|
-
const check = options.
|
|
73
|
+
const check = options.runConformanceCheckFn ?? runConformanceCheck
|
|
74
74
|
// Один read-only детект конформності всіх активованих правил (пряма функція, без subprocess).
|
|
75
75
|
try {
|
|
76
76
|
const { failed, rules } = await check([], processCwd())
|
|
@@ -80,7 +80,7 @@ export async function runPostToolUseFixCli(options = {}) {
|
|
|
80
80
|
}
|
|
81
81
|
return 1
|
|
82
82
|
} catch (error) {
|
|
83
|
-
process.stderr.write(`post-tool-use-
|
|
83
|
+
process.stderr.write(`post-tool-use-check: не вдалося запустити детект конформності — ${error.message}\n`)
|
|
84
84
|
return 1
|
|
85
85
|
}
|
|
86
86
|
}
|