@nitra/cursor 3.22.0 → 3.23.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/.pi-template/extensions/n-cursor-adr/docs/index.md +181 -0
- package/CHANGELOG.md +31 -3
- package/bin/docs/n-cursor.md +636 -0
- package/bin/docs/rename-yaml-extensions.md +207 -0
- package/bin/n-cursor.js +30 -3
- package/package.json +1 -1
- package/rules/abie/docs/fix.md +18 -0
- package/rules/abie/js/docs/applies.md +26 -0
- package/rules/abie/js/docs/env_dns.md +32 -0
- package/rules/abie/js/docs/firebase_hosting.md +23 -0
- package/rules/abie/js/docs/hc_pairing.md +35 -0
- package/rules/abie/js/docs/ua_http_route.md +28 -0
- package/rules/abie/js/docs/ua_node_selector.md +28 -0
- package/rules/abie/lib/docs/enabled.md +29 -0
- package/rules/abie/lib/docs/env-dns.md +35 -0
- package/rules/abie/lib/docs/hc-yaml.md +33 -0
- package/rules/abie/lib/docs/http-route.md +44 -0
- package/rules/abie/lib/docs/k8s-tree.md +40 -0
- package/rules/abie/lib/docs/kustomization-patches.md +47 -0
- package/rules/abie/lib/docs/overlay-paths.md +38 -0
- package/rules/abie/lib/docs/yaml.md +29 -0
- package/rules/adr/docs/fix.md +148 -0
- package/rules/adr/js/docs/hooks.md +259 -0
- package/rules/bun/docs/fix.md +156 -0
- package/rules/bun/js/docs/layout.md +393 -0
- package/rules/capacitor/docs/fix.md +121 -0
- package/rules/capacitor/js/docs/platforms.md +295 -0
- package/rules/changelog/changelog.mdc +2 -2
- package/rules/changelog/docs/fix.md +174 -0
- package/rules/changelog/js/consistency.mjs +114 -13
- package/rules/changelog/js/docs/consistency.md +387 -0
- package/rules/changelog/lib/docs/package-manifest.md +210 -0
- package/rules/ci4/docs/fix.md +179 -0
- package/rules/ci4/js/docs/marksman_config.md +128 -0
- package/rules/docker/docker.mdc +8 -3
- package/rules/docker/docs/fix.md +171 -0
- package/rules/docker/js/docs/lint.md +258 -0
- package/rules/docker/lib/docs/docker-hadolint.md +184 -0
- package/rules/docker/lib/docs/docker-mirror.md +247 -0
- package/rules/docker/lib/docs/docker-native-addon.md +170 -0
- package/rules/docker/lib/docs/docker-nginx-user.md +219 -0
- package/rules/docker/lint/docs/lint.md +193 -0
- package/rules/efes/docs/fix.md +203 -0
- package/rules/feedback/docs/fix.md +140 -0
- package/rules/flow/docs/fix.md +152 -0
- package/rules/ga/docs/fix.md +158 -0
- package/rules/ga/js/docs/lint.md +100 -0
- package/rules/ga/js/docs/workflows.md +217 -0
- package/rules/ga/lint/docs/lint.md +209 -0
- package/rules/ga/policy/clean_merged_branch/clean_merged_branch.rego +11 -2
- package/rules/ga/policy/clean_merged_branch/template/clean-merged-branch.yml.snippet.yml +3 -4
- package/rules/graphql/docs/fix.md +126 -0
- package/rules/graphql/js/docs/tooling.md +264 -0
- package/rules/graphql/lib/docs/graphql-gql-scan.md +219 -0
- package/rules/hasura/docs/fix.md +120 -0
- package/rules/hasura/hasura.mdc +14 -0
- package/rules/hasura/js/docs/internal_urls.md +326 -0
- package/rules/image-avif/docs/fix.md +132 -0
- package/rules/image-avif/js/docs/avif_generation.md +241 -0
- package/rules/image-compress/docs/fix.md +150 -0
- package/rules/image-compress/js/docs/package_setup.md +191 -0
- package/rules/js-bun-db/docs/fix.md +148 -0
- package/rules/js-bun-db/js/docs/safety.md +231 -0
- package/rules/js-bun-db/js-bun-db.mdc +42 -13
- package/rules/js-bun-db/lib/docs/bun-sql-scan.md +347 -0
- package/rules/js-bun-redis/docs/fix.md +123 -0
- package/rules/js-bun-redis/js/docs/imports.md +176 -0
- package/rules/js-bun-redis/lib/docs/redis-imports.md +223 -0
- package/rules/js-lint/docs/fix.md +117 -0
- package/rules/js-lint/js/docs/lint.md +250 -0
- package/rules/js-lint/js/docs/tooling.md +348 -0
- package/rules/js-lint/js/docs/utils_imports.md +207 -0
- package/rules/js-lint-ci/docs/fix.md +154 -0
- package/rules/js-lint-ci/js/docs/lint.md +144 -0
- package/rules/js-mssql/docs/fix.md +128 -0
- package/rules/js-mssql/js/docs/deps.md +263 -0
- package/rules/js-mssql/lib/docs/mssql-pool-scan.md +367 -0
- package/rules/js-run/docs/fix.md +144 -0
- package/rules/js-run/js/docs/runtime.md +388 -0
- package/rules/js-run/lib/docs/bunyan-imports.md +117 -0
- package/rules/js-run/lib/docs/check-env-scan.md +433 -0
- package/rules/js-run/lib/docs/conn-file-rules.md +300 -0
- package/rules/js-run/lib/docs/conn-imports-scan.md +204 -0
- package/rules/js-run/lib/docs/promise-settimeout-scan.md +326 -0
- package/rules/k8s/docs/fix.md +129 -0
- package/rules/k8s/js/docs/manifests.md +344 -0
- package/rules/k8s/js/manifests.mjs +6 -2
- package/rules/k8s/k8s.mdc +4 -2
- package/rules/k8s/lint/docs/lint.md +411 -0
- package/rules/k8s/policy/network_policy/template/deployment.snippet.yaml +2 -0
- package/rules/k8s/policy/network_policy/template/stateful-set.snippet.yaml +2 -0
- package/rules/nginx-default-tpl/docs/fix.md +124 -0
- package/rules/nginx-default-tpl/js/docs/template.md +378 -0
- package/rules/npm-module/docs/fix.md +98 -0
- package/rules/npm-module/js/docs/package_structure.md +274 -0
- package/rules/npm-module/js/docs/rule_meta.md +137 -0
- package/rules/npm-module/js/docs/skill_meta.md +190 -0
- package/rules/php/docs/fix.md +107 -0
- package/rules/php/js/docs/tooling.md +152 -0
- package/rules/php/lint/docs/lint.md +215 -0
- package/rules/python/docs/fix.md +163 -0
- package/rules/python/js/docs/applies.md +108 -0
- package/rules/python/js/docs/tooling.md +153 -0
- package/rules/python/lint/docs/lint.md +322 -0
- package/rules/rego/docs/fix.md +121 -0
- package/rules/rego/js/docs/applies.md +174 -0
- package/rules/rego/js/docs/lint.md +118 -0
- package/rules/rego/lint/docs/lint.md +204 -0
- package/rules/release/docs/change.md +185 -0
- package/rules/release/docs/fix.md +119 -0
- package/rules/release/docs/release.md +222 -0
- package/rules/release/lib/docs/aggregate.md +246 -0
- package/rules/release/lib/docs/change-file.md +200 -0
- package/rules/release/lib/docs/fallback.md +203 -0
- package/rules/rust/docs/fix.md +129 -0
- package/rules/rust/js/docs/applies.md +140 -0
- package/rules/rust/lib/docs/has-cargo-toml.md +130 -0
- package/rules/security/docs/fix.md +86 -0
- package/rules/security/js/docs/lint.md +171 -0
- package/rules/security/js/docs/sample_secret.md +190 -0
- package/rules/security/js/docs/trufflehog.md +137 -0
- package/rules/security/js/lint.mjs +9 -1
- package/rules/style-lint/docs/fix.md +155 -0
- package/rules/style-lint/js/docs/lint.md +184 -0
- package/rules/style-lint/js/docs/tooling.md +194 -0
- package/rules/tauri/docs/fix.md +158 -0
- package/rules/tauri/js/docs/cargo_mutants_config.md +168 -0
- package/rules/tauri/js/docs/tooling.md +228 -0
- package/rules/test/coverage/coverage.mjs +15 -3
- package/rules/test/docs/fix.md +132 -0
- package/rules/test/js/data/stryker_config/docs/stryker-vue-macros-ignorer.md +138 -0
- package/rules/test/js/data/stryker_config/docs/stryker.config.baseline.md +134 -0
- package/rules/test/js/data/stryker_config/docs/stryker.config.vue.baseline.md +160 -0
- package/rules/test/js/data/vitest_config/docs/vitest.config.baseline.md +195 -0
- package/rules/test/js/docs/cargo_mutants_config.md +173 -0
- package/rules/test/js/docs/location.md +136 -0
- package/rules/test/js/docs/no-process-chdir.md +160 -0
- package/rules/test/js/docs/no-relative-fs-path.md +271 -0
- package/rules/test/js/docs/stryker_config.md +152 -0
- package/rules/test/js/docs/vitest-config-pool-forks.md +174 -0
- package/rules/text/docs/fix.md +118 -0
- package/rules/text/js/docs/forbidden-prettier.md +143 -0
- package/rules/text/js/docs/formatting.md +256 -0
- package/rules/text/js/docs/lint.md +122 -0
- package/rules/text/lint/docs/lint.md +220 -0
- package/rules/text/lint/docs/run-dotenv-linter.md +157 -0
- package/rules/text/lint/docs/run-shellcheck.md +212 -0
- package/rules/text/lint/docs/run-v8r.md +197 -0
- package/rules/vue/docs/fix.md +127 -0
- package/rules/vue/js/docs/packages.md +335 -0
- package/rules/vue/lib/docs/vue-forbidden-imports.md +261 -0
- package/rules/worktree/docs/fix.md +161 -0
- package/schemas/rule-meta.json +5 -1
- package/scripts/auto-rules.mjs +7 -4
- package/scripts/coverage-classify/docs/apply.md +202 -0
- package/scripts/coverage-classify/docs/cache.md +203 -0
- package/scripts/coverage-classify/docs/index.md +218 -0
- package/scripts/coverage-classify/docs/prompt.md +132 -0
- package/scripts/coverage-classify/docs/verdict-schema.md +169 -0
- package/scripts/coverage-fix-extract.mjs +122 -0
- package/scripts/coverage-fix.mjs +1 -1
- package/scripts/dispatcher/docs/graph.md +346 -0
- package/scripts/dispatcher/docs/index.md +236 -0
- package/scripts/dispatcher/docs/trace.md +296 -0
- package/scripts/dispatcher/index.mjs +1 -1
- package/scripts/dispatcher/lib/active.mjs +4 -8
- package/scripts/dispatcher/lib/commands.mjs +7 -11
- package/scripts/dispatcher/lib/docs/active.md +348 -0
- package/scripts/dispatcher/lib/docs/artifact.md +232 -0
- package/scripts/dispatcher/lib/docs/budget.md +167 -0
- package/scripts/dispatcher/lib/docs/capability.md +196 -0
- package/scripts/dispatcher/lib/docs/commands.md +210 -0
- package/scripts/dispatcher/lib/docs/events.md +182 -0
- package/scripts/dispatcher/lib/docs/executor.md +190 -0
- package/scripts/dispatcher/lib/docs/flow-lock.md +161 -0
- package/scripts/dispatcher/lib/docs/flow-resolve.md +267 -0
- package/scripts/dispatcher/lib/docs/gate.md +231 -0
- package/scripts/dispatcher/lib/docs/level.md +335 -0
- package/scripts/dispatcher/lib/docs/plan-panel.md +181 -0
- package/scripts/dispatcher/lib/docs/plan.md +200 -0
- package/scripts/dispatcher/lib/docs/planner.md +269 -0
- package/scripts/dispatcher/lib/docs/review.md +255 -0
- package/scripts/dispatcher/lib/docs/reviewer.md +240 -0
- package/scripts/dispatcher/lib/docs/snapshot.md +247 -0
- package/scripts/dispatcher/lib/docs/spec.md +203 -0
- package/scripts/dispatcher/lib/docs/state-store.md +303 -0
- package/scripts/dispatcher/lib/docs/subagent-runner.md +173 -0
- package/scripts/dispatcher/lib/executor.mjs +6 -1
- package/scripts/dispatcher/lib/flow-resolve.mjs +3 -1
- package/scripts/dispatcher/lib/level.mjs +29 -3
- package/scripts/dispatcher/lib/review.mjs +1 -1
- package/scripts/dispatcher/lib/subagent-runner.mjs +5 -3
- package/scripts/docs/auto-rules.md +376 -0
- package/scripts/docs/auto-skills.md +173 -0
- package/scripts/docs/build-agents-commands.md +183 -0
- package/scripts/docs/cli-entry.md +153 -0
- package/scripts/docs/coverage-fix.md +177 -0
- package/scripts/docs/ensure-nitra-cursor-dev-dependencies.md +189 -0
- package/scripts/lib/changed-files.mjs +4 -1
- package/scripts/lib/docs/changed-files.md +149 -0
- package/scripts/lib/docs/check-mdc-template-refs.md +222 -0
- package/scripts/lib/docs/check-reporter.md +175 -0
- package/scripts/lib/docs/discover-check-rules-from-cursor.md +157 -0
- package/scripts/lib/docs/discover-checkable-rules.md +165 -0
- package/scripts/lib/docs/ensure-tool.md +254 -0
- package/scripts/lib/docs/generated-markdown.md +275 -0
- package/scripts/lib/docs/gha-workflow.md +326 -0
- package/scripts/lib/docs/inline-template-links.md +303 -0
- package/scripts/lib/docs/list-rule-ids.md +156 -0
- package/scripts/lib/docs/load-cursor-config.md +147 -0
- package/scripts/lib/docs/mirror-parity.md +167 -0
- package/scripts/lib/worktree.mjs +26 -0
- package/scripts/worktree-cli.mjs +12 -2
- package/skills/coverage-fix/SKILL.md +34 -45
- package/skills/docgen/SKILL.md +44 -23
- package/skills/docgen/bench/etalon/firebase_hosting.md +19 -0
- package/skills/docgen/bench/etalon/k8s-tree.md +24 -0
- package/skills/docgen/bench/etalon/overlay-paths.md +24 -0
- package/skills/docgen/js/docgen-ignore.mjs +54 -0
- package/skills/docgen/js/docgen-scan.mjs +37 -21
- package/skills/llm-patch/SKILL.md +23 -2
- package/skills/start-check/SKILL.md +26 -53
- package/skills/start-check/js/check.mjs +211 -0
- package/skills/taze/SKILL.md +9 -3
- package/skills/taze/js/diff.mjs +154 -0
- package/types/bin/n-cursor.d.ts +1 -1
- package/skills/fix-tests/SKILL.md +0 -119
- package/skills/fix-tests/meta.json +0 -1
|
@@ -0,0 +1,636 @@
|
|
|
1
|
+
# n-cursor.js
|
|
2
|
+
|
|
3
|
+
## Огляд
|
|
4
|
+
|
|
5
|
+
Файл `npm/bin/n-cursor.js` — це виконуваний скрипт (shebang `#!/usr/bin/env node`), що слугує єдиною точкою входу CLI пакета `@nitra/cursor`. Скрипт виконує дві ролі:
|
|
6
|
+
|
|
7
|
+
1. **Синхронізатор пакетних артефактів у проєкті-споживачі** — без аргументів копіює `.mdc`-правила, скіли, slash-команди, генерує `AGENTS.md`, `CLAUDE.md`, синхронізує `.claude/settings.json`, `.cursor/hooks.json`, composite GitHub Action `setup-bun-deps`, `.pi/skills`, а також `.gitignore` для `.worktrees/`.
|
|
8
|
+
2. **Маршрутизатор підкоманд** — диспатчить `fix`, `check`, `rename-yaml-extensions`, `post-tool-use-fix`, `lint`, `lint-ci`, `lint-ga`, `lint-rego`, `lint-k8s`, `lint-docker`, `lint-text`, `coverage`, `change`, `release`, `skill`, `worktree`, `flow`, `trace`, `graph`, `docgen` у відповідні внутрішні модулі пакета.
|
|
9
|
+
|
|
10
|
+
Скрипт — ES-модуль (`import` синтаксис). Виконує реальні файлові операції в `cwd()` і у каталогах пакету (`BUNDLED_PACKAGE_ROOT`). Усі шляхи відносно поточної робочої директорії проєкту-споживача.
|
|
11
|
+
|
|
12
|
+
### Підтримувані команди CLI
|
|
13
|
+
|
|
14
|
+
- `npx @nitra/cursor` — повна синхронізація (`runSync`).
|
|
15
|
+
- `npx @nitra/cursor fix` — прогнати `fix.mjs` для всіх правил з `.cursor/rules/*.mdc`, у яких пакет має програмну перевірку.
|
|
16
|
+
- `npx @nitra/cursor fix bun` — прогнати `fix` лише для вказаних id (ігнорує `.cursor/rules/`).
|
|
17
|
+
- `npx @nitra/cursor check` — deprecated alias для `fix` (виводить попередження).
|
|
18
|
+
- `npx @nitra/cursor rename-yaml-extensions` — перейменування `*.yml`/`*.yaml` у k8s/.github (підтримує `--dry-run`, `--root=…`).
|
|
19
|
+
- `npx @nitra/cursor post-tool-use-fix` — entry point PostToolUse hook Claude Code: читає JSON зі stdin, маршрутизує `tool_input.file_path` у релевантні правила.
|
|
20
|
+
- `npx @nitra/cursor lint` — оркестратор `lint-*` / `oxfmt` ланцюжка з вимірюванням таймінгу (fail-fast).
|
|
21
|
+
- `npx @nitra/cursor lint-ci` — те саме, але режим CI.
|
|
22
|
+
- `npx @nitra/cursor lint-ga` — канонічний `lint-ga` (shellcheck preflight → `bunx github-actionlint` → `uvx zizmor --offline --collect=workflows .`).
|
|
23
|
+
- `npx @nitra/cursor lint-rego` — канонічний `lint-rego` (`opa check --strict` → `regal lint` → опційно `conftest verify`).
|
|
24
|
+
- `npx @nitra/cursor lint-k8s` — канонічний `lint-k8s` (`kubeconform` + `kubescape`).
|
|
25
|
+
- `npx @nitra/cursor lint-docker` — канонічний `lint-docker` (`hadolint`).
|
|
26
|
+
- `npx @nitra/cursor lint-text` — канонічний `lint-text` (`cspell` → `shellcheck` з auto-fix → `markdownlint-cli2 --fix` → `v8r`).
|
|
27
|
+
- `npx @nitra/cursor coverage [--fix] [--changed]` — оркестратор покриття та мутаційного тестування.
|
|
28
|
+
- `npx @nitra/cursor change` — створення change-файлу.
|
|
29
|
+
- `npx @nitra/cursor release` — реліз-команда.
|
|
30
|
+
- `npx @nitra/cursor skill list|taze|cursor|claude …` — керування скілами (промпт на stdout, виклик Cursor/Claude CLI).
|
|
31
|
+
- `npx @nitra/cursor worktree …` — керування git-worktree.
|
|
32
|
+
- `npx @nitra/cursor flow` — Dual-Mode Dispatcher (Пасивний Турнікет + Активний Раннер).
|
|
33
|
+
- `npx @nitra/cursor trace` — наскрізна простежуваність ADR↔spec↔plan↔change.
|
|
34
|
+
- `npx @nitra/cursor graph` — read-only DAG-статус.
|
|
35
|
+
- `npx @nitra/cursor docgen scan|modules` — детермінований JSON-лістинг для скілу docgen; `scan` друкує відносний `sourcePath`, ignore-glob snippet живе в `npm/skills/docgen/js/docgen-ignore.mjs`.
|
|
36
|
+
|
|
37
|
+
### Конвенції та ключові артефакти
|
|
38
|
+
|
|
39
|
+
- `.n-cursor.json` (`CONFIG_FILE`) — конфіг проєкту-споживача (rules, skills, disable-rules, disable-skills, ignore, claude-config, version).
|
|
40
|
+
- `CONFIG_SCHEMA_URL = 'https://unpkg.com/@nitra/cursor/schemas/n-cursor.json'` — публічний URL JSON Schema для поля `$schema`.
|
|
41
|
+
- `.cursor/rules` (`RULES_DIR`) — місце призначення `.mdc`-правил (керовані — з префіксом `n-`).
|
|
42
|
+
- `.cursor/skills` (`SKILLS_DIR`) — місце призначення скілів (керовані — з префіксом `n-`).
|
|
43
|
+
- `.claude/commands` (`COMMANDS_DIR`) — slash-команди Claude Code (`n-<id>.md`).
|
|
44
|
+
- `.pi/skills` (`PI_SKILLS_DIR`) — pi.dev-сумісні скіли (директорії з `SKILL.md`).
|
|
45
|
+
- `AGENTS.md` (`AGENTS_FILE`) і `AGENTS.template.md` (`AGENTS_TEMPLATE_FILE`) — генеруються із шаблону пакета.
|
|
46
|
+
- `RULE_PREFIX = 'n-'` — префікс керованих файлів/каталогів.
|
|
47
|
+
|
|
48
|
+
## Експорти / API
|
|
49
|
+
|
|
50
|
+
Файл — виконуваний CLI-модуль і **не має `export`-декларацій**. Усі його внутрішні функції приватні; зовнішнє API — це аргументи командного рядка (`process.argv.slice(2)`) і поведінка на боці файлової системи.
|
|
51
|
+
|
|
52
|
+
Зовнішні залежності, що делегуються:
|
|
53
|
+
|
|
54
|
+
- `buildAgentsCommandBulletItems` зі `scripts/build-agents-commands.mjs`
|
|
55
|
+
- `formatGeneratedMarkdownLines`, `renderAgentsTemplate` зі `scripts/lib/generated-markdown.mjs`
|
|
56
|
+
- `inlineTemplateLinks` зі `scripts/lib/inline-template-links.mjs`
|
|
57
|
+
- `detectAutoRules`, `detectLegacyRuleIds`, `mergeConfigWithAutoDetected`, `normalizeIdList`, `RULE_MIGRATIONS` зі `scripts/auto-rules.mjs`
|
|
58
|
+
- `detectAutoSkills` зі `scripts/auto-skills.mjs`
|
|
59
|
+
- `readSkillMetaRaw` зі `scripts/lib/skill-meta.mjs`
|
|
60
|
+
- `injectWorktreeNotice` зі `scripts/lib/worktree-notice.mjs`
|
|
61
|
+
- `runPostToolUseFixCli` зі `scripts/post-tool-use-fix.mjs`
|
|
62
|
+
- `discoverCheckRulesFromCursorRules` зі `scripts/lib/discover-check-rules-from-cursor.mjs`
|
|
63
|
+
- `listRuleIds` зі `scripts/lib/list-rule-ids.mjs`
|
|
64
|
+
- `ensureNitraCursorInRootDevDependencies` зі `scripts/ensure-nitra-cursor-dev-dependencies.mjs`
|
|
65
|
+
- `runLintDocker`, `runLintGaCli`, `runLintK8s`, `runLintRego`, `runLintTextCli` — з `rules/*/lint/lint.mjs`
|
|
66
|
+
- `syncClaudeConfig` зі `scripts/sync-claude-config.mjs`
|
|
67
|
+
- `syncGitignoreWorktree` зі `scripts/lib/sync-gitignore-worktree.mjs`
|
|
68
|
+
- `upgradeNitraCursorToLatestAndBunInstall` зі `scripts/upgrade-nitra-cursor-and-install.mjs`
|
|
69
|
+
- `runRenameYamlExtensionsCli` з `./rename-yaml-extensions.mjs`
|
|
70
|
+
- `runSkillsCli` зі `scripts/skills-cli.mjs`
|
|
71
|
+
- `runWorktreeCli` зі `scripts/worktree-cli.mjs`
|
|
72
|
+
- `syncSetupBunDepsAction` зі `scripts/sync-setup-bun-deps-action.mjs`
|
|
73
|
+
- `runLint` зі `scripts/lint-cli.mjs`
|
|
74
|
+
- `formatTimingSummary` зі `scripts/lib/timing-summary.mjs`
|
|
75
|
+
- `ensureHkInstall`, `ensureTool` зі `scripts/lib/ensure-tool.mjs`
|
|
76
|
+
- Динамічно (`await import(...)`) у момент маршрутизації команд:
|
|
77
|
+
- `runCoverageCli` з `../rules/test/coverage/coverage.mjs`
|
|
78
|
+
- `runChangeCli` з `../rules/release/change.mjs`
|
|
79
|
+
- `runReleaseCli` з `../rules/release/release.mjs`
|
|
80
|
+
- `runFlowCli` зі `../scripts/dispatcher/index.mjs`
|
|
81
|
+
- `runTraceCli` зі `../scripts/dispatcher/trace.mjs`
|
|
82
|
+
- `runGraphCli` зі `../scripts/dispatcher/graph.mjs`
|
|
83
|
+
- `runDocgenScanCli`, `runDocgenModulesCli` зі `../skills/docgen/js/docgen-scan.mjs`
|
|
84
|
+
|
|
85
|
+
## Константи модуля
|
|
86
|
+
|
|
87
|
+
- `PACKAGE_NAME = '@nitra/cursor'`
|
|
88
|
+
- `CONFIG_FILE = '.n-cursor.json'`
|
|
89
|
+
- `CONFIG_SCHEMA_URL = 'https://unpkg.com/@nitra/cursor/schemas/n-cursor.json'`
|
|
90
|
+
- `AGENTS_FILE = 'AGENTS.md'`
|
|
91
|
+
- `AGENTS_TEMPLATE_FILE = 'AGENTS.template.md'`
|
|
92
|
+
- `RULES_DIR = '.cursor/rules'`
|
|
93
|
+
- `SKILLS_DIR = '.cursor/skills'`
|
|
94
|
+
- `COMMANDS_DIR = '.claude/commands'`
|
|
95
|
+
- `PI_SKILLS_DIR = '.pi/skills'`
|
|
96
|
+
- `RULE_PREFIX = 'n-'`
|
|
97
|
+
- `binDir` — `dirname(fileURLToPath(import.meta.url))`, тобто фізичний шлях до каталогу `bin/` встановленого пакета.
|
|
98
|
+
- `BUNDLED_RULES_DIR = join(binDir, '..', 'rules')` — `rules/` у пакеті.
|
|
99
|
+
- `BUNDLED_SKILLS_DIR = join(binDir, '..', 'skills')` — `skills/` у пакеті.
|
|
100
|
+
- `BUNDLED_AGENTS_TEMPLATE_PATH = join(binDir, '..', AGENTS_TEMPLATE_FILE)` — шаблон `AGENTS.md`.
|
|
101
|
+
- `BUNDLED_PACKAGE_ROOT = join(binDir, '..')` — корінь установленого пакета.
|
|
102
|
+
- `YAML_FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---/` — регекс для YAML frontmatter.
|
|
103
|
+
- `NEWLINE_RE = /\r?\n/` — поділ на рядки.
|
|
104
|
+
- `LEADING_SPACES_RE = /^\s+/` — провідні пробіли.
|
|
105
|
+
- `CONFIG_SORTED_ARRAY_KEYS = ['rules', 'skills', 'disable-rules', 'disable-skills']` — ключі, чиї масиви сортуються перед записом у `.n-cursor.json`.
|
|
106
|
+
|
|
107
|
+
## Класи
|
|
108
|
+
|
|
109
|
+
### ReexecHandoff (extends Error)
|
|
110
|
+
|
|
111
|
+
Сентинельна помилка, яку кидає `reexecIfPackageVersionChanged` після успішного re-exec нової версії бінаря. Top-level `catch` розпізнає її й виставляє `process.exitCode = code` без друку stack-trace.
|
|
112
|
+
|
|
113
|
+
- `constructor(code)` — `code: number`, exit-код, який повернув child re-exec.
|
|
114
|
+
- Полем `this.name` встановлюється `'ReexecHandoff'`, полем `this.code` — переданий exit-код.
|
|
115
|
+
- Виклик `super('reexec-handoff')` — фіктивне повідомлення, не для логування.
|
|
116
|
+
|
|
117
|
+
## Функції
|
|
118
|
+
|
|
119
|
+
### sortConfigIdArrays(config)
|
|
120
|
+
|
|
121
|
+
- **Сигнатура:** `function sortConfigIdArrays(config: Record<string, unknown>): Record<string, unknown>`
|
|
122
|
+
- **Призначення:** повертає копію `config`, у якій масиви під ключами з `CONFIG_SORTED_ARRAY_KEYS` (`rules`, `skills`, `disable-rules`, `disable-skills`) відсортовано за `localeCompare`. Значення приводяться до рядка через `String`.
|
|
123
|
+
- **Параметри:** `config` — сирий обʼєкт конфігу перед записом на диск.
|
|
124
|
+
- **Повертає:** новий обʼєкт із відсортованими масивами; решта полів залишаються без змін.
|
|
125
|
+
- **Side effects:** жодних — pure-функція.
|
|
126
|
+
|
|
127
|
+
### discoverBundledRuleNames(bundledRulesDir = BUNDLED_RULES_DIR)
|
|
128
|
+
|
|
129
|
+
- **Сигнатура:** `async function discoverBundledRuleNames(bundledRulesDir?: string): Promise<string[]>`
|
|
130
|
+
- **Призначення:** повертає відсортовані id правил із каталогу `rules/` пакета. Правило — це підкаталог `rules/<id>/`, що містить файл `<id>.mdc`.
|
|
131
|
+
- **Параметри:** `bundledRulesDir` — каталог `rules/` у корені пакета.
|
|
132
|
+
- **Повертає:** масив id (імена підкаталогів без `.`).
|
|
133
|
+
- **Side effects:** читає файлову систему (`readdir`, `existsSync`). Кидає `Error`, якщо каталог відсутній або в ньому немає валідних правил.
|
|
134
|
+
|
|
135
|
+
### discoverBundledSkillNames(bundledSkillsDir = BUNDLED_SKILLS_DIR)
|
|
136
|
+
|
|
137
|
+
- **Сигнатура:** `async function discoverBundledSkillNames(bundledSkillsDir?: string): Promise<string[]>`
|
|
138
|
+
- **Призначення:** повертає відсортовані id скілів (без префікса `n-`) із каталогу `skills/` пакета. Підкаталоги, чиї імена починаються на `.` або вже мають `n-`-префікс, відкидаються.
|
|
139
|
+
- **Параметри:** `bundledSkillsDir` — каталог `skills/` у корені пакета.
|
|
140
|
+
- **Повертає:** масив id (порожній, якщо каталог відсутній).
|
|
141
|
+
- **Side effects:** `existsSync`, `readdir`. Не кидає помилку при відсутньому каталозі.
|
|
142
|
+
|
|
143
|
+
### migrateLegacyManagedRuleFilenames(rulesDir)
|
|
144
|
+
|
|
145
|
+
- **Сигнатура:** `async function migrateLegacyManagedRuleFilenames(rulesDir: string): Promise<void>`
|
|
146
|
+
- **Призначення:** у каталозі `.cursor/rules` перейменовує `nitra-*.mdc` → `n-*.mdc`. Якщо `n-*.mdc` уже є — `nitra-*.mdc` видаляється.
|
|
147
|
+
- **Параметри:** `rulesDir` — абсолютний шлях до `.cursor/rules`.
|
|
148
|
+
- **Повертає:** нічого (`void`).
|
|
149
|
+
- **Side effects:** `unlink`/`rename`, лог у stdout про кожне перейменування/видалення.
|
|
150
|
+
|
|
151
|
+
### migrateLegacyConfigIfNeeded()
|
|
152
|
+
|
|
153
|
+
- **Сигнатура:** `async function migrateLegacyConfigIfNeeded(): Promise<void>`
|
|
154
|
+
- **Призначення:** виконує дві міграції: викликає `migrateLegacyManagedRuleFilenames` у `.cursor/rules` і, якщо немає `.n-cursor.json`, але є `nitra-cursor.json`, перейменовує його у `.n-cursor.json`.
|
|
155
|
+
- **Параметри:** немає.
|
|
156
|
+
- **Side effects:** `existsSync`, `rename`, лог у stdout.
|
|
157
|
+
|
|
158
|
+
### readRootPackageJsonSafe()
|
|
159
|
+
|
|
160
|
+
- **Сигнатура:** `async function readRootPackageJsonSafe(): Promise<unknown | null>`
|
|
161
|
+
- **Призначення:** читає `cwd()/package.json` і повертає розпарсений JSON. Якщо файлу немає чи парсинг падає — повертає `null` (помилка не пропагується).
|
|
162
|
+
- **Параметри:** немає.
|
|
163
|
+
- **Повертає:** розпарсений обʼєкт або `null`.
|
|
164
|
+
- **Side effects:** I/O читання файлу. Не кидає винятків.
|
|
165
|
+
|
|
166
|
+
### readConfig(paths = {})
|
|
167
|
+
|
|
168
|
+
- **Сигнатура:** `async function readConfig(paths?: { bundledRulesDir?: string, bundledSkillsDir?: string }): Promise<{ $schema: string, rules: string[], skills: string[], version?: string } & Record<string, unknown>>`
|
|
169
|
+
- **Призначення:** головний акцесор `.n-cursor.json`. Послідовність:
|
|
170
|
+
1. Викликає `migrateLegacyConfigIfNeeded`.
|
|
171
|
+
2. Якщо `.n-cursor.json` немає — створює дефолтний з `auto-detected rules` (`detectAutoRules`) та `skills` (`detectAutoSkills`), сортує і записує.
|
|
172
|
+
3. Якщо файл є — парсить, валідує, логує legacy rule-id (`logRuleMigrationsIfAny`), нормалізує через вкладену `normalizeConfigWithAutoRules` і, якщо результат відрізняється від диска — перезаписує.
|
|
173
|
+
- **Параметри:** `paths.bundledRulesDir` і `paths.bundledSkillsDir` — каталоги пакета-джерела (за замовчуванням `BUNDLED_*` константи).
|
|
174
|
+
- **Повертає:** нормалізований конфіг із обовʼязковими полями `$schema`, `rules`, `skills`; опційно `disable-rules`, `disable-skills`, `ignore`, `claude-config`, `version`.
|
|
175
|
+
- **Side effects:** читає/пише `.n-cursor.json`, лог у stdout про створення/оновлення. Кидає `Error`/`TypeError` для невалідного JSON або неправильних типів полів `rules`/`skills`/`ignore`.
|
|
176
|
+
|
|
177
|
+
#### Вкладена normalizeConfigWithAutoRules(parsedConfig)
|
|
178
|
+
|
|
179
|
+
- **Сигнатура:** `async function normalizeConfigWithAutoRules(parsedConfig: Record<string, unknown>): Promise<Record<string, unknown>>`
|
|
180
|
+
- **Призначення:** перевіряє типи полів, обчислює `auto-detected rules` (`detectAutoRules`), будує ефективний список правил (поточні + auto, мінус `disable-rules`), за яким `detectAutoSkills` визначає скіли. Далі `mergeConfigWithAutoDetected` зливає дані, після чого `$schema` вирівнюється до `CONFIG_SCHEMA_URL`, додаються `disable-rules`/`disable-skills` (якщо непорожні), результат проходить через `sortConfigIdArrays`.
|
|
181
|
+
|
|
182
|
+
### logRuleMigrationsIfAny(parsedConfig)
|
|
183
|
+
|
|
184
|
+
- **Сигнатура:** `function logRuleMigrationsIfAny(parsedConfig: Record<string, unknown>): void`
|
|
185
|
+
- **Призначення:** якщо у `parsedConfig.rules` чи `parsedConfig['disable-rules']` є застарілі id з `RULE_MIGRATIONS`, виводить блок логу про авто-міграцію (саму заміну виконує `migrateRuleIds` всередині `mergeConfigWithAutoDetected`).
|
|
186
|
+
- **Параметри:** `parsedConfig` — сирий обʼєкт після `JSON.parse`.
|
|
187
|
+
- **Повертає:** нічого.
|
|
188
|
+
- **Side effects:** друк у stdout.
|
|
189
|
+
|
|
190
|
+
### normalizeRuleName(ruleName)
|
|
191
|
+
|
|
192
|
+
- **Сигнатура:** `function normalizeRuleName(ruleName: string): string`
|
|
193
|
+
- **Призначення:** витягує чистий id правила з рядка-шляху або базового імені. Виконує `basename`, тримить, відрізає суфікс `.mdc`. Приклади: `"npm/rules/text/text.mdc" → "text"`, `"text.mdc" → "text"`, `"text" → "text"`.
|
|
194
|
+
- **Параметри:** `ruleName` — будь-яке з трьох форм.
|
|
195
|
+
- **Повертає:** id без `.mdc` і без шляху.
|
|
196
|
+
- **Side effects:** немає.
|
|
197
|
+
|
|
198
|
+
### readBundledRuleContent(rule, bundledRulesDir = BUNDLED_RULES_DIR)
|
|
199
|
+
|
|
200
|
+
- **Сигнатура:** `async function readBundledRuleContent(rule: string, bundledRulesDir?: string): Promise<string>`
|
|
201
|
+
- **Призначення:** читає файл `rules/<id>/<id>.mdc` із пакета і прогонить через `inlineTemplateLinks`, щоб inline-посилання шаблонів розкрилися.
|
|
202
|
+
- **Параметри:** `rule` — елемент масиву `rules` з `.n-cursor.json`; `bundledRulesDir` — каталог `rules/`.
|
|
203
|
+
- **Повертає:** готовий до запису текст `.mdc`.
|
|
204
|
+
- **Side effects:** `existsSync`/`readFile`. Кидає `Error`, якщо файлу немає.
|
|
205
|
+
|
|
206
|
+
### normalizeSkillId(skillName)
|
|
207
|
+
|
|
208
|
+
- **Сигнатура:** `function normalizeSkillId(skillName: string): string`
|
|
209
|
+
- **Призначення:** приводить id скілу до форми без префікса `n-` (наприклад `n-fix` → `fix`, `fix` → `fix`).
|
|
210
|
+
- **Параметри:** `skillName` — елемент масиву `skills` або імʼя каталогу.
|
|
211
|
+
- **Повертає:** id без префікса.
|
|
212
|
+
|
|
213
|
+
### managedSkillDirName(skillId)
|
|
214
|
+
|
|
215
|
+
- **Сигнатура:** `function managedSkillDirName(skillId: string): string`
|
|
216
|
+
- **Призначення:** повертає імʼя керованого каталогу скілу в `.cursor/skills` (з префіксом `n-`).
|
|
217
|
+
- **Параметри:** id з префіксом або без — нормалізується через `normalizeSkillId`.
|
|
218
|
+
- **Повертає:** наприклад `'n-fix'`.
|
|
219
|
+
|
|
220
|
+
### extractSkillDescription(text)
|
|
221
|
+
|
|
222
|
+
- **Сигнатура:** `function extractSkillDescription(text: string): string | null`
|
|
223
|
+
- **Призначення:** з YAML frontmatter `SKILL.md` витягує мультирядковий блок `description: >-`. Шукає рядок `description: >-`, далі бере рядки, що починаються з пробілів, доки не зустрінеться рядок без провідних пробілів. Зрізає провідні пробіли, склеює одним пробілом.
|
|
224
|
+
- **Параметри:** `text` — повний вміст `SKILL.md`.
|
|
225
|
+
- **Повертає:** очищений однорядковий опис або `null` (немає frontmatter / немає `description: >-` / блок порожній).
|
|
226
|
+
|
|
227
|
+
### skillDescriptionSafeForMarkdownInline(desc)
|
|
228
|
+
|
|
229
|
+
- **Сигнатура:** `function skillDescriptionSafeForMarkdownInline(desc: string): string`
|
|
230
|
+
- **Призначення:** замінює всі входження літералу `<id>` на `{id}`, щоб markdownlint (MD033) не сприймав їх як inline HTML у звичайному markdown.
|
|
231
|
+
- **Параметри:** `desc` — рядок з frontmatter.
|
|
232
|
+
- **Повертає:** оброблений рядок.
|
|
233
|
+
|
|
234
|
+
### formatClaudeCommandFrontmatter(descriptionRaw)
|
|
235
|
+
|
|
236
|
+
- **Сигнатура:** `function formatClaudeCommandFrontmatter(descriptionRaw: string): string`
|
|
237
|
+
- **Призначення:** формує YAML frontmatter для `.claude/commands/*.md`. Обовʼязкове поле `description` — щоб VSCode-розширення Claude Code побачило команду. Якщо текст порожній — використовує fallback "Див. SKILL.md у каталозі скілу в .cursor/skills.".
|
|
238
|
+
- **Параметри:** `descriptionRaw` — значення з `extractSkillDescription` (може бути `''`/`null`).
|
|
239
|
+
- **Повертає:** блок `---\ndescription: >-\n …\n---\n\n`.
|
|
240
|
+
|
|
241
|
+
### formatPiSkillFrontmatter(skillName, descriptionRaw)
|
|
242
|
+
|
|
243
|
+
- **Сигнатура:** `function formatPiSkillFrontmatter(skillName: string, descriptionRaw: string): string`
|
|
244
|
+
- **Призначення:** YAML frontmatter для `.pi/skills/<dir>/SKILL.md` за специфікацією pi.dev: обовʼязкові поля `name` (1-64, `[a-z0-9-]`) і `description` (≤ 1024). Якщо `descriptionRaw` порожній — fallback як у `formatClaudeCommandFrontmatter`.
|
|
245
|
+
- **Параметри:** `skillName` — імʼя скілу (наприклад `n-fix`); `descriptionRaw` — текст опису.
|
|
246
|
+
- **Повертає:** блок `---\nname: …\ndescription: >-\n …\n---\n\n`.
|
|
247
|
+
|
|
248
|
+
### listProjectRulesMdcFiles()
|
|
249
|
+
|
|
250
|
+
- **Сигнатура:** `async function listProjectRulesMdcFiles(): Promise<string[]>`
|
|
251
|
+
- **Призначення:** повертає відсортовані базові імена `*.mdc`-файлів у `.cursor/rules` поточного проєкту.
|
|
252
|
+
- **Параметри:** немає.
|
|
253
|
+
- **Повертає:** масив імен (без шляху), порожній якщо каталогу немає.
|
|
254
|
+
|
|
255
|
+
### expectedManagedRuleBasenames(configRules)
|
|
256
|
+
|
|
257
|
+
- **Сигнатура:** `function expectedManagedRuleBasenames(configRules: string[]): Set<string>`
|
|
258
|
+
- **Призначення:** будує `Set<string>` базових імен очікуваних керованих файлів (`n-<id>.mdc`) із масиву `rules` конфігу.
|
|
259
|
+
- **Параметри:** `configRules`.
|
|
260
|
+
- **Повертає:** множина імен.
|
|
261
|
+
|
|
262
|
+
### removeOrphanManagedRuleFiles(rulesDir, configRules)
|
|
263
|
+
|
|
264
|
+
- **Сигнатура:** `async function removeOrphanManagedRuleFiles(rulesDir: string, configRules: string[]): Promise<string[]>`
|
|
265
|
+
- **Призначення:** видаляє з `rulesDir` файли `n-*.mdc`, яких немає в конфізі. Файли без префікса `n-` не чіпає.
|
|
266
|
+
- **Параметри:** `rulesDir` — `.cursor/rules`; `configRules` — масив `rules` із `.n-cursor.json`.
|
|
267
|
+
- **Повертає:** відсортований масив імен видалених файлів.
|
|
268
|
+
- **Side effects:** `unlink`.
|
|
269
|
+
|
|
270
|
+
### listProjectSkillDirNames()
|
|
271
|
+
|
|
272
|
+
- **Сигнатура:** `async function listProjectSkillDirNames(): Promise<string[]>`
|
|
273
|
+
- **Призначення:** повертає відсортовані імена підкаталогів `.cursor/skills`, що не починаються з `.`.
|
|
274
|
+
- **Side effects:** `readdir` (з `withFileTypes`).
|
|
275
|
+
|
|
276
|
+
### buildSkillBulletItems()
|
|
277
|
+
|
|
278
|
+
- **Сигнатура:** `async function buildSkillBulletItems(): Promise<{ name: string }[]>`
|
|
279
|
+
- **Призначення:** будує елементи для Mustache-секції `skills` шаблону `AGENTS.md`. Для кожного підкаталогу `.cursor/skills/<dir>` зчитує `SKILL.md`, дістає `description`, формує рядок `- \`.cursor/skills/<dir>/SKILL.md\` — <desc>`. Без опису — лише шлях.
|
|
280
|
+
- **Повертає:** масив обʼєктів `{ name: string }`.
|
|
281
|
+
|
|
282
|
+
### removeOrphanManagedSkillDirs(skillsRoot, configSkills)
|
|
283
|
+
|
|
284
|
+
- **Сигнатура:** `async function removeOrphanManagedSkillDirs(skillsRoot: string, configSkills: string[]): Promise<string[]>`
|
|
285
|
+
- **Призначення:** видаляє з `.cursor/skills` каталоги з префіксом `n-`, яких немає в конфізі (порівняння через `managedSkillDirName`).
|
|
286
|
+
- **Side effects:** `rm` рекурсивно.
|
|
287
|
+
|
|
288
|
+
### buildClaudeLintParallelismSectionLines()
|
|
289
|
+
|
|
290
|
+
- **Сигнатура:** `function buildClaudeLintParallelismSectionLines(): string[]`
|
|
291
|
+
- **Призначення:** повертає готові рядки для секції `## Лінт і ESLint (без паралельних запусків)` у `CLAUDE.md`. Дублює fail-fast правило: один прогон `lint`/ESLint на сесію.
|
|
292
|
+
|
|
293
|
+
### buildClaudeWorktreeEnforcementSectionLines()
|
|
294
|
+
|
|
295
|
+
- **Сигнатура:** `function buildClaudeWorktreeEnforcementSectionLines(): string[]`
|
|
296
|
+
- **Призначення:** повертає рядки для секції `## Worktree-only skills (\`meta.json\` → \`worktree: true\`)`у`CLAUDE.md`(preflight-вимога запуску таких скілів виключно в`.worktrees/`).
|
|
297
|
+
|
|
298
|
+
### buildClaudeSkillsSectionLines()
|
|
299
|
+
|
|
300
|
+
- **Сигнатура:** `async function buildClaudeSkillsSectionLines(): Promise<string[]>`
|
|
301
|
+
- **Призначення:** будує секцію `## Skills` для `CLAUDE.md`. Для кожного `.cursor/skills/<dir>`: читає `SKILL.md` → `description`; якщо є `.claude/commands/<dir>.md` — додає рядок `Команда: /<dir>`.
|
|
302
|
+
- **Повертає:** масив рядків (порожній, якщо скілів немає).
|
|
303
|
+
|
|
304
|
+
### syncClaudeMd(ignore)
|
|
305
|
+
|
|
306
|
+
- **Сигнатура:** `async function syncClaudeMd(ignore?: string[]): Promise<void>`
|
|
307
|
+
- **Призначення:** генерує `CLAUDE.md` у `cwd()`. Структура:
|
|
308
|
+
1. Заголовок-коментар про авто-генерацію.
|
|
309
|
+
2. Опційно секція `## Захищені директорії` (зі `ignore`), якщо передано непорожній масив.
|
|
310
|
+
3. `@.cursor/rules/<file>.mdc`-імпорти всіх `*.mdc` із `.cursor/rules`.
|
|
311
|
+
4. Секції з `buildClaudeLintParallelismSectionLines` + `buildClaudeWorktreeEnforcementSectionLines`.
|
|
312
|
+
5. Секція `## Skills` (`buildClaudeSkillsSectionLines`).
|
|
313
|
+
- **Параметри:** `ignore` — масив директорій (рядків), кожна виводиться через `- \`<dir>/\``. Трейлінгові `/` зрізаються.
|
|
314
|
+
- **Side effects:** `writeFile` `CLAUDE.md`, лог про створення/оновлення.
|
|
315
|
+
|
|
316
|
+
### syncAgentsMd(agentsTemplatePath = BUNDLED_AGENTS_TEMPLATE_PATH)
|
|
317
|
+
|
|
318
|
+
- **Сигнатура:** `async function syncAgentsMd(agentsTemplatePath?: string): Promise<void>`
|
|
319
|
+
- **Призначення:** повністю перезаписує `AGENTS.md` у корені проєкту. Зчитує шаблон, листи `*.mdc`-правил, `skillItems` (`buildSkillBulletItems`), `commandItems` (`buildAgentsCommandBulletItems`); рендерить через `renderAgentsTemplate`. Гарантує trailing newline.
|
|
320
|
+
- **Side effects:** кидає `Error`, якщо шаблону немає; лог про створення/оновлення.
|
|
321
|
+
|
|
322
|
+
### syncSkills(configSkills, bundledSkillsDir = BUNDLED_SKILLS_DIR)
|
|
323
|
+
|
|
324
|
+
- **Сигнатура:** `async function syncSkills(configSkills: string[], bundledSkillsDir?: string): Promise<{ success: number, fail: number }>`
|
|
325
|
+
- **Призначення:** копіює топ-level файли скілів (без `meta.json` і без підкаталогів) із `skills/<id>/` пакета до `.cursor/skills/n-<id>/`. Для `SKILL.md` додатково викликає `injectWorktreeNotice(content, worktree)`, де `worktree` походить із `meta.json` (`readSkillMetaRaw(srcDir)?.worktree === true`).
|
|
326
|
+
- **Параметри:** `configSkills` — id без префікса; `bundledSkillsDir`.
|
|
327
|
+
- **Повертає:** обʼєкт-лічильник `{ success, fail }`.
|
|
328
|
+
- **Side effects:** `mkdir -p`, `writeFile`. Логи прогресу/помилок у stdout/stderr.
|
|
329
|
+
|
|
330
|
+
### syncCommands(configSkills, bundledSkillsDir = BUNDLED_SKILLS_DIR)
|
|
331
|
+
|
|
332
|
+
- **Сигнатура:** `async function syncCommands(configSkills: string[], bundledSkillsDir?: string): Promise<{ success: number, fail: number }>`
|
|
333
|
+
- **Призначення:** генерує файли `.claude/commands/n-<id>.md` для всіх скілів із конфігу. Кожен файл: YAML frontmatter (`formatClaudeCommandFrontmatter` з `description` зі `SKILL.md` пакета) + `# n-<id>` + посилання `Виконай інструкції зі скілу \`.cursor/skills/n-<id>/SKILL.md\``.
|
|
334
|
+
|
|
335
|
+
### removeOrphanManagedCommandFiles(commandsDir, configSkills)
|
|
336
|
+
|
|
337
|
+
- **Сигнатура:** `async function removeOrphanManagedCommandFiles(commandsDir: string, configSkills: string[]): Promise<string[]>`
|
|
338
|
+
- **Призначення:** видаляє з `.claude/commands` файли `n-*.md`, яких немає в конфізі (порівняння `n-<id>.md`).
|
|
339
|
+
- **Side effects:** `unlink`.
|
|
340
|
+
|
|
341
|
+
### syncLocalOnlySkillCommands(configSkills)
|
|
342
|
+
|
|
343
|
+
- **Сигнатура:** `async function syncLocalOnlySkillCommands(configSkills: string[]): Promise<{ success: number, fail: number }>`
|
|
344
|
+
- **Призначення:** створює `.claude/commands/<dirName>.md` для скілів із `.cursor/skills/`, що **не** керуються пакетом (їх каталоги відсутні у списку `configSkills` через `managedSkillDirName`). `description` беруть із локального `SKILL.md`.
|
|
345
|
+
|
|
346
|
+
### removeOrphanLocalSkillCommandFiles(commandsDir, configSkills)
|
|
347
|
+
|
|
348
|
+
- **Сигнатура:** `async function removeOrphanLocalSkillCommandFiles(commandsDir: string, configSkills: string[]): Promise<string[]>`
|
|
349
|
+
- **Призначення:** видаляє з `.claude/commands` файли локальних скілів (без префікса `n-`), яких більше немає в `.cursor/skills/` і яких немає серед керованих.
|
|
350
|
+
- **Side effects:** `unlink`.
|
|
351
|
+
|
|
352
|
+
### syncPiSkills(configSkills, bundledSkillsDir = BUNDLED_SKILLS_DIR)
|
|
353
|
+
|
|
354
|
+
- **Сигнатура:** `async function syncPiSkills(configSkills: string[], bundledSkillsDir?: string): Promise<{ success: number, fail: number }>`
|
|
355
|
+
- **Призначення:** аналог `syncCommands`, але створює директорії `.pi/skills/n-<id>/SKILL.md` із pi.dev-frontmatter (`formatPiSkillFrontmatter`) і тілом-делегатом на джерельний `.cursor/skills/n-<id>/SKILL.md`.
|
|
356
|
+
- **Side effects:** `mkdir`, `writeFile`.
|
|
357
|
+
|
|
358
|
+
### syncLocalOnlyPiSkills(configSkills)
|
|
359
|
+
|
|
360
|
+
- **Сигнатура:** `async function syncLocalOnlyPiSkills(configSkills: string[]): Promise<{ success: number, fail: number }>`
|
|
361
|
+
- **Призначення:** аналог `syncLocalOnlySkillCommands` для `.pi/skills`. Для кожного локального скілу з `.cursor/skills/<dir>` будує `.pi/skills/<dir>/SKILL.md` з frontmatter і делегатом.
|
|
362
|
+
|
|
363
|
+
### removeOrphanManagedPiSkillDirs(piSkillsDir, configSkills)
|
|
364
|
+
|
|
365
|
+
- **Сигнатура:** `async function removeOrphanManagedPiSkillDirs(piSkillsDir: string, configSkills: string[]): Promise<string[]>`
|
|
366
|
+
- **Призначення:** видаляє з `.pi/skills` директорії з префіксом `n-`, яких немає в конфізі.
|
|
367
|
+
- **Side effects:** `rm` рекурсивно.
|
|
368
|
+
|
|
369
|
+
### removeOrphanLocalPiSkillDirs(piSkillsDir, configSkills)
|
|
370
|
+
|
|
371
|
+
- **Сигнатура:** `async function removeOrphanLocalPiSkillDirs(piSkillsDir: string, configSkills: string[]): Promise<string[]>`
|
|
372
|
+
- **Призначення:** видаляє з `.pi/skills` директорії без префікса `n-`, відповідні скіли яких відсутні і в `.cursor/skills/`, і серед керованих.
|
|
373
|
+
- **Side effects:** `rm` рекурсивно.
|
|
374
|
+
|
|
375
|
+
### errorMessage(error)
|
|
376
|
+
|
|
377
|
+
- **Сигнатура:** `function errorMessage(error: unknown): string`
|
|
378
|
+
- **Призначення:** людинозрозумілий текст винятку: якщо `error instanceof Error` — `error.message`; інакше `String(error)`.
|
|
379
|
+
|
|
380
|
+
### runSyncStep(prefix, action)
|
|
381
|
+
|
|
382
|
+
- **Сигнатура:** `async function runSyncStep<T>(prefix: string, action: () => Promise<T>): Promise<T>`
|
|
383
|
+
- **Призначення:** виконує `action()`, при помилці друкує `prefix + errorMessage(error)` у `stderr` і пере-кидає виняток. Уніфікований wrapper для кроків `runSync`.
|
|
384
|
+
|
|
385
|
+
### syncManagedRuleFiles(rules, bundledRulesDir, rulesDir)
|
|
386
|
+
|
|
387
|
+
- **Сигнатура:** `async function syncManagedRuleFiles(rules: string[], bundledRulesDir: string, rulesDir: string): Promise<{ successCount: number, failCount: number }>`
|
|
388
|
+
- **Призначення:** для кожного `rule` із `rules` копіює `n-<id>.mdc` із пакета в `.cursor/rules`. Прогрес виводить у stdout (`⬇`, `✅`/`❌`). Помилки рахуються у `failCount`, не зупиняючи цикл.
|
|
389
|
+
- **Side effects:** `writeFile`.
|
|
390
|
+
|
|
391
|
+
### logRemovedManagedItems(title, basePath, names)
|
|
392
|
+
|
|
393
|
+
- **Сигнатура:** `function logRemovedManagedItems(title: string, basePath: string, names: string[]): void`
|
|
394
|
+
- **Призначення:** друкує у stdout блок `🧹 Видалено <title> поза списком .n-cursor.json (N): …`. Якщо `names` порожній — нічого не друкує.
|
|
395
|
+
|
|
396
|
+
### runFixCommand(requestedRules)
|
|
397
|
+
|
|
398
|
+
- **Сигнатура:** `async function runFixCommand(requestedRules: string[]): Promise<void>`
|
|
399
|
+
- **Призначення:** spawn-wrapper для `npx @nitra/cursor fix [<rule>...]`. Алгоритм:
|
|
400
|
+
1. `ensureTool('hk')` → `ensureHkInstall(hkBin)` → `ensureTool('conftest')`.
|
|
401
|
+
2. `listRuleIds(BUNDLED_RULES_DIR)` — повний перелік доступних правил. Якщо порожньо — кидає `Error('No rules found')`.
|
|
402
|
+
3. Якщо `requestedRules` непорожній — перевіряє, що всі id є серед доступних; інакше виводить список доступних і кидає `Unknown rules: …`.
|
|
403
|
+
4. Якщо `requestedRules` порожній — discovery з `.cursor/rules/*.mdc` (через `listProjectRulesMdcFiles` + `discoverCheckRulesFromCursorRules`). Якщо `.mdc`-файлів немає — кидає `Error` із підказкою синхронізувати; якщо є, але немає правил із програмною перевіркою — друкує повідомлення і `return`.
|
|
404
|
+
5. Для кожного `id` зі списку: `spawnSync('bun', [BUNDLED_RULES_DIR/<id>/fix.mjs], { stdio: 'inherit' })`. Час кроку записує у масив `timings` як `{ id: \`fix-<id>\`, ms, ok }`.
|
|
405
|
+
6. Після циклу — `formatTimingSummary('Fix timing', timings)` у stdout.
|
|
406
|
+
7. Якщо `totalFailed > 0` — кидає `Error(\`<n> з <total> правил мають проблеми\`)`.
|
|
407
|
+
- **Side effects:** запуск дочірніх процесів `bun`, реальне виконання fix-правил, лог таймінгу. Серіалізація паралельних запусків — на рівні `runStandardRule` (`withLock('fix-<id>')`), на рівні `runFixCommand` локу немає.
|
|
408
|
+
|
|
409
|
+
### readBundledVersionAt(packageRoot)
|
|
410
|
+
|
|
411
|
+
- **Сигнатура:** `async function readBundledVersionAt(packageRoot: string): Promise<string | null>`
|
|
412
|
+
- **Призначення:** читає `<packageRoot>/package.json` і повертає поле `version` (рядок). При відсутньому файлі, некоректному JSON чи відсутності поля повертає `null`.
|
|
413
|
+
|
|
414
|
+
### reexecIfPackageVersionChanged(effectivePackageRoot)
|
|
415
|
+
|
|
416
|
+
- **Сигнатура:** `async function reexecIfPackageVersionChanged(effectivePackageRoot: string): Promise<void>`
|
|
417
|
+
- **Призначення:** якщо `upgradeNitraCursorToLatestAndBunInstall` встановив версію в `node_modules/@nitra/cursor`, відмінну від поточної (з npx-кешу), процес перезапускається через `spawnSync(process.execPath, [newBinPath, ...process.argv.slice(2)], { stdio: 'inherit', env: { …, NITRA_CURSOR_REEXEC: '1' } })`. Захист від циклу — env `NITRA_CURSOR_REEXEC=1`. Якщо ‘re-exec’ відбувся — кидає `ReexecHandoff(result.status ?? 1)`, який ловить top-level catch і виставляє `process.exitCode`.
|
|
418
|
+
- **Сценарії пропуску:**
|
|
419
|
+
- `env.NITRA_CURSOR_REEXEC === '1'` (всередині re-exec) — повертає.
|
|
420
|
+
- `effectivePackageRoot === BUNDLED_PACKAGE_ROOT` — пакет той самий, нічого не змінилося.
|
|
421
|
+
- Не вдалося прочитати версії (`currentVersion`/`installedVersion` = null) або вони рівні.
|
|
422
|
+
- Файлу `effectivePackageRoot/bin/n-cursor.js` немає.
|
|
423
|
+
- **Side effects:** spawn нового процесу, друк `🔁` повідомлення, кидання `ReexecHandoff`, або `throw result.error` при spawn-error.
|
|
424
|
+
|
|
425
|
+
### runSync()
|
|
426
|
+
|
|
427
|
+
- **Сигнатура:** `async function runSync(): Promise<void>`
|
|
428
|
+
- **Призначення:** головний оркестратор синхронізації. Порядок кроків:
|
|
429
|
+
1. Print банер `🔧 @nitra/cursor — завантаження cursor-правил`.
|
|
430
|
+
2. `upgradeNitraCursorToLatestAndBunInstall(cwd(), BUNDLED_PACKAGE_ROOT)` (через `runSyncStep`) — оновлює пакет до останнього з npm і робить `bun i`. Повертає `effectivePackageRoot`.
|
|
431
|
+
3. `reexecIfPackageVersionChanged(effectivePackageRoot)` — за потреби перезапускає процес.
|
|
432
|
+
4. Резолвить `bundledRulesDir`, `bundledSkillsDir`, `bundledAgentsTemplatePath` від `effectivePackageRoot`.
|
|
433
|
+
5. `readConfig({ bundledRulesDir, bundledSkillsDir })` — отримує нормалізований конфіг. Деструктуризує `rules`, `skills`, `version`, `ignore`; `claudeConfigEnabled = config['claude-config'] !== false`.
|
|
434
|
+
6. Друкує `📦 Джерело правил: @nitra/cursor@<ver>` (з шляхом, якщо `effectivePackageRoot !== BUNDLED_PACKAGE_ROOT`).
|
|
435
|
+
7. Якщо у конфізі є `version` — попередження, що поле ігнорується.
|
|
436
|
+
8. Друкує лічильники правил/скілів.
|
|
437
|
+
9. `syncSetupBunDepsAction(cwd(), effectivePackageRoot)` — composite `.github/actions/setup-bun-deps/action.yml`.
|
|
438
|
+
10. `mkdir -p .cursor/rules`; `syncManagedRuleFiles(rules, bundledRulesDir, rulesDir)`.
|
|
439
|
+
11. `removeOrphanManagedRuleFiles` → `logRemovedManagedItems('правила', RULES_DIR, …)`.
|
|
440
|
+
12. `syncSkills(skills, bundledSkillsDir)` + `removeOrphanManagedSkillDirs`. При помилках копіювання — кидає `Error`.
|
|
441
|
+
13. `syncCommands(skills, bundledSkillsDir)` + `syncLocalOnlySkillCommands(skills)` + видалення осиротілих (`removeOrphanManagedCommandFiles`, `removeOrphanLocalSkillCommandFiles`).
|
|
442
|
+
14. `syncPiSkills(skills, bundledSkillsDir)` + `syncLocalOnlyPiSkills(skills)` + видалення осиротілих (`removeOrphanManagedPiSkillDirs`, `removeOrphanLocalPiSkillDirs`).
|
|
443
|
+
15. `syncAgentsMd(bundledAgentsTemplatePath)`.
|
|
444
|
+
16. `syncClaudeMd(ignore)`.
|
|
445
|
+
17. `syncClaudeConfig({ projectRoot: cwd(), bundledPackageRoot: effectivePackageRoot, enabled: claudeConfigEnabled, rules })`. Якщо `claudeConfigEnabled === false` — друкує "пропущено". Інакше формує перелік оновлених артефактів: `.claude/settings.json`, `.cursor/hooks.json`, slash-команди, ADR-хуки (`capture-decisions.sh`, `normalize-decisions.sh`), бібліотеки хуків, `.gitignore` (adr fragment), `.pi/extensions/n-cursor-adr/`.
|
|
446
|
+
18. `syncGitignoreWorktree(cwd())` — додає `.worktrees/` до `.gitignore`.
|
|
447
|
+
19. Друкує `✨ Готово: <successCount> завантажено, <failCount> з помилками`. Якщо `failCount > 0` — кидає `Error`.
|
|
448
|
+
- **Side effects:** масові операції з файловою системою у `cwd()`, дочірні процеси `bun i` через `upgradeNitraCursorToLatestAndBunInstall`, мережа (npm) для self-upgrade.
|
|
449
|
+
|
|
450
|
+
## Top-level потік виконання
|
|
451
|
+
|
|
452
|
+
Виконуваний код у кінці файлу:
|
|
453
|
+
|
|
454
|
+
```text
|
|
455
|
+
const [command, ...args] = process.argv.slice(2)
|
|
456
|
+
try {
|
|
457
|
+
await ensureNitraCursorInRootDevDependencies(cwd())
|
|
458
|
+
switch (command) { … }
|
|
459
|
+
} catch (error) {
|
|
460
|
+
if (error instanceof ReexecHandoff) process.exitCode = error.code
|
|
461
|
+
else if (error instanceof Error && error.message) { console.error(error.message); process.exitCode = 1 }
|
|
462
|
+
else { console.error(error); process.exitCode = 1 }
|
|
463
|
+
}
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
### Алгоритм маршрутизації команд (switch)
|
|
467
|
+
|
|
468
|
+
- `'fix'` → `runFixCommand(args)`.
|
|
469
|
+
- `'check'` → друкує deprecated-попередження й виконує `runFixCommand(args)`.
|
|
470
|
+
- `'rename-yaml-extensions'` → `runRenameYamlExtensionsCli(args)`; якщо повернений код `!== 0`, `process.exitCode = 1`.
|
|
471
|
+
- `'post-tool-use-fix'` → `runPostToolUseFixCli()` (PostToolUse hook Claude Code, читає stdin); `process.exitCode` = повернений код.
|
|
472
|
+
- `'lint'` → `runLint({ ci: false })`.
|
|
473
|
+
- `'lint-ci'` → `runLint({ ci: true })`.
|
|
474
|
+
- `'lint-ga'` → `runLintGaCli()` (`await` обовʼязковий — `check-ga` async).
|
|
475
|
+
- `'lint-rego'` → `runLintRego()`.
|
|
476
|
+
- `'lint-k8s'` → `runLintK8s()`.
|
|
477
|
+
- `'lint-docker'` → `runLintDocker()`.
|
|
478
|
+
- `'lint-text'` → `runLintTextCli()`.
|
|
479
|
+
- `'coverage'` → динамічний import `../rules/test/coverage/coverage.mjs`, виклик `runCoverageCli({ fix: args.includes('--fix'), changed: args.includes('--changed') })`.
|
|
480
|
+
- `'change'` → динамічний import `../rules/release/change.mjs` → `runChangeCli(args)`.
|
|
481
|
+
- `'release'` → динамічний import `../rules/release/release.mjs` → `runReleaseCli(args)`.
|
|
482
|
+
- `'skill'` → `runSkillsCli(args)` (синхронний).
|
|
483
|
+
- `'worktree'` → `runWorktreeCli(args)`.
|
|
484
|
+
- `'flow'` → динамічний import `../scripts/dispatcher/index.mjs` → `runFlowCli(args)`.
|
|
485
|
+
- `'trace'` → динамічний import `../scripts/dispatcher/trace.mjs` → `runTraceCli(args)`.
|
|
486
|
+
- `'graph'` → динамічний import `../scripts/dispatcher/graph.mjs` → `runGraphCli(args)`.
|
|
487
|
+
- `'docgen'` → динамічний import `../skills/docgen/js/docgen-scan.mjs`. Якщо `args[0] === 'scan'` → `runDocgenScanCli(args.slice(1))`; якщо `'modules'` → `runDocgenModulesCli(args.slice(1))`; інакше друкує `Usage: …` і `process.exitCode = 1`.
|
|
488
|
+
- `undefined` або `''` (нема команди) → `runSync()`.
|
|
489
|
+
- `default` — невідома команда: stderr, перелік очікуваних, `process.exitCode = 1`.
|
|
490
|
+
|
|
491
|
+
### Обробка винятків верхнього рівня
|
|
492
|
+
|
|
493
|
+
1. `ReexecHandoff` → `process.exitCode = error.code` (мовчазно, без stack-trace).
|
|
494
|
+
2. `Error` із непорожнім `message` → `console.error(error.message)` + `process.exitCode = 1`.
|
|
495
|
+
3. Будь-що інше → `console.error(error)` + `process.exitCode = 1`.
|
|
496
|
+
|
|
497
|
+
### Передумова перед switch
|
|
498
|
+
|
|
499
|
+
`await ensureNitraCursorInRootDevDependencies(cwd())` — якщо у корені проєкту є `package.json` без `@nitra/cursor` у `devDependencies`/`dependencies`, додається запис `^<currentVersion>` (зручно після `npx`). Виконується для **всіх** команд, не лише для `runSync`.
|
|
500
|
+
|
|
501
|
+
## Залежності
|
|
502
|
+
|
|
503
|
+
### Node.js core
|
|
504
|
+
|
|
505
|
+
- `node:child_process` — `spawnSync`.
|
|
506
|
+
- `node:fs` — `existsSync`.
|
|
507
|
+
- `node:fs/promises` — `mkdir`, `readdir`, `readFile`, `rename`, `rm`, `unlink`, `writeFile`.
|
|
508
|
+
- `node:path` — `basename`, `dirname`, `join`.
|
|
509
|
+
- `node:process` — `cwd`, `env`. Опосередковано — глобальні `process.argv`, `process.execPath`, `process.exitCode`, `process.stdout`, `process.stderr`.
|
|
510
|
+
- `node:url` — `fileURLToPath`.
|
|
511
|
+
|
|
512
|
+
### Внутрішні модулі пакета
|
|
513
|
+
|
|
514
|
+
- `../scripts/build-agents-commands.mjs` — `buildAgentsCommandBulletItems`.
|
|
515
|
+
- `../scripts/lib/generated-markdown.mjs` — `formatGeneratedMarkdownLines`, `renderAgentsTemplate`.
|
|
516
|
+
- `../scripts/lib/inline-template-links.mjs` — `inlineTemplateLinks`.
|
|
517
|
+
- `../scripts/auto-rules.mjs` — `detectAutoRules`, `detectLegacyRuleIds`, `mergeConfigWithAutoDetected`, `normalizeIdList`, `RULE_MIGRATIONS`.
|
|
518
|
+
- `../scripts/auto-skills.mjs` — `detectAutoSkills`.
|
|
519
|
+
- `../scripts/lib/skill-meta.mjs` — `readSkillMetaRaw`.
|
|
520
|
+
- `../scripts/lib/worktree-notice.mjs` — `injectWorktreeNotice`.
|
|
521
|
+
- `../scripts/post-tool-use-fix.mjs` — `runPostToolUseFixCli`.
|
|
522
|
+
- `../scripts/lib/discover-check-rules-from-cursor.mjs` — `discoverCheckRulesFromCursorRules`.
|
|
523
|
+
- `../scripts/lib/list-rule-ids.mjs` — `listRuleIds`.
|
|
524
|
+
- `../scripts/ensure-nitra-cursor-dev-dependencies.mjs` — `ensureNitraCursorInRootDevDependencies`.
|
|
525
|
+
- `../rules/docker/lint/lint.mjs` — `runLintDocker`.
|
|
526
|
+
- `../rules/ga/lint/lint.mjs` — `runLintGaCli`.
|
|
527
|
+
- `../rules/k8s/lint/lint.mjs` — `runLintK8s`.
|
|
528
|
+
- `../rules/rego/lint/lint.mjs` — `runLintRego`.
|
|
529
|
+
- `../rules/text/lint/lint.mjs` — `runLintTextCli`.
|
|
530
|
+
- `../scripts/sync-claude-config.mjs` — `syncClaudeConfig`.
|
|
531
|
+
- `../scripts/lib/sync-gitignore-worktree.mjs` — `syncGitignoreWorktree`.
|
|
532
|
+
- `../scripts/upgrade-nitra-cursor-and-install.mjs` — `upgradeNitraCursorToLatestAndBunInstall`.
|
|
533
|
+
- `./rename-yaml-extensions.mjs` — `runRenameYamlExtensionsCli` (сусід у `bin/`).
|
|
534
|
+
- `../scripts/skills-cli.mjs` — `runSkillsCli`.
|
|
535
|
+
- `../scripts/worktree-cli.mjs` — `runWorktreeCli`.
|
|
536
|
+
- `../scripts/sync-setup-bun-deps-action.mjs` — `syncSetupBunDepsAction`.
|
|
537
|
+
- `../scripts/lint-cli.mjs` — `runLint`.
|
|
538
|
+
- `../scripts/lib/timing-summary.mjs` — `formatTimingSummary`.
|
|
539
|
+
- `../scripts/lib/ensure-tool.mjs` — `ensureHkInstall`, `ensureTool`.
|
|
540
|
+
|
|
541
|
+
### Динамічні (lazy) залежності
|
|
542
|
+
|
|
543
|
+
- `../rules/test/coverage/coverage.mjs` — `runCoverageCli`.
|
|
544
|
+
- `../rules/release/change.mjs` — `runChangeCli`.
|
|
545
|
+
- `../rules/release/release.mjs` — `runReleaseCli`.
|
|
546
|
+
- `../scripts/dispatcher/index.mjs` — `runFlowCli`.
|
|
547
|
+
- `../scripts/dispatcher/trace.mjs` — `runTraceCli`.
|
|
548
|
+
- `../scripts/dispatcher/graph.mjs` — `runGraphCli`.
|
|
549
|
+
- `../skills/docgen/js/docgen-scan.mjs` — `runDocgenScanCli`, `runDocgenModulesCli`.
|
|
550
|
+
|
|
551
|
+
### Зовнішні інструменти (виконуються через `spawnSync` / в `fix.mjs`)
|
|
552
|
+
|
|
553
|
+
- `bun` — для `spawnSync('bun', [fixPath], …)` у `runFixCommand` і для `bun i` всередині `upgradeNitraCursorToLatestAndBunInstall`.
|
|
554
|
+
- `hk`, `conftest` — забезпечуються `ensureTool`/`ensureHkInstall` перед `runFixCommand`.
|
|
555
|
+
- `shellcheck`, `bunx github-actionlint`, `uvx zizmor`, `opa`, `regal`, `kubeconform`, `kubescape`, `hadolint`, `cspell`, `markdownlint-cli2`, `v8r` — викликаються відповідними `lint-*` під-CLI.
|
|
556
|
+
|
|
557
|
+
## Потік виконання / Використання
|
|
558
|
+
|
|
559
|
+
### Приклад 1: повна синхронізація проєкту-споживача
|
|
560
|
+
|
|
561
|
+
```bash
|
|
562
|
+
cd <my-project>
|
|
563
|
+
npx @nitra/cursor
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
Це викликає `runSync()`. Якщо `.n-cursor.json` немає — створюється з авто-визначеними правилами/скілами. Усі керовані артефакти переписуються; зайві `n-*` файли/каталоги в `.cursor/rules`, `.cursor/skills`, `.claude/commands`, `.pi/skills` видаляються; `AGENTS.md`, `CLAUDE.md`, composite action, `.claude/settings.json`, `.cursor/hooks.json`, `.gitignore` синхронізуються. По завершенні друкується підсумок `✨ Готово: …`.
|
|
567
|
+
|
|
568
|
+
### Приклад 2: виконати fix лише для заданих правил
|
|
569
|
+
|
|
570
|
+
```bash
|
|
571
|
+
npx @nitra/cursor fix bun ga
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
`runFixCommand(['bun', 'ga'])` перевіряє, що `bun`, `ga` є серед доступних, і запускає `bun rules/bun/fix.mjs`, потім `bun rules/ga/fix.mjs`. По кожному кроку — таймінг. При невдачах кидається `Error`.
|
|
575
|
+
|
|
576
|
+
### Приклад 3: fix-discovery з `.cursor/rules`
|
|
577
|
+
|
|
578
|
+
```bash
|
|
579
|
+
npx @nitra/cursor fix
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
`runFixCommand([])` дивиться у `.cursor/rules/*.mdc` поточного проєкту і запускає `fix.mjs` тільки для тих правил, у яких пакет має програмну перевірку.
|
|
583
|
+
|
|
584
|
+
### Приклад 4: docgen
|
|
585
|
+
|
|
586
|
+
```bash
|
|
587
|
+
npx @nitra/cursor docgen scan --root <dir>
|
|
588
|
+
npx @nitra/cursor docgen modules
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
Динамічно вантажить `../skills/docgen/js/docgen-scan.mjs` і виконує відповідний sub-CLI. Аргумент `args[0]` мусить бути `scan` або `modules`, інакше — друк `Usage: …` і exit code 1.
|
|
592
|
+
|
|
593
|
+
### Приклад 5: PostToolUse hook у Claude Code
|
|
594
|
+
|
|
595
|
+
`.claude/settings.json` зі секцією, де `command = 'npx @nitra/cursor post-tool-use-fix'` (синхронізується автоматично через `syncClaudeConfig`). Hook читає JSON зі stdin, з `tool_input.file_path` маршрутизує файл у потрібні правила і викликає `fix` лише з ними.
|
|
596
|
+
|
|
597
|
+
### Потокова діаграма `runSync`
|
|
598
|
+
|
|
599
|
+
```text
|
|
600
|
+
runSync()
|
|
601
|
+
├─ banner
|
|
602
|
+
├─ upgradeNitraCursorToLatestAndBunInstall → effectivePackageRoot
|
|
603
|
+
├─ reexecIfPackageVersionChanged → ReexecHandoff?
|
|
604
|
+
├─ readConfig({ bundledRulesDir, bundledSkillsDir })
|
|
605
|
+
│ ├─ migrateLegacyConfigIfNeeded
|
|
606
|
+
│ ├─ discoverBundledRuleNames / discoverBundledSkillNames
|
|
607
|
+
│ ├─ (create defaults) | parse+normalize+save
|
|
608
|
+
│ └─ logRuleMigrationsIfAny
|
|
609
|
+
├─ syncSetupBunDepsAction
|
|
610
|
+
├─ syncManagedRuleFiles → removeOrphanManagedRuleFiles
|
|
611
|
+
├─ syncSkills → removeOrphanManagedSkillDirs
|
|
612
|
+
├─ syncCommands + syncLocalOnlySkillCommands
|
|
613
|
+
│ └─ removeOrphan…CommandFiles
|
|
614
|
+
├─ syncPiSkills + syncLocalOnlyPiSkills
|
|
615
|
+
│ └─ removeOrphan…PiSkillDirs
|
|
616
|
+
├─ syncAgentsMd
|
|
617
|
+
├─ syncClaudeMd(ignore)
|
|
618
|
+
├─ syncClaudeConfig({ enabled, rules, … })
|
|
619
|
+
├─ syncGitignoreWorktree
|
|
620
|
+
└─ final summary (or throw)
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
### Інваріанти, важливі для відтворення (Rebuild Test)
|
|
624
|
+
|
|
625
|
+
- Усі масиви id у `.n-cursor.json` (`rules`, `skills`, `disable-rules`, `disable-skills`) сортуються алфавітно за `localeCompare` перед записом.
|
|
626
|
+
- `$schema` у `.n-cursor.json` завжди дорівнює `CONFIG_SCHEMA_URL`; при невідповідності диск перезаписується.
|
|
627
|
+
- `version` у `.n-cursor.json` ігнорується при синхронізації правил; правила беруться з установленого пакета (`effectivePackageRoot`).
|
|
628
|
+
- Префікс `n-` означає "керований пакетом" — застосовується до `.mdc`, каталогів `.cursor/skills/n-<id>`, `.claude/commands/n-<id>.md`, `.pi/skills/n-<id>/SKILL.md`.
|
|
629
|
+
- `meta.json` у джерельному `skills/<id>/` ніколи не копіюється у проєкт; підкаталоги `skills/<id>/<підкаталог>/` (наприклад `js/`) теж не копіюються — їх запускає `npx`.
|
|
630
|
+
- `SKILL.md` під час копіювання проходить `injectWorktreeNotice(content, worktree === true)`, де `worktree` — поле з `meta.json`.
|
|
631
|
+
- `claude-config: false` у `.n-cursor.json` повністю вимикає крок `syncClaudeConfig` (виводиться повідомлення про пропуск).
|
|
632
|
+
- `ignore` у `.n-cursor.json` — масив рядків; у `CLAUDE.md` додається секція `## Захищені директорії` із цими шляхами.
|
|
633
|
+
- `runFixCommand` спочатку гарантує наявність `hk` і `conftest`. При запуску без аргументів і за наявності `.mdc` без жодних із програмними перевірками — функція друкує повідомлення і завершується успішно (`return`), не кидаючи помилки.
|
|
634
|
+
- `reexecIfPackageVersionChanged` ніколи не респавнить себе більше одного разу через env `NITRA_CURSOR_REEXEC=1`.
|
|
635
|
+
- Top-level catch розрізняє `ReexecHandoff` від звичайних помилок — у першому випадку stack-trace **не** друкується.
|
|
636
|
+
- `ensureNitraCursorInRootDevDependencies(cwd())` виконується **до** свічу команд — а отже, навіть для команд на кшталт `lint` або `worktree`.
|