claudeos-core 2.4.0 → 2.4.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 +57 -3
- package/README.de.md +139 -79
- package/README.es.md +140 -80
- package/README.fr.md +140 -80
- package/README.hi.md +140 -80
- package/README.ja.md +142 -82
- package/README.ko.md +140 -80
- package/README.md +140 -80
- package/README.ru.md +140 -80
- package/README.vi.md +140 -80
- package/README.zh-CN.md +165 -105
- package/package.json +1 -1
package/README.ru.md
CHANGED
|
@@ -7,7 +7,11 @@
|
|
|
7
7
|
[](LICENSE)
|
|
8
8
|
[](https://www.npmjs.com/package/claudeos-core)
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
**Заставьте Claude Code следовать конвенциям _именно вашего_ проекта с первой попытки — а не общим дефолтам.**
|
|
11
|
+
|
|
12
|
+
Детерминированный Node.js scanner сначала читает ваш код; затем 4-pass конвейер Claude пишет полный набор — `CLAUDE.md` + автоматически загружаемые `.claude/rules/` + standards + skills + L4 memory. 10 языков вывода, 5 post-generation validator-ов и явный path allowlist, не позволяющий LLM выдумывать файлы или фреймворки, отсутствующие в вашем коде.
|
|
13
|
+
|
|
14
|
+
Работает на [**12 стеках**](#supported-stacks) (включая monorepo) — одна команда `npx`, без конфигурации, resume-safe, идемпотентно.
|
|
11
15
|
|
|
12
16
|
```bash
|
|
13
17
|
npx claudeos-core init
|
|
@@ -19,18 +23,28 @@ npx claudeos-core init
|
|
|
19
23
|
|
|
20
24
|
## Что это такое?
|
|
21
25
|
|
|
22
|
-
Вы используете Claude Code. Он
|
|
23
|
-
|
|
24
|
-
- Ваша
|
|
25
|
-
-
|
|
26
|
+
Вы используете Claude Code. Он мощный, но каждая сессия начинается с нуля — у него нет памяти о том, как устроен _ваш_ проект. Поэтому он откатывается на «в целом хорошие» дефолты, которые редко совпадают с тем, что реально делает ваша команда:
|
|
27
|
+
|
|
28
|
+
- Ваша команда использует **MyBatis**, а Claude генерирует JPA-репозитории.
|
|
29
|
+
- Ваша обёртка для ответов — `ApiResponse.ok()`, а Claude пишет `ResponseEntity.success()`.
|
|
30
|
+
- Ваши пакеты — layer-first (`controller/order/`), а Claude создаёт domain-first (`order/controller/`).
|
|
31
|
+
- Ваши ошибки идут через централизованный middleware, а Claude разбрасывает `try/catch` по каждому endpoint.
|
|
32
|
+
|
|
33
|
+
Хочется иметь набор `.claude/rules/` для каждого проекта — Claude Code автоматически загружает его в каждой сессии — но писать эти rules вручную для каждого нового repo занимает часы, и они расходятся с кодом по мере его эволюции.
|
|
34
|
+
|
|
35
|
+
**ClaudeOS-Core пишет их за вас, прямо из вашего реального исходного кода.** Детерминированный Node.js scanner сначала читает ваш проект (стек, ORM, layout пакетов, конвенции, пути файлов). Затем 4-pass конвейер Claude превращает извлечённые факты в полный набор документации:
|
|
26
36
|
|
|
27
|
-
|
|
37
|
+
- **`CLAUDE.md`** — индекс проекта, который Claude читает в каждой сессии
|
|
38
|
+
- **`.claude/rules/`** — автоматически загружаемые rules по категориям (`00.core` / `10.backend` / `20.frontend` / `30.security-db` / `40.infra` / `60.memory` / `70.domains` / `80.verification`)
|
|
39
|
+
- **`claudeos-core/standard/`** — справочные документы («почему» за каждым rule)
|
|
40
|
+
- **`claudeos-core/skills/`** — переиспользуемые паттерны (CRUD scaffolding, шаблоны страниц)
|
|
41
|
+
- **`claudeos-core/memory/`** — decision log + failure patterns, растущие вместе с проектом
|
|
28
42
|
|
|
29
|
-
|
|
43
|
+
Поскольку scanner передаёт Claude явный path allowlist, LLM **не может выдумать файлы или фреймворки, которых нет в вашем коде**. Пять post-generation validator-ов (`claude-md-validator`, `content-validator`, `pass-json-validator`, `plan-validator`, `sync-checker`) проверяют вывод до отправки — language-invariant, поэтому одни и те же правила применяются независимо от того, генерируете ли вы на английском, русском или одном из 8 других языков.
|
|
30
44
|
|
|
31
45
|
```
|
|
32
|
-
До: Вы → Claude Code → "в целом хороший" код →
|
|
33
|
-
После: Вы → Claude Code → код, соответствующий
|
|
46
|
+
До: Вы → Claude Code → "в целом хороший" код → ручные правки каждый раз
|
|
47
|
+
После: Вы → Claude Code → код, соответствующий ВАШЕМУ проекту → используйте как есть
|
|
34
48
|
```
|
|
35
49
|
|
|
36
50
|
---
|
|
@@ -119,37 +133,45 @@ npx claudeos-core init
|
|
|
119
133
|
</details>
|
|
120
134
|
|
|
121
135
|
<details>
|
|
122
|
-
<summary><strong>📄 Что попадает в ваш <code>CLAUDE.md</code> (реальный фрагмент)</strong></summary>
|
|
136
|
+
<summary><strong>📄 Что попадает в ваш <code>CLAUDE.md</code> (реальный фрагмент — Section 1 + 2)</strong></summary>
|
|
123
137
|
|
|
124
138
|
```markdown
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
139
|
+
# CLAUDE.md — spring-boot-realworld-example-app
|
|
140
|
+
|
|
141
|
+
> Reference implementation of the RealWorld backend specification on
|
|
142
|
+
> Java 11 + Spring Boot 2.6, exposing both REST and GraphQL endpoints
|
|
143
|
+
> over a hexagonal MyBatis persistence layer.
|
|
144
|
+
|
|
145
|
+
## 1. Role Definition
|
|
146
|
+
|
|
147
|
+
As the senior developer for this repository, you are responsible for
|
|
148
|
+
writing, modifying, and reviewing code. Responses must be written in English.
|
|
149
|
+
A Java Spring Boot REST + GraphQL API server organized around a hexagonal
|
|
150
|
+
(ports & adapters) architecture, with a CQRS-lite read/write split inside
|
|
151
|
+
an XML-driven MyBatis persistence layer and JWT-based authentication.
|
|
152
|
+
|
|
153
|
+
## 2. Project Overview
|
|
154
|
+
|
|
155
|
+
| Item | Value |
|
|
156
|
+
|---|---|
|
|
157
|
+
| Language | Java 11 |
|
|
158
|
+
| Framework | Spring Boot 2.6.3 |
|
|
159
|
+
| Build Tool | Gradle (Groovy DSL) |
|
|
160
|
+
| Persistence | MyBatis 3 via `mybatis-spring-boot-starter:2.2.2` (no JPA) |
|
|
161
|
+
| Database | SQLite (`org.xerial:sqlite-jdbc:3.36.0.3`) — `dev.db` (default), `:memory:` (test) |
|
|
162
|
+
| Migration | Flyway — single baseline `V1__create_tables.sql` |
|
|
163
|
+
| API Style | REST (`io.spring.api.*`) + GraphQL via Netflix DGS `:4.9.21` |
|
|
164
|
+
| Authentication | JWT HS512 (`jjwt-api:0.11.2`) + Spring Security `PasswordEncoder` |
|
|
165
|
+
| Server Port | 8080 (default) |
|
|
166
|
+
| Test Stack | JUnit Jupiter 5, Mockito, AssertJ, rest-assured, spring-mock-mvc |
|
|
145
167
|
```
|
|
146
168
|
|
|
147
|
-
|
|
169
|
+
Каждое значение выше — точные координаты зависимостей, имя файла `dev.db`, имя миграции `V1__create_tables.sql`, «no JPA» — извлечено сканером из `build.gradle` / `application.properties` / дерева исходников ещё до того, как Claude начал писать файл. Ничего не угадано.
|
|
148
170
|
|
|
149
171
|
</details>
|
|
150
172
|
|
|
151
173
|
<details>
|
|
152
|
-
<summary><strong>🛡️ Реальное автоматически загружаемое правило (<code>.claude/rules/10.backend/
|
|
174
|
+
<summary><strong>🛡️ Реальное автоматически загружаемое правило (<code>.claude/rules/10.backend/01.controller-rules.md</code>)</strong></summary>
|
|
153
175
|
|
|
154
176
|
````markdown
|
|
155
177
|
---
|
|
@@ -157,42 +179,56 @@ paths:
|
|
|
157
179
|
- "**/*"
|
|
158
180
|
---
|
|
159
181
|
|
|
160
|
-
#
|
|
182
|
+
# Controller Rules
|
|
183
|
+
|
|
184
|
+
## REST (`io.spring.api.*`)
|
|
161
185
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
-
|
|
168
|
-
|
|
186
|
+
- Controllers are the SOLE response wrapper for HTTP — no aggregator/facade above them.
|
|
187
|
+
Return `ResponseEntity<?>` or a body Spring serializes via `JacksonCustomizations`.
|
|
188
|
+
- Each controller method calls exactly ONE application service method. Multi-source
|
|
189
|
+
composition lives in the application service.
|
|
190
|
+
- Controllers MUST NOT import `io.spring.infrastructure.*`. No direct `@Mapper` access.
|
|
191
|
+
- Validate command-param arguments with `@Valid`. Custom JSR-303 constraints live under
|
|
192
|
+
`io.spring.application.{aggregate}.*`.
|
|
193
|
+
- Resolve the current user via `@AuthenticationPrincipal User`.
|
|
194
|
+
- Let exceptions propagate to `io.spring.api.exception.CustomizeExceptionHandler`
|
|
195
|
+
(`@ControllerAdvice`). Do NOT `try/catch` business exceptions inside the controller.
|
|
169
196
|
|
|
170
|
-
##
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
197
|
+
## GraphQL (`io.spring.graphql.*`)
|
|
198
|
+
|
|
199
|
+
- DGS components (`@DgsComponent`) are the sole GraphQL response wrappers.
|
|
200
|
+
Use `@DgsQuery` / `@DgsData` / `@DgsMutation`.
|
|
201
|
+
- Resolve the current user via `io.spring.graphql.SecurityUtil.getCurrentUser()`.
|
|
174
202
|
|
|
175
203
|
## Examples
|
|
176
204
|
|
|
177
205
|
✅ Correct:
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
206
|
+
```java
|
|
207
|
+
@PostMapping
|
|
208
|
+
public ResponseEntity<?> createArticle(@AuthenticationPrincipal User user,
|
|
209
|
+
@Valid @RequestBody NewArticleParam param) {
|
|
210
|
+
Article article = articleCommandService.createArticle(param, user);
|
|
211
|
+
ArticleData data = articleQueryService.findById(article.getId(), user)
|
|
212
|
+
.orElseThrow(ResourceNotFoundException::new);
|
|
213
|
+
return ResponseEntity.ok(Map.of("article", data));
|
|
214
|
+
}
|
|
187
215
|
```
|
|
188
216
|
|
|
189
217
|
❌ Incorrect:
|
|
190
|
-
```
|
|
191
|
-
|
|
218
|
+
```java
|
|
219
|
+
@PostMapping
|
|
220
|
+
public ResponseEntity<?> create(@RequestBody NewArticleParam p) {
|
|
221
|
+
try {
|
|
222
|
+
articleCommandService.createArticle(p, currentUser);
|
|
223
|
+
} catch (Exception e) { // NO — let CustomizeExceptionHandler handle it
|
|
224
|
+
return ResponseEntity.status(500).body(e.getMessage()); // NO — leaks raw message
|
|
225
|
+
}
|
|
226
|
+
return ResponseEntity.ok().build();
|
|
227
|
+
}
|
|
192
228
|
```
|
|
193
229
|
````
|
|
194
230
|
|
|
195
|
-
Glob `paths: ["**/*"]` означает, что Claude Code автоматически загружает это правило при редактировании любого файла в проекте.
|
|
231
|
+
Glob `paths: ["**/*"]` означает, что Claude Code автоматически загружает это правило при редактировании любого файла в проекте. Каждое имя класса, путь пакета и exception handler в правиле берутся прямо из просканированного кода — включая реальные `CustomizeExceptionHandler` и `JacksonCustomizations` этого проекта.
|
|
196
232
|
|
|
197
233
|
</details>
|
|
198
234
|
|
|
@@ -200,25 +236,26 @@ Glob `paths: ["**/*"]` означает, что Claude Code автоматиче
|
|
|
200
236
|
<summary><strong>🧠 Автоматически сгенерированный сид <code>decision-log.md</code> (реальный фрагмент)</strong></summary>
|
|
201
237
|
|
|
202
238
|
```markdown
|
|
203
|
-
## 2026-04-26 —
|
|
204
|
-
|
|
205
|
-
- **Context:**
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
`
|
|
209
|
-
|
|
210
|
-
- **Options considered:**
|
|
211
|
-
|
|
212
|
-
- **Decision:**
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
- **Consequences:**
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
239
|
+
## 2026-04-26 — Hexagonal ports & adapters with MyBatis-only persistence
|
|
240
|
+
|
|
241
|
+
- **Context:** `io.spring.core.*` exposes `*Repository` ports (e.g.,
|
|
242
|
+
`io.spring.core.article.ArticleRepository`) implemented by
|
|
243
|
+
`io.spring.infrastructure.repository.MyBatis*Repository` adapters.
|
|
244
|
+
The domain layer has zero `org.springframework.*` /
|
|
245
|
+
`org.apache.ibatis.*` / `io.spring.infrastructure.*` imports.
|
|
246
|
+
- **Options considered:** JPA/Hibernate, Spring Data, MyBatis-Plus
|
|
247
|
+
`BaseMapper`. None adopted.
|
|
248
|
+
- **Decision:** MyBatis 3 (`mybatis-spring-boot-starter:2.2.2`) with
|
|
249
|
+
hand-written XML statements under `src/main/resources/mapper/*.xml`.
|
|
250
|
+
Hexagonal port/adapter wiring keeps the domain framework-free.
|
|
251
|
+
- **Consequences:** Every SQL lives in XML — `@Select`/`@Insert`/`@Update`/`@Delete`
|
|
252
|
+
annotations are forbidden. New aggregates require both a
|
|
253
|
+
`core.{aggregate}.{Aggregate}Repository` port AND a
|
|
254
|
+
`MyBatis{Aggregate}Repository` adapter; introducing a JPA repository would
|
|
255
|
+
split the persistence model.
|
|
219
256
|
```
|
|
220
257
|
|
|
221
|
-
Pass 4 заполняет `decision-log.md` архитектурными решениями, извлечёнными из `pass2-merged.json`, чтобы будущие сессии помнили *почему* кодовая база выглядит так,
|
|
258
|
+
Pass 4 заполняет `decision-log.md` архитектурными решениями, извлечёнными из `pass2-merged.json`, чтобы будущие сессии помнили *почему* кодовая база выглядит так, как выглядит — не только *как* она выглядит. Каждый рассмотренный вариант («JPA/Hibernate», «MyBatis-Plus») и каждое следствие основаны на реальном блоке зависимостей `build.gradle`.
|
|
222
259
|
|
|
223
260
|
</details>
|
|
224
261
|
|
|
@@ -277,13 +314,17 @@ your-project/
|
|
|
277
314
|
|
|
278
315
|
## Кому это подходит?
|
|
279
316
|
|
|
280
|
-
| Если вы... |
|
|
317
|
+
| Если вы... | Боль, которую это снимает |
|
|
281
318
|
|---|---|
|
|
282
|
-
| **Соло-разработчик**, начинающий новый проект с Claude Code |
|
|
283
|
-
| **Тимлид**, поддерживающий общие стандарты
|
|
284
|
-
| **Уже использующий Claude Code**, но устал править генерируемый код |
|
|
319
|
+
| **Соло-разработчик**, начинающий новый проект с Claude Code | «Учить Claude нашим конвенциям каждую сессию» — больше нет. `CLAUDE.md` + 8-категорийные `.claude/rules/` сгенерированы за один проход. |
|
|
320
|
+
| **Тимлид**, поддерживающий общие стандарты в нескольких repo | `.claude/rules/` расходятся по мере того, как люди переименовывают пакеты, меняют ORM или response wrapper. ClaudeOS-Core пере-синхронизирует детерминированно — один и тот же вход → byte-identical вывод, без diff-шума. |
|
|
321
|
+
| **Уже использующий Claude Code**, но устал править генерируемый код | Неправильный response wrapper, неправильный layout пакетов, JPA вместо MyBatis, `try/catch` повсюду, когда у вас централизованный middleware. Scanner извлекает ваши реальные конвенции; каждый pass Claude работает с явным path allowlist. |
|
|
322
|
+
| **Onboarding на новый repo** (существующий проект, вход в команду) | Запустите `init` на repo и получите живую architecture map: stack-таблица в CLAUDE.md, rules по слоям с примерами ✅/❌, decision log, заполненный «почему» за крупными выборами (JPA vs MyBatis, REST vs GraphQL и т. д.). Прочитать 5 файлов лучше, чем 5000 файлов исходников. |
|
|
323
|
+
| **Работающий на корейском / японском / китайском / ещё 7 языках** | Большинство генераторов rules для Claude Code — только английский. ClaudeOS-Core пишет полный набор на **10 языках** (`en/ko/ja/zh-CN/es/vi/hi/ru/fr/de`) с **byte-identical структурной валидацией** — одинаковый verdict `claude-md-validator` независимо от языка вывода. |
|
|
324
|
+
| **Работающий на monorepo** (Turborepo, pnpm/yarn workspaces, Lerna) | Backend- и frontend-домены анализируются в одном запуске разными промптами; `apps/*/` и `packages/*/` обходятся автоматически; per-stack rules emit-ятся под `70.domains/{type}/`. |
|
|
325
|
+
| **Контрибьютор OSS или экспериментатор** | Вывод gitignore-friendly — `claudeos-core/` это ваш локальный рабочий каталог, отправлять нужно только `CLAUDE.md` + `.claude/`. Resume-safe при прерывании; идемпотентно при повторных запусках (ваши ручные правки rules сохраняются без `--force`). |
|
|
285
326
|
|
|
286
|
-
**Не подходит, если:** вы хотите универсальный preset bundle из agents/skills/rules, который работает с первого дня без шага сканирования (см. [docs/ru/comparison.md](docs/ru/comparison.md) — что под какие задачи подходит), либо ваш проект пока не вписывается в один из [поддерживаемых стеков](#supported-stacks).
|
|
327
|
+
**Не подходит, если:** вы хотите универсальный preset bundle из agents/skills/rules, который работает с первого дня без шага сканирования (см. [docs/ru/comparison.md](docs/ru/comparison.md) — что под какие задачи подходит), либо ваш проект пока не вписывается в один из [поддерживаемых стеков](#supported-stacks), либо вам нужен только один `CLAUDE.md` (встроенного `claude /init` достаточно — нет необходимости устанавливать ещё один инструмент).
|
|
287
328
|
|
|
288
329
|
---
|
|
289
330
|
|
|
@@ -296,9 +337,28 @@ ClaudeOS-Core инвертирует обычный workflow Claude Code:
|
|
|
296
337
|
Здесь: Код читает ваш стек → Код передаёт подтверждённые факты Claude → Claude пишет docs из фактов
|
|
297
338
|
```
|
|
298
339
|
|
|
299
|
-
|
|
340
|
+
Конвейер выполняется в **три стадии**, с кодом по обе стороны от LLM-вызова:
|
|
341
|
+
|
|
342
|
+
**1. Шаг A — Scanner (детерминированно, без LLM).** Node.js scanner обходит корень проекта, читает `package.json` / `build.gradle` / `pom.xml` / `pyproject.toml`, парсит файлы `.env*` (с redaction чувствительных переменных вроде `PASSWORD/SECRET/TOKEN/JWT_SECRET/...`), классифицирует архитектурный паттерн (5 паттернов Java A/B/C/D/E, Kotlin CQRS / multi-module, Next.js App vs. Pages Router, FSD, components-pattern), обнаруживает домены и строит явный allowlist всех существующих путей к исходникам. Вывод: `project-analysis.json` — единственный source of truth для всего, что следует дальше.
|
|
343
|
+
|
|
344
|
+
**2. Шаг B — 4-Pass Claude конвейер (ограничен фактами шага A).**
|
|
345
|
+
- **Pass 1** читает репрезентативные файлы по группам доменов и извлекает ~50–100 конвенций на домен — response wrapper, logging library, error handling, naming convention, test pattern. Запускается один раз на группу доменов (`max 4 domains, 40 files per group`), так что context никогда не переполняется.
|
|
346
|
+
- **Pass 2** объединяет весь per-domain анализ в общую картину проекта и разрешает разногласия, выбирая доминирующую конвенцию.
|
|
347
|
+
- **Pass 3** пишет `CLAUDE.md` + `.claude/rules/` + `claudeos-core/standard/` + skills + guides — разбит на стадии (`3a` facts → `3b-core/3b-N` rules+standards → `3c-core/3c-N` skills+guides → `3d-aux` database+mcp-guide), так что промпт каждой стадии помещается в context window LLM, даже когда `pass2-merged.json` большой. Sub-divides 3b/3c в batch-и по ≤15 доменов для проектов с ≥16 доменами.
|
|
348
|
+
- **Pass 4** заполняет L4 memory layer (`decision-log.md`, `failure-patterns.md`, `compaction.md`, `auto-rule-update.md`) и добавляет универсальные scaffold rules. Pass 4 **запрещено модифицировать `CLAUDE.md`** — Section 8 Pass 3 авторитетна.
|
|
349
|
+
|
|
350
|
+
**3. Шаг C — Верификация (детерминированно, без LLM).** Пять validator-ов проверяют вывод:
|
|
351
|
+
- `claude-md-validator` — 25 структурных проверок `CLAUDE.md` (8 sections, H3/H4 counts, memory file uniqueness, T1 canonical heading invariant). Language-invariant: тот же verdict независимо от `--lang`.
|
|
352
|
+
- `content-validator` — 10 content-проверок, включая path-claim верификацию (`STALE_PATH` ловит выдуманные ссылки `src/...`) и MANIFEST drift detection.
|
|
353
|
+
- `pass-json-validator` — well-formedness JSON Pass 1/2/3/4 + stack-aware section count.
|
|
354
|
+
- `plan-validator` — консистентность plan ↔ disk (legacy, в основном no-op с v2.1.0).
|
|
355
|
+
- `sync-checker` — консистентность регистраций disk ↔ `sync-map.json` по 7 отслеживаемым каталогам.
|
|
356
|
+
|
|
357
|
+
Три уровня severity (`fail` / `warn` / `advisory`), так что warning-и не блокируют CI на LLM-галлюцинациях, которые пользователь может починить вручную.
|
|
358
|
+
|
|
359
|
+
Инвариант, связывающий всё вместе: **Claude может цитировать только пути, реально существующие в вашем коде**, потому что шаг A передаёт ему конечный allowlist. Если LLM всё-таки попытается что-то выдумать (редко, но случается на определённых seed), шаг C ловит это до отправки docs.
|
|
300
360
|
|
|
301
|
-
|
|
361
|
+
Подробности по pass-ам, marker-based resume, обходной путь staged-rules для блока чувствительных путей `.claude/` в Claude Code и внутренности обнаружения стека — см. [docs/ru/architecture.md](docs/ru/architecture.md).
|
|
302
362
|
|
|
303
363
|
---
|
|
304
364
|
|