@nitra/cursor 1.9.21 → 1.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/hooks/capture-decisions.sh +3 -3
- package/.claude-template/hooks/normalize-decisions.sh +370 -0
- package/CHANGELOG.md +43 -0
- package/bin/n-cursor.js +56 -49
- package/package.json +10 -5
- package/rules/abie/auto.md +1 -0
- package/{scripts/check-abie.mjs → rules/abie/js/check.mjs} +5 -5
- package/rules/adr/adr.mdc +150 -0
- package/{scripts/check-adr.mjs → rules/adr/js/check.mjs} +85 -41
- package/rules/adr/policy/settings_json/settings_json.rego +37 -0
- package/rules/adr/policy/settings_local_json/settings_local_json.rego +40 -0
- package/rules/bun/auto.md +1 -0
- package/{scripts/check-bun.mjs → rules/bun/js/check.mjs} +1 -1
- package/rules/capacitor/auto.md +1 -0
- package/{scripts/check-capacitor.mjs → rules/capacitor/js/check.mjs} +1 -1
- package/rules/changelog/auto.md +1 -0
- package/{scripts/check-changelog.mjs → rules/changelog/js/check.mjs} +2 -2
- package/rules/docker/auto.md +1 -0
- package/{scripts/check-docker.mjs → rules/docker/js/check.mjs} +5 -5
- package/{scripts/run-docker.mjs → rules/docker/js/run.mjs} +5 -5
- package/rules/ga/auto.md +1 -0
- package/{scripts/check-ga.mjs → rules/ga/js/check.mjs} +4 -4
- package/{scripts/lint-ga.mjs → rules/ga/js/lint.mjs} +2 -2
- package/rules/graphql/auto.md +1 -0
- package/{scripts/check-graphql.mjs → rules/graphql/js/check.mjs} +5 -5
- package/rules/hasura/auto.md +1 -0
- package/{scripts/check-hasura.mjs → rules/hasura/js/check.mjs} +4 -4
- package/rules/image-avif/auto.md +1 -0
- package/{scripts/check-image-avif.mjs → rules/image-avif/js/check.mjs} +5 -5
- package/rules/image-compress/auto.md +1 -0
- package/{scripts/check-image-compress.mjs → rules/image-compress/js/check.mjs} +1 -1
- package/rules/js-bun-db/auto.md +1 -0
- package/{scripts/check-js-bun-db.mjs → rules/js-bun-db/js/check.mjs} +5 -5
- package/rules/js-bun-redis/auto.md +1 -0
- package/{scripts/check-js-bun-redis.mjs → rules/js-bun-redis/js/check.mjs} +4 -4
- package/rules/js-lint/auto.md +1 -0
- package/{scripts/check-js-lint.mjs → rules/js-lint/js/check.mjs} +1 -1
- package/rules/js-mssql/auto.md +1 -0
- package/{scripts/check-js-mssql.mjs → rules/js-mssql/js/check.mjs} +5 -5
- package/rules/js-run/auto.md +1 -0
- package/{scripts/check-js-run.mjs → rules/js-run/js/check.mjs} +11 -11
- package/rules/k8s/auto.md +1 -0
- package/{scripts/check-k8s.mjs → rules/k8s/js/check.mjs} +4 -4
- package/{scripts/run-k8s.mjs → rules/k8s/js/run.mjs} +4 -4
- package/rules/nginx-default-tpl/auto.md +1 -0
- package/{scripts/check-nginx-default-tpl.mjs → rules/nginx-default-tpl/js/check.mjs} +7 -7
- package/rules/npm-module/auto.md +1 -0
- package/{scripts/check-npm-module.mjs → rules/npm-module/js/check.mjs} +4 -4
- package/rules/php/auto.md +1 -0
- package/{scripts/check-php.mjs → rules/php/js/check.mjs} +1 -1
- package/{scripts/run-php.mjs → rules/php/js/run.mjs} +3 -3
- package/rules/rego/auto.md +1 -0
- package/{scripts/check-rego.mjs → rules/rego/js/check.mjs} +4 -4
- package/{scripts/lint-rego.mjs → rules/rego/js/lint.mjs} +1 -1
- package/rules/style-lint/auto.md +1 -0
- package/{scripts/check-style-lint.mjs → rules/style-lint/js/check.mjs} +1 -1
- package/rules/tauri/auto.md +1 -0
- package/{scripts/check-tauri.mjs → rules/tauri/js/check.mjs} +2 -2
- package/rules/text/auto.md +1 -0
- package/{scripts/check-text.mjs → rules/text/js/check.mjs} +2 -2
- package/{scripts/run-shellcheck-text.mjs → rules/text/js/run-shellcheck.mjs} +2 -2
- package/{scripts → rules/text/js}/run-v8r.mjs +2 -2
- package/{mdc → rules/text}/text.mdc +4 -0
- package/rules/vue/auto.md +1 -0
- package/{scripts/check-vue.mjs → rules/vue/js/check.mjs} +5 -5
- package/scripts/auto-rules.mjs +5 -5
- package/scripts/auto-skills.mjs +8 -6
- package/scripts/lint-conftest.mjs +13 -13
- package/scripts/sync-claude-config.mjs +70 -14
- package/scripts/utils/run-conftest-batch.mjs +9 -4
- package/skills/abie-clean/auto.md +1 -0
- package/skills/abie-kustomize/auto.md +1 -0
- package/skills/adr-normalize/SKILL.md +71 -0
- package/skills/adr-normalize/auto.md +1 -0
- package/skills/fix/auto.md +1 -0
- package/skills/lint/auto.md +1 -0
- package/skills/llm-patch/auto.md +1 -0
- package/skills/publish-telegram/auto.md +1 -0
- package/skills/taze/auto.md +1 -0
- package/bin/auto-rules.md +0 -59
- package/bin/auto-skills.md +0 -25
- package/mdc/adr.mdc +0 -86
- package/policy/adr/settings_json/settings_json.rego +0 -31
- package/policy/adr/settings_local_json/settings_local_json.rego +0 -28
- /package/{mdc → rules/abie}/abie.mdc +0 -0
- /package/{policy/abie → rules/abie/policy}/base_deployment_preem/base_deployment_preem.rego +0 -0
- /package/{policy/abie → rules/abie/policy}/base_deployment_preem/base_deployment_preem_test.rego +0 -0
- /package/{policy/abie → rules/abie/policy}/clean_merged_ignore_branches/clean_merged_ignore_branches.rego +0 -0
- /package/{policy/abie → rules/abie/policy}/clean_merged_ignore_branches/clean_merged_ignore_branches_test.rego +0 -0
- /package/{policy/abie → rules/abie/policy}/health_check_policy/health_check_policy.rego +0 -0
- /package/{policy/abie → rules/abie/policy}/health_check_policy/health_check_policy_test.rego +0 -0
- /package/{policy/abie → rules/abie/policy}/http_route_base/http_route_base.rego +0 -0
- /package/{policy/abie → rules/abie/policy}/http_route_base/http_route_base_test.rego +0 -0
- /package/{mdc → rules/bun}/bun.mdc +0 -0
- /package/{policy/bun → rules/bun/policy}/bunfig/bunfig.rego +0 -0
- /package/{policy/bun → rules/bun/policy}/package_json/package_json.rego +0 -0
- /package/{policy/bun → rules/bun/policy}/package_json/package_json_test.rego +0 -0
- /package/{mdc → rules/capacitor}/capacitor.mdc +0 -0
- /package/{policy/capacitor → rules/capacitor/policy}/package_json/package_json.rego +0 -0
- /package/{mdc → rules/changelog}/changelog.mdc +0 -0
- /package/{mdc → rules/ci4}/ci4.mdc +0 -0
- /package/{mdc → rules/docker}/docker.mdc +0 -0
- /package/{policy/docker → rules/docker/policy}/lint_docker_yml/lint_docker_yml.rego +0 -0
- /package/{policy/docker → rules/docker/policy}/lint_docker_yml/lint_docker_yml_test.rego +0 -0
- /package/{policy/docker → rules/docker/policy}/package_json/package_json.rego +0 -0
- /package/{policy/docker → rules/docker/policy}/package_json/package_json_test.rego +0 -0
- /package/{mdc → rules/ga}/ga.mdc +0 -0
- /package/{policy/ga → rules/ga/policy}/clean_ga_workflows/clean_ga_workflows.rego +0 -0
- /package/{policy/ga → rules/ga/policy}/clean_merged_branch/clean_merged_branch.rego +0 -0
- /package/{policy/ga → rules/ga/policy}/git_ai/git_ai.rego +0 -0
- /package/{policy/ga → rules/ga/policy}/lint_ga/lint_ga.rego +0 -0
- /package/{policy/ga → rules/ga/policy}/workflow_common/workflow_common.rego +0 -0
- /package/{mdc → rules/graphql}/graphql.mdc +0 -0
- /package/{policy/graphql → rules/graphql/policy}/vscode_extensions/vscode_extensions.rego +0 -0
- /package/{policy/graphql → rules/graphql/policy}/vscode_extensions/vscode_extensions_test.rego +0 -0
- /package/{mdc → rules/hasura}/hasura.mdc +0 -0
- /package/{policy/hasura → rules/hasura/policy}/svc_hl/svc_hl.rego +0 -0
- /package/{mdc → rules/image-avif}/image-avif.mdc +0 -0
- /package/{policy/image_avif → rules/image-avif/policy}/package_json/package_json.rego +0 -0
- /package/{policy/image_avif → rules/image-avif/policy}/package_json/package_json_test.rego +0 -0
- /package/{mdc → rules/image-compress}/image-compress.mdc +0 -0
- /package/{policy/image_compress → rules/image-compress/policy}/package_json/package_json.rego +0 -0
- /package/{mdc → rules/js-bun-db}/js-bun-db.mdc +0 -0
- /package/{policy/js_bun_db → rules/js-bun-db/policy}/package_json/package_json.rego +0 -0
- /package/{mdc → rules/js-bun-redis}/js-bun-redis.mdc +0 -0
- /package/{policy/js_bun_redis → rules/js-bun-redis/policy}/package_json/package_json.rego +0 -0
- /package/{mdc → rules/js-lint}/js-lint.mdc +0 -0
- /package/{policy/js_lint → rules/js-lint/policy}/lint_js_yml/lint_js_yml.rego +0 -0
- /package/{policy/js_lint → rules/js-lint/policy}/package_json/package_json.rego +0 -0
- /package/{policy/js_lint → rules/js-lint/policy}/package_json/package_json_test.rego +0 -0
- /package/{mdc → rules/js-mssql}/js-mssql.mdc +0 -0
- /package/{policy/js_mssql → rules/js-mssql/policy}/package_json/package_json.rego +0 -0
- /package/{mdc → rules/js-run}/js-run.mdc +0 -0
- /package/{policy/js_run → rules/js-run/policy}/configmap/configmap.rego +0 -0
- /package/{policy/js_run → rules/js-run/policy}/jsconfig/jsconfig.rego +0 -0
- /package/{policy/js_run → rules/js-run/policy}/jsconfig/jsconfig_test.rego +0 -0
- /package/{policy/js_run → rules/js-run/policy}/package_json/package_json.rego +0 -0
- /package/{mdc → rules/k8s}/k8s.mdc +0 -0
- /package/{policy/k8s → rules/k8s/policy}/base_kustomization/base_kustomization.rego +0 -0
- /package/{policy/k8s → rules/k8s/policy}/base_kustomization/base_kustomization_test.rego +0 -0
- /package/{policy/k8s → rules/k8s/policy}/base_manifest/base_manifest.rego +0 -0
- /package/{policy/k8s → rules/k8s/policy}/base_manifest/base_manifest_test.rego +0 -0
- /package/{policy/k8s → rules/k8s/policy}/gateway/gateway.rego +0 -0
- /package/{policy/k8s → rules/k8s/policy}/gateway/gateway_test.rego +0 -0
- /package/{policy/k8s → rules/k8s/policy}/hasura_configmap/hasura_configmap.rego +0 -0
- /package/{policy/k8s → rules/k8s/policy}/hasura_configmap/hasura_configmap_test.rego +0 -0
- /package/{policy/k8s → rules/k8s/policy}/hasura_httproute/hasura_httproute.rego +0 -0
- /package/{policy/k8s → rules/k8s/policy}/hasura_httproute/hasura_httproute_test.rego +0 -0
- /package/{policy/k8s → rules/k8s/policy}/hpa_pdb/hpa_pdb.rego +0 -0
- /package/{policy/k8s → rules/k8s/policy}/hpa_pdb/hpa_pdb_test.rego +0 -0
- /package/{policy/k8s → rules/k8s/policy}/kustomization/kustomization.rego +0 -0
- /package/{policy/k8s → rules/k8s/policy}/kustomization/kustomization_test.rego +0 -0
- /package/{policy/k8s → rules/k8s/policy}/manifest/manifest.rego +0 -0
- /package/{policy/k8s → rules/k8s/policy}/manifest/manifest_test.rego +0 -0
- /package/{policy/k8s → rules/k8s/policy}/svc_hl_yaml/svc_hl_yaml.rego +0 -0
- /package/{policy/k8s → rules/k8s/policy}/svc_hl_yaml/svc_hl_yaml_test.rego +0 -0
- /package/{policy/k8s → rules/k8s/policy}/svc_yaml/svc_yaml.rego +0 -0
- /package/{policy/k8s → rules/k8s/policy}/svc_yaml/svc_yaml_test.rego +0 -0
- /package/{mdc → rules/nginx-default-tpl}/nginx-default-tpl.mdc +0 -0
- /package/{policy/nginx_default_tpl → rules/nginx-default-tpl/policy}/vscode_extensions/vscode_extensions.rego +0 -0
- /package/{policy/nginx_default_tpl → rules/nginx-default-tpl/policy}/vscode_extensions/vscode_extensions_test.rego +0 -0
- /package/{policy/nginx_default_tpl → rules/nginx-default-tpl/policy}/vscode_settings/vscode_settings.rego +0 -0
- /package/{policy/nginx_default_tpl → rules/nginx-default-tpl/policy}/vscode_settings/vscode_settings_test.rego +0 -0
- /package/{mdc → rules/npm-module}/npm-module.mdc +0 -0
- /package/{policy/npm_module → rules/npm-module/policy}/emit_types_config/emit_types_config.rego +0 -0
- /package/{policy/npm_module → rules/npm-module/policy}/npm_package_json/npm_package_json.rego +0 -0
- /package/{policy/npm_module → rules/npm-module/policy}/npm_package_json/npm_package_json_test.rego +0 -0
- /package/{policy/npm_module → rules/npm-module/policy}/npm_publish_yml/npm_publish_yml.rego +0 -0
- /package/{policy/npm_module → rules/npm-module/policy}/root_package_json/root_package_json.rego +0 -0
- /package/{mdc → rules/php}/php.mdc +0 -0
- /package/{policy/php → rules/php/policy}/lint_php_yml/lint_php_yml.rego +0 -0
- /package/{policy/php → rules/php/policy}/package_json/package_json.rego +0 -0
- /package/{policy/rego → rules/rego/policy}/package_json/package_json.rego +0 -0
- /package/{policy/rego → rules/rego/policy}/package_json/package_json_test.rego +0 -0
- /package/{policy/rego → rules/rego/policy}/vscode_extensions/vscode_extensions.rego +0 -0
- /package/{policy/rego → rules/rego/policy}/vscode_extensions/vscode_extensions_test.rego +0 -0
- /package/{policy/rego → rules/rego/policy}/vscode_settings/vscode_settings.rego +0 -0
- /package/{policy/rego → rules/rego/policy}/vscode_settings/vscode_settings_test.rego +0 -0
- /package/{mdc → rules/rego}/rego.mdc +0 -0
- /package/{policy/style_lint → rules/style-lint/policy}/lint_style_yml/lint_style_yml.rego +0 -0
- /package/{policy/style_lint → rules/style-lint/policy}/package_json/package_json.rego +0 -0
- /package/{policy/style_lint → rules/style-lint/policy}/vscode_extensions/vscode_extensions.rego +0 -0
- /package/{policy/style_lint → rules/style-lint/policy}/vscode_extensions/vscode_extensions_test.rego +0 -0
- /package/{policy/style_lint → rules/style-lint/policy}/vscode_settings/vscode_settings.rego +0 -0
- /package/{policy/style_lint → rules/style-lint/policy}/vscode_settings/vscode_settings_test.rego +0 -0
- /package/{mdc → rules/style-lint}/style-lint.mdc +0 -0
- /package/{policy/tauri → rules/tauri/policy}/vscode_extensions/vscode_extensions.rego +0 -0
- /package/{policy/tauri → rules/tauri/policy}/vscode_extensions/vscode_extensions_test.rego +0 -0
- /package/{mdc → rules/tauri}/tauri.mdc +0 -0
- /package/{policy/text → rules/text/policy}/cspell/cspell.rego +0 -0
- /package/{policy/text → rules/text/policy}/markdownlint/markdownlint.rego +0 -0
- /package/{policy/text → rules/text/policy}/markdownlint/markdownlint_test.rego +0 -0
- /package/{policy/text → rules/text/policy}/oxfmtrc/oxfmtrc.rego +0 -0
- /package/{policy/text → rules/text/policy}/package_json/package_json.rego +0 -0
- /package/{policy/text → rules/text/policy}/vscode_extensions/vscode_extensions.rego +0 -0
- /package/{policy/text → rules/text/policy}/vscode_extensions/vscode_extensions_test.rego +0 -0
- /package/{policy/text → rules/text/policy}/vscode_settings/vscode_settings.rego +0 -0
- /package/{policy/text → rules/text/policy}/vscode_settings/vscode_settings_test.rego +0 -0
- /package/{policy/vue → rules/vue/policy}/package_json/package_json.rego +0 -0
- /package/{mdc → rules/vue}/vue.mdc +0 -0
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
import { spawnSync } from 'node:child_process'
|
|
16
16
|
import { basename, dirname, relative } from 'node:path'
|
|
17
17
|
|
|
18
|
-
import { isRunAsCli } from '
|
|
19
|
-
import { loadCursorIgnorePaths } from '
|
|
20
|
-
import { resolveCmd } from '
|
|
21
|
-
import { walkDir } from '
|
|
18
|
+
import { isRunAsCli } from '../../../scripts/cli-entry.mjs'
|
|
19
|
+
import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
|
|
20
|
+
import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
|
|
21
|
+
import { walkDir } from '../../../scripts/utils/walkDir.mjs'
|
|
22
22
|
|
|
23
23
|
const PATH_SEPARATOR_RE = /[/\\]/u
|
|
24
24
|
const YAML_EXT_RE = /\.yaml$/iu
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
якщо присутній хоч один файл з переліку - default.conf.template, default.conf, nginx.conf
|
|
@@ -17,11 +17,11 @@ import { existsSync } from 'node:fs'
|
|
|
17
17
|
import { readdir, readFile, rename, unlink, writeFile } from 'node:fs/promises'
|
|
18
18
|
import { basename, dirname, join, relative } from 'node:path'
|
|
19
19
|
|
|
20
|
-
import { findDockerfilePaths } from '
|
|
21
|
-
import { createCheckReporter } from '
|
|
22
|
-
import { loadCursorIgnorePaths } from '
|
|
23
|
-
import { runConftestBatch } from '
|
|
24
|
-
import { walkDir } from '
|
|
20
|
+
import { findDockerfilePaths } from '../../docker/js/check.mjs'
|
|
21
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
22
|
+
import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
|
|
23
|
+
import { runConftestBatch } from '../../../scripts/utils/run-conftest-batch.mjs'
|
|
24
|
+
import { walkDir } from '../../../scripts/utils/walkDir.mjs'
|
|
25
25
|
|
|
26
26
|
const LINE_SPLIT_RE = /\r?\n/u
|
|
27
27
|
const INI_KEY_RE = /^([A-Za-z_]\w*)\s*=/u
|
|
@@ -363,7 +363,7 @@ function checkVscodeNginx(passFn, failFn) {
|
|
|
363
363
|
const extPath = '.vscode/extensions.json'
|
|
364
364
|
if (existsSync(extPath)) {
|
|
365
365
|
const violations = runConftestBatch({
|
|
366
|
-
policyDirRel: '
|
|
366
|
+
policyDirRel: 'nginx-default-tpl/vscode_extensions',
|
|
367
367
|
namespace: 'nginx_default_tpl.vscode_extensions',
|
|
368
368
|
files: [extPath]
|
|
369
369
|
})
|
|
@@ -382,7 +382,7 @@ function checkVscodeNginx(passFn, failFn) {
|
|
|
382
382
|
return
|
|
383
383
|
}
|
|
384
384
|
const violations = runConftestBatch({
|
|
385
|
-
policyDirRel: '
|
|
385
|
+
policyDirRel: 'nginx-default-tpl/vscode_settings',
|
|
386
386
|
namespace: 'nginx_default_tpl.vscode_settings',
|
|
387
387
|
files: [setPath]
|
|
388
388
|
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
якщо в корені присутня директорія npm
|
|
@@ -32,10 +32,10 @@ import { promisify } from 'node:util'
|
|
|
32
32
|
|
|
33
33
|
import { parseSync } from 'oxc-parser'
|
|
34
34
|
|
|
35
|
-
import { dynamicImportModule, langFromPath, requireCallModule, walkAstWithAncestors } from '
|
|
36
|
-
import { createCheckReporter } from '
|
|
37
|
-
import { loadCursorIgnorePaths } from '
|
|
38
|
-
import { walkDir } from '
|
|
35
|
+
import { dynamicImportModule, langFromPath, requireCallModule, walkAstWithAncestors } from '../../../scripts/utils/ast-scan-utils.mjs'
|
|
36
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
37
|
+
import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
|
|
38
|
+
import { walkDir } from '../../../scripts/utils/walkDir.mjs'
|
|
39
39
|
|
|
40
40
|
const execFileAsync = promisify(execFile)
|
|
41
41
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
якщо в корені є composer.json
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { existsSync } from 'node:fs'
|
|
13
13
|
|
|
14
|
-
import { createCheckReporter } from '
|
|
14
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Перевіряє відповідність проєкту правилам php.mdc.
|
|
@@ -12,9 +12,9 @@ import { spawnSync } from 'node:child_process'
|
|
|
12
12
|
import { existsSync, statSync } from 'node:fs'
|
|
13
13
|
import { join, resolve } from 'node:path'
|
|
14
14
|
|
|
15
|
-
import { isRunAsCli } from '
|
|
16
|
-
import { createCheckReporter } from '
|
|
17
|
-
import { resolveCmd } from '
|
|
15
|
+
import { isRunAsCli } from '../../../scripts/cli-entry.mjs'
|
|
16
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
17
|
+
import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
|
|
18
18
|
|
|
19
19
|
const PHPCS_CODE_DIR_CANDIDATES = ['app', 'src', 'lib', 'public', 'www']
|
|
20
20
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
якщо в проекті є хоч один rego
|
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
*/
|
|
26
26
|
import { existsSync } from 'node:fs'
|
|
27
27
|
|
|
28
|
-
import { createCheckReporter } from '
|
|
29
|
-
import { loadCursorIgnorePaths } from '
|
|
30
|
-
import { runConftestBatch } from '
|
|
31
|
-
import { walkDir } from '
|
|
28
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
29
|
+
import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
|
|
30
|
+
import { runConftestBatch } from '../../../scripts/utils/run-conftest-batch.mjs'
|
|
31
|
+
import { walkDir } from '../../../scripts/utils/walkDir.mjs'
|
|
32
32
|
|
|
33
33
|
/** Список (path, namespace, policyDirRel) для трьох канонічних конфігів rego.mdc. */
|
|
34
34
|
const REGO_TARGETS = [
|
|
@@ -26,7 +26,7 @@ import { spawnSync } from 'node:child_process'
|
|
|
26
26
|
import { existsSync } from 'node:fs'
|
|
27
27
|
import { resolve } from 'node:path'
|
|
28
28
|
|
|
29
|
-
import { resolveCmd } from '
|
|
29
|
+
import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
|
|
30
30
|
|
|
31
31
|
/** Шляхи з Rego-полісі (відносно cwd). Існують не всі на ранніх стадіях — фільтруємо нижче. */
|
|
32
32
|
const LINT_TARGETS = ['npm/policy']
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
якщо присутній хоч один vue або css файл
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
import { existsSync } from 'node:fs'
|
|
20
20
|
import { readFile } from 'node:fs/promises'
|
|
21
21
|
|
|
22
|
-
import { createCheckReporter } from '
|
|
22
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Альтернатива полю `stylelint` у `package.json` — зовнішній файл конфігу. Якщо
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
якщо в хоч в package.json в секції dependencies присутній пакет @tauri-apps/api
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
import { existsSync, statSync } from 'node:fs'
|
|
19
19
|
import { readFile } from 'node:fs/promises'
|
|
20
20
|
|
|
21
|
-
import { createCheckReporter } from '
|
|
22
|
-
import { runConftestBatch } from '
|
|
21
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
22
|
+
import { runConftestBatch } from '../../../scripts/utils/run-conftest-batch.mjs'
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Чи є префікс `@tauri-apps/` у ключах `dependencies` або `devDependencies`.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
завжди
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
import { existsSync } from 'node:fs'
|
|
33
33
|
import { readFile } from 'node:fs/promises'
|
|
34
34
|
|
|
35
|
-
import { createCheckReporter } from '
|
|
36
|
-
import { anyRunStepIncludes, parseWorkflowYaml } from '
|
|
35
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
36
|
+
import { anyRunStepIncludes, parseWorkflowYaml } from '../../../scripts/utils/gha-workflow.mjs'
|
|
37
37
|
|
|
38
38
|
/** Заголовок абзацу про апостроф у text.mdc / n-text.mdc. */
|
|
39
39
|
const UK_APOSTROPHE_HEADING = '**Український апостроф:**'
|
|
@@ -19,8 +19,8 @@ import { spawnSync } from 'node:child_process'
|
|
|
19
19
|
import { globSync } from 'node:fs'
|
|
20
20
|
import { resolve } from 'node:path'
|
|
21
21
|
|
|
22
|
-
import { isRunAsCli } from '
|
|
23
|
-
import { resolveCmd } from '
|
|
22
|
+
import { isRunAsCli } from '../../../scripts/cli-entry.mjs'
|
|
23
|
+
import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
|
|
24
24
|
|
|
25
25
|
/** Підрядок у stderr ShellCheck, коли є зауваження, але без авто-виправлення у форматі diff. */
|
|
26
26
|
const NON_AUTOFIXABLE_HINT = 'none were auto-fixable'
|
|
@@ -18,8 +18,8 @@ import { existsSync } from 'node:fs'
|
|
|
18
18
|
import { dirname, join } from 'node:path'
|
|
19
19
|
import { fileURLToPath } from 'node:url'
|
|
20
20
|
|
|
21
|
-
import { isRunAsCli } from '
|
|
22
|
-
import { resolveCmd } from '
|
|
21
|
+
import { isRunAsCli } from '../../../scripts/cli-entry.mjs'
|
|
22
|
+
import { resolveCmd } from '../../../scripts/utils/resolve-cmd.mjs'
|
|
23
23
|
|
|
24
24
|
/** Типові glob-и для форматів, які обробляє v8r (див. опис CLI v8r). */
|
|
25
25
|
export const DEFAULT_V8R_GLOBS = ['**/*.json', '**/*.json5', '**/*.yml', '**/*.yaml', '**/*.toml']
|
|
@@ -296,6 +296,10 @@ jobs:
|
|
|
296
296
|
|
|
297
297
|
Якщо потрібна мова вже є в залежностях **`@nitra/cspell-dict`** — додай лише код у **`language`**, без окремих **`@cspell/dict-*`** у споживачі. Якщо мови немає в корпоративному пакеті — розширюй **`@nitra/cspell-dict`**, а не підключай **`@cspell/dict-*`** у корені репозиторію-споживача. Огляд upstream-словників: [streetsidesoftware/cspell-dicts](https://github.com/streetsidesoftware/cspell-dicts).
|
|
298
298
|
|
|
299
|
+
## Найменування каталогів
|
|
300
|
+
|
|
301
|
+
kebab-case
|
|
302
|
+
|
|
299
303
|
## Перевірка
|
|
300
304
|
|
|
301
305
|
`npx @nitra/cursor check text` (охоплює oxfmt, cspell, shellcheck у `lint-text`, markdownlint, v8r, CI для `lint-text`)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
якщо присутній хоч один vue файл
|
|
@@ -21,16 +21,16 @@ import { existsSync } from 'node:fs'
|
|
|
21
21
|
import { readFile } from 'node:fs/promises'
|
|
22
22
|
import { join, relative } from 'node:path'
|
|
23
23
|
|
|
24
|
-
import { createCheckReporter } from '
|
|
24
|
+
import { createCheckReporter } from '../../../scripts/utils/check-reporter.mjs'
|
|
25
25
|
import {
|
|
26
26
|
findForbiddenNodeImportsInVueFile,
|
|
27
27
|
findForbiddenVueImportsInSourceFile,
|
|
28
28
|
isVueImportScanSourceFile,
|
|
29
29
|
shouldSkipFileForVueImportScan
|
|
30
|
-
} from '
|
|
31
|
-
import { loadCursorIgnorePaths } from '
|
|
32
|
-
import { walkDir } from '
|
|
33
|
-
import { getMonorepoPackageRootDirs } from '
|
|
30
|
+
} from '../../../scripts/utils/vue-forbidden-imports.mjs'
|
|
31
|
+
import { loadCursorIgnorePaths } from '../../../scripts/utils/load-cursor-config.mjs'
|
|
32
|
+
import { walkDir } from '../../../scripts/utils/walkDir.mjs'
|
|
33
|
+
import { getMonorepoPackageRootDirs } from '../../../scripts/utils/workspaces.mjs'
|
|
34
34
|
|
|
35
35
|
const ESBUILD_RE = /\besbuild\b/
|
|
36
36
|
|
package/scripts/auto-rules.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Автовизначення правил для `.n-cursor.json` за умовами з `npm/
|
|
2
|
+
* Автовизначення правил для `.n-cursor.json` за умовами з `npm/rules/<rule>/auto.md`.
|
|
3
3
|
*
|
|
4
4
|
* Модуль аналізує дерево проєкту (наявність файлів/директорій, `gql\`...\`` у source,
|
|
5
5
|
* залежності `mssql` / `pg` / `pg-format` / `mysql2` / `ioredis` / `node-redis` у `package.json`,
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Враховує винятки `disable-rules`: елементи зі списку не додаються автоматично.
|
|
10
10
|
*
|
|
11
|
-
* Автодетект скілів — у `./auto-skills.mjs` (умови — у `npm/
|
|
11
|
+
* Автодетект скілів — у `./auto-skills.mjs` (умови — у `npm/skills/<skill>/auto.md`).
|
|
12
12
|
* `mergeConfigWithAutoDetected` нижче приймає вже виявлені rules і skills і вливає
|
|
13
13
|
* їх у конфіг із поправкою на legacy-id (`migrateRuleIds`).
|
|
14
14
|
*/
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
} from './utils/graphql-gql-scan.mjs'
|
|
25
25
|
import { contentForVueImportScan } from './utils/vue-forbidden-imports.mjs'
|
|
26
26
|
|
|
27
|
-
/** Порядок автододавання правил відповідно до `auto
|
|
27
|
+
/** Порядок автододавання правил відповідно до `rules/<rule>/auto.md`. */
|
|
28
28
|
export const AUTO_RULE_ORDER = Object.freeze([
|
|
29
29
|
'abie',
|
|
30
30
|
'bun',
|
|
@@ -91,7 +91,7 @@ export function detectLegacyRuleIds(ids) {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
/**
|
|
94
|
-
* Граф залежностей між правилами (`auto
|
|
94
|
+
* Граф залежностей між правилами (`rules/<rule>/auto.md` синтаксис `rule - [other]`).
|
|
95
95
|
* Ключ варто автододати, коли всі правила-залежності вже додані до конфігу — щоб
|
|
96
96
|
* не дублювати вихідну умову, достатньо описати її у залежності.
|
|
97
97
|
*/
|
|
@@ -576,7 +576,7 @@ function resolveRuleDependencies(detectedRules, addRule) {
|
|
|
576
576
|
}
|
|
577
577
|
|
|
578
578
|
/**
|
|
579
|
-
* Визначає авто-правила згідно з `auto
|
|
579
|
+
* Визначає авто-правила згідно з `rules/<rule>/auto.md`.
|
|
580
580
|
* @param {object} params параметри аналізу
|
|
581
581
|
* @param {string} params.root абсолютний шлях до кореня репозиторію
|
|
582
582
|
* @param {string[]} params.availableRules перелік доступних правил з пакету
|
package/scripts/auto-skills.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Автовизначення skills для `.n-cursor.json` за умовами з `npm/
|
|
2
|
+
* Автовизначення skills для `.n-cursor.json` за умовами з `npm/skills/<skill>/auto.md`.
|
|
3
3
|
*
|
|
4
4
|
* Скіли автододаються залежно від уже виявлених правил (auto-rules) — щоб не дублювати
|
|
5
5
|
* умови, які вже формалізовані для відповідного правила. Наприклад:
|
|
@@ -7,13 +7,14 @@
|
|
|
7
7
|
* - `abie-kustomize - [abie]` — додається разом з правилом `abie`
|
|
8
8
|
* - `taze - [bun]` — додається разом з правилом `bun`
|
|
9
9
|
*
|
|
10
|
-
* Скіли без секції `[rules]` у `auto
|
|
10
|
+
* Скіли без секції `[rules]` у `skills/<skill>/auto.md` (`fix`, `lint`, `llm-patch`, `publish-telegram`)
|
|
11
11
|
* додаються завжди, якщо доступні в пакеті й не у `disable-skills`.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
/** Порядок автододавання skills відповідно до `auto
|
|
14
|
+
/** Порядок автододавання skills відповідно до `skills/<skill>/auto.md`. */
|
|
15
15
|
export const AUTO_SKILL_ORDER = Object.freeze([
|
|
16
16
|
'abie-kustomize',
|
|
17
|
+
'adr-normalize',
|
|
17
18
|
'fix',
|
|
18
19
|
'lint',
|
|
19
20
|
'llm-patch',
|
|
@@ -22,23 +23,24 @@ export const AUTO_SKILL_ORDER = Object.freeze([
|
|
|
22
23
|
])
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
|
-
* Залежність скілів від правил (`auto
|
|
26
|
+
* Залежність скілів від правил (`skills/<skill>/auto.md` синтаксис `skill - [rules]`).
|
|
26
27
|
* Ключ варто автододати, коли всі правила-залежності вже додані до конфігу автодетектом.
|
|
27
28
|
*/
|
|
28
29
|
export const AUTO_SKILL_RULE_DEPENDENCIES = Object.freeze(
|
|
29
30
|
/** @type {Record<string, readonly string[]>} */ ({
|
|
30
31
|
'abie-kustomize': Object.freeze(['abie']),
|
|
32
|
+
'adr-normalize': Object.freeze(['adr']),
|
|
31
33
|
taze: Object.freeze(['bun'])
|
|
32
34
|
})
|
|
33
35
|
)
|
|
34
36
|
|
|
35
|
-
/** Скіли без залежностей — додаються завжди (рядок «завжди» в `auto
|
|
37
|
+
/** Скіли без залежностей — додаються завжди (рядок «завжди» в `skills/<skill>/auto.md`). */
|
|
36
38
|
const ALWAYS_ON_SKILLS = Object.freeze(['fix', 'lint', 'llm-patch', 'publish-telegram'])
|
|
37
39
|
|
|
38
40
|
const DEFAULT_DISABLED_LIST = Object.freeze([])
|
|
39
41
|
|
|
40
42
|
/**
|
|
41
|
-
* Визначає авто-skills згідно з `auto
|
|
43
|
+
* Визначає авто-skills згідно з `skills/<skill>/auto.md`.
|
|
42
44
|
* @param {object} params параметри
|
|
43
45
|
* @param {string[]} params.availableSkills перелік доступних skills із пакету (id без префікса n-)
|
|
44
46
|
* @param {string[]} params.detectedRules id правил, виявлених auto-rules (вхідні залежності)
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Прогоняє `conftest test` по всіх Rego-полісі з `npm/policy/` (окрім `ga/*`,
|
|
3
|
-
* які вже виконуються через `lint
|
|
2
|
+
* Прогоняє `conftest test` по всіх Rego-полісі з `npm/rules/<rule>/policy/` (окрім `ga/*`,
|
|
3
|
+
* які вже виконуються через `npm/rules/ga/js/lint.mjs`).
|
|
4
4
|
*
|
|
5
|
-
* Кожна полісі має свій namespace,
|
|
6
|
-
* інакше таргет пропускається — як гейтинг у `check
|
|
5
|
+
* Кожна полісі має свій namespace, обов'язковий `rule` (id у `.n-cursor.json:rules`,
|
|
6
|
+
* інакше таргет пропускається — як гейтинг у `check.mjs`), і список цільових
|
|
7
7
|
* файлів — single-file або walk-предикат для дерева. Якщо цільових файлів немає
|
|
8
8
|
* або правило не активне — таргет мовчки пропускається.
|
|
9
9
|
*
|
|
10
10
|
* Поведінка fallback:
|
|
11
11
|
* - якщо `conftest` не в `PATH` — друкуємо `ℹ` повідомлення з підказкою
|
|
12
|
-
* встановлення і повертаємо 0 (структурні JS-перевірки в `check
|
|
13
|
-
* лишаються паралельно). Те саме рішення — у `lint
|
|
14
|
-
* - якщо `npm/
|
|
12
|
+
* встановлення і повертаємо 0 (структурні JS-перевірки в `check.mjs`
|
|
13
|
+
* лишаються паралельно). Те саме рішення — у `rules/ga/js/lint.mjs`.
|
|
14
|
+
* - якщо `npm/rules/` не існує (нетипова інсталяція) — також `ℹ` skip.
|
|
15
15
|
*
|
|
16
16
|
* Перший ненульовий exit-код conftest — повертаємо як результат, але всі
|
|
17
17
|
* наступні таргети все одно виконуємо, щоб одразу побачити повний список
|
|
@@ -27,11 +27,11 @@ import { fileURLToPath } from 'node:url'
|
|
|
27
27
|
|
|
28
28
|
import { resolveCmd } from './utils/resolve-cmd.mjs'
|
|
29
29
|
|
|
30
|
-
/** Каталог пакету `@nitra/cursor`, від якого ресолвимо
|
|
30
|
+
/** Каталог пакету `@nitra/cursor`, від якого ресолвимо вшиті директорії правил. */
|
|
31
31
|
const PACKAGE_ROOT = dirname(dirname(fileURLToPath(import.meta.url)))
|
|
32
32
|
|
|
33
|
-
/** Шлях до кореня
|
|
34
|
-
const
|
|
33
|
+
/** Шлях до кореня правил. У npm-tarball публікується через `files: ["rules"]`. Кожне правило: `rules/<id>/policy/`. */
|
|
34
|
+
const RULES_DIR = join(PACKAGE_ROOT, 'rules')
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
37
|
* Опис одного таргета: namespace + спосіб розвʼязати цільові файли.
|
|
@@ -438,7 +438,7 @@ function resolveTargetFiles(target, cwd) {
|
|
|
438
438
|
* @returns {number} exit-код
|
|
439
439
|
*/
|
|
440
440
|
function runConftestForTarget(conftestBin, target, files) {
|
|
441
|
-
const policyAbs = join(
|
|
441
|
+
const policyAbs = join(RULES_DIR, target.rule, 'policy')
|
|
442
442
|
if (!existsSync(policyAbs)) {
|
|
443
443
|
return 0
|
|
444
444
|
}
|
|
@@ -471,8 +471,8 @@ export function runLintConftestCli() {
|
|
|
471
471
|
)
|
|
472
472
|
return 0
|
|
473
473
|
}
|
|
474
|
-
if (!existsSync(
|
|
475
|
-
console.log(`ℹ Каталог
|
|
474
|
+
if (!existsSync(RULES_DIR)) {
|
|
475
|
+
console.log(`ℹ Каталог правил не знайдено (${RULES_DIR}) — пропускаю conftest.`)
|
|
476
476
|
return 0
|
|
477
477
|
}
|
|
478
478
|
|
|
@@ -10,10 +10,12 @@
|
|
|
10
10
|
* - `npm/CLAUDE.md` — **fully owned**: завжди перезаписується; пропускається,
|
|
11
11
|
* якщо в проєкті немає каталогу `npm/`.
|
|
12
12
|
* - `.claude/commands/n-check.md` — fully owned slash-команда.
|
|
13
|
-
* - `.claude/hooks/capture-decisions.sh` — fully owned bash-скрипт ADR Stop-hook;
|
|
13
|
+
* - `.claude/hooks/capture-decisions.sh` — fully owned bash-скрипт ADR capture Stop-hook;
|
|
14
14
|
* копіюється з `.claude-template/hooks/`, лише коли в `.n-cursor.json` `rules`
|
|
15
15
|
* присутнє `adr` (правило вмикається вручну). Якщо правила немає, керована
|
|
16
16
|
* ADR-група в hooks так само автоматично прибирається з settings.json.
|
|
17
|
+
* - `.claude/hooks/normalize-decisions.sh` — fully owned bash-скрипт ADR normalize
|
|
18
|
+
* Stop-hook (батч-нормалізація чернеток); умови — ті самі, що для `capture`.
|
|
17
19
|
*
|
|
18
20
|
* Опт-аут — `claude-config: false` у `.n-cursor.json`.
|
|
19
21
|
*/
|
|
@@ -23,20 +25,27 @@ import { join } from 'node:path'
|
|
|
23
25
|
|
|
24
26
|
/** Маркер lint Stop-hook'а (`npx --no \@nitra/cursor stop-hook`). */
|
|
25
27
|
export const MANAGED_HOOK_COMMAND_MARKER = '@nitra/cursor stop-hook'
|
|
26
|
-
/** Маркер ADR Stop-hook'а — підрядок шляху до bash
|
|
28
|
+
/** Маркер ADR Stop-hook'а — підрядок шляху до bash-скрипта capture-decisions. */
|
|
27
29
|
export const ADR_HOOK_COMMAND_MARKER = '.claude/hooks/capture-decisions.sh'
|
|
30
|
+
/** Маркер ADR Stop-hook'а — підрядок шляху до bash-скрипта normalize-decisions. */
|
|
31
|
+
export const ADR_NORMALIZE_HOOK_COMMAND_MARKER = '.claude/hooks/normalize-decisions.sh'
|
|
28
32
|
/** Усі маркери managed-hook'ів пакета — за ними відрізняємо свої записи від користувацьких. */
|
|
29
|
-
export const MANAGED_HOOK_COMMAND_MARKERS = Object.freeze([
|
|
33
|
+
export const MANAGED_HOOK_COMMAND_MARKERS = Object.freeze([
|
|
34
|
+
MANAGED_HOOK_COMMAND_MARKER,
|
|
35
|
+
ADR_HOOK_COMMAND_MARKER,
|
|
36
|
+
ADR_NORMALIZE_HOOK_COMMAND_MARKER
|
|
37
|
+
])
|
|
30
38
|
|
|
31
39
|
const CLAUDE_DIR = '.claude'
|
|
32
40
|
const CLAUDE_SETTINGS_FILE = `${CLAUDE_DIR}/settings.json`
|
|
33
41
|
const CLAUDE_COMMANDS_DIR = `${CLAUDE_DIR}/commands`
|
|
34
42
|
const CLAUDE_HOOKS_DIR = `${CLAUDE_DIR}/hooks`
|
|
35
43
|
const ADR_HOOK_SCRIPT_NAME = 'capture-decisions.sh'
|
|
44
|
+
const ADR_NORMALIZE_HOOK_SCRIPT_NAME = 'normalize-decisions.sh'
|
|
36
45
|
const NPM_CLAUDE_MD_FILE = 'npm/CLAUDE.md'
|
|
37
46
|
const TEMPLATE_DIR_NAME = '.claude-template'
|
|
38
47
|
|
|
39
|
-
/** Канонічна група hooks для ADR Stop-hook'а — додається в settings, коли `adr` у `rules`. */
|
|
48
|
+
/** Канонічна група hooks для ADR capture Stop-hook'а — додається в settings, коли `adr` у `rules`. */
|
|
40
49
|
const ADR_STOP_HOOK_GROUP = Object.freeze({
|
|
41
50
|
matcher: '',
|
|
42
51
|
hooks: Object.freeze([
|
|
@@ -49,6 +58,19 @@ const ADR_STOP_HOOK_GROUP = Object.freeze({
|
|
|
49
58
|
])
|
|
50
59
|
})
|
|
51
60
|
|
|
61
|
+
/** Канонічна група hooks для ADR normalize Stop-hook'а — батч-нормалізація чернеток у `docs/adr/`. */
|
|
62
|
+
const ADR_NORMALIZE_STOP_HOOK_GROUP = Object.freeze({
|
|
63
|
+
matcher: '',
|
|
64
|
+
hooks: Object.freeze([
|
|
65
|
+
Object.freeze({
|
|
66
|
+
type: 'command',
|
|
67
|
+
command: `bash "$CLAUDE_PROJECT_DIR/${ADR_NORMALIZE_HOOK_COMMAND_MARKER}"`,
|
|
68
|
+
async: true,
|
|
69
|
+
timeout: 600
|
|
70
|
+
})
|
|
71
|
+
])
|
|
72
|
+
})
|
|
73
|
+
|
|
52
74
|
/**
|
|
53
75
|
* @typedef {object} HookEntry
|
|
54
76
|
* @property {string} type тип hook'а у форматі Claude Code (зазвичай `'command'`)
|
|
@@ -140,7 +162,11 @@ function templateWithAdrHook(template) {
|
|
|
140
162
|
for (const [event, groups] of Object.entries(template.hooks ?? {})) {
|
|
141
163
|
hooks[event] = Array.isArray(groups) ? [...groups] : []
|
|
142
164
|
}
|
|
143
|
-
hooks.Stop = [
|
|
165
|
+
hooks.Stop = [
|
|
166
|
+
...(hooks.Stop ?? []),
|
|
167
|
+
/** @type {HookGroup} */ (ADR_STOP_HOOK_GROUP),
|
|
168
|
+
/** @type {HookGroup} */ (ADR_NORMALIZE_STOP_HOOK_GROUP)
|
|
169
|
+
]
|
|
144
170
|
return { ...template, hooks }
|
|
145
171
|
}
|
|
146
172
|
|
|
@@ -209,24 +235,45 @@ export async function syncClaudeSettings(projectRoot, templateDir, options = {})
|
|
|
209
235
|
}
|
|
210
236
|
|
|
211
237
|
/**
|
|
212
|
-
* Копіює канонічний
|
|
238
|
+
* Копіює один канонічний bash-скрипт hook'а з темплейту пакета у `.claude/hooks/`.
|
|
213
239
|
* Файл повністю керується пакетом — на кожен sync перезаписується (як setup-bun-deps).
|
|
214
240
|
* @param {string} projectRoot корінь проєкту, куди писати
|
|
215
241
|
* @param {string} templateDir каталог `.claude-template/` усередині пакету
|
|
242
|
+
* @param {string} scriptName базове ім'я скрипта (наприклад `capture-decisions.sh`)
|
|
216
243
|
* @returns {Promise<{ written: boolean, path: string }>} результат: чи писали файл, та його відносний шлях
|
|
217
244
|
*/
|
|
218
|
-
|
|
219
|
-
const templatePath = join(templateDir, 'hooks',
|
|
245
|
+
async function syncHookScript(projectRoot, templateDir, scriptName) {
|
|
246
|
+
const templatePath = join(templateDir, 'hooks', scriptName)
|
|
220
247
|
if (!existsSync(templatePath)) {
|
|
221
248
|
return { written: false, path: '' }
|
|
222
249
|
}
|
|
223
250
|
const content = await readFile(templatePath, 'utf8')
|
|
224
251
|
const hooksDir = join(projectRoot, CLAUDE_HOOKS_DIR)
|
|
225
252
|
await mkdir(hooksDir, { recursive: true })
|
|
226
|
-
const destPath = join(hooksDir,
|
|
253
|
+
const destPath = join(hooksDir, scriptName)
|
|
227
254
|
await writeFile(destPath, content, 'utf8')
|
|
228
255
|
await chmod(destPath, 0o755)
|
|
229
|
-
return { written: true, path: `${CLAUDE_HOOKS_DIR}/${
|
|
256
|
+
return { written: true, path: `${CLAUDE_HOOKS_DIR}/${scriptName}` }
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Копіює канонічний `.claude/hooks/capture-decisions.sh` з темплейту пакета.
|
|
261
|
+
* @param {string} projectRoot корінь проєкту, куди писати
|
|
262
|
+
* @param {string} templateDir каталог `.claude-template/` усередині пакету
|
|
263
|
+
* @returns {Promise<{ written: boolean, path: string }>} результат: чи писали файл, та його відносний шлях
|
|
264
|
+
*/
|
|
265
|
+
export function syncAdrHookScript(projectRoot, templateDir) {
|
|
266
|
+
return syncHookScript(projectRoot, templateDir, ADR_HOOK_SCRIPT_NAME)
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Копіює канонічний `.claude/hooks/normalize-decisions.sh` з темплейту пакета.
|
|
271
|
+
* @param {string} projectRoot корінь проєкту, куди писати
|
|
272
|
+
* @param {string} templateDir каталог `.claude-template/` усередині пакету
|
|
273
|
+
* @returns {Promise<{ written: boolean, path: string }>} результат: чи писали файл, та його відносний шлях
|
|
274
|
+
*/
|
|
275
|
+
export function syncAdrNormalizeHookScript(projectRoot, templateDir) {
|
|
276
|
+
return syncHookScript(projectRoot, templateDir, ADR_NORMALIZE_HOOK_SCRIPT_NAME)
|
|
230
277
|
}
|
|
231
278
|
|
|
232
279
|
/**
|
|
@@ -283,20 +330,29 @@ export async function syncClaudeCommands(projectRoot, templateDir) {
|
|
|
283
330
|
* @param {string} options.bundledPackageRoot корінь установленого `@nitra/cursor`
|
|
284
331
|
* @param {boolean} options.enabled чи увімкнено sync (з `.n-cursor.json` `claude-config`)
|
|
285
332
|
* @param {string[]} [options.rules] список увімкнених правил із `.n-cursor.json` — впливає на ADR Stop-hook (`adr`)
|
|
286
|
-
* @returns {Promise<{ settings: boolean, npmClaudeMd: boolean, commands: string[], adrHook: boolean }>} прапорці записів settings/CLAUDE.md/ADR-hook та список записаних slash-команд
|
|
333
|
+
* @returns {Promise<{ settings: boolean, npmClaudeMd: boolean, commands: string[], adrHook: boolean, adrNormalizeHook: boolean }>} прапорці записів settings/CLAUDE.md/ADR-hook(s) та список записаних slash-команд
|
|
287
334
|
*/
|
|
288
335
|
export async function syncClaudeConfig({ projectRoot, bundledPackageRoot, enabled, rules = [] }) {
|
|
289
336
|
if (!enabled) {
|
|
290
|
-
return { settings: false, npmClaudeMd: false, commands: [], adrHook: false }
|
|
337
|
+
return { settings: false, npmClaudeMd: false, commands: [], adrHook: false, adrNormalizeHook: false }
|
|
291
338
|
}
|
|
292
339
|
const templateDir = join(bundledPackageRoot, TEMPLATE_DIR_NAME)
|
|
293
340
|
if (!existsSync(templateDir)) {
|
|
294
|
-
return { settings: false, npmClaudeMd: false, commands: [], adrHook: false }
|
|
341
|
+
return { settings: false, npmClaudeMd: false, commands: [], adrHook: false, adrNormalizeHook: false }
|
|
295
342
|
}
|
|
296
343
|
const includeAdrHook = Array.isArray(rules) && rules.includes('adr')
|
|
297
344
|
const adrHook = includeAdrHook ? await syncAdrHookScript(projectRoot, templateDir) : { written: false, path: '' }
|
|
345
|
+
const adrNormalizeHook = includeAdrHook
|
|
346
|
+
? await syncAdrNormalizeHookScript(projectRoot, templateDir)
|
|
347
|
+
: { written: false, path: '' }
|
|
298
348
|
const settings = await syncClaudeSettings(projectRoot, templateDir, { includeAdrHook })
|
|
299
349
|
const npmClaudeMd = await syncNpmClaudeMd(projectRoot, templateDir)
|
|
300
350
|
const commands = await syncClaudeCommands(projectRoot, templateDir)
|
|
301
|
-
return {
|
|
351
|
+
return {
|
|
352
|
+
settings: settings.written,
|
|
353
|
+
npmClaudeMd: npmClaudeMd.written,
|
|
354
|
+
commands,
|
|
355
|
+
adrHook: adrHook.written,
|
|
356
|
+
adrNormalizeHook: adrNormalizeHook.written
|
|
357
|
+
}
|
|
302
358
|
}
|
|
@@ -21,11 +21,11 @@ import { fileURLToPath } from 'node:url'
|
|
|
21
21
|
|
|
22
22
|
import { resolveCmd } from './resolve-cmd.mjs'
|
|
23
23
|
|
|
24
|
-
/** Каталог пакета `@nitra/cursor`, від якого ресолвимо
|
|
24
|
+
/** Каталог пакета `@nitra/cursor`, від якого ресолвимо вшиті директорії правил. */
|
|
25
25
|
const PACKAGE_ROOT = dirname(dirname(dirname(fileURLToPath(import.meta.url))))
|
|
26
26
|
|
|
27
|
-
/** Шлях до кореня
|
|
28
|
-
const
|
|
27
|
+
/** Шлях до кореня правил. У npm-tarball публікується через `files: ["rules"]`. Кожне правило: `rules/<id>/policy/<name>/`. */
|
|
28
|
+
const RULES_ROOT = join(PACKAGE_ROOT, 'rules')
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
31
|
* Друкує install-hint для conftest і кидає виняток, щоб викликана `check-*`
|
|
@@ -72,7 +72,12 @@ export function runConftestBatch(opts) {
|
|
|
72
72
|
if (!conftestBin) {
|
|
73
73
|
failConftestMissing()
|
|
74
74
|
}
|
|
75
|
-
|
|
75
|
+
// policyDirRel — формат `<rule>/<name>` (наприклад `abie/base_deployment_preem`).
|
|
76
|
+
// Реальний шлях у новій структурі: `rules/<rule>/policy/<name>`.
|
|
77
|
+
const slash = opts.policyDirRel.indexOf('/')
|
|
78
|
+
const ruleId = slash === -1 ? opts.policyDirRel : opts.policyDirRel.slice(0, slash)
|
|
79
|
+
const sub = slash === -1 ? '' : opts.policyDirRel.slice(slash + 1)
|
|
80
|
+
const policyAbs = sub ? join(RULES_ROOT, ruleId, 'policy', sub) : join(RULES_ROOT, ruleId, 'policy')
|
|
76
81
|
if (!existsSync(policyAbs)) {
|
|
77
82
|
throw new Error(`runConftestBatch: rego-каталог не знайдено: ${policyAbs}`)
|
|
78
83
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[abie]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[abie]
|