@nitra/cursor 1.17.3 → 1.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-template/hooks/capture-decisions.sh +79 -0
- package/.claude-template/hooks/normalize-decisions.sh +98 -0
- package/CHANGELOG.md +26 -0
- package/package.json +1 -1
- package/rules/adr/adr.mdc +5 -1
- package/rules/test/js/stryker_config.mjs +5 -5
- package/rules/test/test.mdc +2 -2
- package/rules/text/policy/cspell/template/.cspell.json.snippet.json +2 -1
- package/rules/text/text.mdc +5 -3
- package/skills/adr-normalize/SKILL.md +2 -0
|
@@ -34,6 +34,62 @@ mkdir -p "$ADR_DIR" "$LOG_DIR"
|
|
|
34
34
|
|
|
35
35
|
log() { printf '%s %s\n' "$(date -Iseconds)" "$*" >> "$LOG"; }
|
|
36
36
|
|
|
37
|
+
# Структурний скіп ADR-генерації для "tooling-only" сесій.
|
|
38
|
+
# Вхід: рядки-шляхи у stdin (один шлях на лінію), відносні до $PROJECT_ROOT
|
|
39
|
+
# або абсолютні з префіксом $PROJECT_ROOT (нормалізуємо тут).
|
|
40
|
+
# Вихід: 0 — усі шляхи в allowlist; 1 — є хоч один змістовний шлях.
|
|
41
|
+
# Bash 3.2: без mapfile/асоц. масивів.
|
|
42
|
+
is_tooling_only_change() {
|
|
43
|
+
local proj="$1"
|
|
44
|
+
local had_file=0
|
|
45
|
+
local f rel
|
|
46
|
+
while IFS= read -r f; do
|
|
47
|
+
[ -z "$f" ] && continue
|
|
48
|
+
had_file=1
|
|
49
|
+
case "$f" in
|
|
50
|
+
"$proj"/*) rel="${f#"$proj"/}" ;;
|
|
51
|
+
/*) return 1 ;;
|
|
52
|
+
*) rel="$f" ;;
|
|
53
|
+
esac
|
|
54
|
+
case "$rel" in
|
|
55
|
+
.cspell.json) ;;
|
|
56
|
+
docs/adr/*.md) ;;
|
|
57
|
+
AGENTS.md|CLAUDE.md) ;;
|
|
58
|
+
CHANGELOG.md) ;;
|
|
59
|
+
*/CHANGELOG.md) ;;
|
|
60
|
+
package.json|*/package.json)
|
|
61
|
+
if ! git_diff_only_version_field "$proj" "$rel"; then
|
|
62
|
+
return 1
|
|
63
|
+
fi
|
|
64
|
+
;;
|
|
65
|
+
*) return 1 ;;
|
|
66
|
+
esac
|
|
67
|
+
done
|
|
68
|
+
[ "$had_file" = "1" ] && return 0
|
|
69
|
+
return 1
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
# Допоміжна: чи git-diff для файлу торкається ЛИШЕ рядків з `"version":`.
|
|
73
|
+
# Поза git-репо або при помилці — вертаємо 1 (не tooling).
|
|
74
|
+
git_diff_only_version_field() {
|
|
75
|
+
local proj="$1" path="$2"
|
|
76
|
+
[ -d "$proj/.git" ] || return 1
|
|
77
|
+
local diff
|
|
78
|
+
diff=$(cd "$proj" && git diff HEAD --unified=0 -- "$path" 2>/dev/null) || return 1
|
|
79
|
+
[ -z "$diff" ] && return 1
|
|
80
|
+
local line
|
|
81
|
+
while IFS= read -r line; do
|
|
82
|
+
case "$line" in
|
|
83
|
+
'+++ '*|'--- '*|'@@ '*|'') continue ;;
|
|
84
|
+
[+-]*'"version":'*) continue ;;
|
|
85
|
+
[+-]*) return 1 ;;
|
|
86
|
+
esac
|
|
87
|
+
done <<EOF
|
|
88
|
+
$diff
|
|
89
|
+
EOF
|
|
90
|
+
return 0
|
|
91
|
+
}
|
|
92
|
+
|
|
37
93
|
log "fired: $SESSION_ID"
|
|
38
94
|
|
|
39
95
|
if [[ -z "$TRANSCRIPT_PATH" || ! -f "$TRANSCRIPT_PATH" ]]; then
|
|
@@ -86,6 +142,29 @@ if [[ -z "$TRANSCRIPT" ]]; then
|
|
|
86
142
|
exit 0
|
|
87
143
|
fi
|
|
88
144
|
|
|
145
|
+
# Structural skip: якщо в сесії змінювалися лише tooling-файли — не викликаємо LLM.
|
|
146
|
+
# ENV `ADR_NORMALIZE_SKIP_TOOLING_ONLY=0` вимикає скіп.
|
|
147
|
+
if [[ "${ADR_NORMALIZE_SKIP_TOOLING_ONLY:-1}" = "1" ]]; then
|
|
148
|
+
CHANGED_FILES=$(jq -r '
|
|
149
|
+
select(.type == "assistant" or .role == "assistant")
|
|
150
|
+
| .message as $m
|
|
151
|
+
| ($m.content // [])
|
|
152
|
+
| if type == "array" then
|
|
153
|
+
map(select(.type == "tool_use" and (.name == "Edit" or .name == "Write" or .name == "MultiEdit"))
|
|
154
|
+
| .input.file_path // empty)
|
|
155
|
+
| .[]
|
|
156
|
+
else empty end
|
|
157
|
+
' "$TRANSCRIPT_PATH" 2>/dev/null | sort -u || true)
|
|
158
|
+
|
|
159
|
+
if [[ -n "$CHANGED_FILES" ]]; then
|
|
160
|
+
if printf '%s\n' "$CHANGED_FILES" | is_tooling_only_change "$PROJECT_ROOT"; then
|
|
161
|
+
log " → skipping ADR capture: tooling-only session"
|
|
162
|
+
log " files: $(printf '%s' "$CHANGED_FILES" | tr '\n' ' ')"
|
|
163
|
+
exit 0
|
|
164
|
+
fi
|
|
165
|
+
fi
|
|
166
|
+
fi
|
|
167
|
+
|
|
89
168
|
PROMPT=$(cat <<'EOF'
|
|
90
169
|
You analyze an AI coding session transcript and produce durable decision documentation.
|
|
91
170
|
|
|
@@ -39,6 +39,65 @@ mkdir -p "$LOG_DIR"
|
|
|
39
39
|
|
|
40
40
|
log() { printf '%s %s\n' "$(date -Iseconds)" "$*" >> "$LOG"; }
|
|
41
41
|
|
|
42
|
+
# Структурний скіп ADR-нормалізації для "tooling-only" сесій.
|
|
43
|
+
# Дублікат із capture-decisions.sh: `.claude-template/hooks/` копіюється плоско,
|
|
44
|
+
# спільний helper-файл туди не вписується.
|
|
45
|
+
is_tooling_only_change() {
|
|
46
|
+
proj="$1"
|
|
47
|
+
had_file=0
|
|
48
|
+
while IFS= read -r f; do
|
|
49
|
+
[ -z "$f" ] && continue
|
|
50
|
+
had_file=1
|
|
51
|
+
case "$f" in
|
|
52
|
+
"$proj"/*) rel="${f#"$proj"/}" ;;
|
|
53
|
+
/*) return 1 ;;
|
|
54
|
+
*) rel="$f" ;;
|
|
55
|
+
esac
|
|
56
|
+
case "$rel" in
|
|
57
|
+
.cspell.json) ;;
|
|
58
|
+
docs/adr/*.md) ;;
|
|
59
|
+
AGENTS.md|CLAUDE.md) ;;
|
|
60
|
+
CHANGELOG.md) ;;
|
|
61
|
+
*/CHANGELOG.md) ;;
|
|
62
|
+
package.json|*/package.json)
|
|
63
|
+
if ! git_diff_only_version_field "$proj" "$rel"; then
|
|
64
|
+
return 1
|
|
65
|
+
fi
|
|
66
|
+
;;
|
|
67
|
+
*) return 1 ;;
|
|
68
|
+
esac
|
|
69
|
+
done
|
|
70
|
+
[ "$had_file" = "1" ] && return 0
|
|
71
|
+
return 1
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# Допоміжна: чи git-diff для файлу торкається ЛИШЕ рядків з `"version":`.
|
|
75
|
+
git_diff_only_version_field() {
|
|
76
|
+
proj="$1"; path="$2"
|
|
77
|
+
[ -d "$proj/.git" ] || return 1
|
|
78
|
+
diff=$(cd "$proj" && git diff HEAD --unified=0 -- "$path" 2>/dev/null) || return 1
|
|
79
|
+
[ -z "$diff" ] && return 1
|
|
80
|
+
while IFS= read -r line; do
|
|
81
|
+
case "$line" in
|
|
82
|
+
'+++ '*|'--- '*|'@@ '*|'') continue ;;
|
|
83
|
+
[+-]*'"version":'*) continue ;;
|
|
84
|
+
[+-]*) return 1 ;;
|
|
85
|
+
esac
|
|
86
|
+
done <<EOF
|
|
87
|
+
$diff
|
|
88
|
+
EOF
|
|
89
|
+
return 0
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
# Витягає поле `transcript:` з YAML frontmatter ADR-чернетки.
|
|
93
|
+
draft_transcript_path() {
|
|
94
|
+
awk '
|
|
95
|
+
NR==1 && /^---$/ { fm=1; next }
|
|
96
|
+
fm && /^---$/ { exit }
|
|
97
|
+
fm && /^transcript: / { sub(/^transcript: /, ""); print; exit }
|
|
98
|
+
' "$1" 2>/dev/null
|
|
99
|
+
}
|
|
100
|
+
|
|
42
101
|
# Skip if repo is mid-rebase / mid-merge — editing files now would tangle the user.
|
|
43
102
|
if [ -d "$PROJECT_ROOT/.git" ]; then
|
|
44
103
|
for marker in MERGE_HEAD CHERRY_PICK_HEAD REVERT_HEAD rebase-apply rebase-merge; do
|
|
@@ -120,6 +179,45 @@ head -n "$BATCH_SIZE" "$DRAFTS_LIST" > "$BATCH_LIST"
|
|
|
120
179
|
BATCH_COUNT=$(wc -l < "$BATCH_LIST" | tr -d ' ')
|
|
121
180
|
log "batch size: $BATCH_COUNT"
|
|
122
181
|
|
|
182
|
+
# Structural skip: чернетки з tooling-only сесій видаляємо без виклику LLM.
|
|
183
|
+
if [ "${ADR_NORMALIZE_SKIP_TOOLING_ONLY:-1}" = "1" ]; then
|
|
184
|
+
FILTERED_LIST="$TMP_DIR/batch-filtered.txt"
|
|
185
|
+
: > "$FILTERED_LIST"
|
|
186
|
+
TOOLING_REMOVED=0
|
|
187
|
+
while IFS= read -r draft; do
|
|
188
|
+
[ -f "$draft" ] || continue
|
|
189
|
+
tpath=$(draft_transcript_path "$draft")
|
|
190
|
+
if [ -n "$tpath" ] && [ -f "$tpath" ]; then
|
|
191
|
+
changed=$(jq -r '
|
|
192
|
+
select(.type == "assistant" or .role == "assistant")
|
|
193
|
+
| .message as $m
|
|
194
|
+
| ($m.content // [])
|
|
195
|
+
| if type == "array" then
|
|
196
|
+
map(select(.type == "tool_use" and (.name == "Edit" or .name == "Write" or .name == "MultiEdit"))
|
|
197
|
+
| .input.file_path // empty)
|
|
198
|
+
| .[]
|
|
199
|
+
else empty end
|
|
200
|
+
' "$tpath" 2>/dev/null | sort -u || true)
|
|
201
|
+
if [ -n "$changed" ] && printf '%s\n' "$changed" | is_tooling_only_change "$PROJECT_ROOT"; then
|
|
202
|
+
rm -f -- "$draft"
|
|
203
|
+
log "tooling-only delete: $(basename "$draft") (files: $(printf '%s' "$changed" | tr '\n' ' '))"
|
|
204
|
+
TOOLING_REMOVED=$(( TOOLING_REMOVED + 1 ))
|
|
205
|
+
continue
|
|
206
|
+
fi
|
|
207
|
+
fi
|
|
208
|
+
printf '%s\n' "$draft" >> "$FILTERED_LIST"
|
|
209
|
+
done < "$BATCH_LIST"
|
|
210
|
+
mv "$FILTERED_LIST" "$BATCH_LIST"
|
|
211
|
+
BATCH_COUNT=$(wc -l < "$BATCH_LIST" | tr -d ' ')
|
|
212
|
+
if [ "$TOOLING_REMOVED" -gt 0 ]; then
|
|
213
|
+
log "after tooling-only filter: $BATCH_COUNT drafts remain (removed $TOOLING_REMOVED)"
|
|
214
|
+
fi
|
|
215
|
+
if [ "$BATCH_COUNT" -eq 0 ]; then
|
|
216
|
+
log "batch is empty after tooling-only filter — exit"
|
|
217
|
+
exit 0
|
|
218
|
+
fi
|
|
219
|
+
fi
|
|
220
|
+
|
|
123
221
|
# Find clean ADR files at root of docs/adr/ (no `session:`).
|
|
124
222
|
find "$ADR_DIR" -maxdepth 1 -type f -name '*.md' 2>/dev/null | while IFS= read -r f; do
|
|
125
223
|
if ! is_draft "$f"; then
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,32 @@
|
|
|
4
4
|
|
|
5
5
|
Формат — [Keep a Changelog](https://keepachangelog.com/uk/1.1.0/), нумерація — [SemVer](https://semver.org/lang/uk/).
|
|
6
6
|
|
|
7
|
+
## [1.18.0] - 2026-05-25
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- `text`: `docs/adr/**` у канонічному `ignorePaths` правила `.cspell.json` (`policy/cspell/template/.cspell.json.snippet.json`). Машинно-генеровані ADR-документи більше не валідуються cspell-ом — це розриває петлю «правка `.cspell.json` → новий ADR-draft → знову `cspell` ламається на ньому». Локальні розширення `ignorePaths` лишаються дозволені (rego subset-of).
|
|
12
|
+
- `adr`: ENV `ADR_NORMALIZE_SKIP_TOOLING_ONLY` (default `1`) — вимикає structural skip у capture-/normalize-хуках. Документація в `adr.mdc` (таблиця ENV) і `skills/adr-normalize/SKILL.md`.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- `adr`: `.claude-template/hooks/capture-decisions.sh` — перед LLM-викликом перевіряє список `tool_use`-правок із transcript'у. Якщо всі правки у вузькому allowlist (`.cspell.json`, `docs/adr/*.md`, кореневі `AGENTS.md`/`CLAUDE.md`, `CHANGELOG.md`, `*/package.json` із diff виключно по ключу `version`) — `exit 0` із записом `skipping ADR capture: tooling-only session` у лог. Inline-функція `is_tooling_only_change` + `git_diff_only_version_field`, bash 3.2-сумісно.
|
|
17
|
+
- `adr`: `.claude-template/hooks/normalize-decisions.sh` — після формування батча для кожної чернетки читає `transcript:` із frontmatter і та сама перевірка allowlist'у. Tooling-only чернетки видаляються без виклику LLM; якщо батч порожній — `exit 0`.
|
|
18
|
+
- `text.mdc` 1.29 → 1.30: документація `docs/adr/**` у `ignorePaths`; приклади `.cspell.json` оновлено.
|
|
19
|
+
- `adr.mdc` 2.1 → 2.2: нова секція «Tooling-only skip» у Фазі 1, bullet у Фазі 2, рядок у таблиці ENV.
|
|
20
|
+
|
|
21
|
+
### Notes
|
|
22
|
+
|
|
23
|
+
- Існуючі ENV (`ADR_NORMALIZE_THRESHOLD`, `…_MIN_INTERVAL_HOURS`, `…_BATCH`, `…_DRY`, recursion-guard `CAPTURE_DECISIONS_RUNNING` / `ADR_NORMALIZE_RUNNING`) поведінку не змінюють.
|
|
24
|
+
- `cspell.rego` subset-of-перевірку зберігає — нічого не зламано для проєктів, де користувач уже руками додав `docs/adr/**` у свій `.cspell.json`.
|
|
25
|
+
|
|
26
|
+
## [1.17.4] - 2026-05-24
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- Концерн `stryker_config`: gitignore-патерн `**/reports/stryker/.tmp/` + `**/reports/stryker/mutation.json` замінено на один broader `**/reports/stryker/` — увесь каталог Stryker-output-у. Покриває не лише `.tmp/` + `mutation.json`, а й HTML/dashboard-репорти якщо користувач додасть інші reporter-и. Існуючі дрібніші патерни в `.gitignore` користувача не видаляються (idempotent helper лише дописує), але стають надлишковими — користувач може почистити вручну за бажанням.
|
|
31
|
+
- `test.mdc` 2.1 → 2.2: оновлено опис gitignore-керування під новий broader patern.
|
|
32
|
+
|
|
7
33
|
## [1.17.3] - 2026-05-24
|
|
8
34
|
|
|
9
35
|
### Added
|
package/package.json
CHANGED
package/rules/adr/adr.mdc
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Автоматичний збір ADR/Runbook/Knowledge-чернеток і батч-нормалізація у `docs/adr/` через Stop-хуки Claude Code та Cursor Agent
|
|
3
3
|
alwaysApply: true
|
|
4
|
-
version: '2.
|
|
4
|
+
version: '2.2'
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
## MADR v4 і дві фази
|
|
@@ -29,6 +29,8 @@ Stop-hook `capture-decisions.sh` зчитує JSONL-транскрипт сес
|
|
|
29
29
|
|
|
30
30
|
Для Cursor payload скрипт бере `transcript_path`, `conversation_id` / `generation_id` і `workspace_roots[0]`; для Claude Code — `transcript_path`, `session_id` і `CLAUDE_PROJECT_DIR`.
|
|
31
31
|
|
|
32
|
+
**Tooling-only skip:** перед викликом LLM `capture-decisions.sh` дивиться у transcript на `tool_use`-правки (`Edit`/`Write`/`MultiEdit`). Якщо всі змінені файли потрапляють у вузький allowlist — `.cspell.json`, `docs/adr/*.md`, `CHANGELOG.md`, кореневі `AGENTS.md`/`CLAUDE.md`, або `package.json` з diff виключно по ключу `version` — хук виходить з `exit 0` без LLM-виклику. Це розриває петлю «`/n-lint` править `.cspell.json` → з'являється новий ADR-draft → наступний `/n-lint` знов псує правопис у цьому draft». Поведінку вимикає `ADR_NORMALIZE_SKIP_TOOLING_ONLY=0`.
|
|
33
|
+
|
|
32
34
|
### Фаза 2 — Normalize
|
|
33
35
|
|
|
34
36
|
Stop-hook `normalize-decisions.sh` спрацьовує на тому самому `Stop`-евенті, але:
|
|
@@ -38,6 +40,7 @@ Stop-hook `normalize-decisions.sh` спрацьовує на тому самом
|
|
|
38
40
|
- Бере не більше **`ADR_NORMALIZE_BATCH`** чернеток (default 10, найстарші за іменем-timestamp), формує один промпт LLM і чекає JSON-відповідь зі списком операцій.
|
|
39
41
|
- Виходить миттєво, якщо репозиторій у стані `MERGE_HEAD` / `rebase-*` — небезпечно правити файли посеред конфлікту.
|
|
40
42
|
- Виходить миттєво, якщо інший normalize-запуск тримає `flock` на `.claude/hooks/.normalize.lock` (тільки де `flock` доступний).
|
|
43
|
+
- Перед викликом LLM для кожної чернетки batch'а читає `transcript:` із frontmatter і той самий tool_use-список. Чернетки tooling-only — видаляє без виклику LLM. Якщо після фільтра batch порожній — `exit 0`.
|
|
41
44
|
|
|
42
45
|
LLM повертає масив операцій:
|
|
43
46
|
|
|
@@ -65,6 +68,7 @@ LLM повертає масив операцій:
|
|
|
65
68
|
| `ADR_NORMALIZE_DRY` | `0` | `1` — лише лог запланованих операцій, без змін на диску. |
|
|
66
69
|
| `ADR_NORMALIZE_MODEL` | `sonnet` | Модель для `claude -p`. |
|
|
67
70
|
| `ADR_NORMALIZE_CURSOR_MODEL` | `claude-4.6-sonnet-medium` | Модель для `cursor-agent -p`. |
|
|
71
|
+
| `ADR_NORMALIZE_SKIP_TOOLING_ONLY` | `1` | `0` — вимкнути structural skip tooling-only сесій (старий behavior). |
|
|
68
72
|
|
|
69
73
|
Для ручного запуску (поза порогом і поза Stop-хуком) є **`/n-adr-normalize`** — slash-команда тимчасово виставляє `ADR_NORMALIZE_THRESHOLD=0` і `ADR_NORMALIZE_MIN_INTERVAL_HOURS=0` та викликає скрипт напряму.
|
|
70
74
|
|
|
@@ -23,11 +23,11 @@ import { resolveAllJsRoots } from '../../../scripts/utils/resolve-js-root.mjs'
|
|
|
23
23
|
const HERE = dirname(fileURLToPath(import.meta.url))
|
|
24
24
|
const BASELINE_PATH = join(HERE, 'data', 'stryker_config', 'stryker.config.baseline.mjs')
|
|
25
25
|
|
|
26
|
-
// Stryker-output
|
|
27
|
-
// (`tempDirName
|
|
28
|
-
//
|
|
29
|
-
//
|
|
30
|
-
const STRYKER_GITIGNORE_ENTRIES = ['**/reports/stryker
|
|
26
|
+
// Stryker-output патерн для .gitignore: увесь каталог reports/stryker/ — це
|
|
27
|
+
// build-артефакти (`tempDirName` backup'и, mutation.json, HTML/dashboard-репорти
|
|
28
|
+
// якщо користувач додасть інші reporter-и). Покриваємо одним патерном замість
|
|
29
|
+
// перелічування під-патернів. Подвійний-зірочка-префікс — для monorepo workspaces.
|
|
30
|
+
const STRYKER_GITIGNORE_ENTRIES = ['**/reports/stryker/']
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* @returns {Promise<number>} 0 — OK або silently skipped, 1 — порушення
|
package/rules/test/test.mdc
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: JS-тести (*.test.mjs) живуть у tests/. Правило `test` керує stryker.config.mjs (якщо js-lint enabled) і .cargo/mutants.toml (якщо rust enabled).
|
|
3
|
-
version: '2.
|
|
3
|
+
version: '2.2'
|
|
4
4
|
globs: "**/{.n-cursor.json,package.json,Cargo.toml,stryker.config.mjs,.cargo/mutants.toml},**/*.test.mjs"
|
|
5
5
|
alwaysApply: false
|
|
6
6
|
---
|
|
@@ -82,4 +82,4 @@ Recursive globs ловлять файли всередині `tests/` так с
|
|
|
82
82
|
|
|
83
83
|
Customization (mutate patterns, exclude rules, timeout) — відповідальність проєкту-споживача; концерни лише забезпечують наявність файлу як стартового baseline в кожному з виявлених workspace-каталогів.
|
|
84
84
|
|
|
85
|
-
Додатково: коли `js-lint` enabled, концерн `stryker_config` ідемпотентно додає у кореневий `.gitignore`
|
|
85
|
+
Додатково: коли `js-lint` enabled, концерн `stryker_config` ідемпотентно додає у кореневий `.gitignore` патерн `**/reports/stryker/` — увесь каталог Stryker-output-у (backup'и `tempDirName`, `mutation.json`, HTML/dashboard-репорти якщо додасте інші reporter-и). Це запобігає випадковому коміту build-артефактів.
|
package/rules/text/text.mdc
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Обробка та перевірка текстових файлів, oxfmt, cspell, shellcheck (sh), dotenv-linter (.env*), markdownlint-cli2, v8r, CI
|
|
3
3
|
alwaysApply: true
|
|
4
|
-
version: '1.
|
|
4
|
+
version: '1.30'
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
**oxfmt** (`.oxfmtrc.json`, редактор), **cspell**, **shellcheck** (tracked `*.sh` у `lint-text`), **[dotenv-linter](https://dotenv-linter.github.io/)** (`.env*` у `lint-text`), **markdownlint-cli2**, **[v8r](https://chris48s.github.io/v8r/)** ([Schema Store](https://www.schemastore.org/)), розширення **DavidAnson.vscode-markdownlint** / **timonwong.shellcheck**, workflow **`lint-text`**.
|
|
@@ -186,7 +186,7 @@ version: '1.29'
|
|
|
186
186
|
{
|
|
187
187
|
"version": "0.2",
|
|
188
188
|
"language": "nitra",
|
|
189
|
-
"ignorePaths": ["**/node_modules/**", "**/vscode-extension/**", "**/.git/**", ".vscode", "report", "*.svg", "**/k8s/**/*.yaml"],
|
|
189
|
+
"ignorePaths": ["**/node_modules/**", "**/vscode-extension/**", "**/.git/**", ".vscode", "report", "*.svg", "**/k8s/**/*.yaml", "docs/adr/**"],
|
|
190
190
|
"import": ["@nitra/cspell-dict/cspell-ext.json"],
|
|
191
191
|
"words": []
|
|
192
192
|
}
|
|
@@ -194,6 +194,8 @@ version: '1.29'
|
|
|
194
194
|
|
|
195
195
|
Канон базових ключів `.cspell.json` (`version`, `ignorePaths`): [.cspell.json.snippet.json](./policy/cspell/template/.cspell.json.snippet.json). Обовʼязковий запис у `import`: [.cspell.json.contains.json](./policy/cspell/template/.cspell.json.contains.json). Заборонено імпортувати окремі `@cspell/dict-*` у `.cspell.json`: [.cspell.json.deny.json](./policy/cspell/template/.cspell.json.deny.json).
|
|
196
196
|
|
|
197
|
+
`docs/adr/**` у канонічному `ignorePaths` — машинно-генеровані MADR-документи (драфти `capture-decisions.sh` + clean-ADR-и після `normalize-decisions.sh`). cspell-перевірка там безглузда: чернетка стирається наступним прогоном хук-ланцюжка, а будь-яка ручна правка правопису перезаписується. Локальні розширення `ignorePaths` дозволені — це лише мінімум.
|
|
198
|
+
|
|
197
199
|
```json title="package.json"
|
|
198
200
|
{
|
|
199
201
|
"scripts": {
|
|
@@ -230,7 +232,7 @@ version: '1.29'
|
|
|
230
232
|
{
|
|
231
233
|
"version": "0.2",
|
|
232
234
|
"language": "en,uk,ru-ru,nitra",
|
|
233
|
-
"ignorePaths": ["**/node_modules/**", "**/vscode-extension/**", "**/.git/**", ".vscode", "report", "*.svg", "**/k8s/**/*.yaml"],
|
|
235
|
+
"ignorePaths": ["**/node_modules/**", "**/vscode-extension/**", "**/.git/**", ".vscode", "report", "*.svg", "**/k8s/**/*.yaml", "docs/adr/**"],
|
|
234
236
|
"import": ["@nitra/cspell-dict/cspell-ext.json"],
|
|
235
237
|
"words": []
|
|
236
238
|
}
|
|
@@ -62,9 +62,11 @@ description: >-
|
|
|
62
62
|
- `ADR_NORMALIZE_BATCH=30` — більший батч (менше викликів LLM, більше токенів за раз).
|
|
63
63
|
- `ADR_NORMALIZE_MODEL=opus` — інша модель `claude -p`.
|
|
64
64
|
- `ADR_NORMALIZE_CURSOR_MODEL=…` — інша модель для cursor-agent fallback.
|
|
65
|
+
- `ADR_NORMALIZE_SKIP_TOOLING_ONLY=0` — вимкнути structural skip для tooling-only сесій (default `1`). Корисно лише якщо хочеш зберегти чернетки навіть для правок у `.cspell.json` / `CHANGELOG.md` / `version`-bump-ів.
|
|
65
66
|
|
|
66
67
|
## Якщо щось пішло не так
|
|
67
68
|
|
|
68
69
|
- LLM повернув криву JSON → у логу буде `invalid JSON response (first 200 chars): …`. Запусти ще раз — нерідко це разовий збій.
|
|
69
70
|
- Скрипт виходить миттєво без логу → перевір `ADR_NORMALIZE_RUNNING` у env (recursion guard) і чи репо не у стані merge/rebase.
|
|
70
71
|
- Перейменування зробило дублі імен (`<timestamp>-<slug>-2.md`) → це нормально, скрипт детермінований; під час review можна обʼєднати руками й видалити `-2`.
|
|
72
|
+
- ADR-чернетки видаляються мовчки → це structural tooling-only skip. Перевір лог: `tail .claude/hooks/normalize-decisions.log | grep tooling-only`. Для діагностики на capture-стороні: `tail .claude/hooks/capture-decisions.log | grep tooling-only`. Аби тимчасово вимкнути — `ADR_NORMALIZE_SKIP_TOOLING_ONLY=0 bash .claude/hooks/normalize-decisions.sh`.
|