@7n/rules 1.43.1 → 1.44.1
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/CHANGELOG.md +21 -0
- package/docs/vitest.config.md +14 -19
- package/package.json +1 -1
- package/rules/abie/lib/docs/index.md +0 -2
- package/rules/abie/lib/http-route.mjs +1 -0
- package/rules/abie/lib/yaml.mjs +2 -0
- package/rules/ci4/marksman_config/docs/index.md +10 -0
- package/rules/ci4/marksman_config/main.mjs +2 -0
- package/rules/doc-files/docgen-prompts/docs/index.md +9 -0
- package/rules/doc-files/docgen-prompts/main.mjs +5 -0
- package/rules/hasura/internal_urls/docs/index.md +0 -2
- package/rules/hasura/internal_urls/docs/main.md +27 -15
- package/rules/hasura/internal_urls/main.mjs +1 -0
- package/rules/image-avif/avif_generation/docs/index.md +10 -0
- package/rules/image-avif/avif_generation/main.mjs +2 -0
- package/rules/rego/vscode_settings/docs/fix-vscode_settings.md +12 -10
- package/rules/rego/vscode_settings/fix-vscode_settings.mjs +5 -0
- package/rules/tauri/cargo_mutants_config/docs/index.md +0 -2
- package/rules/tauri/cargo_mutants_config/docs/main.md +38 -12
- package/rules/tauri/cargo_mutants_config/main.mjs +5 -1
- package/rules/tauri/core_test_isolation/docs/main.md +19 -16
- package/rules/tauri/core_test_isolation/main.mjs +3 -1
- package/rules/tauri/linux_deps/docs/main.md +25 -18
- package/rules/tauri/linux_deps/main.mjs +2 -1
- package/rules/tauri/release/docs/main.md +20 -12
- package/rules/tauri/release/main.mjs +2 -0
- package/rules/tauri/updater/docs/main.md +31 -14
- package/rules/tauri/updater/main.mjs +4 -0
- package/rules/test/coverage/concern.json +9 -0
- package/rules/test/coverage/fix-worker.mjs +111 -0
- package/rules/test/coverage/lib/classify/apply.mjs +67 -0
- package/rules/test/coverage/lib/classify/cache.mjs +77 -0
- package/rules/test/coverage/lib/classify/docs/apply.md +28 -0
- package/rules/test/coverage/lib/classify/docs/cache.md +34 -0
- package/rules/test/coverage/lib/classify/docs/index.md +37 -0
- package/rules/test/coverage/lib/classify/docs/prompt.md +30 -0
- package/rules/test/coverage/lib/classify/docs/verdict-schema.md +30 -0
- package/rules/test/coverage/lib/classify/index.mjs +140 -0
- package/rules/test/coverage/lib/classify/prompt.mjs +136 -0
- package/rules/test/coverage/lib/classify/verdict-schema.mjs +163 -0
- package/rules/test/coverage/lib/llm.mjs +100 -0
- package/rules/test/coverage/main.mjs +161 -0
- package/rules/test/main.json +1 -0
- package/rules/test/main.mdc +140 -0
- package/rules/test/package_json/concern.json +11 -0
- package/rules/test/package_json/package_json.mdc +18 -0
- package/rules/test/package_json/package_json.rego +25 -0
- package/rules/test/package_json/template/package.json.contains.json +6 -0
- package/rules/text/oxfmtrc/fix-oxfmtrc.mjs +5 -0
- package/rules/text/vscode_settings/fix-vscode_settings.mjs +5 -0
- package/rules/worktree/vscode_settings/docs/fix-vscode_settings.md +10 -7
- package/rules/worktree/vscode_settings/fix-vscode_settings.mjs +5 -0
- package/rules/worktree/zed_settings/fix-zed_settings.mjs +5 -0
- package/schemas/n-rules.json +18 -1
- package/scripts/lib/adr/docs/index.md +0 -2
- package/scripts/lib/adr/docs/normalize-pipeline.md +44 -28
- package/scripts/lib/adr/normalize-pipeline.mjs +11 -0
- package/scripts/lib/auto-worktree.mjs +9 -3
- package/scripts/lib/docs/auto-worktree.md +50 -12
- package/scripts/lib/docs/inline-template-links.md +17 -8
- package/scripts/lib/docs/plugin-api.md +1 -1
- package/scripts/lib/docs/worktree-notice.md +65 -10
- package/scripts/lib/inline-template-links.mjs +5 -0
- package/scripts/lib/lint-surface/docs/run-detectors.md +25 -22
- package/scripts/lib/lint-surface/docs/tier-sampling-experiment.md +30 -14
- package/scripts/lib/lint-surface/run-detectors.mjs +1 -1
- package/scripts/lib/lint-surface/tier-sampling-experiment.mjs +1 -0
- package/scripts/lib/plugin-api.mjs +46 -0
- package/scripts/lib/worktree-notice.mjs +5 -3
- package/scripts/utils/docs/walkDir.md +26 -15
- package/scripts/utils/docs/worktree-fingerprint.md +16 -15
- package/scripts/utils/walkDir.mjs +9 -5
- package/scripts/utils/worktree-fingerprint.mjs +5 -0
- package/skills/storybook/SKILL.md +4 -4
- package/skills/taze/js/migration-cache.mjs +1 -1
|
@@ -78,6 +78,52 @@ export const PLUGIN_API_VERSION = 1
|
|
|
78
78
|
const REQUIRED_PROVIDER_FUNCTIONS = ['detect', 'available', 'backup', 'bump', 'diff', 'promptFor', 'cleanup']
|
|
79
79
|
const REQUIRED_PROVIDER_STRINGS = ['id', 'title', 'manifestNoun', 'skillSection']
|
|
80
80
|
|
|
81
|
+
/**
|
|
82
|
+
* @typedef {object} CoverageRow
|
|
83
|
+
* Агрегований вимір однієї області (`JS`, `Vue (Storybook)`, `Rust`, …).
|
|
84
|
+
* @property {string} area назва рядка звіту
|
|
85
|
+
* @property {{lines:{covered:number,total:number}, functions:{covered:number,total:number}}} coverage line/function coverage
|
|
86
|
+
* @property {{caught:number, total:number}} mutation вбиті/всі мутанти (0/0 — мутаційне тестування не вимірювалось)
|
|
87
|
+
* @property {Array<{file:string, mutants:Array<object>, exampleTest?:object|null, recommendationText?:string|null}>} survived вцілілі мутанти по файлах (шляхи relative до cwd)
|
|
88
|
+
*/
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @typedef {object} CoverageProvider
|
|
92
|
+
* Порт мовної екосистеми для концерну `coverage` правила `test` (spec
|
|
93
|
+
* 2026-07-22 absorb-7n-test). Ядро викликає: `detect` → повний вимір
|
|
94
|
+
* `collect` (full/`lint test`) АБО делта-вимір `collectPerFile` (делта-lint,
|
|
95
|
+
* без мутаційного тестування). Реєстрація — `contributes.handlers.coverage`
|
|
96
|
+
* у маніфесті плагіна, default-експорт handler-модуля.
|
|
97
|
+
* @property {string} id стабільний ідентифікатор екосистеми (напр. `js`)
|
|
98
|
+
* @property {string} title заголовок для звітів/повідомлень
|
|
99
|
+
* @property {(cwd: string) => Promise<boolean>} detect чи застосовний вимір у проєкті (false → тихий skip виміру)
|
|
100
|
+
* @property {(cwd: string, opts?: {changedFiles?: string[], base?: string|null, runner?: object}) => Promise<CoverageRow[]>} collect повний вимір: coverage + мутаційне тестування по всіх workspaces
|
|
101
|
+
* @property {(cwd: string, opts: {files: string[], runner?: object}) => Promise<Array<{file:string, pct:number, linesFound:number, linesCovered:number, reason?:string}>>} collectPerFile легкий делта-вимір per-file line coverage змінених файлів (без мутаційного тестування)
|
|
102
|
+
*/
|
|
103
|
+
|
|
104
|
+
const REQUIRED_COVERAGE_FUNCTIONS = ['detect', 'collect', 'collectPerFile']
|
|
105
|
+
const REQUIRED_COVERAGE_STRINGS = ['id', 'title']
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Валідує форму coverage-провайдера з модуля плагіна.
|
|
109
|
+
* @param {unknown} candidate default-експорт handler-модуля плагіна
|
|
110
|
+
* @param {string} source ім'я плагіна/шлях модуля для повідомлення
|
|
111
|
+
* @returns {CoverageProvider} той самий обʼєкт, якщо валідний
|
|
112
|
+
*/
|
|
113
|
+
export function assertCoverageProvider(candidate, source) {
|
|
114
|
+
if (!candidate || typeof candidate !== 'object') {
|
|
115
|
+
throw new TypeError(`plugin-api: ${source} — default-експорт не є обʼєктом CoverageProvider`)
|
|
116
|
+
}
|
|
117
|
+
const missing = [
|
|
118
|
+
...REQUIRED_COVERAGE_STRINGS.filter(k => typeof candidate[k] !== 'string' || candidate[k] === ''),
|
|
119
|
+
...REQUIRED_COVERAGE_FUNCTIONS.filter(k => typeof candidate[k] !== 'function')
|
|
120
|
+
]
|
|
121
|
+
if (missing.length > 0) {
|
|
122
|
+
throw new TypeError(`plugin-api: ${source} — CoverageProvider без обовʼязкових полів: ${missing.join(', ')}`)
|
|
123
|
+
}
|
|
124
|
+
return /** @type {CoverageProvider} */ (candidate)
|
|
125
|
+
}
|
|
126
|
+
|
|
81
127
|
/**
|
|
82
128
|
* Валідує форму провайдера з модуля плагіна — зрозуміла помилка замість
|
|
83
129
|
* «undefined is not a function» глибоко в оркестраторі.
|
|
@@ -133,7 +133,9 @@ git branch --show-current
|
|
|
133
133
|
|
|
134
134
|
**Root-assert.** Якщо \`pwd\` **не** збігається з виводом \`git rev-parse --show-toplevel\` — ти в **піддиректорії** робочого дерева (worktree-шляхи нижче відносні до кореня репо). Спершу перейди в корінь: \`cd <toplevel>\` (literal-шлях із виводу), і лише тоді продовжуй preflight. Не створюй worktree з піддиректорії — \`cd .worktrees/<…>\` звідти впаде.
|
|
135
135
|
|
|
136
|
-
Якщо \`git rev-parse --show-toplevel\`
|
|
136
|
+
**Вже ізольований — нічого не створюй.** Якщо \`git rev-parse --show-toplevel\` містить сегмент \`.worktrees/<…>\` (репо-конвенція) **або** \`.claude/worktrees/<…>\` (worktree харнесу Claude Code — туди \`npx @7n/mt worktree create\` класти заборонено, \`n-worktree.mdc\`) — ти вже виконуєшся в окремому git-worktree. Preflight пройдено: нічого не створюй, нікого не питай про назву гілки — переходь одразу до Кроку 0.1.
|
|
137
|
+
|
|
138
|
+
Інакше, якщо toplevel не містить жодного з цих сегментів, візьми вивід \`git branch --show-current\` як \`<current-branch>\` і виконай **literal-команди без shell expansion** (без command substitution, variable expansion чи backticks). Наприклад, якщо поточна гілка \`feature/x\`:
|
|
137
139
|
|
|
138
140
|
\`\`\`bash
|
|
139
141
|
npx @7n/mt worktree create "feature/x-${suffix}" "n-${suffix}: worktree-only skill"
|
|
@@ -142,10 +144,10 @@ cd ".worktrees/feature-x-${suffix}"
|
|
|
142
144
|
|
|
143
145
|
Тобто branch-argument лишає slash як у git-гілці, а шлях для \`cd\` бере sanitized форму: slash → \`-\`.
|
|
144
146
|
|
|
145
|
-
**Крок 0.1 — bootstrap
|
|
147
|
+
**Крок 0.1 — bootstrap (якщо в дереві ще нема \`node_modules\`).** Свіжостворений worktree (Крок 0) точно без \`node_modules\`; вже ізольований harness-worktree може мати їх або ні — постав локально, тоді \`npx @7n/rules <cmd>\` бере локальну копію без походу в реєстр:
|
|
146
148
|
|
|
147
149
|
\`\`\`bash
|
|
148
|
-
bun install
|
|
150
|
+
test -d node_modules || bun install
|
|
149
151
|
\`\`\``
|
|
150
152
|
}
|
|
151
153
|
|
|
@@ -3,31 +3,42 @@ type: JS Module
|
|
|
3
3
|
title: walkDir.mjs
|
|
4
4
|
resource: npm/scripts/utils/walkDir.mjs
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
7
|
-
model:
|
|
6
|
+
crc: 1bbc24bc
|
|
7
|
+
model: openai-codex/gpt-5.5
|
|
8
|
+
tier: cloud-avg
|
|
8
9
|
score: 100
|
|
10
|
+
judgeModel: openai-codex/gpt-5.4-mini
|
|
9
11
|
---
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
## Огляд
|
|
14
|
+
|
|
15
|
+
Файл описує правила пропуску службових і агентських шляхів під час читання репозиторію. `WORKTREE_CHECKOUT_GLOBS` задає шаблони агентських worktree-копій, `ALWAYS_IGNORE` фіксує завжди ігноровані `.git` і `node_modules`.
|
|
16
|
+
|
|
17
|
+
`isWorktreeCheckoutPath` перевіряє вже відомий відносний шлях на належність до агентського worktree. `walkDir` виконує fail-safe обхід файлового дерева: перехоплює помилки читання і не передає винятки назовні.
|
|
12
18
|
|
|
13
19
|
## Поведінка
|
|
14
20
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
`WORKTREE_CHECKOUT_GLOBS` задає спільне правило безпеки для агентських worktree-копій, щоб обхід не сприймав дублікати репозиторію як робочий код.
|
|
22
|
+
|
|
23
|
+
`ALWAYS_IGNORE` розширює це правило постійними пропусками `.git` і `node_modules`; ці винятки застосовуються під час повного обходу незалежно від налаштувань репозиторію.
|
|
24
|
+
|
|
25
|
+
`walkDir` приймає корінь обходу, додає до спільних правил додаткові локальні винятки, читає файлове дерево з урахуванням `.gitignore` і передає знайдені файли далі як абсолютні шляхи. Якщо обхід неможливий, він завершується без помилки назовні, щоб перевірки залишались fail-safe.
|
|
26
|
+
|
|
27
|
+
`isWorktreeCheckoutPath` використовує те саме смислове правило пропуску worktree-чекаутів для уже наявних відносних шляхів, які не проходять через `walkDir`, наприклад зі списків git.
|
|
22
28
|
|
|
23
29
|
## Публічний API
|
|
24
30
|
|
|
25
|
-
-
|
|
26
|
-
|
|
27
|
-
|
|
31
|
+
- WORKTREE_CHECKOUT_GLOBS — Сесійні git-worktree чекаути (Claude/агенти): повні копії репо, не робочий код.
|
|
32
|
+
Споживацькі репо часто не мають цих шляхів у .gitignore, тож без safety net
|
|
33
|
+
lint-обхід бачив би дубль усього дерева.
|
|
34
|
+
- ALWAYS_IGNORE — .git ніколи не потрапляє в .gitignore — пропускаємо завжди.
|
|
35
|
+
node_modules — safety net: проєкт може не мати .gitignore або запускатись поза git-репо.
|
|
36
|
+
- isWorktreeCheckoutPath — Чи лежить відносний posix-шлях усередині worktree-чекаута (`.worktrees/` або
|
|
37
|
+
`.claude/worktrees/`). Для фільтрації git-списків, що не проходять через walkDir.
|
|
38
|
+
- walkDir — Рекурсивно обходить каталог, поважаючи .gitignore (включно з вкладеними).
|
|
28
39
|
|
|
29
40
|
## Гарантії поведінки
|
|
30
41
|
|
|
31
|
-
-
|
|
42
|
+
- Власних операцій запису (ФС/БД) у файлі немає; виклики імпортованих модулів можуть писати.
|
|
32
43
|
- Перехоплює помилки і не пропускає винятків назовні (fail-safe).
|
|
33
|
-
- Свідомо пропускає шляхи: `.git`, `node_modules
|
|
44
|
+
- Свідомо пропускає шляхи: `.git`, `node_modules`.
|
|
@@ -3,29 +3,30 @@ type: JS Module
|
|
|
3
3
|
title: worktree-fingerprint.mjs
|
|
4
4
|
resource: npm/scripts/utils/worktree-fingerprint.mjs
|
|
5
5
|
docgen:
|
|
6
|
-
crc:
|
|
6
|
+
crc: 38831a93
|
|
7
|
+
model: openai-codex/gpt-5.4-mini
|
|
8
|
+
tier: cloud-min
|
|
9
|
+
score: 100
|
|
10
|
+
judgeModel: openai-codex/gpt-5.4-mini
|
|
7
11
|
---
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
## Огляд
|
|
14
|
+
|
|
15
|
+
`worktreeFingerprint` формує стабільний fingerprint git-робочого дерева з `HEAD`, diff і `untracked`-файлів. Це потрібно, щоб розпізнавати той самий стан дерева й дедуплікувати повторні `lint --full` прогони без змін.
|
|
10
16
|
|
|
11
17
|
## Поведінка
|
|
12
18
|
|
|
13
|
-
1.
|
|
14
|
-
2.
|
|
15
|
-
3.
|
|
16
|
-
4.
|
|
17
|
-
5.
|
|
18
|
-
6.
|
|
19
|
-
7. Повертає отриманий SHA256 хеш у форматі 64-значної шестнадцяткової строки.
|
|
20
|
-
8. Якщо виникає помилка під час виконання будь-якої з операцій, повертає `null`.
|
|
19
|
+
1. worktreeFingerprint визначає, чи поточне git-робоче дерево вже має унікальний стан для повторного повного lint-прогону.
|
|
20
|
+
2. Якщо дерево не належить git-репо або перевірку неможливо виконати, повертає `null`.
|
|
21
|
+
3. Інакше бере базовий стан з `HEAD`, додає різницю від `HEAD` і враховує всі untracked-файли, щоб зміна вмісту або набору нових файлів впливала на результат.
|
|
22
|
+
4. Для untracked-файлів формує впорядковану сукупність «шлях + вміст», щоб однаковий набір файлів давав той самий fingerprint незалежно від порядку їх виявлення.
|
|
23
|
+
5. На основі цього зводить весь стан дерева в один SHA-256 fingerprint у вигляді hex-рядка.
|
|
24
|
+
6. Використовується як стабільний маркер незміненого дерева для відсікання повторних повних lint-прогонів.
|
|
21
25
|
|
|
22
26
|
## Публічний API
|
|
23
27
|
|
|
24
|
-
worktreeFingerprint —
|
|
28
|
+
- worktreeFingerprint — Fingerprint поточного стану git-робочого дерева.
|
|
25
29
|
|
|
26
30
|
## Гарантії поведінки
|
|
27
31
|
|
|
28
|
-
-
|
|
29
|
-
- Функція повертає `null`, якщо обчислення відбитка дерева робіт не вдалося.
|
|
30
|
-
- Функція не викликає винятків.
|
|
31
|
-
- Функція не використовує кеш.
|
|
32
|
+
- (специфічних машинно-виведених гарантій немає)
|
|
@@ -2,13 +2,17 @@
|
|
|
2
2
|
import { join, relative, resolve, sep } from 'node:path'
|
|
3
3
|
import { globby } from 'globby'
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Сесійні git-worktree чекаути (Claude/агенти): повні копії репо, не робочий код.
|
|
7
|
+
* Споживацькі репо часто не мають цих шляхів у .gitignore, тож без safety net
|
|
8
|
+
* lint-обхід бачив би дубль усього дерева.
|
|
9
|
+
*/
|
|
8
10
|
export const WORKTREE_CHECKOUT_GLOBS = ['**/.worktrees/**', '**/.claude/worktrees/**']
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
+
/**
|
|
13
|
+
* .git ніколи не потрапляє в .gitignore — пропускаємо завжди.
|
|
14
|
+
* node_modules — safety net: проєкт може не мати .gitignore або запускатись поза git-репо.
|
|
15
|
+
*/
|
|
12
16
|
export const ALWAYS_IGNORE = ['.git/**', 'node_modules/**', ...WORKTREE_CHECKOUT_GLOBS]
|
|
13
17
|
|
|
14
18
|
const WORKTREE_CHECKOUT_RE = /(?:^|\/)(?:\.worktrees|\.claude\/worktrees)\//u
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fingerprint git-робочого дерева (HEAD + diff + untracked-файли) —
|
|
3
|
+
* використовується для дедуплікації повторних lint --full прогонів на
|
|
4
|
+
* незміненому дереві.
|
|
5
|
+
*/
|
|
1
6
|
import { spawnSync } from 'node:child_process'
|
|
2
7
|
import { createHash } from 'node:crypto'
|
|
3
8
|
|
|
@@ -12,7 +12,7 @@ version: '1.0'
|
|
|
12
12
|
|
|
13
13
|
Джерело рішення: `docs/adr/канон-storybook-для-vue-компонентних-бібліотек.md`. Уся логіка канону
|
|
14
14
|
(скоуп, скафолд, vitest-конфіг, гігієна залежностей, adopt-діагностика) живе в правилі `storybook`
|
|
15
|
-
пакета `@7n/rules-lang-js` (`node_modules/@7n/rules-lang-js/rules/
|
|
15
|
+
пакета `@7n/rules-lang-js` (`node_modules/@7n/rules-lang-js/rules/test/`) — цей скіл лише
|
|
16
16
|
тонка обгортка запуску, за зразком `doc-files`.
|
|
17
17
|
|
|
18
18
|
## Передумови
|
|
@@ -50,14 +50,14 @@ npx @7n/rules lint storybook
|
|
|
50
50
|
|
|
51
51
|
```bash
|
|
52
52
|
# Діагностика всіх пакетів у скоупі (без запису)
|
|
53
|
-
bun node_modules/@7n/rules-lang-js/rules/storybook
|
|
53
|
+
bun node_modules/@7n/rules-lang-js/rules/test/storybook-adopt/main.mjs
|
|
54
54
|
|
|
55
55
|
# + генерація повністю відсутніх секцій (main.js/preview.js/mocks/scripts/vitest-конфіги
|
|
56
56
|
# лишаються недоторканими, якщо вже існують хоч у якомусь вигляді)
|
|
57
|
-
bun node_modules/@7n/rules-lang-js/rules/storybook
|
|
57
|
+
bun node_modules/@7n/rules-lang-js/rules/test/storybook-adopt/main.mjs --fix-missing
|
|
58
58
|
|
|
59
59
|
# Звузити діагностику до конкретних пакетів (root dir, той самий формат що storybook.optOut)
|
|
60
|
-
bun node_modules/@7n/rules-lang-js/rules/storybook
|
|
60
|
+
bun node_modules/@7n/rules-lang-js/rules/test/storybook-adopt/main.mjs --fix-missing packages/ui packages/legacy-ui
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
Прогін через прямий виклик скрипта плагіна (`node_modules/@7n/rules-lang-js/...`) — CLI-плюмбінг
|
|
@@ -69,7 +69,7 @@ export async function writeMigrationCache(pkg, from, to, entry, deps = {}) {
|
|
|
69
69
|
|
|
70
70
|
/**
|
|
71
71
|
* Дописує до промпта `provider.promptFor(entry)` підсумок відомої міграції,
|
|
72
|
-
* якщо кеш її знайшов — каже
|
|
72
|
+
* якщо кеш її знайшов — каже runner-у пропустити крок 1 (CHANGELOG/diff-
|
|
73
73
|
* дослідження) і одразу шукати використання в поточному проєкті.
|
|
74
74
|
* @param {string} prompt базовий промпт з `provider.promptFor(entry)`
|
|
75
75
|
* @param {{notes: string, sourceRepo: string}} cached кешований запис
|