@dzhechkov/p-replicator 1.5.5 → 1.5.7
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/LICENSE +21 -0
- package/README/eng/01_quickstart.md +244 -0
- package/README/eng/02_user_guide.md +634 -0
- package/README/eng/03_admin_guide.md +333 -0
- package/README/eng/04_api_reference.md +302 -0
- package/README/eng/05_architecture.md +370 -0
- package/README/eng/06_troubleshooting.md +353 -0
- package/README/eng/07_changelog.md +134 -0
- package/README/eng/README.md +60 -0
- package/README/ru/01_quickstart.md +244 -0
- package/README/ru/02_user_guide.md +633 -0
- package/README/ru/03_admin_guide.md +337 -0
- package/README/ru/04_api_reference.md +333 -0
- package/README/ru/05_architecture.md +372 -0
- package/README/ru/06_troubleshooting.md +355 -0
- package/README/ru/07_changelog.md +146 -0
- package/README/ru/README.md +60 -0
- package/README/ru/html/build.js +553 -0
- package/README/ru/html/index.html +1312 -0
- package/README/ru/html/script.js +496 -0
- package/README/ru/html/style.css +804 -0
- package/bin/cli.js +0 -0
- package/package.json +10 -10
- package/src/cli.js +7 -1
- package/src/commands/init.js +4 -1
- package/templates/.claude/agents/replicate-coordinator.md +23 -21
- package/templates/.claude/commands/replicate.md +4 -2
- package/templates/.claude/skills/cc-toolkit-generator-enhanced/modules/03-generate-p0.md +15 -0
- package/templates/.claude/skills/cc-toolkit-generator-enhanced/modules/04-generate-p1.md +20 -0
- package/templates/.claude/skills/cc-toolkit-generator-enhanced/modules/README.md +11 -0
- package/templates/.claude/skills/explore/SKILL.md +8 -5
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
# 05. Архитектура
|
|
2
|
+
|
|
3
|
+
Внутреннее устройство `p-replicator` — как ставится, как обновляется,
|
|
4
|
+
как сосуществует с user customizations.
|
|
5
|
+
|
|
6
|
+
## Двухуровневая модель: Pre-shipped vs Project-generated
|
|
7
|
+
|
|
8
|
+
Главное архитектурное разделение:
|
|
9
|
+
|
|
10
|
+
| Уровень | Кто создаёт | Где живёт | Изменяется |
|
|
11
|
+
|---|---|---|---|
|
|
12
|
+
| **Pre-shipped** | `npx p-replicator init` | `.claude/{skills,commands,agents,rules,hooks}/` + `settings.json` | На каждом upgrade пакета |
|
|
13
|
+
| **Project-generated** | `/replicate` Phase 3 (LLM execution) | Различные места: `CLAUDE.md`, `.claude/agents/planner.md`, `docs/`, и т.д. | Только при пересоздании |
|
|
14
|
+
|
|
15
|
+
Это **главный фикс** v1.4.0 — раньше `/replicate` Phase 3 пыталась генерировать
|
|
16
|
+
ВСЕ артефакты (включая generic команды как `/run`, `/feature`), что приводило
|
|
17
|
+
к flaky outputs (LLM compression, missed templates). После v1.4.0
|
|
18
|
+
generic-команды pre-shipped, Phase 3 генерирует ТОЛЬКО project-specific.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## SSOT: `utils.COMPONENTS`
|
|
23
|
+
|
|
24
|
+
Единый источник правды о том что shipped и что generated. Структура:
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
const COMPONENTS = {
|
|
28
|
+
// Pre-shipped (6 групп, install via npx init):
|
|
29
|
+
skills: { kind: 'pre-shipped', src: '.claude/skills', items: { /* 10 */ } },
|
|
30
|
+
commands: { kind: 'pre-shipped', src: '.claude/commands', items: { /* 11 */ } },
|
|
31
|
+
agents: { kind: 'pre-shipped', src: '.claude/agents', items: { /* 4 */ } },
|
|
32
|
+
rules: { kind: 'pre-shipped', src: '.claude/rules', items: { /* 5 */ } },
|
|
33
|
+
settings: { kind: 'pre-shipped', isFile: true, src: '.claude/settings.json' },
|
|
34
|
+
hooks: { kind: 'pre-shipped', src: '.claude/hooks', items: { /* 6 */ } },
|
|
35
|
+
|
|
36
|
+
// Project-generated (3 группы, created by /replicate Phase 3):
|
|
37
|
+
projectAgents: { kind: 'project-generated', items: { /* full paths */ } },
|
|
38
|
+
projectRules: { kind: 'project-generated', items: { /* full paths */ } },
|
|
39
|
+
projectFiles: { kind: 'project-generated', items: { /* full paths */ } },
|
|
40
|
+
};
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**Consumers:**
|
|
44
|
+
- `init.js` / `update.js` — итерируют только `kind === 'pre-shipped'` для install
|
|
45
|
+
- `doctor.js` — проверяет существование pre-shipped artifacts
|
|
46
|
+
- `list.js` — выводит metadata
|
|
47
|
+
- `verify.js` — проверяет ОБЕ группы (pre-shipped strict, project-generated
|
|
48
|
+
hints)
|
|
49
|
+
- `cli.js` showHelp — динамически считает items для отображения
|
|
50
|
+
|
|
51
|
+
**Любая будущая правка items автоматически обновляет все 5 поверхностей** —
|
|
52
|
+
устранены drift-проблемы которые были до v1.3.1.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Path derivation: `getItemRelativePath()`
|
|
57
|
+
|
|
58
|
+
Один helper централизует derivation для всех групп:
|
|
59
|
+
|
|
60
|
+
```javascript
|
|
61
|
+
function getItemRelativePath(comp, itemKey) {
|
|
62
|
+
if (comp.isFile) return comp.src; // settings.json
|
|
63
|
+
if (comp.kind === 'project-generated') return itemKey; // full paths
|
|
64
|
+
if (comp.src === '.claude/skills') return path.join(comp.src, itemKey, 'SKILL.md');
|
|
65
|
+
if (comp.src === '.claude/hooks') return path.join(comp.src, itemKey + '.cjs');
|
|
66
|
+
return path.join(comp.src, itemKey + '.md'); // commands/rules/agents
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Cross-platform hooks (v1.4.1)
|
|
73
|
+
|
|
74
|
+
**Дизайн-принцип:** zero shell dependency.
|
|
75
|
+
|
|
76
|
+
Все 6 hook-скриптов написаны на pure Node, используют `execFileSync('git', [...])`
|
|
77
|
+
вместо shell-pipes. Это эквивалентно работает на:
|
|
78
|
+
- Windows cmd.exe (нет `2>/dev/null`, есть `2>nul` — не нужен ни тот ни другой)
|
|
79
|
+
- Bash / zsh / Git Bash на Windows
|
|
80
|
+
- PowerShell
|
|
81
|
+
|
|
82
|
+
**Pattern для autocommit-скрипта:**
|
|
83
|
+
|
|
84
|
+
```javascript
|
|
85
|
+
const fs = require('node:fs');
|
|
86
|
+
const path = require('node:path');
|
|
87
|
+
const { execFileSync } = require('node:child_process');
|
|
88
|
+
|
|
89
|
+
const TARGET = path.resolve(process.cwd(), '.claude', 'feature-roadmap.json');
|
|
90
|
+
const SILENT = { stdio: 'ignore' };
|
|
91
|
+
const git = (args) => execFileSync('git', args, SILENT);
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
if (!fs.existsSync(TARGET)) process.exit(0);
|
|
95
|
+
try { git(['rev-parse', '--git-dir']); } catch { process.exit(0); }
|
|
96
|
+
git(['add', '--', TARGET]);
|
|
97
|
+
let hasDiff = false;
|
|
98
|
+
try { git(['diff', '--cached', '--quiet', '--', TARGET]); }
|
|
99
|
+
catch { hasDiff = true; }
|
|
100
|
+
if (hasDiff) git(['commit', '--only', '--', TARGET, '-m', '...']);
|
|
101
|
+
} catch { process.exit(0); }
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Defensive properties:**
|
|
105
|
+
- `if (!fs.existsSync) exit 0` — нет файла, нечего коммитить
|
|
106
|
+
- `try { rev-parse } catch { exit 0 }` — нет git репозитория, skip
|
|
107
|
+
- `try { diff } catch { hasDiff = true }` — `git diff --quiet` exits 1 if diff
|
|
108
|
+
- Outer `try/catch` гарантирует exit 0 при любых ошибках (best-effort)
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Sync-templates: MERGE mode (v1.4.1)
|
|
113
|
+
|
|
114
|
+
**Файл:** `scripts/sync-templates.js` — runs as `prepublishOnly` hook.
|
|
115
|
+
|
|
116
|
+
**Цель:** скопировать `.claude/` из source-repo в `templates/.claude/`
|
|
117
|
+
(который попадает в npm tarball).
|
|
118
|
+
|
|
119
|
+
**До v1.4.1 (BUG):** `cleanDir(target)` + `copyRecursive(source, target)` —
|
|
120
|
+
очищал target перед copy. Удалял файлы которые есть в `templates/` но нет в
|
|
121
|
+
source. Это **silently удалило все v1.4.0 pre-shipped команды** во время
|
|
122
|
+
`npm publish --dry-run`.
|
|
123
|
+
|
|
124
|
+
**После v1.4.1 (FIX):** `ensureDir(target)` + `copyRecursive(source, target)` —
|
|
125
|
+
копирует/перезаписывает source-файлы, но НЕ удаляет target-only. Pre-shipped
|
|
126
|
+
файлы выживают, source файлы overwrite'ят с правильным содержимым.
|
|
127
|
+
|
|
128
|
+
**Идемпотентность:** прогон 2 раза подряд → одинаковый result.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Settings.json merge (v1.4.2)
|
|
133
|
+
|
|
134
|
+
`init --force` и `update` используют `mergeSettingsJson(existing, template)`
|
|
135
|
+
для preserve user customizations:
|
|
136
|
+
|
|
137
|
+
### Алгоритм
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
mergeSettingsJson(existing, template):
|
|
141
|
+
if !existing: return template (fresh install)
|
|
142
|
+
if !template: return existing (defensive)
|
|
143
|
+
|
|
144
|
+
merged = {...existing}
|
|
145
|
+
|
|
146
|
+
# Top-level: template добавляет только то чего нет у user
|
|
147
|
+
for each (key, value) in template:
|
|
148
|
+
if key not in merged: merged[key] = value
|
|
149
|
+
|
|
150
|
+
# Hooks: deep merge per event type
|
|
151
|
+
if template.hooks:
|
|
152
|
+
merged.hooks = mergeHookEvents(existing.hooks, template.hooks)
|
|
153
|
+
|
|
154
|
+
return merged
|
|
155
|
+
|
|
156
|
+
mergeHookEvents(existing, template):
|
|
157
|
+
for each eventType in template:
|
|
158
|
+
if !existing[eventType]: existing[eventType] = template[eventType]
|
|
159
|
+
else: mergeHookMatchers(existing[eventType], template[eventType])
|
|
160
|
+
|
|
161
|
+
mergeHookMatchers(existing[], template[]):
|
|
162
|
+
for each tplEntry in template:
|
|
163
|
+
target = existing.find(e => e.matcher === tplEntry.matcher)
|
|
164
|
+
if !target: existing.push(tplEntry)
|
|
165
|
+
else:
|
|
166
|
+
existingCmds = Set(target.hooks.map(h => h.command))
|
|
167
|
+
for each tplHook in tplEntry.hooks:
|
|
168
|
+
if !existingCmds.has(tplHook.command):
|
|
169
|
+
target.hooks.push(tplHook) # de-dup by command string
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Identity model
|
|
173
|
+
|
|
174
|
+
Hooks сравниваются по `command` string. Implications:
|
|
175
|
+
|
|
176
|
+
- User-added hook (отсутствует в template): **preserved**
|
|
177
|
+
- User-modified default (изменил command): treated как user-added → **preserved**
|
|
178
|
+
(старый default удаляется через orphan detection если был в shippedDefaults)
|
|
179
|
+
- Identical command в template и user: **de-duped** (только одна копия)
|
|
180
|
+
- New hook in template: **added** к user's settings
|
|
181
|
+
|
|
182
|
+
### Override
|
|
183
|
+
|
|
184
|
+
`--reset-settings` flag отключает merge — full overwrite. Для случаев когда
|
|
185
|
+
user хочет clean-slate.
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Orphan detection (v1.4.3)
|
|
190
|
+
|
|
191
|
+
**Проблема merge-only логики:** если в новой версии package удаляет hook,
|
|
192
|
+
старый hook остаётся у user'а forever (user-added perspective).
|
|
193
|
+
|
|
194
|
+
**Решение:** `manifest.shippedDefaults` baseline.
|
|
195
|
+
|
|
196
|
+
### Алгоритм
|
|
197
|
+
|
|
198
|
+
```
|
|
199
|
+
init/update upgrade flow:
|
|
200
|
+
1. previousManifest = read .p-replicator.json BEFORE overwrite
|
|
201
|
+
2. oldTpl = previousManifest.shippedDefaults['settings.json']
|
|
202
|
+
3. newTpl = read templates/.claude/settings.json (current)
|
|
203
|
+
4. existing = read user's .claude/settings.json
|
|
204
|
+
5. cleaned = removeOrphanHooks(existing, oldTpl, newTpl)
|
|
205
|
+
6. merged = mergeSettingsJson(cleaned, newTpl)
|
|
206
|
+
7. write merged to .claude/settings.json
|
|
207
|
+
8. write new manifest with shippedDefaults = newTpl (для следующего upgrade)
|
|
208
|
+
|
|
209
|
+
removeOrphanHooks(existing, oldTpl, newTpl):
|
|
210
|
+
if !oldTpl: return existing (first upgrade, no baseline yet)
|
|
211
|
+
oldCmds = extractCommands(oldTpl)
|
|
212
|
+
newCmds = extractCommands(newTpl)
|
|
213
|
+
orphans = oldCmds.filter(c => !newCmds.has(c))
|
|
214
|
+
return existing with orphan commands filtered out
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Свойства
|
|
218
|
+
|
|
219
|
+
- **User-added** (никогда не было в `oldTpl`) → preserved
|
|
220
|
+
- **Removed default** (было в `oldTpl`, нет в `newTpl`, есть у user) → удалён
|
|
221
|
+
- **Unchanged default** (есть везде) → kept
|
|
222
|
+
- **Renamed/modified default** (cmd-string changed) → старый orphaned, новый
|
|
223
|
+
added через merge
|
|
224
|
+
|
|
225
|
+
### Backward compat
|
|
226
|
+
|
|
227
|
+
Если manifest без `shippedDefaults` (pre-1.4.3 install) — orphan detection
|
|
228
|
+
skipped на первый upgrade. Manifest заполняется на текущем install для
|
|
229
|
+
будущих upgrade'ов.
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Statusline architecture (v1.5.0)
|
|
234
|
+
|
|
235
|
+
**Цель:** single-script multi-line dashboard.
|
|
236
|
+
|
|
237
|
+
```
|
|
238
|
+
┌─ statusline.cjs (entry, ~330 LOC) ─────────────────────────┐
|
|
239
|
+
│ │
|
|
240
|
+
│ 1. main() │
|
|
241
|
+
│ ├── parseManifest() ───────► .p-replicator.json │
|
|
242
|
+
│ ├── parseState() ──────────► .claude/.p-replicator-state.json (with stale-check) │
|
|
243
|
+
│ ├── parseRoadmap() ────────► .claude/feature-roadmap.json │
|
|
244
|
+
│ ├── parseSparcDocs() ──────► docs/PRD.md, ..., ADR.md │
|
|
245
|
+
│ ├── parseValidationScore() ► docs/validation-report.md (regex) │
|
|
246
|
+
│ ├── parseAdrs() ───────────► docs/ADR.md OR docs/adr/ OR docs/ddd/adr/ │
|
|
247
|
+
│ ├── parsePlans() ──────────► docs/plans/*.md │
|
|
248
|
+
│ ├── parseInsights() ───────► .claude/insights/index.md │
|
|
249
|
+
│ ├── parseToolkit() ────────► filesystem walks │
|
|
250
|
+
│ ├── parseSettingsStatus() ─► deep-equals current vs shippedDefaults │
|
|
251
|
+
│ ├── parseMcpServers() ─────► .mcp.json │
|
|
252
|
+
│ ├── parseKeysarium() ──────► .keysarium.json existence │
|
|
253
|
+
│ ├── parseDomain() ─────────► CLAUDE.md keyword grep │
|
|
254
|
+
│ ├── parseLastHarvest() ────► TOOLKIT_HARVEST.md mtime │
|
|
255
|
+
│ └── parseLastTest() ───────► .claude/.last-test.json (optional) │
|
|
256
|
+
│ │
|
|
257
|
+
│ 2. lines = [ │
|
|
258
|
+
│ buildHeader(manifest), │
|
|
259
|
+
│ buildPipeline(state), │
|
|
260
|
+
│ buildRoadmap(roadmap, domain), │
|
|
261
|
+
│ buildDocs(sparc, validation, plans, adrs, lastHarvest), │
|
|
262
|
+
│ buildToolkit(toolkit, expected), │
|
|
263
|
+
│ buildStatus(insights, lastTest, mcpServers, settingsStatus, keysarium), │
|
|
264
|
+
│ ] │
|
|
265
|
+
│ │
|
|
266
|
+
│ 3. process.stdout.write(lines.join('\n') + '\n') │
|
|
267
|
+
│ │
|
|
268
|
+
└─────────────────────────────────────────────────────────────┘
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**Defensive design:** каждая `parse*` функция wrapped в `safeRun()` с
|
|
272
|
+
fallback. Один parse error → fallback value, остальные секции работают.
|
|
273
|
+
|
|
274
|
+
**State-file flow:**
|
|
275
|
+
|
|
276
|
+
```
|
|
277
|
+
команда (e.g., /run) ──Bash──► node .claude/hooks/state-update.cjs --command /run --phase loop --progress 0.4
|
|
278
|
+
│
|
|
279
|
+
▼
|
|
280
|
+
.claude/.p-replicator-state.json (atomic write)
|
|
281
|
+
▲
|
|
282
|
+
│
|
|
283
|
+
Claude Code prompt ────────► node .claude/hooks/statusline.cjs
|
|
284
|
+
│
|
|
285
|
+
▼
|
|
286
|
+
читает state, считает heuristics, рендерит 6 строк
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
**Stale check:** state старше 30 минут → ignore (показывается `idle` в Pipeline
|
|
290
|
+
секции).
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## Test infrastructure
|
|
295
|
+
|
|
296
|
+
**Suite:** 105 tests, 36 suites, ~25 sec runtime.
|
|
297
|
+
|
|
298
|
+
| Layer | File | Coverage |
|
|
299
|
+
|---|---|---|
|
|
300
|
+
| **Unit** | `tests/unit/utils.test.js` (54 tests) | Pure functions: createManifest, mergeSettingsJson, removeOrphanHooks, getItemRelativePath, parseToolkit logic |
|
|
301
|
+
| **E2E** | `tests/e2e/lifecycle.test.js` (48 tests) | Full CLI lifecycle, hooks installation, settings merge edge cases, statusline output, --feature-branches docs |
|
|
302
|
+
| **Snapshot** | `tests/snapshot/templates.test.js` (3 tests) | SHA-256 baseline для всех 115 файлов в `templates/` |
|
|
303
|
+
|
|
304
|
+
**Меta-тесты:** проверяют consistency между документами. Например:
|
|
305
|
+
- `replicate-pipeline.md` упоминает все pre-shipped commands (no orphan in rule)
|
|
306
|
+
- `replicate.md` Phase 3 не утверждает «Generate `<pre-shipped>.md`» (no
|
|
307
|
+
drift в spec)
|
|
308
|
+
|
|
309
|
+
**Snapshot baseline** регенерируется через `npm run snapshot:baseline` после
|
|
310
|
+
intentional template changes.
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## Module composition: `view()` syntax (Claude Code-specific)
|
|
315
|
+
|
|
316
|
+
Skills используют `view()` для cross-skill loading в runtime:
|
|
317
|
+
|
|
318
|
+
```markdown
|
|
319
|
+
view() .claude/skills/explore/SKILL.md
|
|
320
|
+
view() .claude/skills/explore/references/questioning-techniques.md
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Claude Code разрешает эти ссылки динамически: при выполнении skill,
|
|
324
|
+
LLM читает referenced files в момент использования. Это позволяет skill A
|
|
325
|
+
делегировать в skill B без duplicate-копий контента.
|
|
326
|
+
|
|
327
|
+
**Ограничение:** только Claude Code поддерживает этот runtime-механизм. Для
|
|
328
|
+
других платформ (Codex, OpenCode) skill content должен быть **inlined**
|
|
329
|
+
(скомпилирован в command markdown) на install-time. См.
|
|
330
|
+
`MULTIPLATFORM_ROADMAP.md`.
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## Pipeline: `/replicate` фазы
|
|
335
|
+
|
|
336
|
+
```
|
|
337
|
+
INPUT (idea or company name)
|
|
338
|
+
│
|
|
339
|
+
▼
|
|
340
|
+
Phase 0: PRODUCT DISCOVERY (опц.)
|
|
341
|
+
│ skill: reverse-engineering-unicorn
|
|
342
|
+
│ output: docs/00_product_discovery.md
|
|
343
|
+
▼
|
|
344
|
+
Phase 1: PLANNING
|
|
345
|
+
│ skill: sparc-prd-mini (внутри: explore + research + solve + 5 SPARC phases)
|
|
346
|
+
│ output: docs/PRD.md, Architecture.md, Pseudocode.md, ... (11 docs)
|
|
347
|
+
▼
|
|
348
|
+
Phase 2: VALIDATION (5-agent swarm)
|
|
349
|
+
│ skill: requirements-validator
|
|
350
|
+
│ output: docs/validation-report.md, docs/test-scenarios.md (BDD)
|
|
351
|
+
│ verdict: 🟢 READY / 🟡 CAVEATS / 🔴 NEEDS WORK (max 3 retries)
|
|
352
|
+
▼
|
|
353
|
+
Phase 3: TOOLKIT GENERATION (project-specific only)
|
|
354
|
+
│ skill: cc-toolkit-generator-enhanced (9 modules)
|
|
355
|
+
│ output: project agents (planner, code-reviewer, architect),
|
|
356
|
+
│ project rules (security, coding-style, testing),
|
|
357
|
+
│ project skills (project-context, coding-standards),
|
|
358
|
+
│ CLAUDE.md, feature-roadmap.json, DEVELOPMENT_GUIDE.md
|
|
359
|
+
▼
|
|
360
|
+
Phase 4: FINALIZE
|
|
361
|
+
│ output: docker-compose.yml, Dockerfile, .gitignore
|
|
362
|
+
│ action: git commit
|
|
363
|
+
▼
|
|
364
|
+
DONE — project готов к /start или /run
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## Дальше
|
|
370
|
+
|
|
371
|
+
- [06_troubleshooting.md](./06_troubleshooting.md) — типичные проблемы
|
|
372
|
+
- [07_changelog.md](./07_changelog.md) — история эволюции
|