eska-tool-runtime 0.15.0

Owned component processes and bounded internal tool protocols
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
# eska

[![Release-plz](https://github.com/1c-tooling/eska/actions/workflows/release-plz.yml/badge.svg)](https://github.com/1c-tooling/eska/actions/workflows/release-plz.yml)
[![Binaries](https://github.com/1c-tooling/eska/actions/workflows/release.yml/badge.svg)](https://github.com/1c-tooling/eska/actions/workflows/release.yml)
[![crates.io](https://img.shields.io/crates/v/eska.svg)](https://crates.io/crates/eska)
[![License: Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)

**Проекты 1С из терминала: от задачи в Git до готового файла поставки.**

`eska` помогает подключить XML-выгрузку к проекту, вести задачи в Git, смотреть
изменения на уровне объектов 1С, сохранять коммиты и собирать `.cf`, `.cfe`,
`.epf` и `.erf` через установленную платформу.

Исходники редактируются привычными инструментами. CLI работает с
**XML-выгрузкой Конфигуратора** и не выгружает изменения из информационной базы
автоматически. Интерфейс доступен на русском и английском.

В рабочей ветке доступен самостоятельный [проектный инструмент](docs/project-cli.md)
`eska-project`: создание и подключение Designer XML, проверка корневых
дескрипторов, контексты приложений, существующие metadata/version без полной
ESKA, Git и платформы 1С. Сборка: `cargo build -p eska-project`.
Производный [конфиг bsl-analyzer и миграция](docs/analyzer-configuration.md)
доступны через `eska-project analyzer-config` и Metadata API 1.12.
Самостоятельный [CI-компонент](docs/check-cli.md) `eska-check` проверяет XML,
запускает полный анализ внешним bsl-analyzer и выдаёт проверенный отчёт с порогами.
Сборка: `cargo build -p eska-check`; Git, IDE и платформа для него не нужны.
Общий вход — `eska check`, с теми же параметрами и результатом.
Нативный [eska-build](docs/build-tool.md) использует общую реализацию сборки
и распаковывает CF/CFE/EPF/ERF только в новый каталог XML. Ему нужна платформа
1С; Git, анализатор и проектный сервер не требуются.
Самостоятельный [eska-vcs](docs/vcs-tool.md) сохраняет workflow, полки и semantic
diff; платформа, анализатор и остальные ESKA-компоненты ему не нужны.
[Общая команда делегирует операции компонентам](docs/component-delegation.md).
Составные операции связывают владельцев через process-протокол; Git и native
исполнители не входят в зависимости оболочки.
[Выборочные локальные архивы и установщик](docs/component-installation.md)
поддерживают проверенные manifests/checksums, update/remove и rollback одного компонента.

[Установка](#установка) · [Быстрый старт](#быстрый-старт) ·
[Работа над задачей](#работа-над-задачей) · [Сборка](#сборка) ·
[Версия проекта 1С](#версия-проекта-1с) · [Настройки](#настройки) ·
[Все команды](#все-команды)

## Установка

Linux и macOS:

```bash
curl --proto '=https' --tlsv1.2 -LsSf https://1c-tooling.github.io/eska/install | sh
```

Windows PowerShell:

```powershell
powershell -ExecutionPolicy Bypass -c "irm https://1c-tooling.github.io/eska/install.ps1 | iex"
```

Установщик выберет комплект из пяти инструментов для текущей ОС и архитектуры и добавит
`~/.eska/bin` в `PATH`. После первой установки откройте новый терминал, затем
проверьте CLI:

```bash
eska --version
eska --help
```

Поддерживаются Linux и macOS на x86-64 и ARM64, а также Windows x86-64. Для
сборки из исходников по-прежнему можно использовать Rust и Cargo:

```bash
cargo install eska-project eska-check eska-build eska-vcs eska --locked
```

### Обновление CLI

```bash
eska update --check
eska update
```

Команда сохраняет способ установки: Cargo обновляется через Cargo, установка
готового бинарника — через официальный установщик. Проверка не меняет файлы;
обычный запуск устанавливает новую стабильную версию. Проект и `eska.toml` не нужны.

Если старая версия ещё не знает команду `update`, один раз повторите
команду установки пяти пакетов выше либо запуск установщика, которым пользовались раньше.
При переходе с монолитной Cargo-версии также сначала установите все пять пакетов:
старый `eska update` знает только пакет `eska`. Новый обновляет весь комплект.
[Способы установки, параметры и JSON-контракт обновления](docs/cli-update.md).
[Подготовка и проверка релиза](docs/releases.md).

### Необходимые программы

Для корректной работы установите программы, которые нужны вашему сценарию:

- **Git** — для сохранения изменений командой `eska save`, создания и
  переключения веток задач, клонирования, получения изменений и завершения
  задач. Перед первым коммитом настройте в Git имя и электронную почту автора.
- **Git LFS** — если XML-выгрузка содержит двоичные файлы, отмеченные в
  `.gitattributes` через `filter=lfs`. `eska` создаёт правила атрибутов, но
  установку и настройку Git LFS нужно выполнить отдельно.
- **Платформа 1С:Предприятие с `ibcmd`** — для команд `eska build` и
  `eska patch`, а также для `eska new --from` и `eska import`. Версия `ibcmd`
  должна совпадать с выбранной версией платформы.
  Для `eska patch` дополнительно нужен исполняемый файл `1cv8` из той же
  установки платформы.

**Distrobox устанавливать необязательно.** Он нужен на Linux, если платформа 1С
установлена внутри контейнера и недоступна напрямую на основной системе. В этом
случае сначала самостоятельно установите Distrobox, создайте контейнер и
установите в него платформу 1С. Затем укажите имя контейнера в глобальных
настройках `eska` или передайте `--distrobox <имя-контейнера>` при сборке.
Если `ibcmd` доступен непосредственно на основной системе, Distrobox не нужен.

## Быстрый старт

### Подключить существующую выгрузку

Допустим, XML-выгрузка основной конфигурации находится в каталоге
`my_configuration/src`, а файл
`my_configuration/src/Configuration.xml` уже существует:

```bash
cd my_configuration
eska init
eska
eska save -m "chore: Подключён проект eska"
```

В интерактивном терминале `eska init` сам определит тип выгрузки и предложит
выбрать workflow и установленную платформу 1С. Выберите вариант стрелками и
нажмите Enter. Команда сохранит версию в `eska.toml` и создаст недостающие
`.gitignore` / `.gitattributes`. Существующий Git-репозиторий сохраняется; если
его нет, создаётся новый с начальной веткой `main`.

Для скрипта или перенаправленного ввода workflow и версию нужно передать явно:

```bash
eska init --workflow trunk --platform-version 8.3.27.2325
```

Нестандартный каталог исходников задаётся явно:

```bash
eska init --source sources/configurator --workflow trunk --platform-version 8.3.27.2325
```

`--select-platform` открывает меню установленных версий. Выбранный `ibcmd` должен
соответствовать версии; `--ibcmd`, `--platform-arch` и `--distrobox` позволяют
уточнить поиск. `init` проверяет версию платформы, но не запускает сборку или
создание информационной базы. Отмена выбора не создаёт файлов проекта.

### Создать новый проект

```bash
eska new my_configuration
cd my_configuration
```

В интерактивном терминале команда последовательно предложит выбрать тип проекта
и workflow. Для основной конфигурации выберите `configuration`, затем подходящий
процесс работы, например `trunk`. Управление: стрелки `↑`/`↓`, подтверждение —
Enter, отмена — Esc или Ctrl+C.

В скриптах и при перенаправленном вводе оба значения обязательны:

```bash
eska new my_configuration --type configuration --workflow trunk
```

Получится каркас:

```text
my_configuration/
├── eska.toml       # Тип проекта, исходники, платформа и правила Git
├── .gitignore
├── .gitattributes
└── src/            # Сюда нужно поместить XML-выгрузку Конфигуратора
```

`new` создаёт каталог и настройки, но **не генерирует конфигурацию 1С**.
Поместите в `src` XML-выгрузку соответствующего типа проекта 1С — конфигурации,
расширения, внешней обработки или внешнего отчёта — и выполните первый
`eska save`. Существующий каталог команда не заменяет.

Типы проекта: `configuration`, `extension`, `processing`, `report`.
Доступные workflow описаны в разделе [«Работа над задачей»](#работа-над-задачей).
Флаг `--no-vcs` у `new` и `init` отключает создание Git-репозитория.

### Создать проект из файла 1С

```bash
eska new accounting --from accounting.cf --workflow trunk --platform-version 8.3.27.2325
eska new processor --from processor.epf --workflow trunk --platform-version 8.3.27.2325
```

Поддерживаются `.cf`, `.cfe`, `.epf` и `.erf`. Тип определяется по XML,
полученному через установленный `ibcmd`; `--type` вместе с `--from` запрещён.
В терминале неизвестные workflow и версия платформы выбираются интерактивно;
без терминала укажите их явно. Выбранная версия сохраняется в новом проекте.
Параметры `--ibcmd`, `--platform-arch`, `--distrobox` и `--select-platform`
используют тот же поиск платформы, что и сборка.
CF сначала загружается во временную файловую базу через `ibcmd config load`,
затем выгружается в XML. CFE/EPF/ERF распаковываются через `config export --file`.
Рабочая информационная база при этом не используется.
При `new --from` сначала эксклюзивно создаётся каталог standalone-проекта,
затем файл распаковывается в `<проект>/.eska/import/`. При ошибке удаляется
весь созданный проект вместе со служебными файлами. В workspace временная
область может быть общей; как и для `import`, она находится в `.eska/import/`
у ближайшего существующего родителя целевого каталога. Локальный `.gitignore`
внутри служебного каталога исключает всё его содержимое, включая себя; проектный
`.gitignore` не меняется. Ссылки и пересечение с целевым каталогом запрещены.

В workspace `eska new processor --from processor.epf` создаёт участника
`src/processor` и наследует версию платформы корня. Явный выбор другой версии
сохраняет переопределение у участника. Workflow и Git принадлежат workspace.
Файл распаковывается и проверяется во временной области;
исходники и настройки проекта публикуются после проверки. Существующее
назначение отклоняется.

Служебные сообщения `new` и `import` используют тематические маркеры:
`✓` — успех, `⚠` — предупреждение, `✗` — ошибка, `↩` — отмена.
В интерактивном терминале пути в результатах, preview и диагностике `eska`
оформляются ссылками OSC 8 на соответствующие файлы или каталоги.
Цвета включаются по тем же правилам, что у `build`; `NO_COLOR` отключает
цвета, сохраняя ссылки. При перенаправлении пути остаются обычным текстом
без управляющих последовательностей. Строки платформы `[INFO]`, `[WARN]`
и других уровней сохраняют только подсветку уровня, без новых маркеров.

### Обновить исходники из файла 1С

```bash
eska import ../accounting.cf --dry-run
eska import ../accounting.cf
eska import ../accounting.cf --force --format json
eska import processor.epf -p processor
```

`import` полностью заменяет содержимое настроенного каталога исходников,
включая удаление отсутствующих объектов и посторонних файлов. `eska.toml`,
Git-репозиторий, index и файлы вне source сохраняются. Поддерживается отдельный
каталог исходников; `source = "."`, символические ссылки и вложенные проекты
внутри source отклоняются. Пустой каркас `eska new` можно заполнить через `import`.

Тип файла должен совпадать с типом проекта. Сравниваются UUID и внутреннее
`Name` корневого объекта 1С, независимо от имени файла, каталога и workspace
alias. Различие UUID/имени или незакоммиченные исходники вызывает предупреждение
и выбор: `1`/Enter/Esc — отменить, `2` — перезаписать. Заполненный проект без Git
также требует подтверждения. Без TTY и в режиме JSON для подтверждения нужен
явный `--force`; проверки типа, путей и изменений во время операции сохраняются.
Изменения вне исходников выбранного проекта не блокируют импорт.

В workspace выбирается текущий участник либо один `-p <имя>`; из корня нужен
явный `-p`. `--dry-run` выполняет реальную распаковку и проверки, но оставляет
проект без изменений; human-вывод завершается сообщением `ℹ` о завершённой
проверке. Платформа берётся из настроек проекта/workspace;
`--platform-version` и `--select-platform` задают одноразовый выбор для импорта.

Публикация выполняется после распаковки и повторной проверки исходников по
SHA-256. Ошибка замены возвращает прежний каталог; при ошибке восстановления
путь сохранённой копии выводится явно. Гарантия отката относится к обычным
ошибкам файловой системы; аварийное завершение процесса и изменения другим
процессом непосредственно во время переименования каталогов не транзакционны.

JSON имеет `schema_version: 1`, `kind: "import"`, `applied`, `project` (workspace
alias либо `null`), `source`, `current`, `incoming`, `existing_files`,
`local_changes`, `identity_changed`, `retained_backup`. Identity содержит
`type`, `uuid`, `name`; пути используют `path` + `path_encoding`.
При отказе возвращаются `error.code` и `preview` (если план уже подготовлен).
JSON не зависит от локали; сообщения платформы и диагностика идут в stderr.
`import` и `new --from` используют те же цвета уровней диагностики и индикатор
работы, что и `build`. Цвета отключаются при перенаправлении stderr и с
`NO_COLOR`; интерактивный индикатор отсутствует в JSON. Ошибки платформы
выводятся один раз, без повторения журнала в итоговом сообщении.
Коды завершения: `0` — выполнено или показан план, `1` — отказ/отмена/ошибка,
`2` — ошибка разбора параметров CLI.

### Клонировать готовый проект

```bash
eska clone https://example.org/team/my_configuration.git
cd my_configuration
eska status
```

Замените пример адресом своего репозитория с `eska.toml`. Можно указать имя нового
каталога и remote: `eska clone <url> <directory> --remote upstream`.
Существующий каталог не перезаписывается.

## Работа над задачей

Workflow задаёт, от какой ветки начинать задачу, как назвать рабочую ветку и в
какую ветку должны попасть изменения перед `eska finish`. Его нужно выбрать при
`new` или `init`, потому что `eska` не угадывает процесс команды по существующим
веткам.

| Workflow | Для какого процесса | Базовая и рабочая ветки |
|---|---|---|
| `trunk` | Короткие задачи с интеграцией в основную ветку | `main` → `task/<ID>` |
| `github-flow` | Работа через PR/MR в основную ветку | `main` → `feature/<ID>` |
| `git-flow` | Разработка через отдельную ветку `develop` | `develop` → `feature/<ID>` |
| `custom` | Собственные правила именования и завершения задач | Полностью задаются в `eska.toml` |

Выбор сохраняется в `eska.toml` и применяется командами `start`, `status`,
`switch`, `finish` и `patch`. Если стандартные имена веток вашей команды
отличаются, настройте policy, как показано в разделе
[«Правила работы с Git»](#правила-работы-с-git).

Дальнейший пример использует `trunk`: базовая ветка — `main`, ветки задач —
`task/<ID>`. До начала задачи исходники и настройки должны быть закоммичены.

### 1. Начать задачу

```bash
eska start FI-1234
```

Команда создаёт и активирует `task/FI-1234` от `main`. Если `origin` настроен,
сначала получает изменения и обновляет базовую ветку только fast-forward.
Без remote работает с локальной базовой веткой. При расхождении истории или
несохранённых файлах останавливается с объяснением.

### 2. Изменить исходники и проверить результат

После работы в Конфигураторе выгрузите изменения обратно в каталог исходников.
При редактировании XML/BSL напрямую этот шаг не нужен.

```bash
eska status
eska diff
eska diff --semantic
```

`status` показывает ветку, задачу и состояние файлов. Обычный `diff` сводит
изменённые пути к объектам Конфигуратора; `--semantic` уточняет изменения
методов, модулей, форм и свойств метаданных. Разделы semantic-вывода следуют
порядку дерева Конфигуратора. Процедуры и функции объединены в группы методов,
методы каждого объекта следуют порядку объявления в исходном файле, а строка
события сохраняет вид объявления и 1-based координаты его начала:

```text
ОбщийМодуль.Обмен — Процедура.ЗагрузитьДанные (42, 3)
```

Добавление или удаление объекта подавляет производные события изменения того же
объекта. Заголовок уточняет источник: `между Git-ревизиями`, `в индексе`,
`в рабочей копии` или оба workspace-состояния. Raw и JSON сохраняют прежние
machine event kinds и не получают координаты. Это обзор изменений, а не проверка
BSL.

Для сравнения сохранённых версий:

```bash
eska diff main                         # main → HEAD
eska diff main --since-branch-point    # От общей базы веток до HEAD
eska diff v1.0.0 v1.1.0                # Между двумя существующими тегами
```

Сравнение версий читает локальную историю и не включает несохранённые файлы.

В workspace команды из корня группируют данные по проектам и отдельно показывают
файлы самого workspace. Один или несколько members можно выбрать через `-p`, а
`--workspace` из каталога member возвращает полный обзор:

```bash
eska status -p sales-report
eska diff -p sales-report -p import-orders
eska diff --workspace --semantic
```

Один выбранный member сохраняет прежние JSON-схемы. Aggregate `status` и `diff`
используют отдельные versioned-документы с `projects[]` и `workspace_files`.
В aggregate `diff --raw` первая колонка содержит имя проекта или `-` для файла
workspace.

### 3. Сохранить изменения

```bash
eska save
```

Команда подготавливает сообщение по изменениям и открывает Git editor.
Отредактируйте сообщение и сохраните его для создания коммита.
Сообщение можно передать сразу:

```bash
eska save -m "fix: Исправлен расчёт скидки"
eska history --limit 20
```

Перед сохранением можно вывести точный план без изменения репозитория:

```bash
eska save --dry-run
eska save --dry-run -m "fix: Исправлен расчёт скидки"
```

Preview показывает выбранный project/workspace scope, все включаемые пути,
отдельные состояния index и рабочего дерева и сгенерированное или переданное
сообщение commit. Команда не запускает editor и hooks, не меняет index, refs и
рабочее дерево. Последующий `save` заново проверяет актуальное состояние.

`save` включает **все неигнорируемые изменения внутри проекта**, в том числе новые
и удалённые файлы. Если проект вложен в большой репозиторий, изменения соседних
проектов в коммит не попадут. Пустое сообщение или конфликт блокируют сохранение.

Из корня workspace `save` создаёт один commit со всеми изменениями members и
корневых файлов workspace, но не включает соседние каталоги репозитория.
Точечное сохранение и явный полный scope доступны из любого member:

```bash
eska save -p sales-report
eska save --workspace -m "fix: Обновлены внешние инструменты"
```

Несколько `-p` для `save` запрещены: выберите один member или весь workspace.

### 4. Переключиться и вернуться

```bash
eska switch --base
eska switch FI-1234
```

`switch` активирует только существующие ветки. `--base` позволяет временно
вернуться на `main`, сохранив задачу. Новую ветку создаёт `start`.
`switch` автоматически сохраняет незакоммиченные изменения текущей ветки в
полку и восстанавливает полку целевой ветки. Сохраняются staged и unstaged
изменения, удаления, переименования, права файлов и неигнорируемые новые файлы
во всём репозитории, включая соседние workspace members и файлы вне проекта.
Ignored-файлы остаются на диске; коллизия останавливает операцию.
`start` и `finish` по-прежнему требуют чистого worktree.

Полкой можно управлять явно:

```bash
eska shelve --dry-run
eska shelve
eska shelves
eska unshelve --dry-run
eska unshelve
eska switch FI-1234 --dry-run --format json
```

На одну ветку допускается одна полка. `unshelve [id]` восстанавливает её только
на исходной ветке и исходном commit; после проверки полного восстановления
полка удаляется. `shelves` показывает ID, ветку, время и число изменённых путей.
Все четыре команды поддерживают `--format human|json`; `--dry-run` у `shelve`,
`unshelve` и `switch` показывает пути и состояния index/worktree без записи.

Если целевая ветка сдвинулась или восстановлению мешают новые файлы, полка
остаётся доступна через `eska shelves`. После устранения коллизии повторите
`eska unshelve`. Ошибка восстановления может оставить целевую ветку активной;
проверьте `eska status`. При ошибке самого переключения команда пытается вернуть
состояние исходной ветки. Незавершённые merge/rebase, detached/unborn HEAD,
конфликты, sparse/split index, submodules, intent-to-add, skip-worktree и
assume-unchanged отклоняются. Существующую ветку в другой рабочей копии
активировать нельзя.

Полки локальны: исходный index и снимки изменённых файлов хранятся в
`eska-shelves/` общего Git-каталога, staged-объекты защищены внутренней ref.
Байты файлов, включая BOM/CRLF, восстанавливаются без повторной нормализации.
Формат хранения внутренний. Параллельные операции полок сериализуются; внешние
Git-команды и редакторы не должны менять эти файлы во время операции. После
прерывания очистки данные сохраняются, но может потребоваться ручное
восстановление из полки; после частичного восстановления доступен повторный
`unshelve`, если пути всё ещё совпадают с журналом операции.

### 5. Передать изменения и завершить задачу

После проверки и сборки опубликуйте ветку привычными средствами Git:

```bash
git push -u origin task/FI-1234
```

Создайте PR/MR и интегрируйте изменения в `main` средствами вашего Git-сервиса.
Затем, находясь в ветке задачи, выполните:

```bash
eska finish
```

Стандартный `finish` проверит, что текущий коммит задачи входит в целевую ветку,
переключится на базовую и удалит локальную ветку задачи. При настроенном remote
проверяется полученная удалённая история, без remote — локальная.
Команда сама не делает merge, push или PR/MR. После squash/rebase исходный коммит
может не входить в историю: тогда `finish` откажет, даже если изменения перенесены.

## Сборка

### Настроить платформу

Укажите установленную версию в `eska.toml`:

```toml
[build]
platform_version = "" # Укажите версию из `eska platform list`
artifacts_directory = "build"
```

Обычный `new` оставляет версию пустой. `init` и `new --from` сохраняют выбранную
версию. Для сборки незаполненную версию нужно указать в конфиге либо выбрать на
один запуск; версия найденного `ibcmd` должна точно совпадать с выбранной.

```bash
eska platform list
eska build --select-platform
```

### Собрать полный файл

```bash
eska build
eska build --output build/application.cf
```

| Тип проекта | Результат |
|---|---|
| `configuration` | `.cf` — полная конфигурация |
| `extension` | `.cfe` — существующее расширение |
| `processing` | `.epf` — внешняя обработка |
| `report` | `.erf` — внешний отчёт |

Если внешняя обработка или отчёт использует типы, картинки либо другие объекты
основной конфигурации, передайте её собранный `.cf`:

```bash
eska build --base-configuration ../application/build/application.cf
```

`eska` загружает этот `.cf` в управляемую служебную информационную базу и
передаёт `ibcmd infobase config import` полный каталог XML-выгрузки
Конфигуратора. Основная информационная база не изменяется. Параметр доступен только для проектов
`processing` и `report`; относительный путь считается от корня проекта или
workspace.

`build` читает текущие исходники с диска, включая несохранённые в Git изменения.
Артефакт помещается в каталог сборки; `--output` задаёт другой путь с расширением
своего типа. Существующий файл заменяется только после успешной сборки.
Служебная база хранится в `build/.eska/infobases/` и повторно используется
следующими сборками того же проекта. При смене версии платформы или содержимого
базового `.cf` она пересоздаётся автоматически. Одновременный доступ
блокируется файловой блокировкой.

Чтобы принудительно получить свежую базу, используйте:

```bash
eska build --recreate-infobase
```

Удалить служебную базу можно отдельно; готовые артефакты сохраняются:

```bash
eska clean
```

В workspace доступны те же selectors: `eska clean -p <project>` и `eska clean
--workspace`.

Снимки исходников и незавершённые артефакты по-прежнему удаляются после
завершения, ошибки или прерывания.

До запуска сборки можно проверить полный план:

```bash
eska build --dry-run
eska build --dry-run --format json
```

Preview выполняет обычные selection, построение `BuildPlan`, group preflight,
поиск `ibcmd` и проверку его версии. Он показывает проекты в порядке исполнения,
source, тип и путь артефакта, наличие заменяемого результата, требуемую и
найденную платформу, runner и режим служебной базы. Команда не создаёт каталог
артефактов и служебную базу и не запускает import. Обычный `build` повторяет preflight для актуального
состояния и может получить другой результат, если после preview изменились файлы.
Успешный preview не гарантирует, что платформа 1С примет XML/BSL при импорте.

Успешный `build --dry-run --format json` возвращает отдельный документ плана:

```json
{
  "schema_version": 1,
  "kind": "build-plan",
  "scope": "project",
  "projects": [
    {
      "name": null,
      "root": { "path": "/work/demo", "path_encoding": "utf-8" },
      "source": { "path": "/work/demo/src", "path_encoding": "utf-8" },
      "artifact": {
        "type": "configuration",
        "path": "/work/demo/build/demo.cf",
        "path_encoding": "utf-8",
        "replaces_existing": false
      },
      "platform": {
        "required_version": "8.3.27.2325",
        "found_version": "8.3.27.2325",
        "runner": "host"
      }
    }
  ]
}
```

`scope` принимает `project` или `workspace`; `projects[]` всегда сохраняет
порядок будущего исполнения. У workspace member поле `name` содержит его
стабильное имя. Пути используют тот же обратимый `path_encoding`, что и результат
обычной сборки. Ошибки сохраняют общий JSON error envelope сборки версии 1.

Чтобы связать артефакт с фактически прочитанными исходниками, включите паспорт:

```bash
eska build --manifest
```

Команда копирует Designer XML в закрытый временный снимок, собирает только из
этой копии и создаёт рядом `<artifact>.manifest.json`. Паспорт схемы 1 содержит
тип и SHA-256 артефакта, версию проекта из снимка, точную версию платформы,
SHA-256-идентификатор структуры и байтов снимка, а также commit и dirty state,
если Git доступен. Для сборки с `--base-configuration` паспорт также содержит
SHA-256 использованного `.cf`. Отсутствующие Git и версия проекта представлены
явными статусами `absent`/`unavailable`, без вымышленных значений и абсолютных
путей.

```json
{
  "schema_version": 1,
  "kind": "artifact-manifest",
  "project": {
    "name": "demo",
    "version": { "status": "available", "value": "1.2.3.4" }
  },
  "artifact": {
    "type": "configuration",
    "checksum": { "algorithm": "sha256", "value": "..." }
  },
  "platform": { "version": "8.3.27.2325" },
  "source": {
    "snapshot_id": "sha256:...",
    "git": { "status": "available", "commit": "...", "dirty": true }
  }
}
```

Из снимка исключаются `.git`, настроенный каталог артефактов, текущие artifact,
manifest и временный workspace. Символические ссылки и специальные файлы в
source для этого режима отклоняются: снимок не читает данные за своей границей.
Новая пара публикуется согласованно; при ошибке сохраняется предыдущая пара.
В workspace каждый успешный member получает свой паспорт, а ошибка одного member
не откатывает результаты других. Обычный `build`, его human/JSON-вывод и чтение
исходников напрямую не меняются. Паспорт фиксирует входные байты и checksum, но
не обещает побайтную детерминированность результата платформы 1С.

Из корня workspace команда без selectors последовательно собирает все проекты в
порядке `members`. Можно выбрать один или несколько проектов либо явно собрать
весь workspace из каталога участника:

```bash
eska build -p sales-report
eska build -p sales-report -p import-orders
eska build --workspace
```

Общие артефакты записываются как `build/<project.name>.<расширение>`. До первой
сборки проверяются планы, исходники, пути результатов и все требуемые версии
`ibcmd`; ошибка preflight блокирует всю группу. Ошибка уже запущенной сборки не
мешает собрать следующие проекты, но команда завершится с ненулевым кодом.
`--output` доступен только при выборе ровно одного проекта. Для одного проекта
сохраняется прежний JSON v1, для группы JSON v1 содержит `projects[]` со статусом,
артефактом или стабильным кодом ошибки каждого участника.

Матрица переносимых тестов и отдельный протокол приёмки с настоящей платформой
1С описаны в [проверке сборки на поддерживаемых ОС](docs/build-validation.md).

### Собрать патч из изменений ветки

Для проекта `configuration` доступна отдельная команда:

```bash
eska patch --dry-run
eska patch --base main --output build/fix.cfe
```

`eska patch` делегирует `eska-build patch`; планирование и снимок выполняет
`eska-vcs`. Самостоятельный вход работает без полной ESKA.

`patch` берёт **закоммиченные изменения от общей базы выбранной ветки и HEAD**.
Без `--base` используется локальный `integration_target` из workflow.
Рабочая копия должна быть чистой. `--dry-run` показывает план без запуска 1С.

Поддерживается узкий случай: изменение тела существующего метода серверного
неглобального общего модуля с неизменной сигнатурой и свойствами объекта.
В изменённом теле не допускаются вызовы, обращения к членам и индексам,
директивы и динамическое выполнение; переменные модуля также не поддерживаются.
Добавление, удаление и переименование методов или объектов отклоняется.

Для сборки патча нужен `1cv8` рядом с выбранным `ibcmd`. Проверяются BSL и
применимость в отдельной временной базе. Существующий `.cfe` не заменяется.
Выполнение приложения не проверяется. Для подключения такого патча требуется
отключённый безопасный режим расширения; `eska` не меняет эту настройку в базе.
Подробнее: [границы и проверки патчей](docs/roadmap/t42-patch-extension.md).

## Версия проекта 1С

Текущая версия читается из `Properties/Version` корневого объекта Designer XML:

```bash
eska version
eska version --format json
```

Версия должна состоять из четырёх числовых компонентов. Команды изменения
соответствуют первым трём компонентам 1С `revision.subrevision.version.build`:

```bash
eska version bump patch  # 1.0.2.01 -> 1.0.3.01
eska version bump minor  # 1.0.2.01 -> 1.1.1.01
eska version bump major  # 1.0.2.01 -> 2.0.1.01
```

В workspace команда из корня показывает версии всех участников, а из каталога
участника — только его версию:

```bash
eska version
eska version -p sales-report
eska version --workspace --format json
eska version -p sales-report bump patch
```

Несколько `-p` можно передать только при чтении. Из корня workspace изменение
версии требует ровно одного `--project`; массовый bump не выполняется. JSON
одного проекта сохраняет прежнюю схему, а список возвращает отдельный документ
`{"schema_version": 1, "projects": [...]}` с именем, типом, версией и
относительным путём дескриптора каждого участника.

После увеличения младшие компоненты начинают отсчёт заново: subrevision — с 0,
version и build — с 1. Ширина исходных компонентов сохраняется, поэтому `01`
не превращается в `1`.

`eska` не сериализует XML заново: меняются только байты значения внутри
единственного `Properties/Version` корневого объекта. BOM, CRLF, отступы,
атрибуты и остальной текст файла остаются побайтно прежними. Команда не создаёт
commit и не меняет версию бинарника `eska`.

## Настройки

### Проект: `eska.toml`

```toml
[project]
type = "configuration"
source = "src"

[build]
platform_version = "" # Укажите версию из `eska platform list`
artifacts_directory = "build"

[vcs.workflow]
preset = "trunk"
```

`source` — относительный каталог XML-выгрузки Конфигуратора, по умолчанию `src`;
допустим `.`.
Пути с `..` и исходники за пределами проекта не принимаются. `eska` без подкоманды
проверяет настройки и наличие исходников, но не компилирует BSL.
Ближайший `eska.toml` ищется вверх от текущего каталога:

```bash
eska --project-dir /path/to/my_configuration status
```

### Workspace: несколько проектов в одном репозитории

Корневой `eska.toml` может перечислять независимые проекты:

```toml
[workspace]
members = ["src/sales-report", "src/import-orders"]

[build]
platform_version = "8.3.27.2325"
artifacts_directory = "build"

[vcs.workflow]
preset = "trunk"
```

У каждого участника свой `eska.toml`; имя обязательно и уникально:

```toml
[project]
name = "sales-report"
type = "report"
source = "."
```

Новый member создаётся из корня workspace или каталога любого существующего
member. В workspace нужен только тип проекта: workflow и Git принадлежат корню.

```bash
eska new my-orders --type processing
```

Команда создаст `src/my-orders`, запишет туда member `eska.toml` и автоматически
добавит `src/my-orders` в корневой `workspace.members`. Комментарии и остальное
форматирование корневого TOML сохраняются.

Чтобы подключить уже скопированную Designer XML выгрузку:

```bash
cd src/my-orders
eska init
```

Тип определяется по XML, а имя — по каталогу. Если каталог не подходит под
переносимый формат `[a-z0-9][a-z0-9_-]*`, укажите `eska init --name my-orders`.
Версия платформы наследуется из корня без запуска `ibcmd`. `--platform-version`
или `--select-platform` сохраняют переопределение только у нового участника.
Если в корне версия не задана, `init` предлагает выбрать её; без интерактивного
терминала требуется `--platform-version`.
Вложенный Git repository, `.gitignore`, `.gitattributes` и member-level workflow
не создаются. `--workflow` в workspace отклоняется как корневая настройка.

`eska` без подкоманды проверяет корневой manifest, все явно перечисленные
каталоги, уникальность имён, границы путей и наследование общих настроек. Участник
может переопределить только `[build].platform_version`; workflow и каталог
артефактов задаются в корне. `build`, `version`, `status`, `diff` и `save`
поддерживают current/named/all selection через `-p` и `--workspace` в пределах
семантики каждой команды. Repository-wide команды `start`, `switch`, `finish` и
`history`, а также `shelve`, `unshelve`, `shelves` не делятся по members.
Полный контракт: [project workspaces](docs/roadmap/11-workspaces.md).

### Контекст приложения для анализа

Корневой workspace может явно связать конфигурацию, расширения и внешние
объекты через имена members:

```toml
[analysis]
default_application = "accounting"

[applications.accounting]
configuration = "main"
extensions = ["integration", "reports"]
external_objects = ["data-import"]
extension_dependencies = { reports = ["integration"] }
```

`eska` без подкоманды проверяет имена, типы members и граф. Пути берутся из
их `project.source`; несколько приложений не объединяются. Resolver контекста
доступен в общей Rust-библиотеке; самостоятельный CLI и интеграция анализатора
ещё разрабатываются. [Полная схема, выбор и платформа](docs/application-context.md).

### Правила работы с Git

| Preset | Основная ветка | Базовая ветка | Ветка задачи | Цель интеграции |
|---|---|---|---|---|
| `trunk` | `main` | `main` | `task/{task}` | `main` |
| `github-flow` | `main` | `main` | `feature/{task}` | `main` |
| `git-flow` | `main` | `develop` | `feature/{task}` | `develop` |

Базовая ветка должна существовать и иметь первый коммит. `new` создаёт пустую
`main` независимо от preset; для Git Flow подготовьте `develop` средствами Git.
`custom` требует полной policy или наследования от стандартного preset.
Ветки release/hotfix Git Flow пока не создаются командами `eska`.

Чтобы использовать `master` как основную production-ветку Git Flow, сохранив
создание и интеграцию feature-веток через `develop`:

```toml
[vcs.workflow]
preset = "git-flow"

[vcs.workflow.policy]
main_branch = "master"
```

Чтобы использовать `master` как общую базу и цель интеграции Trunk:

```toml
[vcs.workflow]
preset = "trunk"

[vcs.workflow.policy]
main_branch = "master"
base_branch = "master"
integration_target = "master"
task_branch_template = "task/{task}"
```

`main_branch`, `base_branch` и `integration_target` — разные роли. Настройки
описывают уже подготовленный репозиторий, но не переименовывают ветки и не меняют
HEAD. В частности, `eska start` использует `base_branch`, поэтому приведённый
Git Flow override продолжает создавать `feature/*` от `develop`.
Подробнее: [модель workflow](docs/roadmap/03-repository-workflow.md).

### Машина: платформа и Distrobox

Пути установки и контейнер хранятся отдельно от проекта:

```bash
eska config init
eska config edit
```

Глобальный конфиг использует системный пользовательский каталог настроек.
`config edit` проверяет изменения и сохраняет резервную копию предыдущей версии.

Рекомендуемый режим — `auto`:

```toml
[build]
runner = "auto"
```

Сначала `eska` ищет `ibcmd` в `PATH` и стандартном каталоге установки платформы
на основной системе. Если там ничего нет, а в настройках указано имя контейнера,
поиск может продолжиться через Distrobox. Режим `host` ограничивает поиск основной
системой.

Если платформа установлена только в Distrobox, задайте контейнер явно:

```toml
[build]
runner = "distrobox"
container = "1c-ubuntu-env"
platform_arch = "x86_64"
```

Контейнер должен уже существовать, запускаться командой `distrobox` и содержать
нужную платформу 1С. `eska` не создаёт контейнер и не устанавливает в него 1С.
Имя контейнера можно передать только для одного запуска:

```bash
eska build --distrobox 1c-ubuntu-env
```

Если известен путь к `ibcmd` на основной системе, его также можно передать для
одного запуска:

```bash
eska build --ibcmd /path/to/ibcmd
```

Приоритет: CLI → `ESKA_IBCMD`, `ESKA_PLATFORM_ARCH`, `ESKA_DISTROBOX` →
глобальный конфиг → автоматический поиск. Явный `--ibcmd` выбирает запуск на хосте.
Параметры платформы доступны также у `patch`.

### Диагностика окружения

Перед началом работы можно проверить проект, инструменты 1С и Git одним
read-only запуском:

```bash
eska doctor
eska doctor --format json
```

`doctor` проверяет конфигурацию и корневой Designer XML-дескриптор, требуемую
версию платформы, `ibcmd` и `1cv8`, repository/workflow, незавершённые операции
Git, автора commit, remote и Git LFS, когда его требует `.gitattributes`.
Проверка remote не обращается к сети. Отсутствующий remote допустим для локальной
работы, а пустой каркас после `new` показывается отдельно от повреждённой или
неполной выгрузки.

В workspace действуют общие selectors:

```bash
eska doctor -p sales-report
eska doctor --workspace
```

Независимые проверки продолжаются после ошибки, зависимые получают статус
`skipped` с причиной. Human-вывод содержит способы исправления; JSON schema 1
содержит стабильные `id`, `status`, `code`, список затронутых команд и summary и
не зависит от языка. В интерактивном терминале маркеры статусов выделяются
цветом; перенаправленный вывод и режим `NO_COLOR` остаются без ANSI. `doctor`
возвращает код `0`, если нет статуса `fail`
(предупреждения допустимы), `1` при одном или нескольких `fail` и `2` при ошибке
аргументов. Команда не изменяет исходники, config, Git index/refs и artifacts и
не подтверждает успешность будущей сборки или выполнения приложения 1С.

## Редактирование свойств метаданных

`eska metadata inspect` возвращает JSON со свойствами и схемой допустимых
изменений. `metadata types` перечисляет типы, `metadata choices` — допустимые
ссылки на объекты, `metadata check` показывает точный
patch без записи, `metadata apply` применяет одно изменение с проверкой снимка.
Эти команды используют тот же core, что редактор свойств VS Code.
[Контракт JSON, ограничения и гарантии записи](docs/metadata-editing.md).

## Все команды

| Команда | Назначение |
|---|---|
| `eska` | Проверить настройки проекта и каталог исходников |
| `update [--check]` | Проверить или обновить установленную ESKA |
| `new <path> [--from <file>]` | Создать каркас либо проект из файла 1С |
| `import <file> [--dry-run]` | Проверить и обновить исходники одного проекта из файла 1С |
| `init [path]` | Подключить XML-выгрузку Конфигуратора |
| `clone <url> [directory]` | Клонировать репозиторий с проектом |
| `start <task>` | Создать ветку задачи |
| `status` | Посмотреть состояние проекта |
| `diff [revision] [revision]` | Посмотреть изменения файлов или объектов |
| `save [--dry-run] [-m <message>]` | Просмотреть или сохранить изменения в commit |
| `history [--limit <n>]` | Посмотреть локальную историю |
| `doctor` | Проверить готовность окружения для текущих команд |
| `switch <task>` / `switch --base` | Перейти к задаче или базовой ветке с сохранением незавершённых изменений |
| `shelve` / `unshelve [id]` / `shelves` | Сохранить, восстановить или посмотреть полки веток |
| `finish` | Проверить условия завершения и закрыть локальную задачу |
| `check` | Полная структурная и статическая проверка через самостоятельный `eska-check` |
| `build [--dry-run|--manifest]` | Просмотреть план или собрать полный нативный файл с необязательным паспортом |
| `patch` | Собрать ограниченный patch-extension из Git delta |
| `version` / `version bump <patch|minor|major>` | Показать или точечно изменить версии проектов 1С |
| `platform list` | Найти установки платформы |
| `ide --stdio` | Запустить backend дерева и поиска; запись свойств включается явно в API 1.6 |
| `metadata` | Читать схемы, проверять и применять изменения свойств через JSON |
| `config init` / `config edit` | Настроить локальное окружение |

Все флаги конкретной команды: `eska <command> --help`.
Публикация, синхронизация, блокировки объектов, `check`, `fmt`, `apply`
и `run` пока не представлены отдельными работающими командами.

### Подключение IDE

`eska ide --stdio` обслуживает дерево Designer XML, свойства, пути исходников и
поиск в одном процессе. Клиент открывает проект по обязательному `eska.toml`,
явно запускает индекс и передаёт события своего файлового наблюдателя.
Подписи свойств и известных значений на русском и английском предоставляет отдельный
[каталог платформы 8.3.27/8.5.1](docs/platform-catalog.md); XML-имена сохраняются.
Исходники, manifest и Git не изменяются; по умолчанию разрешён производный кеш
`.eska/cache/metadata`, отключаемый параметром `diskCache:false` при открытии.

Stdout содержит только JSON-RPC 2.0 с заголовками `Content-Length`; это отдельный
[IDE protocol 1.3](docs/ide-protocol.md), не CLI JSON и не LSP. Платформа 1С для
него не требуется. В отдельном репозитории `eska-vscode-explorer` реализована
основа подключения расширения `eska: 1C Explorer`, дерево, открытие XML/BSL,
поиск, фильтр пустых разделов корня и внутри «Общие», иконки (T76–T80).
В T81 подготовлена локальная упаковка VSIX `1c-tooling.eska-explorer`; итоговая приёмка продолжается.
[Границы расширения](docs/roadmap/14-vscode-extension.md) отделены от команд сборки/Git
и выбранной пользователем поддержки языка BSL.

Проверка поддержки при открытии исходника использует `metadata/supportFiles`:
читаются текущие правила и дескрипторы владельца выбранного файла. Полный обход
конфигурации и загрузка всех ограничений больше не нужны для открытия дерева.

### Язык и вывод для скриптов

```bash
eska --lang ru status
eska --lang en build --help
eska status --format json
eska diff --semantic --format json
eska diff --raw
```

Язык выбирается через `--lang`, затем `ESKA_LANG`, затем локаль ОС.
JSON доступен у `status`, `diff`, `history`, `doctor`, `build`, `patch`, `version`,
`platform list`;
он не зависит от языка. Диагностика идёт в stderr. У `diff` схема JSON зависит
от режима: workspace — 1, revisions — 2, semantic — 4.
`--raw` и `--format` у `diff` взаимоисключающие.

Успешный semantic JSON v4 содержит `analysis.complete`. При значении `false`
массив `analysis.fallbacks` перечисляет точные `path`, `path_encoding`, `stage`
и стабильную `reason`; команда сохраняет exit code 0, а пояснение выводит в
stderr. Поддерживаются причины `descriptor-parse`, `routine-parse`,
`owner-inferred` и `owner-unresolved`. Ошибка самого semantic-анализа после
получения файлового diff возвращает exit code 1 и документ
`{"schema_version":4,"kind":"semantic","status":"error","error":{"code":"…"}}`;
для workspace значение `kind` равно `semantic_workspace`. Коды ошибок:
`repository`, `object-model` и `project-outside-repository`.

`status --format json` использует schema 3; `workflow.main_branch` содержит
эффективную основную production-ветку. Значения UTF-8 сохранены без
изменений и помечены `utf-8` в `root_encoding`, `name_encoding` и
`branch_encoding`. Произвольные байты Unix-путей и Git-веток представлены как
последовательность `%HH` с encoding `percent`; не-Unicode Windows-пути — как
последовательность UTF-16 units `%HHHH` с encoding `utf-16-percent`.

После успешного разбора аргументов ошибка `build --format json` возвращается в
stdout как `{"schema_version":1,"status":"error","error":{"code":"…"}}`.
В `error` также присутствуют `stage` и `project`, когда этап и workspace member
известны. `code`, `stage` и `project` не зависят от языка; локализованное описание
остаётся в stderr. Ошибки самого разбора аргументов выводит CLI parser без
JSON-документа.

Код `0` означает успешное выполнение, `1` — ошибку операции, `2` — ошибку
аргументов. Наличие изменений в `diff` само по себе не является ошибкой.
При перенаправлении вывод остаётся без терминального оформления;
непустой `NO_COLOR` отключает цвет.

### JSON полок и переключения

Успешный `shelve`/`unshelve` возвращает `schema_version: 1`, `operation`,
`dry_run` и `shelf`. `shelves` возвращает `schema_version: 1` и массив `shelves`.
У `switch` поля `operation: "switch"`, `dry_run`, `task` (либо `null` для базы),
`branch`, `saved` и `restored`; отсутствующая полка представлена `null`.

Документ полки содержит `id`, полную `branch` ref, `branch_encoding`, исходный
commit `base`, `created_at` (Unix seconds) и `files`. У preview новой полки
`id` и `created_at` равны `null`. Каждый путь содержит `path`, `path_encoding`,
`index` и `worktree`; состояния независимы, отсутствие изменения — `null`.
Переименования представлены удалением и добавлением. Для UTF-8 используется
encoding `utf-8`, для произвольных байтов Git — `percent`.

Ошибка после разбора аргументов возвращает в stdout
`{"schema_version":1,"status":"error","error":{"code":"…"}}`,
локализованную причину в stderr и exit code 1. Коды полок: `repository`,
`command`, `io`, `invalid-shelf`, `locked`, `detached`, `unborn`, `in-progress`,
`unsupported-index`, `empty`, `shelf-exists`, `shelf-missing`, `wrong-branch`,
`moved-branch`, `dirty`, `collision`, `incomplete`. Discovery возвращает
`project-discovery`; `switch` дополнительно использует `workflow-missing`,
`policy`, `project-outside-repository`, `task-branch-missing`,
`base-branch-missing`, `target-checked-out`. Machine-facing значения не зависят
от языка; ошибки CLI parsing сохраняют exit code 2 без JSON.

Правила поддержки Designer XML и ограничения их чтения: [описание](docs/support-policy.md).