@nitra/cursor 12.8.9 → 12.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (274) hide show
  1. package/.claude-template/settings.template.json +1 -23
  2. package/CHANGELOG.md +14 -1
  3. package/bin/n-cursor.js +21 -48
  4. package/docs/stryker.config.md +0 -2
  5. package/lib/docs/llm.md +16 -21
  6. package/lib/docs/omlx.md +20 -25
  7. package/lib/llm.mjs +25 -7
  8. package/lib/omlx.mjs +10 -3
  9. package/package.json +5 -5
  10. package/rules/abie/docs/index.md +0 -1
  11. package/rules/abie/docs/main.md +0 -2
  12. package/rules/abie/lib/docs/http-route.md +9 -12
  13. package/rules/abie/lib/http-route.mjs +3 -0
  14. package/rules/abie/main.mdc +0 -22
  15. package/rules/abie/policy/health_check_policy/health_check_policy.mdc +3 -1
  16. package/rules/abie/policy/health_check_policy/health_check_policy.rego +27 -0
  17. package/rules/adr/docs/index.md +0 -1
  18. package/rules/adr/docs/main.md +0 -2
  19. package/rules/adr/js/madr_format.mdc +13 -1
  20. package/rules/adr/main.mdc +0 -9
  21. package/rules/bun/docs/index.md +0 -1
  22. package/rules/bun/docs/main.md +0 -2
  23. package/rules/bun/main.mdc +1 -15
  24. package/rules/bun/policy/package_json/package_json.rego +12 -0
  25. package/rules/capacitor/docs/index.md +0 -1
  26. package/rules/capacitor/docs/main.md +0 -2
  27. package/rules/capacitor/main.mdc +0 -6
  28. package/rules/changelog/docs/index.md +0 -1
  29. package/rules/changelog/docs/main.md +0 -2
  30. package/rules/changelog/js/agent-workflow.mdc +1 -1
  31. package/rules/changelog/js/consistency.mjs +3 -3
  32. package/rules/changelog/js/docs/consistency.md +18 -23
  33. package/rules/changelog/main.mdc +0 -5
  34. package/rules/ci4/docs/index.md +0 -1
  35. package/rules/ci4/docs/main.md +0 -2
  36. package/rules/ci4/main.mdc +0 -5
  37. package/rules/doc-files/docs/index.md +0 -1
  38. package/rules/doc-files/docs/main.md +7 -11
  39. package/rules/doc-files/js/docs/docgen-crc.md +0 -2
  40. package/rules/doc-files/js/docs/docgen-extract.md +0 -2
  41. package/rules/doc-files/js/docs/docgen-files-batch.md +0 -2
  42. package/rules/doc-files/js/docs/docgen-gen.md +0 -2
  43. package/rules/doc-files/js/docs/docgen-judge-measure.md +0 -2
  44. package/rules/doc-files/js/docs/docgen-judge.md +0 -2
  45. package/rules/doc-files/js/docs/docgen-scan.md +0 -2
  46. package/rules/doc-files/js/docs/run-lint.md +0 -2
  47. package/rules/doc-files/main.mjs +2 -3
  48. package/rules/docker/docs/index.md +0 -1
  49. package/rules/docker/docs/main.md +0 -2
  50. package/rules/docker/js/docs/lint.md +0 -2
  51. package/rules/docker/lib/docs/docker-hadolint.md +0 -2
  52. package/rules/docker/main.mdc +1 -21
  53. package/rules/efes/docs/index.md +0 -1
  54. package/rules/efes/docs/main.md +0 -2
  55. package/rules/efes/main.mdc +0 -1
  56. package/rules/feedback/docs/index.md +0 -1
  57. package/rules/feedback/docs/main.md +0 -2
  58. package/rules/ga/docs/index.md +0 -1
  59. package/rules/ga/docs/main.md +0 -2
  60. package/rules/ga/js/docs/index.md +0 -1
  61. package/rules/ga/main.mdc +1 -31
  62. package/rules/graphql/docs/index.md +0 -1
  63. package/rules/graphql/docs/main.md +0 -2
  64. package/rules/graphql/main.mdc +0 -5
  65. package/rules/hasura/docs/index.md +0 -1
  66. package/rules/hasura/docs/main.md +0 -2
  67. package/rules/hasura/js/docs/index.md +1 -0
  68. package/rules/hasura/js/docs/migrations.md +28 -0
  69. package/rules/hasura/js/migrations.mjs +47 -0
  70. package/rules/hasura/main.mdc +1 -11
  71. package/rules/image-avif/docs/index.md +0 -1
  72. package/rules/image-avif/docs/main.md +0 -2
  73. package/rules/image-avif/main.mdc +1 -9
  74. package/rules/image-compress/docs/index.md +0 -1
  75. package/rules/image-compress/docs/main.md +0 -2
  76. package/rules/image-compress/js/docs/index.md +0 -1
  77. package/rules/image-compress/main.mdc +1 -9
  78. package/rules/js/docs/index.md +0 -1
  79. package/rules/js/docs/main.md +0 -2
  80. package/rules/js/js/dep-policy.mjs +91 -0
  81. package/rules/js/js/docs/check.md +0 -2
  82. package/rules/js/js/docs/dep-policy.md +34 -0
  83. package/rules/js/js/docs/index.md +5 -4
  84. package/rules/js/js/docs/tooling.md +0 -2
  85. package/rules/js/js/docs/utils_imports.md +0 -2
  86. package/rules/js/main.mdc +0 -31
  87. package/rules/js/policy/package_json/package_json.rego +16 -0
  88. package/rules/js-bun-db/docs/index.md +0 -1
  89. package/rules/js-bun-db/docs/main.md +0 -2
  90. package/rules/js-bun-db/js/docs/safety.md +18 -23
  91. package/rules/js-bun-db/js/safety.mjs +31 -3
  92. package/rules/js-bun-db/lib/bun-sql-scan.mjs +123 -0
  93. package/rules/js-bun-db/lib/docs/bun-sql-scan.md +37 -331
  94. package/rules/js-bun-db/main.mdc +1 -23
  95. package/rules/js-bun-redis/docs/index.md +0 -1
  96. package/rules/js-bun-redis/docs/main.md +0 -2
  97. package/rules/js-bun-redis/main.mdc +0 -5
  98. package/rules/js-mssql/docs/index.md +0 -1
  99. package/rules/js-mssql/docs/main.md +0 -2
  100. package/rules/js-mssql/main.mdc +0 -12
  101. package/rules/js-run/docs/index.md +0 -1
  102. package/rules/js-run/docs/main.md +0 -2
  103. package/rules/js-run/js/docs/runtime.md +15 -13
  104. package/rules/js-run/js/runtime.mjs +48 -4
  105. package/rules/js-run/main.mdc +0 -25
  106. package/rules/k8s/docs/index.md +0 -1
  107. package/rules/k8s/docs/main.md +0 -2
  108. package/rules/k8s/main.mdc +0 -45
  109. package/rules/nginx-default-tpl/docs/index.md +0 -1
  110. package/rules/nginx-default-tpl/docs/main.md +0 -2
  111. package/rules/nginx-default-tpl/main.mdc +0 -13
  112. package/rules/npm-module/docs/index.md +0 -1
  113. package/rules/npm-module/docs/main.md +0 -2
  114. package/rules/npm-module/js/docs/header_doc_pointer.md +0 -2
  115. package/rules/npm-module/js/docs/rule_meta.md +0 -2
  116. package/rules/npm-module/js/docs/skill_meta.md +0 -2
  117. package/rules/npm-module/main.mdc +1 -15
  118. package/rules/php/docs/index.md +0 -1
  119. package/rules/php/docs/main.md +0 -2
  120. package/rules/php/js/docs/index.md +0 -1
  121. package/rules/php/main.mdc +1 -9
  122. package/rules/python/docs/index.md +0 -1
  123. package/rules/python/docs/main.md +0 -2
  124. package/rules/python/js/docs/index.md +0 -1
  125. package/rules/python/main.mdc +1 -13
  126. package/rules/rego/docs/index.md +0 -1
  127. package/rules/rego/docs/main.md +0 -2
  128. package/rules/rego/js/docs/index.md +1 -1
  129. package/rules/rego/js/docs/tooling.md +26 -0
  130. package/rules/rego/js/tooling.mdc +14 -0
  131. package/rules/rego/js/tooling.mjs +24 -0
  132. package/rules/rego/main.mdc +0 -9
  133. package/rules/rego/policy/package_json/package_json.mdc +12 -0
  134. package/rules/rego/policy/package_json/package_json.rego +21 -0
  135. package/rules/rego/policy/package_json/target.json +4 -0
  136. package/rules/release/docs/index.md +0 -1
  137. package/rules/release/docs/main.md +0 -2
  138. package/rules/release/main.mdc +2 -2
  139. package/rules/rust/docs/index.md +0 -1
  140. package/rules/rust/docs/main.md +0 -2
  141. package/rules/rust/js/docs/index.md +0 -1
  142. package/rules/rust/main.mdc +1 -11
  143. package/rules/rust/policy/lint_rust_yml/lint_rust_yml.rego +24 -0
  144. package/rules/rust/policy/package_json/package_json.mdc +12 -0
  145. package/rules/rust/policy/package_json/package_json.rego +20 -0
  146. package/rules/rust/policy/package_json/target.json +4 -0
  147. package/rules/security/docs/index.md +0 -1
  148. package/rules/security/docs/main.md +0 -2
  149. package/rules/security/js/docs/index.md +0 -1
  150. package/rules/security/main.mdc +0 -13
  151. package/rules/style/docs/index.md +0 -1
  152. package/rules/style/docs/main.md +0 -2
  153. package/rules/style/js/docs/index.md +0 -1
  154. package/rules/style/js/docs/tooling.md +12 -10
  155. package/rules/style/js/tooling.mjs +8 -2
  156. package/rules/style/main.mdc +1 -23
  157. package/rules/style/policy/lint_style_yml/lint_style_yml.rego +5 -0
  158. package/rules/tauri/docs/index.md +0 -1
  159. package/rules/tauri/docs/main.md +0 -2
  160. package/rules/tauri/main.mdc +1 -11
  161. package/rules/test/docs/index.md +0 -1
  162. package/rules/test/docs/main.md +0 -2
  163. package/rules/test/js/docs/index.md +2 -0
  164. package/rules/test/js/docs/no-console-store-restore.md +30 -0
  165. package/rules/test/js/docs/sandbox-aware-test.md +30 -0
  166. package/rules/test/js/docs/stryker_config.md +0 -2
  167. package/rules/test/js/docs/vitest-config-pool-forks.md +0 -2
  168. package/rules/test/js/no-console-store-restore.mjs +88 -0
  169. package/rules/test/js/sandbox-aware-test.mjs +89 -0
  170. package/rules/test/main.mdc +1 -21
  171. package/rules/text/docs/index.md +0 -1
  172. package/rules/text/docs/main.md +0 -2
  173. package/rules/text/js/docs/cspell-fix.md +0 -2
  174. package/rules/text/js/docs/run-dotenv-linter.md +0 -2
  175. package/rules/text/js/docs/run-shellcheck.md +0 -2
  176. package/rules/text/js/docs/run-v8r.md +0 -2
  177. package/rules/text/main.mdc +0 -33
  178. package/rules/tool-surface/docs/index.md +0 -1
  179. package/rules/tool-surface/docs/main.md +0 -2
  180. package/rules/vue/docs/index.md +0 -1
  181. package/rules/vue/docs/main.md +0 -2
  182. package/rules/vue/main.mdc +0 -22
  183. package/rules/worktree/docs/index.md +0 -1
  184. package/rules/worktree/docs/main.md +0 -2
  185. package/scripts/docs/auto-rules.md +0 -2
  186. package/scripts/docs/auto-skills.md +0 -2
  187. package/scripts/docs/hook.md +30 -0
  188. package/scripts/docs/index.md +1 -2
  189. package/scripts/docs/post-tool-use-check.md +0 -2
  190. package/scripts/docs/sync-claude-config.md +1 -3
  191. package/scripts/docs/sync-setup-bun-deps-action.md +0 -2
  192. package/scripts/hook.mjs +71 -0
  193. package/scripts/lib/docs/check-mdc-template-refs.md +0 -2
  194. package/scripts/lib/docs/index.md +35 -36
  195. package/scripts/lib/docs/inline-template-links.md +6 -8
  196. package/scripts/lib/docs/list-project-rules-mdc.md +0 -2
  197. package/scripts/lib/docs/list-rule-ids.md +0 -2
  198. package/scripts/lib/docs/mirror-parity.md +8 -10
  199. package/scripts/lib/docs/read-n-cursor-config-lite.md +0 -2
  200. package/scripts/lib/docs/rule-meta.md +0 -2
  201. package/scripts/lib/docs/run-lint.md +9 -10
  202. package/scripts/lib/docs/run-rule-cli.md +0 -2
  203. package/scripts/lib/docs/run-rule.md +7 -9
  204. package/scripts/lib/docs/run-standard-lint.md +0 -2
  205. package/scripts/lib/docs/run-standard-rule.md +0 -2
  206. package/scripts/lib/docs/skill-meta.md +0 -2
  207. package/scripts/lib/docs/timing-summary.md +0 -2
  208. package/scripts/lib/docs/worktree-notice.md +0 -2
  209. package/scripts/lib/fix/docs/analyze-escalation.md +0 -2
  210. package/scripts/lib/fix/docs/index.md +10 -10
  211. package/scripts/lib/fix/docs/llm-worker.md +18 -8
  212. package/scripts/lib/fix/docs/orchestrator.md +44 -20
  213. package/scripts/lib/fix/docs/run-conformance-check.md +0 -2
  214. package/scripts/lib/fix/docs/t0.md +0 -2
  215. package/scripts/lib/fix/docs/verbose-block.md +27 -0
  216. package/scripts/lib/fix/llm-worker.mjs +75 -22
  217. package/scripts/lib/fix/orchestrator.mjs +13 -3
  218. package/scripts/lib/fix/verbose-block.mjs +82 -0
  219. package/scripts/lib/inline-template-links.mjs +32 -22
  220. package/scripts/lib/mirror-parity.mjs +2 -2
  221. package/scripts/lib/run-lint.mjs +15 -2
  222. package/scripts/lib/run-rule.mjs +1 -2
  223. package/scripts/sync-claude-config.mjs +7 -4
  224. package/scripts/utils/docs/resolve-js-root.md +0 -2
  225. package/skills/adr-normalize/SKILL.md +1 -0
  226. package/skills/coverage-fix/SKILL.md +1 -0
  227. package/skills/doc-aggregate/SKILL.md +1 -0
  228. package/skills/doc-files/SKILL.md +10 -24
  229. package/skills/lint/SKILL.md +24 -19
  230. package/skills/llm-patch/SKILL.md +5 -4
  231. package/skills/publish-telegram/SKILL.md +1 -0
  232. package/skills/start-check/SKILL.md +1 -0
  233. package/skills/taze/SKILL.md +3 -2
  234. package/types/bin/n-cursor.d.ts +1 -1
  235. package/rules/abie/docs/fix.md +0 -37
  236. package/rules/adr/docs/fix.md +0 -37
  237. package/rules/bun/docs/fix.md +0 -30
  238. package/rules/capacitor/docs/fix.md +0 -36
  239. package/rules/changelog/docs/fix.md +0 -37
  240. package/rules/ci4/docs/fix.md +0 -32
  241. package/rules/doc-files/docs/fix.md +0 -29
  242. package/rules/docker/docs/fix.md +0 -35
  243. package/rules/efes/docs/fix.md +0 -37
  244. package/rules/feedback/docs/fix.md +0 -30
  245. package/rules/ga/docs/fix.md +0 -30
  246. package/rules/graphql/docs/fix.md +0 -37
  247. package/rules/hasura/docs/fix.md +0 -39
  248. package/rules/image-avif/docs/fix.md +0 -28
  249. package/rules/image-compress/docs/fix.md +0 -27
  250. package/rules/js/docs/fix.md +0 -37
  251. package/rules/js-bun-db/docs/fix.md +0 -30
  252. package/rules/js-bun-redis/docs/fix.md +0 -32
  253. package/rules/js-mssql/docs/fix.md +0 -30
  254. package/rules/js-run/docs/fix.md +0 -36
  255. package/rules/k8s/docs/fix.md +0 -31
  256. package/rules/nginx-default-tpl/docs/fix.md +0 -35
  257. package/rules/npm-module/docs/fix.md +0 -34
  258. package/rules/php/docs/fix.md +0 -35
  259. package/rules/python/docs/fix.md +0 -38
  260. package/rules/rego/docs/fix.md +0 -31
  261. package/rules/release/docs/fix.md +0 -28
  262. package/rules/rust/docs/fix.md +0 -32
  263. package/rules/security/docs/fix.md +0 -33
  264. package/rules/style/docs/fix.md +0 -28
  265. package/rules/tauri/docs/fix.md +0 -39
  266. package/rules/test/docs/fix.md +0 -31
  267. package/rules/text/docs/fix.md +0 -37
  268. package/rules/tool-surface/docs/fix.md +0 -32
  269. package/rules/vue/docs/fix.md +0 -32
  270. package/rules/worktree/docs/fix.md +0 -40
  271. package/scripts/docs/post-tool-use-fix.md +0 -32
  272. package/scripts/docs/worktree-cli.md +0 -27
  273. package/scripts/lib/docs/worktree.md +0 -42
  274. package/scripts/lib/fix/docs/run-fix-check.md +0 -33
@@ -16,32 +16,10 @@
16
16
  "hooks": [
17
17
  {
18
18
  "type": "command",
19
- "command": "npx --no @nitra/cursor post-tool-use-check",
19
+ "command": "npx --no @nitra/cursor hook --post-tool-use",
20
20
  "timeout": 300
21
21
  }
22
22
  ]
23
- },
24
- {
25
- "matcher": "Edit|Write|MultiEdit",
26
- "hooks": [
27
- {
28
- "type": "command",
29
- "command": "npx --no @nitra/cursor lint-doc-files --hook",
30
- "timeout": 120
31
- }
32
- ]
33
- }
34
- ],
35
- "Stop": [
36
- {
37
- "matcher": "",
38
- "hooks": [
39
- {
40
- "type": "command",
41
- "command": "npx --no @nitra/cursor lint-doc-files --git",
42
- "timeout": 120
43
- }
44
- ]
45
23
  }
46
24
  ]
47
25
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## [12.10.0] - 2026-06-24
4
+
5
+ ### Changed
6
+
7
+ - Оновлено LLM-виклик для повернення багатого об'єкта з reasoning та thinkingBudget
8
+
9
+ ## [12.9.0] - 2026-06-24
10
+
11
+ ### Changed
12
+
13
+ - Додано підтримку hook-режиму для linting через `n-cursor
14
+ - Додано перевірку порту 8080 для HTTPRoute та політики HealthCheckPolicy
15
+
3
16
  ## [12.8.9] - 2026-06-22
4
17
 
5
18
  ### Changed
@@ -10,7 +23,7 @@
10
23
 
11
24
  ### Changed
12
25
 
13
- - ✨ feat(rules): policy mdc для всіх npm/rules/*/policy/<concern>/
26
+ - ✨ feat(rules): policy mdc для всіх npm/rules/\*/policy/<concern>/
14
27
 
15
28
  ## [12.8.7] - 2026-06-22
16
29
 
package/bin/n-cursor.js CHANGED
@@ -7,17 +7,13 @@
7
7
  * `npx \@nitra/cursor` — завантажити cursor-правила (синк); якщо в корені вже є `.n-cursor.json`,
8
8
  * спочатку зчитується конфіг і за потреби дописується `$schema`
9
9
  * `npx \@nitra/cursor rename-yaml-extensions` — k8s `*.yml` → `*.yaml`, `.github` `*.yaml` → `*.yml` (опції: `--dry-run`, `--root=…`; див. bin/rename-yaml-extensions.mjs)
10
- * `npx \@nitra/cursor post-tool-use-check` — точка входу PostToolUse hook Claude Code: читає stdin JSON,
11
- * дістає `tool_input.file_path`, маршрутизує його у відповідні правила
12
- * (`*.mjs` → `js-lint`, `*.vue` → `js-lint style vue` тощо) і викликає
13
- * `fix` лише з ними. Прописується автоматично в `.claude/settings.json`.
10
+ * `npx \@nitra/cursor hook --post-tool-use` — PostToolUse hook: per-file lint правила для зміненого файлу (stdin JSON `tool_input.file_path`). Прописується автоматично в `.claude/settings.json`.
11
+ * `npx \@nitra/cursor hook --stop` Stop hook: per-file lint по всіх змінених файлах (git diff HEAD + untracked).
14
12
  * `npx \@nitra/cursor lint` — data-driven оркестратор lint+конформності по `rules/<id>/meta.json` (`lint: per-file|full`):
15
13
  * за замовчуванням fix-by-default по дельті vs origin (лише `per-file` правила); `--full` =
16
14
  * весь репо (`per-file` ∪ `full`); `--read-only` = без мутацій/LLM (CI); позиційні
17
15
  * (не-флаг) аргументи — фільтр правил конформності (мапить колишній `fix <rule>`).
18
16
  * CI = `lint --read-only --full` (весь репо, нуль мутацій/LLM).
19
- * `npx \@nitra/cursor lint-doc-files` — детермінований детектор застарілості файлових док (`stale`: `missing`|`crc-mismatch`); правило doc-files (ignore-glob у `npm/rules/doc-files/js/docgen-ignore.mjs`; тека `docs/` поряд із джерелом). Режими: повний (exit 1), `--json` (exit 0), `--missing-only`, `--hook`/`--git` (hook-протокол, exit 2), `--degraded`
20
- * `npx \@nitra/cursor fix-doc-files` — JS-оркестрована генерація файлових док (роутинг local/cloud) зі штампом CRC (`--limit`/`--from`/`--overwrite`); `--stamp` — детерміноване перештампування CRC без LLM
21
17
  * `npx \@nitra/cursor doc-aggregate modules` — JSON-лістинг логічних модулів (межі за `package.json`) для Tier 2 скілу doc-aggregate
22
18
  * `npx \@nitra/cursor skill list` — скіли пакета без синку в проєкт
23
19
  * `npx \@nitra/cursor skill taze` — промпт на stdout
@@ -74,7 +70,7 @@ import { fileURLToPath } from 'node:url'
74
70
 
75
71
  import { buildAgentsCommandBulletItems } from '../scripts/build-agents-commands.mjs'
76
72
  import { formatGeneratedMarkdownLines, renderAgentsTemplate } from '../scripts/lib/generated-markdown.mjs'
77
- import { inlineMarkdownIncludes, inlineTemplateLinks } from '../scripts/lib/inline-template-links.mjs'
73
+ import { appendDiscoveredMdcFiles, inlineTemplateLinks } from '../scripts/lib/inline-template-links.mjs'
78
74
  import {
79
75
  detectAutoRules,
80
76
  detectLegacyRuleIds,
@@ -86,7 +82,6 @@ import { detectAutoSkills } from '../scripts/auto-skills.mjs'
86
82
  import { readSkillMetaRaw } from '../scripts/lib/skill-meta.mjs'
87
83
  import { injectWorktreeNotice } from '../scripts/lib/worktree-notice.mjs'
88
84
  import { injectRootNotice } from '../scripts/lib/root-notice.mjs'
89
- import { runPostToolUseCheckCli } from '../scripts/post-tool-use-check.mjs'
90
85
  import { listProjectRulesMdcFiles } from '../scripts/lib/list-project-rules-mdc.mjs'
91
86
  import { ensureNitraCursorInRootDevDependencies } from '../scripts/ensure-nitra-cursor-dev-dependencies.mjs'
92
87
  import { assertCwdIsProjectRoot } from '../scripts/lib/assert-project-root.mjs'
@@ -142,7 +137,7 @@ function sortConfigIdArrays(config) {
142
137
 
143
138
  /**
144
139
  * Імена правил з каталогу `rules/` поточної інсталяції пакету. Кожне правило — окремий
145
- * підкаталог `rules/<id>/`, у якому має бути `<id>.mdc`.
140
+ * підкаталог `rules/<id>/`, у якому має бути `main.mdc`.
146
141
  * @param {string} [bundledRulesDir] каталог `rules/` у корені пакету
147
142
  * @returns {Promise<string[]>} відсортовані id правил (імена підкаталогів)
148
143
  */
@@ -157,11 +152,11 @@ async function discoverBundledRuleNames(bundledRulesDir = BUNDLED_RULES_DIR) {
157
152
  const entries = await readdir(bundledRulesDir, { withFileTypes: true })
158
153
  const rules = entries
159
154
  .filter(e => e.isDirectory() && !e.name.startsWith('.'))
160
- .filter(e => existsSync(join(bundledRulesDir, e.name, `${e.name}.mdc`)))
155
+ .filter(e => existsSync(join(bundledRulesDir, e.name, 'main.mdc')))
161
156
  .map(e => e.name)
162
157
  .toSorted((a, b) => a.localeCompare(b))
163
158
  if (rules.length === 0) {
164
- throw new Error(`У каталозі rules/ пакету немає підкаталогів з <id>.mdc. Створіть ${CONFIG_FILE} вручну.`)
159
+ throw new Error(`У каталозі rules/ пакету немає підкаталогів з main.mdc. Створіть ${CONFIG_FILE} вручну.`)
165
160
  }
166
161
  return rules
167
162
  }
@@ -407,23 +402,23 @@ function normalizeRuleName(ruleName) {
407
402
  }
408
403
 
409
404
  /**
410
- * Читає вміст правила з каталогу `rules/<id>/<id>.mdc` установленого пакету
411
- * (наприклад `node_modules/@nitra/cursor/rules/<id>/<id>.mdc` або кеш npx).
405
+ * Читає вміст правила з каталогу `rules/<id>/main.mdc` установленого пакету
406
+ * (наприклад `node_modules/@nitra/cursor/rules/<id>/main.mdc` або кеш npx).
412
407
  * @param {string} rule елемент масиву rules з `.n-cursor.json`
413
408
  * @param {string} [bundledRulesDir] каталог `rules/` у корені пакету-джерела
414
409
  * @returns {Promise<string>} текст правила для запису в `.cursor/rules/n-*.mdc`
415
410
  */
416
411
  async function readBundledRuleContent(rule, bundledRulesDir = BUNDLED_RULES_DIR) {
417
412
  const id = normalizeRuleName(rule)
418
- const bundledPath = join(bundledRulesDir, id, `${id}.mdc`)
413
+ const bundledPath = join(bundledRulesDir, id, 'main.mdc')
419
414
  if (!existsSync(bundledPath)) {
420
415
  throw new Error(
421
- `Немає файлу ${id}/${id}.mdc у ${bundledRulesDir}. Оновіть ${PACKAGE_NAME} або приберіть "${rule}" з rules у ${CONFIG_FILE}.`
416
+ `Немає файлу ${id}/main.mdc у ${bundledRulesDir}. Оновіть ${PACKAGE_NAME} або приберіть "${rule}" з rules у ${CONFIG_FILE}.`
422
417
  )
423
418
  }
424
419
  const text = await readFile(bundledPath, 'utf8')
425
420
  const withTemplates = await inlineTemplateLinks(text, dirname(bundledPath))
426
- return inlineMarkdownIncludes(withTemplates, dirname(bundledPath))
421
+ return appendDiscoveredMdcFiles(withTemplates, dirname(bundledPath))
427
422
  }
428
423
 
429
424
  /**
@@ -655,7 +650,7 @@ function buildClaudeDocFilesSectionLines() {
655
650
  '',
656
651
  '## Файлова документація (`doc-files` — обовʼязковий крок, як lint)',
657
652
  '',
658
- 'Після зміни чи додавання кодового файлу його файлова дока (`<dir>/docs/<stem>.md`) має бути **актуальною** — це **обовʼязковий крок кожної задачі**, нарівні з lint. Застарілість детермінується за **CRC** джерела у frontmatter доки. PostToolUse hook (`lint-doc-files --hook`) **сигналить** про дрейф після правки; Stop-hook (`lint-doc-files --git`) **блокує завершення** задачі за наявності застарілих док (виняток — масовий прогін понад поріг `N_CURSOR_DOC_FILES_GATE_MAX`, дефолт 50). Регенерація — `/doc-files` (JS-оркестрована, не диспатч субагентів). Агрегуюча дока (module-summary, доменні) — окремий скіл `/doc-aggregate`, за запитом.',
653
+ 'Після зміни чи додавання кодового файлу його файлова дока (`<dir>/docs/<stem>.md`) має бути **актуальною** — це **обовʼязковий крок кожної задачі**, нарівні з lint. Застарілість детермінується за **CRC** джерела у frontmatter доки. PostToolUse hook (`hook --post-tool-use`) **сигналить** про дрейф після правки через per-file lint правила. Регенерація — `/doc-files` (JS-оркестрована, не диспатч субагентів). Агрегуюча дока (module-summary, доменні) — окремий скіл `/doc-aggregate`, за запитом.',
659
654
  ''
660
655
  ]
661
656
  }
@@ -1459,7 +1454,7 @@ async function runSync() {
1459
1454
  /**
1460
1455
  * Команди, що мутують проєкт у CWD і вимагають кореня репо. `undefined`/`''` —
1461
1456
  * дефолтний sync; `check` — deprecated-alias `fix`. Решта (read-only `trace`,
1462
- * `--root`-команди `lint-doc-files`/`fix-doc-files`/`doc-files`/`doc-aggregate`/`rename-yaml-extensions`,
1457
+ * `--root`-команди `doc-aggregate`/`rename-yaml-extensions`,
1463
1458
  * sub-лінтери) гард не зачіпає.
1464
1459
  */
1465
1460
  const ROOT_GUARDED_COMMANDS = new Set([undefined, '', 'lint', 'coverage', 'change', 'release'])
@@ -1501,7 +1496,7 @@ try {
1501
1496
  // .n-cursor.json + bun install, а fix/lint/coverage/change/release переписують файли в CWD —
1502
1497
  // усе це ключиться на cwd(). Запуск із піддиректорії git-репо (типово прямий
1503
1498
  // `bun npm/bin/n-cursor.js` не з кореня) зачепив би не той каталог → STOP. Read-only та
1504
- // `--root`-команди (trace, graph, lint-doc-files, fix-doc-files, doc-aggregate, rename-yaml-extensions) не зачіпаємо.
1499
+ // `--root`-команди (trace, graph, doc-aggregate, rename-yaml-extensions) не зачіпаємо.
1505
1500
  if (ROOT_GUARDED_COMMANDS.has(command)) {
1506
1501
  assertCwdIsProjectRoot(cwd(), describeRootGuardedAction(command))
1507
1502
  }
@@ -1515,11 +1510,12 @@ try {
1515
1510
 
1516
1511
  break
1517
1512
  }
1518
- case 'post-tool-use-check': {
1519
- // Викликається з .claude/settings.json як PostToolUse hook Claude Code.
1520
- // Маршрутизує змінений файл у релевантні правила і прокидає `fix` лише з ними.
1521
- const code = await runPostToolUseCheckCli()
1522
- process.exitCode = code
1513
+ case 'hook': {
1514
+ // Thin hook entrypoint для Claude Code hooks. Делегує в runLint, перекодовує exit 1→2.
1515
+ // --post-tool-use PostToolUse: file_path зі stdin JSON
1516
+ // --stop Stop: робоче дерево vs HEAD
1517
+ const { runHookCli } = await import('../scripts/hook.mjs')
1518
+ process.exitCode = await runHookCli(args)
1523
1519
 
1524
1520
  break
1525
1521
  }
@@ -1606,29 +1602,6 @@ try {
1606
1602
 
1607
1603
  break
1608
1604
  }
1609
- case 'lint-doc-files': {
1610
- // n-cursor lint-doc-files — детермінований детектор застарілості файлових док
1611
- // (missing ∪ crc-mismatch). Режими: (повний) exit 1, --json exit 0, --missing-only,
1612
- // --hook/--git/--degraded — hook-протокол (exit 2/0). Деталі — doc-files.mdc.
1613
- const { runLintDocFilesCli } = await import('../rules/doc-files/main.mjs')
1614
- process.exitCode = await runLintDocFilesCli(args)
1615
-
1616
- break
1617
- }
1618
- case 'fix-doc-files': {
1619
- // n-cursor fix-doc-files — local-only генерація файлових док (omlx) + CRC-штамп
1620
- // (--limit/--from/--overwrite); --stamp — детерміноване
1621
- // перештампування source+crc без LLM. У CI не запускається (потрібна локальна модель).
1622
- if (args.includes('--stamp')) {
1623
- const { runDocFilesStampCli } = await import('../rules/doc-files/js/docgen-files-batch.mjs')
1624
- process.exitCode = runDocFilesStampCli(args.filter(a => a !== '--stamp'))
1625
- } else {
1626
- const { runDocFilesGenCli } = await import('../rules/doc-files/js/docgen-files-batch.mjs')
1627
- process.exitCode = await runDocFilesGenCli(args)
1628
- }
1629
-
1630
- break
1631
- }
1632
1605
  case 'adr-normalize-local': {
1633
1606
  // Local-backend ADR-нормалізації: викликається з .claude/hooks/normalize-decisions.sh
1634
1607
  // як заміна single-shot LLM-виклику. Проганяє конвеєр (retrieval→edge-judge→
@@ -1661,7 +1634,7 @@ try {
1661
1634
  default: {
1662
1635
  console.error(`❌ Невідома команда: ${command}`)
1663
1636
  console.error(
1664
- ` Очікується: (без аргументів) синхронізація правил, rename-yaml-extensions, post-tool-use-check, adr-normalize-local, lint (включно зі scope: lint ga|rego|k8s|docker|text), lint-doc-files, fix-doc-files, coverage, coverage-fix, analyze-escalation, taze, start-check, change, release, skill, trace, doc-aggregate`
1637
+ ` Очікується: (без аргументів) синхронізація правил, rename-yaml-extensions, hook, adr-normalize-local, lint (включно зі scope: lint ga|rego|k8s|docker|text), coverage, coverage-fix, analyze-escalation, taze, start-check, release, skill, trace, doc-aggregate`
1665
1638
  )
1666
1639
  process.exitCode = 1
1667
1640
  }
@@ -8,8 +8,6 @@ docgen:
8
8
  score: 100
9
9
  ---
10
10
 
11
- ## Огляд
12
-
13
11
  Цей файл конфігурує процес тестування та мутаційного аналізу, використовуючи Vitest як тестовий раннер. Він визначає, які файли підлягають мутації (у `scripts`, `rules`, `bin`) та які виключаються, спираючись на `mutation.json`. Конфігурація налаштовує Stryker для запуску лише тестів, що покривають мутовані рядки. Також конфігурація використовує `incremental.json` для збереження даних між запусками.
14
12
 
15
13
  ## Поведінка
package/lib/docs/llm.md CHANGED
@@ -3,36 +3,31 @@ type: JS Module
3
3
  title: llm.mjs
4
4
  resource: npm/lib/llm.mjs
5
5
  docgen:
6
- crc: 7b27f689
6
+ crc: 22d2906f
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
7
8
  score: 100
8
9
  ---
9
10
 
10
- Файл надає механізми для виклику великих мовних моделей. Маршрутизація вибору транспортного каналу залежить від префікса ідентифікатора моделі згідно з конвенцією `npm/lib/models.mjs`. Виклик LLM виконує виклик з визначеною маршрутизацією та запис трасування. Перевірка стану omlx сервера визначає доступність моделі.
11
+ Файл є єдиною точкою LLM-викликів для JS-оркестраторів (див. ADR 260610-2228). Він маршрутизує запити виключно за префіксом `model-id` (конвенція `npm/lib/models.mjs`): `omlx/<model>` прямий HTTP до локального omlx-сервера (`callOmlx`), будь-що інше — через `pi` CLI (хмарні провайдери або pi-дефолт). Рядок моделі сам визначає транспорт; відсутні env-перемикачі бекенду. Кожен виклик має **always-on** багатий JSONL-запис трасування (reasoning + слід). Для `omlx` захоплюються `content/reasoning/usage/finish_reason/attempts`, для `pi` — лише те, що надає CLI (rich-поля null). Код спирається на конфігурації, визначені у settings.json.
11
12
 
12
13
  ## Поведінка
13
14
 
14
- pickBackend
15
- Маршрутизує модель по префіксу до визначеного бекенда
16
-
17
- callLlm
18
- Виконує універсальний виклик LLM з маршрутизацією за моделью та wire-trace
19
-
20
- omlxHealthCheck
21
- Перевіряє стан omlx сервера для визначення доступності моделі
15
+ pickBackend визначає, чи має бути використаний локальний omlx-сервер для виклику LLM, чи зовнішній CLI `pi`, на основі префікса `model-id`.
16
+ callLlmRich виконує універсальний виклик LLM з маршрутизацією між omlx та `pi` CLI, завжди записуючи детальний слід (wire-trace) для обох каналів, і повертає вміст та монолог обробки.
17
+ callLlm повертає лише текстовий вміст відповіді від LLM, використовуючи `callLlmRich` як внутрішню обгортку.
18
+ classifyOmlxError класифікує помилку, отриману від omlx-сервера, як тимчасову, системну чи постійну, для прийняття рішення оркестратором.
19
+ omlxHealthCheck виконує мінімальний перевірочний виклик до omlx-сервера для визначення його стану (працює, потребує ключа, перевантажений).
20
+ preflightLocalModel перевіряє стан локальної omlx-моделі, щоб визначити, чи можна безпечно ініціювати виклик, надаючи зрозуміле повідомлення про проблеми з пам'яттю, автентифікацією чи доступністю сервера.
22
21
 
23
22
  ## Публічний API
24
23
 
25
- pickBackend — Бекенд для model-id: `omlx` прямий HTTP, `pi` CLI.
26
- callLlmУніверсальний виклик LLM з маршрутизацією за префіксом model-id і постійне відстеження (wire-trace) обох каналів.
27
- omlxHealthCheckПеревірка omlx перед масовим прогоном через мінімальний чат-виклик (`max_tokens: 1`). Розрізняє стани:
28
- downСервер не відповідає (не запущений / не той порт).
29
- memory-guardМодель не влазить у динамічну стелю пам'яті зайнятої машини відкладає прогін.
30
- authСервер вимагає API-ключ виставляє `N_CURSOR_OMLX_KEY`.
31
- error — Інша помилка API.
32
- Порожній контент відповіді — означає, що сервер живий і модель завантажена.
24
+ pickBackend — Визначає, який механізм зв'язку використовувати для моделі: прямий HTTP або CLI.
25
+ callLlmRichВиконує універсальний запит до LLM, маршрутизуючи його за префіксом моделі та відстежуючи трасування, повертаючи детальний об'єкт з відповіддю та логікою обґрунтування.
26
+ callLlmВикликає LLM, повертаючи лише текстовий вміст відповіді, зберігаючи сумісність зі старими споживачами.
27
+ classifyOmlxErrorАналізує помилки omlx після вичерпання внутрішніх спроб, щоб визначити, чи потрібно ігнорувати, зупинити роботу (circuit-breaker) чи обробляти як звичайну помилку.
28
+ omlxHealthCheckПеревіряє готовність omlx-сервера мінімальним запитом, щоб визначити його стан: відсутність відповіді, обмеження пам'яті, відсутність ключа або інша помилка.
29
+ preflightLocalModelПеревіряє можливість використання локальної моделі для швидкого пропуску викликів, використовуючи файли документації та словники.
33
30
 
34
31
  ## Гарантії поведінки
35
32
 
36
- - Read-only: файл не виконує операцій запису у файлову систему.
37
- - Перехоплює помилки і не пропускає винятків назовні (fail-safe).
38
- - Не звертається до мережі.
33
+ - Read-only: не виконує операцій запису (ФС/БД).
package/lib/docs/omlx.md CHANGED
@@ -3,44 +3,39 @@ type: JS Module
3
3
  title: omlx.mjs
4
4
  resource: npm/lib/omlx.mjs
5
5
  docgen:
6
- crc: 9a14ddbe
7
- score: 90
6
+ crc: 23163fe9
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 100
8
9
  ---
9
10
 
10
- Файл забезпечує комунікацію з локальним omlx-сервером для отримання відповідей. Він маршрутизує запити, використовуючи конвенцію префікса для визначення, чи слід використовувати прямий HTTP виклик до omlx, чи CLI. Функції надають інструменти для роботи з API ключами та викликів до inference-сервера.
11
+ Модуль реалізує логіку маршрутизації запитів до локального omlx-сервера, який надає OpenAI-сумісні відповіді за адресою `http://localhost:8000/v1/chat/completions`. Константа DEFAULT_OMLX_URL визначає цю базову адресу. Модуль визначає, чи є модель локальною, аналізуючи префікс у `model-id` (`omlx/<model>`). Якщо модель локальна, виконується прямий HTTP-запит до omlx. Якщо ж модель не локальна, запит спрямовується до pi CLI. При необхідності, API-ключ для omlx резолвиться з конфігураційного файлу settings.json або змінної N_CURSOR_OMLX_KEY і передається у заголовку `Authorization: Bearer …`. Обробка обмежується лише текстовим контентом, оскільки сервер не підтримує виклики інструментів.
11
12
 
12
13
  ## Поведінка
13
14
 
14
- DEFAULT_OMLX_URL: Дефолтний endpoint omlx
15
+ DEFAULT_OMLX_URL надає стандартний URL для доступу до omlx-сервера, який є `http://127.0.0.1:8000/v1/chat/completions`.
16
+ resolveOmlxApiKey визначає API-ключ для omlx-сервера, шукаючи його в опціях виклику, змінній середовища `N_CURSOR_OMLX_KEY` або в файлі `~/.omlx/settings.json`.
17
+ isOmlxModel перевіряє, чи відповідає наданий model-id локальному omlx-бекенду, тобто чи починається він з префікса `omlx/`.
18
+ omlxModelId видаляє префікс `omlx/` з model-id, якщо він присутній, для отримання чистого ідентифікатора для omlx API.
19
+ extractReasoning витягує текст думок (reasoning) з відповіді omlx-сервера, надаючи його разом із джерелом вилучення (поле, тег ``або зрізаний контент).
20
+ callOmlxRaw виконує блокуючий HTTP-виклик до omlx-сервера через`curl`, повторюючи спроби при транзієнтних помилках, і повертає багатий об'єкт з контентом, думками, використанням та статусом завершення.
21
+ callOmlx викликає `callOmlxRaw` і повертає лише текстовий контент відповіді від omlx-сервера.
15
22
 
16
- resolveOmlxApiKey: Резолвить API ключ для omlx-сервера
17
-
18
- DEFAULT_OMLX_MODEL: Дефолтна модель для omlx
23
+ ## Публічний API
19
24
 
20
- isOmlxModel: Перевіряє, чи model-id адресує локальний omlx-бекенд
25
+ DEFAULT_OMLX_URL Дефолтний URL для звернення до omlx-сервера, який може бути перевизначений.
21
26
 
22
- omlxModelId: Прибирає префікс omlx/ з model-id
27
+ resolveOmlxApiKey Визначає ключ доступу до omlx-сервера, використовуючи пріоритет: явний ключ, змінна середовища, конфігурація з `settings.json` або відсутність ключа.
23
28
 
24
- extractReasoning: Витягує reasoning з message
29
+ isOmlxModel Визначає, чи ідентифікатор моделі вказує на локальний omlx-бекенд (за наявністю префікса `omlx/`).
25
30
 
26
- callOmlxRaw: Ядро прямого HTTP-виклику до omlx через curl
31
+ omlxModelId Видаляє префікс `omlx/` з ідентифікатора моделі, залишаючи чистий ідентифікатор для API.
27
32
 
28
- callOmlx: Тонка обгортка для отримання тексту відповіді
33
+ extractReasoning Витягує внутрішні роздуми моделі з відповіді omlx, шукаючи їх у спеціальному полі, тегу `` або в тексті, якщо відповідь була обрізана.
29
34
 
30
- ## Публічний API
35
+ callOmlxRaw Здійснює прямий HTTP-запит до omlx, повертаючи повний об'єкт відповіді (включаючи контент, роздуми, використання та причину завершення). Автоматично повторює запит при тимчасових збоях.
31
36
 
32
- DEFAULT_OMLX_URLдефолтний endpoint omlx (перевизначається як `N_CURSOR_OMLX_URL`).
33
- resolveOmlxApiKey — отримує API-ключ для omlx-сервера, коли ввімкнено автентифікацію (`auth.skip_api_key_verification: false`). Порядок: явний `apiKey` → env `N_CURSOR_OMLX_KEY` → `auth.api_key` з `~/.omlx/settings.json` (для локальної машини, з читанням як за замовчуванням; читання як за замовчуванням; безпечне читання) → `null` (відсутність заголовка).
34
- DEFAULT_OMLX_MODEL — дефолтна модель, якщо в ідентифікаторі залишився префікс `omlx/` (перевизначається як `N_CURSOR_OMLX_MODEL`).
35
- isOmlxModel — перевіряє, чи адресує цей model-id локальний omlx-бекенед (наявність префікса `omlx/`).
36
- omlxModelId — видаляє префікс `omlx/` — отримує чистий model-id для omlx API. Не-omlx-рядки повертаються без змін.
37
- extractReasoning — витягує обґрунтування з відповіді.
38
- callOmlxRaw — виконує прямий HTTP-виклик до omlx через `curl` (за допомогою `spawnSync`). Повертає збагачений об'єкт: контент, обґрунтування, використання, результат завершення та кількість спроб. Перезапускає лише тимчасові помилки curl (18 = закритий трансфер, 52 = порожня відповідь, 56 = збій при отриманні).
39
- callOmlx — тонко інкапсулює `callOmlxRaw` для споживачів, яким потрібен лише текст. Контракт: повертає вміст з `choices[0].message.content`. Без використання заголовків чи загальних фраз.
37
+ callOmlxСпрощує виклик до omlx, повертаючи лише текстовий вміст відповіді, ігноруючи інші деталі.
40
38
 
41
39
  ## Гарантії поведінки
42
40
 
43
- - Read-only: файл не виконує операцій запису у файлову систему.
44
- - Перехоплює помилки і не пропускає винятків назовні (fail-safe).
45
- - За невдачі повертає значення помилки (`false`/`null`/`Err`) замість генерування винятку чи паніки.
46
- - Не звертається до мережі.
41
+ - Read-only: не виконує операцій запису (ФС/БД).
package/lib/llm.mjs CHANGED
@@ -52,14 +52,14 @@ function callPi(messages, model, timeoutMs) {
52
52
 
53
53
  /**
54
54
  * Універсальний LLM-виклик з маршрутизацією за префіксом model-id і always-on
55
- * wire-trace (обидва канали).
55
+ * wire-trace (обидва канали). Повертає **багатий** обʼєкт із вмістом і reasoning.
56
56
  * @param {Array<{role:string, content:string}>} messages OpenAI-style messages (system зберігається на omlx)
57
57
  * @param {string} model model-id; `omlx/<m>` → прямий HTTP, інакше → pi CLI
58
- * @param {{ timeoutMs?: number, temperature?: number, maxTokens?: number, url?: string, caller?: string }} [opts] timeout, температура, ліміт виходу, override URL, мітка викликача для trace
59
- * @returns {string} текст відповіді (непорожній на omlx; pi може повернути '')
58
+ * @param {{ timeoutMs?: number, temperature?: number, maxTokens?: number, url?: string, caller?: string, thinkingBudget?: number }} [opts] timeout, температура, ліміт виходу, override URL, мітка викликача для trace, бюджет thinking-токенів (лише omlx)
59
+ * @returns {{ content: string, reasoning: string|null, reasoningSource: string|null }} вміст відповіді і thinking-монолог
60
60
  */
61
- export function callLlm(messages, model, opts = {}) {
62
- const { timeoutMs = DEFAULT_TIMEOUT_MS, temperature = 0.2, maxTokens, url, caller } = opts
61
+ export function callLlmRich(messages, model, opts = {}) {
62
+ const { timeoutMs = DEFAULT_TIMEOUT_MS, temperature = 0.2, maxTokens, url, caller, thinkingBudget } = opts
63
63
  const backend = pickBackend(model)
64
64
  const resolvedCaller = caller ?? env.N_CURSOR_TRACE_CALLER ?? 'unknown'
65
65
  const t0 = Date.now()
@@ -71,7 +71,13 @@ export function callLlm(messages, model, opts = {}) {
71
71
  let usage = null
72
72
  let attempts = 1
73
73
  if (backend === 'omlx') {
74
- const raw = callOmlxRaw(messages, model, { url, timeoutMs, temperature, ...(maxTokens ? { maxTokens } : {}) })
74
+ const raw = callOmlxRaw(messages, model, {
75
+ url,
76
+ timeoutMs,
77
+ temperature,
78
+ ...(maxTokens ? { maxTokens } : {}),
79
+ ...(thinkingBudget ? { thinkingBudget } : {})
80
+ })
75
81
  ;({ content, reasoning, reasoningSource, finishReason, usage, attempts } = raw)
76
82
  } else {
77
83
  content = callPi(messages, model, timeoutMs)
@@ -96,7 +102,7 @@ export function callLlm(messages, model, opts = {}) {
96
102
  error: null
97
103
  })
98
104
  )
99
- return content
105
+ return { content, reasoning, reasoningSource }
100
106
  } catch (error) {
101
107
  writeTrace(
102
108
  buildTraceRecord({
@@ -117,6 +123,18 @@ export function callLlm(messages, model, opts = {}) {
117
123
  }
118
124
  }
119
125
 
126
+ /**
127
+ * Тонка обгортка над `callLlmRich` — повертає лише рядок контенту. Зберігає
128
+ * backward-compatible контракт для споживачів, яким reasoning не потрібен.
129
+ * @param {Array<{role:string, content:string}>} messages OpenAI-style messages
130
+ * @param {string} model model-id
131
+ * @param {{ timeoutMs?: number, temperature?: number, maxTokens?: number, url?: string, caller?: string }} [opts]
132
+ * @returns {string} текст відповіді
133
+ */
134
+ export function callLlm(messages, model, opts = {}) {
135
+ return callLlmRich(messages, model, opts).content
136
+ }
137
+
120
138
  /** Фрагмент повідомлення omlx про memory-guard (динамічна стеля пам'яті). */
121
139
  const MEMORY_GUARD_MARKER = 'memory ceiling'
122
140
  /** Тип помилки omlx про відсутній/хибний API-ключ. */
package/lib/omlx.mjs CHANGED
@@ -130,7 +130,7 @@ function parseOmlxResponse(stdout, attempt) {
130
130
  * transient-помилки (curl 18/28/52/56 + spawnSync ETIMEDOUT) із backoff 2s→8s.
131
131
  * @param {Array<{role:string, content:string}>} messages OpenAI-messages (system+user збережено)
132
132
  * @param {string} model model-id (з/без `omlx/`-префікса); порожній і без `fallbackModel` → throw
133
- * @param {{ url?: string, timeoutMs?: number, temperature?: number, maxTokens?: number, fallbackModel?: string, apiKey?: string, backoffMs?: number[] }} [opts] URL, timeout, температура, ліміт виходу, fallback-модель, API-ключ, backoff між ретраями (мс)
133
+ * @param {{ url?: string, timeoutMs?: number, temperature?: number, maxTokens?: number, fallbackModel?: string, apiKey?: string, backoffMs?: number[], thinkingBudget?: number }} [opts] URL, timeout, температура, ліміт виходу, fallback-модель, API-ключ, backoff між ретраями (мс), бюджет thinking-токенів (0 = вимкнено)
134
134
  * @returns {{ content:string, reasoning:string|null, reasoningSource:string|null, finishReason:string|null, usage:object|null, attempts:number }} багатий результат виклику
135
135
  * @throws {Error} на curl-помилці, не-200 exit, поганому JSON чи порожньому контенті
136
136
  */
@@ -142,14 +142,21 @@ export function callOmlxRaw(messages, model, opts = {}) {
142
142
  maxTokens = 4096,
143
143
  fallbackModel = env.N_CURSOR_OMLX_MODEL ?? '',
144
144
  apiKey,
145
- backoffMs = BACKOFF_MS
145
+ backoffMs = BACKOFF_MS,
146
+ thinkingBudget = 0
146
147
  } = opts
147
148
 
148
149
  const m = omlxModelId(model) || fallbackModel
149
150
  if (!m) {
150
151
  throw new Error('omlx: модель не задано — постав N_LOCAL_MIN_MODEL (або N_CURSOR_OMLX_MODEL)')
151
152
  }
152
- const body = JSON.stringify({ model: m, messages, max_tokens: maxTokens, temperature })
153
+ const body = JSON.stringify({
154
+ model: m,
155
+ messages,
156
+ max_tokens: maxTokens,
157
+ temperature,
158
+ ...(thinkingBudget > 0 ? { thinking_budget: thinkingBudget } : {})
159
+ })
153
160
  // Ключ локального сервера в argv допустимий: localhost-секрет власної машини,
154
161
  // короткоживучий процес; stdin уже зайнятий body (`--data-binary @-`).
155
162
  const key = resolveOmlxApiKey(apiKey)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nitra/cursor",
3
- "version": "12.8.9",
3
+ "version": "12.10.0",
4
4
  "description": "CLI для завантаження cursor-правил (префікс n-) у локальний репозиторій",
5
5
  "keywords": [
6
6
  "cli",
@@ -53,11 +53,11 @@
53
53
  "rename-yaml-extensions": "bun ./bin/n-cursor.js rename-yaml-extensions"
54
54
  },
55
55
  "dependencies": {
56
- "@7n/mt": "^0.5.0",
57
- "oxc-parser": "^0.128.0",
56
+ "@7n/mt": "^0.5.1",
57
+ "oxc-parser": "^0.137.0",
58
58
  "picomatch": "^4.0.4",
59
- "smol-toml": "^1.6.1",
60
- "yaml": "^2.8.3",
59
+ "smol-toml": "^1.7.0",
60
+ "yaml": "^2.9.0",
61
61
  "zod": "^4.4.3"
62
62
  },
63
63
  "engines": {
@@ -8,5 +8,4 @@ resource: npm/rules/abie/
8
8
 
9
9
  | Файл | Тип |
10
10
  | ------------------- | --------- |
11
- | [fix.mjs](fix.md) | JS Module |
12
11
  | [main.mjs](main.md) | JS Module |
@@ -8,8 +8,6 @@ docgen:
8
8
  score: 100
9
9
  ---
10
10
 
11
- ## Огляд
12
-
13
11
  Модуль застосовує політику до JS-запитів, посилаючись на MDC-ресурси відповідно до конфігурації `meta.json`. При запуску як окремий інструмент (CLI) він виконує повний цикл обробки, завантажує конфігурації та формує підсумковий звіт. Модуль є Read-only, тобто не здійснює записів у файлову систему чи бази даних. Кешування даних відбувається у межах одного прогону.
14
12
 
15
13
  ## Поведінка
@@ -3,26 +3,23 @@ type: JS Module
3
3
  title: http-route.mjs
4
4
  resource: npm/rules/abie/lib/http-route.mjs
5
5
  docgen:
6
- crc: 3ec544d6
6
+ crc: 1ffd9c0b
7
+ model: omlx/gemma-4-e4b-it-OptiQ-4bit
8
+ score: 100
7
9
  ---
8
10
 
9
- Файл надає інструмент для порівняльного аналізу конфігурації HTTP-маршрутів. Він виконує порівняння кількості `backendRefs` для сервісів `auth-run-hl` та `file-link-hl` у базових маніфестах пакета з кількістю патчів, визначеною в оверлеях. Цей механізм використовується для синхронізації кількості патчів у верхньому рівні з фактичною кількістю посилань у базі. (abie.mdc)
11
+ Виконує крос-документну аналітику для підрахунку `backendRefs` до спільних сервісів (`auth-run-hl`, `file-link-hl`) у base-маніфестах пакета, що знаходяться поза overlay `ua`. Використовується фіксований список спільних сервісів, визначений через `ABIE_SHARED_CROSS_NS_BACKEND_NAMES`. Функція `analyzeAbieSharedBackendRefsInPackageK8s` підраховує ці посилання. Це забезпечує синхронізацію числа патчів namespace в overlay із кількістю base-reference, використовуючи `ua_http_route-концерном` для забезпечення узгодженості (abie.mdc).
10
12
 
11
13
  ## Поведінка
12
14
 
13
- ABIE_SHARED_CROSS_NS_BACKEND_NAMES
14
- Визначає список спільних сервісів, які підлягають аналітиці.
15
-
16
- analyzeAbieSharedBackendRefsInPackageK8s
17
- Збирає кількість посилань на спільні бекенди та порушення вимог до namespace у базових документах HTTPRoute пакета.
15
+ ABIE_SHARED_CROSS_NS_BACKEND_NAMES надає фіксований список назв спільних сервісів (`auth-run-hl`, `file-link-hl`), які підлягають аналізу.
16
+ analyzeAbieSharedBackendRefsInPackageK8s збирає кількість посилань на спільні сервіси (`backendRefs`) у base-маніфестах пакета (виключаючи overlay `ua`) та виявляє порушення вимог до цих посилань (наприклад, відсутність `namespace: dev` або `port: 8080` (abie.mdc)).
18
17
 
19
18
  ## Публічний API
20
19
 
21
- ABIE_SHARED_CROSS_NS_BACKEND_NAMES — Формує імена для крос-нішових зв'язків між бекендами. (abie.mdc)
22
-
23
- analyzeAbieSharedBackendRefsInPackageK8s — Збирає кількість спільних посилань `backendRefs` та базові помилки з YAML-файлів пакета, ігноруючи неймспейс `dev`. (abie.mdc)
20
+ ABIE_SHARED_CROSS_NS_BACKEND_NAMES — Визначає імена бекендів, що використовуються між різними неймспейсами.
21
+ analyzeAbieSharedBackendRefsInPackageK8s — Підраховує кількість посилань на спільні бекенди у YAML-файлах пакета (крім overlay ua) та фіксує базові помилки (без неймспейсу dev). (abie.mdc)
24
22
 
25
23
  ## Гарантії поведінки
26
24
 
27
- - Read-only: файл не виконує операцій запису у файлову систему.
28
- - Не звертається до мережі.
25
+ - Read-only: не виконує операцій запису (ФС/БД).
@@ -27,6 +27,9 @@ function checkSharedBackendRef(br, rel, errors) {
27
27
  if (typeof brRec.namespace !== 'string' || brRec.namespace !== 'dev') {
28
28
  errors.push(`${rel}: HTTPRoute backendRefs до ${name} має містити namespace: dev (abie.mdc)`)
29
29
  }
30
+ if (brRec.port !== 8080) {
31
+ errors.push(`${rel}: HTTPRoute backendRefs до ${name} має містити port: 8080 (abie.mdc)`)
32
+ }
30
33
  return 1
31
34
  }
32
35
 
@@ -16,16 +16,6 @@ version: '1.22'
16
16
 
17
17
  Без цього запису `@nitra/cursor` пропускає всі abie-перевірки (JS-концерни та rego-полісі).
18
18
 
19
- [k8s-hc-yaml](./js/hc_pairing.mdc)
20
-
21
- [k8s-http-route-base](./js/http_route_base.mdc)
22
-
23
- [k8s-http-route-ua](./js/ua_http_route.mdc)
24
-
25
- [k8s-nodeselector](./js/ua_node_selector.mdc)
26
-
27
- [env-dns](./js/env_dns.mdc)
28
-
29
19
  ## `@nitra/abie-shared` у `devDependencies`
30
20
 
31
21
  У кореневому **`package.json`** abie-проєкту в **`devDependencies`** має бути **`@nitra/abie-shared`** — пакет зі спільними abie-ресурсами: канонічні GraphQL-схеми, скіли, типи (наприклад, шляхи `node_modules/@nitra/abie-shared/schema/...` для імпорту схем). Версію правило не фіксує — лише presence. Додати:
@@ -34,8 +24,6 @@ version: '1.22'
34
24
  bun add -d @nitra/abie-shared
35
25
  ```
36
26
 
37
- [firebase](./js/firebase_hosting.mdc)
38
-
39
27
  ## Git branches
40
28
 
41
29
  У **`.github/workflows/clean-merged-branch.yml`** у кроці **`phpdocker-io/github-actions-delete-abandoned-branches`** значення **`with.ignore_branches`** має містити **dev** та **ua** (разом з іншими гілками, якщо потрібно):
@@ -48,16 +36,6 @@ bun add -d @nitra/abie-shared
48
36
 
49
37
  Пакети (директорія в **`npm/policy/abie/`** → namespace → що перевіряє):
50
38
 
51
- [abie-http-route-base](./policy/http_route_base/http_route_base.mdc)
52
-
53
- [abie-health-check-policy](./policy/health_check_policy/health_check_policy.mdc)
54
-
55
- [abie-base-deployment-preem](./policy/base_deployment_preem/base_deployment_preem.mdc)
56
-
57
- [abie-clean-merged-ignore-branches](./policy/clean_merged_ignore_branches/clean_merged_ignore_branches.mdc)
58
-
59
- [abie-package-json-shared](./policy/package_json_shared/package_json_shared.mdc)
60
-
61
39
  Cross-file / FS-логіка лишається у JS-частинах (`js/<concern>.mjs`) — Rego не читає файлову систему й не робить cross-document резолюцію:
62
40
 
63
41
  - парність HCP↔Deployment у каталозі та modeline `hc.yaml` — `js/hc_pairing.mjs`;