odata1c-gate 0.1.0__tar.gz
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.
- odata1c_gate-0.1.0/.gitignore +65 -0
- odata1c_gate-0.1.0/CHANGELOG.md +83 -0
- odata1c_gate-0.1.0/LICENSE +21 -0
- odata1c_gate-0.1.0/PKG-INFO +233 -0
- odata1c_gate-0.1.0/README.md +209 -0
- odata1c_gate-0.1.0/pyproject.toml +78 -0
- odata1c_gate-0.1.0/src/odata1c/__about__.py +1 -0
- odata1c_gate-0.1.0/src/odata1c/__init__.py +5 -0
- odata1c_gate-0.1.0/src/odata1c/__main__.py +11 -0
- odata1c_gate-0.1.0/src/odata1c/cli.py +1278 -0
- odata1c_gate-0.1.0/src/odata1c/client1c/__init__.py +0 -0
- odata1c_gate-0.1.0/src/odata1c/client1c/client.py +319 -0
- odata1c_gate-0.1.0/src/odata1c/client1c/errors.py +119 -0
- odata1c_gate-0.1.0/src/odata1c/config/__init__.py +0 -0
- odata1c_gate-0.1.0/src/odata1c/config/home.py +186 -0
- odata1c_gate-0.1.0/src/odata1c/config/importer.py +87 -0
- odata1c_gate-0.1.0/src/odata1c/config/loader.py +250 -0
- odata1c_gate-0.1.0/src/odata1c/config/models.py +149 -0
- odata1c_gate-0.1.0/src/odata1c/config/writer.py +602 -0
- odata1c_gate-0.1.0/src/odata1c/daemon.py +2224 -0
- odata1c_gate-0.1.0/src/odata1c/doctor.py +490 -0
- odata1c_gate-0.1.0/src/odata1c/gate/__init__.py +0 -0
- odata1c_gate-0.1.0/src/odata1c/gate/contact_info.py +392 -0
- odata1c_gate-0.1.0/src/odata1c/gate/detectors.py +399 -0
- odata1c_gate-0.1.0/src/odata1c/gate/dictionary.py +1291 -0
- odata1c_gate-0.1.0/src/odata1c/gate/field_rules.py +237 -0
- odata1c_gate-0.1.0/src/odata1c/gate/filter_lexer.py +119 -0
- odata1c_gate-0.1.0/src/odata1c/gate/guard.py +574 -0
- odata1c_gate-0.1.0/src/odata1c/gate/masking.py +1191 -0
- odata1c_gate-0.1.0/src/odata1c/gate/overlaps.py +224 -0
- odata1c_gate-0.1.0/src/odata1c/gate/pipeline.py +590 -0
- odata1c_gate-0.1.0/src/odata1c/gate/policy.py +578 -0
- odata1c_gate-0.1.0/src/odata1c/gate/policy_check.py +362 -0
- odata1c_gate-0.1.0/src/odata1c/gate/policy_edit.py +115 -0
- odata1c_gate-0.1.0/src/odata1c/gate/revealed.py +336 -0
- odata1c_gate-0.1.0/src/odata1c/gate/service.py +124 -0
- odata1c_gate-0.1.0/src/odata1c/gate/tokens.py +213 -0
- odata1c_gate-0.1.0/src/odata1c/gate/unmasking.py +1757 -0
- odata1c_gate-0.1.0/src/odata1c/index/__init__.py +0 -0
- odata1c_gate-0.1.0/src/odata1c/index/edmx.py +547 -0
- odata1c_gate-0.1.0/src/odata1c/index/naming.py +83 -0
- odata1c_gate-0.1.0/src/odata1c/index/reindex.py +229 -0
- odata1c_gate-0.1.0/src/odata1c/index/repository.py +561 -0
- odata1c_gate-0.1.0/src/odata1c/index/schema.py +107 -0
- odata1c_gate-0.1.0/src/odata1c/launch_parent.py +244 -0
- odata1c_gate-0.1.0/src/odata1c/launcher.py +614 -0
- odata1c_gate-0.1.0/src/odata1c/recipes/__init__.py +0 -0
- odata1c_gate-0.1.0/src/odata1c/recipes/model.py +579 -0
- odata1c_gate-0.1.0/src/odata1c/recipes/render.py +179 -0
- odata1c_gate-0.1.0/src/odata1c/registry/__init__.py +0 -0
- odata1c_gate-0.1.0/src/odata1c/registry/registry.py +158 -0
- odata1c_gate-0.1.0/src/odata1c/templates/__init__.py +1 -0
- odata1c_gate-0.1.0/src/odata1c/templates/bases.example.yaml +58 -0
- odata1c_gate-0.1.0/src/odata1c/templates/daemon.example.yaml +17 -0
- odata1c_gate-0.1.0/src/odata1c/templates/policy.example.yaml +49 -0
- odata1c_gate-0.1.0/src/odata1c/templates/recipes/__init__.py +1 -0
- odata1c_gate-0.1.0/src/odata1c/templates/recipes/bp.yaml +8 -0
- odata1c_gate-0.1.0/src/odata1c/templates/recipes/ut.yaml +165 -0
- odata1c_gate-0.1.0/src/odata1c/templates/recipes/zup.yaml +12 -0
- odata1c_gate-0.1.0/src/odata1c/tools/__init__.py +0 -0
- odata1c_gate-0.1.0/src/odata1c/tools/describe.py +189 -0
- odata1c_gate-0.1.0/src/odata1c/tools/info.py +317 -0
- odata1c_gate-0.1.0/src/odata1c/tools/odata_query.py +503 -0
- odata1c_gate-0.1.0/src/odata1c/tools/response.py +208 -0
- odata1c_gate-0.1.0/src/odata1c/tools/service.py +2740 -0
- odata1c_gate-0.1.0/src/odata1c/write/__init__.py +0 -0
- odata1c_gate-0.1.0/src/odata1c/write/confirm.py +96 -0
- odata1c_gate-0.1.0/src/odata1c/write/errors.py +34 -0
- odata1c_gate-0.1.0/src/odata1c/write/journal.py +461 -0
- odata1c_gate-0.1.0/src/odata1c/write/pending.py +312 -0
- odata1c_gate-0.1.0/src/odata1c/write/permissions.py +202 -0
- odata1c_gate-0.1.0/src/odata1c/write/preview.py +65 -0
- odata1c_gate-0.1.0/src/odata1c/write/service.py +3339 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# --- Секреты и локальные данные шлюза (SPEC §2.3, §3.4) --------------------
|
|
2
|
+
# bases.yaml содержит пароли 1С открытым текстом и не попадает в репозиторий
|
|
3
|
+
# ни при каких условиях; в git живут только файлы-шаблоны *.example.yaml.
|
|
4
|
+
bases.yaml
|
|
5
|
+
daemon.yaml
|
|
6
|
+
policy.yaml
|
|
7
|
+
recipes.yaml
|
|
8
|
+
!*.example.yaml
|
|
9
|
+
!src/odata1c/templates/**
|
|
10
|
+
|
|
11
|
+
# env-файлы прежнего сервера 1c-odata-mcp (источник для `odata1c base import`)
|
|
12
|
+
.env
|
|
13
|
+
.env.*
|
|
14
|
+
*.env
|
|
15
|
+
!*.env.example
|
|
16
|
+
|
|
17
|
+
# Домашний каталог шлюза, если он поднят внутри дерева репозитория (--home .)
|
|
18
|
+
gate.sqlite
|
|
19
|
+
journal.sqlite
|
|
20
|
+
metadata.sqlite
|
|
21
|
+
*.sqlite
|
|
22
|
+
*.sqlite-wal
|
|
23
|
+
*.sqlite-shm
|
|
24
|
+
metadata.edmx
|
|
25
|
+
logs/
|
|
26
|
+
|
|
27
|
+
# Полные выгрузки $metadata боевых баз: в тестах живут урезанные образцы,
|
|
28
|
+
# многомегабайтные дампы в репозиторий не кладём (SPEC §12).
|
|
29
|
+
tests/fixtures/edmx/*.full.edmx
|
|
30
|
+
|
|
31
|
+
# --- Python ----------------------------------------------------------------
|
|
32
|
+
__pycache__/
|
|
33
|
+
*.py[cod]
|
|
34
|
+
*.egg-info/
|
|
35
|
+
build/
|
|
36
|
+
dist/
|
|
37
|
+
.venv/
|
|
38
|
+
venv/
|
|
39
|
+
.pytest_cache/
|
|
40
|
+
.mypy_cache/
|
|
41
|
+
.ruff_cache/
|
|
42
|
+
.coverage
|
|
43
|
+
.coverage.*
|
|
44
|
+
htmlcov/
|
|
45
|
+
|
|
46
|
+
# --- Окружение разработчика ------------------------------------------------
|
|
47
|
+
# Служебные файлы, к проекту не относятся (AGENTS.md «Структура репозитория»)
|
|
48
|
+
.remember/
|
|
49
|
+
*.code-workspace
|
|
50
|
+
.claude/settings.local.json
|
|
51
|
+
.idea/
|
|
52
|
+
.vscode/
|
|
53
|
+
Thumbs.db
|
|
54
|
+
.DS_Store
|
|
55
|
+
|
|
56
|
+
# Рабочие каталоги исполнения планов (superpowers SDD)
|
|
57
|
+
.superpowers/
|
|
58
|
+
|
|
59
|
+
# Служебные каталоги: кэш hypothesis, рабочие копии агентов Claude Code
|
|
60
|
+
.hypothesis/
|
|
61
|
+
.claude/worktrees/
|
|
62
|
+
|
|
63
|
+
# --- Плагин Claude Code ------------------------------------------------------
|
|
64
|
+
# Результаты прогонов claude plugin eval — не поставка, локальный вывод (M3 задача 7).
|
|
65
|
+
plugin/evals/results/
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Изменения
|
|
2
|
+
|
|
3
|
+
Формат — по [Keep a Changelog](https://keepachangelog.com/ru/1.1.0/), нумерация —
|
|
4
|
+
[семантическая](https://semver.org/lang/ru/). Даты в формате ГГГГ-ММ-ДД.
|
|
5
|
+
|
|
6
|
+
## 0.1.0 — 2026-09-14
|
|
7
|
+
|
|
8
|
+
Первый выпуск. Дистрибутив на PyPI — `odata1c-gate`, пакет Python и команда — `odata1c`.
|
|
9
|
+
|
|
10
|
+
### Чтение (этап M1)
|
|
11
|
+
|
|
12
|
+
- Демон `odata1c daemon` — единственный процесс на машину, MCP Streamable HTTP на
|
|
13
|
+
`127.0.0.1:7171`; лаунчер `odata1c mcp` — тонкий stdio-процесс на сессию без собственной логики.
|
|
14
|
+
- Несколько баз 1С в одном `bases.yaml`, роли `prod | test | dev` с умолчаниями уровня гейта,
|
|
15
|
+
разрешения записи и лимита коммитов; видимость баз сужается аргументами лаунчера.
|
|
16
|
+
- Индекс метаданных: разбор `$metadata` (EDMX) в SQLite, нечёткий поиск сущностей, реиндекс по
|
|
17
|
+
контрольной сумме, классы полей по классификатору.
|
|
18
|
+
- Гейт псевдонимизации трёх уровней (`off | identifiers | identifiers+names`): реквизиты
|
|
19
|
+
(ИНН, КПП, ОГРН, счета, БИК, карты, СНИЛС, документы, телефоны, почта, даты рождения, адреса),
|
|
20
|
+
названия организаций и ФИО заменяются токенами `[[type:tail]]`; обратная подмена в отборах,
|
|
21
|
+
ключах и параметрах — только внутри шлюза. Страж утечек — последний проход по готовому ответу.
|
|
22
|
+
- Девять тулов чтения: `odata1c_bases`, `odata1c_find_entity`, `odata1c_describe_entity`,
|
|
23
|
+
`odata1c_query`, `odata1c_get`, `odata1c_info`, `odata1c_reindex`, `odata1c_raw_get`,
|
|
24
|
+
`odata1c_recipe`; ресурсы и промпт `explore`.
|
|
25
|
+
- Контактная информация БСП закрывается по типу строки, адреса физических лиц, ИП и доставки — по
|
|
26
|
+
правилу адресов; отбор по полям контактной информации принимается только токеном.
|
|
27
|
+
- Приёмка на живой базе 1С: 15 проверок из 15 чтения и 11 из 11 контактной информации
|
|
28
|
+
(`docs/probes/M1d-live-check.md`).
|
|
29
|
+
|
|
30
|
+
### Запись (этап M2)
|
|
31
|
+
|
|
32
|
+
- Двухфазный протокол: пишущий тул готовит pending-операцию с превью в токенах и не трогает 1С;
|
|
33
|
+
выполняет её `odata1c_commit` после подтверждения человека механизмом клиента (диалог
|
|
34
|
+
разрешения Claude Code или elicitation). `commit` идемпотентен по `pending_id`.
|
|
35
|
+
- Семь тулов записи: `odata1c_create`, `odata1c_update`, `odata1c_mark_for_deletion`,
|
|
36
|
+
`odata1c_action` (`Post`/`Unpost`), `odata1c_undo`, `odata1c_commit`, `odata1c_journal`.
|
|
37
|
+
- Разрешения базы проверяются до создания pending-операции; журнал коммитов и откат каждой записи.
|
|
38
|
+
- Подпись лаунчера ключом `launcher.key` и заверение его родительского процесса: механизм
|
|
39
|
+
подтверждения Claude Code демон выдаёт только настоящему лаунчеру.
|
|
40
|
+
- Приёмка на живой базе 1С: 249 проверок из 249 скриптом и ручная проверка диалога разрешения
|
|
41
|
+
владельцем (`docs/probes/M2-live-check.md`).
|
|
42
|
+
|
|
43
|
+
### Политика владельца (ADR-0015)
|
|
44
|
+
|
|
45
|
+
- Две точки управления: `bases.yaml` на машину («кто база, как с ней работать, скрывать ли») и
|
|
46
|
+
`bases/<база>/policy.yaml` на базу («что скрывать и что открыть»). Авторазметка реиндекса
|
|
47
|
+
отдельным файлом `policy.auto.yaml`, который владелец не редактирует.
|
|
48
|
+
- Конструктор политики: `odata1c policy show | check | hide | open | set` пишет `policy.yaml` с
|
|
49
|
+
сохранением комментариев; навык плагина `odata1c-policy` ведёт к этим командам. Тула MCP для
|
|
50
|
+
изменения политики нет.
|
|
51
|
+
- `bases.yaml` и `policy.yaml` перечитываются по изменению файла, без перезапуска демона.
|
|
52
|
+
|
|
53
|
+
### Поставка (этап M3)
|
|
54
|
+
|
|
55
|
+
- Пакет `odata1c-gate` на PyPI; установка командной строки — `uv tool install odata1c-gate`,
|
|
56
|
+
запуск без установки — `uvx --from odata1c-gate odata1c …`.
|
|
57
|
+
- Плагин Claude Code `odata1c` из маркетплейса GitHub: MCP-сервер с закреплённой версией пакета,
|
|
58
|
+
три навыка (`odata1c`, `odata1c-policy`, `odata1c-recipe`), хук `PreToolUse` и агент-следователь
|
|
59
|
+
`odata1c-investigator` (только чтение).
|
|
60
|
+
- `odata1c doctor [--online]` — проверка окружения без секретов в выводе; `odata1c --version`.
|
|
61
|
+
- Библиотека рецептов по конфигурации 1С: `recipes/<конфигурация>/<имя>.yaml`, поле `config` у
|
|
62
|
+
записи базы, три слоя (рецепт базы → библиотека конфигурации → шаблон пакета) и команды
|
|
63
|
+
`odata1c recipe check | list`.
|
|
64
|
+
- Документация для внешнего читателя: `README.md`, `docs/install.md`, этот файл.
|
|
65
|
+
- Непрерывная проверка в GitHub Actions на Windows и Ubuntu, Python 3.12 и 3.13; выпуск на PyPI
|
|
66
|
+
по тегу через trusted publishing.
|
|
67
|
+
|
|
68
|
+
### Ограничения выпуска
|
|
69
|
+
|
|
70
|
+
- Физического удаления объектов нет: только пометка удаления. `PUT` не используется. Удаление
|
|
71
|
+
записей независимых регистров сведений в первую поставку не вошло.
|
|
72
|
+
- Записи в регистры, подчинённые регистратору, нет ни при каком флаге разрешений.
|
|
73
|
+
- Сокращённое название организации в свободном тексте (комментарий документа) гейт не заменяет:
|
|
74
|
+
словарь знает полные написания, а ловить «ядро» названия отвергнуто из-за ложных срабатываний.
|
|
75
|
+
- Шаблоны рецептов заполнены только для УТ; для БП и ЗУП они пустые, пока нет базы для сверки имён.
|
|
76
|
+
- Строка табличной части в теле `odata1c_create` должна нести `LineNumber`, иначе 1С отвечает
|
|
77
|
+
внутренней ошибкой сервиса OData; шлюз этого не проверяет. Поле `Edm.Int64` публикация отдаёт
|
|
78
|
+
строкой, а шлюз на запись требует число — расхождение видно по предупреждению после перечитывания
|
|
79
|
+
объекта.
|
|
80
|
+
- У демона нет аутентификации, он слушает только `127.0.0.1`; публикация по сети с TLS и токенами
|
|
81
|
+
— этап M4.
|
|
82
|
+
- Поддерживается Claude Code; Claude Desktop и Cowork — нет (ADR-0012). Настоящий Claude Code на
|
|
83
|
+
Linux в этом выпуске не проверялся: Linux закрыт прогонами GitHub Actions.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Roman Danilov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: odata1c-gate
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Локальный MCP-шлюз к OData 1С:Предприятие с гейтом псевдонимизации
|
|
5
|
+
Project-URL: Homepage, https://github.com/Romandredan/odata1c-gate
|
|
6
|
+
Project-URL: Repository, https://github.com/Romandredan/odata1c-gate
|
|
7
|
+
Author: Roman Danilov
|
|
8
|
+
License: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Python: >=3.12
|
|
11
|
+
Requires-Dist: ahocorasick-rs>=0.22
|
|
12
|
+
Requires-Dist: httpx2>=2.12
|
|
13
|
+
Requires-Dist: httpx>=0.27
|
|
14
|
+
Requires-Dist: lxml>=5.2
|
|
15
|
+
Requires-Dist: mcp>=2.2
|
|
16
|
+
Requires-Dist: pydantic>=2.7
|
|
17
|
+
Requires-Dist: pyyaml>=6.0
|
|
18
|
+
Requires-Dist: ruamel-yaml>=0.18
|
|
19
|
+
Requires-Dist: snowballstemmer>=2.2
|
|
20
|
+
Requires-Dist: uvicorn>=0.30
|
|
21
|
+
Provides-Extra: keyring
|
|
22
|
+
Requires-Dist: keyring>=25.0; extra == 'keyring'
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# odata1c-gate
|
|
26
|
+
|
|
27
|
+
Локальный MCP-шлюз между Claude Code и стандартным OData-интерфейсом 1С:Предприятие 8.3.
|
|
28
|
+
Модель получает доступ к данным базы — справочникам, документам, регистрам, — но между ней и 1С
|
|
29
|
+
стоит **гейт псевдонимизации**: реквизиты (ИНН, счета, паспорта, телефоны) и, на выбранном уровне,
|
|
30
|
+
названия организаций и ФИО заменяются токенами вида `[[type:tail]]` до того, как данные увидит
|
|
31
|
+
модель. Обратная подмена происходит только внутри шлюза, перед отправкой запроса в 1С.
|
|
32
|
+
|
|
33
|
+
Один пользователь, одна машина, несколько сессий агентов одновременно, несколько баз 1С.
|
|
34
|
+
Клиент — Claude Code (другие клиенты MCP работают, но подтверждение записи у них устроено иначе,
|
|
35
|
+
см. [docs/install.md](docs/install.md)).
|
|
36
|
+
|
|
37
|
+
**Статус: чтение и запись закрыты (M1, M2), идёт этап поставки M3.** Работают демон, лаунчер,
|
|
38
|
+
индекс метаданных, гейт всех уровней, девять тулов чтения и семь тулов записи; приёмка на живой
|
|
39
|
+
базе 1С пройдена и для чтения, и для записи ([docs/probes/M1d-live-check.md](docs/probes/M1d-live-check.md),
|
|
40
|
+
[docs/probes/M2-live-check.md](docs/probes/M2-live-check.md)). Этап M3 собирает всё это в пакет
|
|
41
|
+
PyPI и плагин Claude Code; первый выпуск — `0.1.0` ([CHANGELOG.md](CHANGELOG.md)).
|
|
42
|
+
|
|
43
|
+
## Зачем это
|
|
44
|
+
|
|
45
|
+
Дать модели читать рабочую базу 1С — значит отдать ей персональные данные и коммерческую тайну:
|
|
46
|
+
ИНН контрагентов, расчётные счета, телефоны и адреса физических лиц, названия клиентов.
|
|
47
|
+
Обезличивать выгрузку заранее неудобно (модель должна видеть свежие данные и уметь дозапрашивать),
|
|
48
|
+
а инструктировать модель «не показывай ИНН» бессмысленно — инструкция не механизм.
|
|
49
|
+
|
|
50
|
+
Шлюз решает это подменой на границе: модель работает с живой базой, но защищаемые значения
|
|
51
|
+
заменяются токенами до того, как попадут в её контекст. Токен детерминирован (одно значение — один
|
|
52
|
+
токен), поэтому по нему можно отбирать, связывать записи и вести разговор, не зная исходного
|
|
53
|
+
значения. Разработчик, который читает ответы модели, видит `[[inn:M4T2Q9XZ7K]]`, а не ИНН — и при
|
|
54
|
+
необходимости раскрывает его сам, командой в терминале, мимо модели.
|
|
55
|
+
|
|
56
|
+
## Что видит модель, а что нет
|
|
57
|
+
|
|
58
|
+
**Что уходит модели.** Структура базы (сущности, поля, ключи, навигация) и данные, прошедшие
|
|
59
|
+
гейт. Номера и даты документов, суммы, количества, коды, GUID, значения перечислений не
|
|
60
|
+
защищаются ни на одном уровне — без них работа с базой теряет смысл. Названия организаций и ФИО
|
|
61
|
+
(классы `org` и `person`) и защищаемые реквизиты — ИНН, КПП, ОГРН, счета, БИК, карты, СНИЛС,
|
|
62
|
+
документы, телефоны, почта, даты рождения, адреса — приходят токенами `[[type:tail]]` по правилам
|
|
63
|
+
политики базы. Уровень задаётся на базу: `off` — гейт выключен, `identifiers` — реквизиты,
|
|
64
|
+
`identifiers+names` — реквизиты плюс названия и ФИО.
|
|
65
|
+
|
|
66
|
+
**Что не уходит никогда.** Реальные значения защищаемых классов не выходят через MCP ни в одном
|
|
67
|
+
ответе: ни в данных, ни в текстах ошибок 1С, ни в превью записи, ни в журнале, ни в
|
|
68
|
+
`odata1c_raw_get`, ни в вопросах подтверждения. Это инвариант, а не тест: последний проход по
|
|
69
|
+
готовому ответу делает страж утечек — он ищет в сериализованном ответе известные словарю значения
|
|
70
|
+
и заменяет их токенами, если что-то прошло мимо гейта. Учётные данные 1С модель не получает:
|
|
71
|
+
пароль не покидает домашнего каталога вовсе, имя пользователя 1С не попадает ни в один ответ, а
|
|
72
|
+
адрес публикации базы не возвращает ни один тул. О самой базе модель узнаёт ровно то, что
|
|
73
|
+
перечисляет `odata1c_bases`: имя, подпись, роль, уровень гейта, разрешена ли запись, состояние
|
|
74
|
+
индекса (собран ли, когда, сколько сущностей) и конфигурацию 1С, к которой база отнесена.
|
|
75
|
+
Единственное исключение по адресу — текст сетевого сбоя, в который его может вписать HTTP-клиент.
|
|
76
|
+
Хук плагина вдобавок запрещает модели читать файлы домашнего каталога шлюза. Раскрыть токен может
|
|
77
|
+
только владелец машины, командой `odata1c reveal` в своём терминале.
|
|
78
|
+
|
|
79
|
+
**Кто подтверждает запись.** Тулы записи ничего не пишут в 1С: они готовят операцию, показывают
|
|
80
|
+
превью в токенах и возвращают `pending_id`. Выполняет её отдельный вызов `odata1c_commit`, и
|
|
81
|
+
только после подтверждения человека механизмом клиента — в Claude Code это диалог разрешения,
|
|
82
|
+
у клиентов с elicitation — вопрос шлюза. Реплика «да» в чате подтверждением не считается: модель
|
|
83
|
+
не может подтвердить запись сама себе. Каждая выполненная запись попадает в локальный журнал и
|
|
84
|
+
откатывается тулом `odata1c_undo`. Записи в базах с ролью `prod` по умолчанию нет вовсе, а состав
|
|
85
|
+
разрешённого сужается флагами разрешений в настройках базы.
|
|
86
|
+
|
|
87
|
+
## Установка
|
|
88
|
+
|
|
89
|
+
Нужен [`uv`](https://docs.astral.sh/uv/) — он сам поставит подходящий Python, отдельно ставить
|
|
90
|
+
интерпретатор не нужно. Дальше две команды в терминале ставят плагин Claude Code вместе со шлюзом:
|
|
91
|
+
|
|
92
|
+
```text
|
|
93
|
+
claude plugin marketplace add Romandredan/odata1c-gate
|
|
94
|
+
claude plugin install odata1c@odata1c-gate
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Плагин приносит MCP-сервер шлюза, три навыка, хук подтверждения записи и агента-следователя.
|
|
98
|
+
Версия пакета закреплена в `plugin/.mcp.json`, поэтому `claude plugin update odata1c` обновляет и
|
|
99
|
+
плагин, и шлюз.
|
|
100
|
+
|
|
101
|
+
**Две оговорки.** Первая: обе команды заработают начиная с выпуска `0.1.0` — пока тег не
|
|
102
|
+
опубликован, пакета `odata1c-gate` на PyPI нет, и `uvx` при первом запуске шлюза ответит отказом
|
|
103
|
+
(`.mcp.json` плагина закреплён на версии из репозитория). Вторая: репозиторий пока приватный,
|
|
104
|
+
`claude plugin marketplace add` клонирует его через git, поэтому на машине нужны учётные данные
|
|
105
|
+
git с доступом к нему. Открытие репозитория — отдельное решение владельца.
|
|
106
|
+
|
|
107
|
+
Отдельно ставится командная строка — она нужна владельцу базы, а не модели (описать базу, собрать
|
|
108
|
+
индекс, раскрыть токен, править политику гейта):
|
|
109
|
+
|
|
110
|
+
```text
|
|
111
|
+
uv tool install odata1c-gate
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
После этого команда `odata1c` доступна в терминале. Без установки то же самое запускается как
|
|
115
|
+
`uvx --from odata1c-gate odata1c <команда>`. Подробности, Linux, обновление и разбор типовых
|
|
116
|
+
сбоев — [docs/install.md](docs/install.md).
|
|
117
|
+
|
|
118
|
+
## Первые пять минут
|
|
119
|
+
|
|
120
|
+
```text
|
|
121
|
+
odata1c init # ~/.claude/odata1c/ с шаблонами настроек, права владельца
|
|
122
|
+
odata1c base add ut_test --role test --recipes ut # спросит адрес, подпись, пользователя, пароль
|
|
123
|
+
odata1c base test ut_test # проверить соединение с 1С
|
|
124
|
+
odata1c reindex ut_test # разобрать $metadata и построить индекс метаданных
|
|
125
|
+
odata1c doctor # проверить окружение: uv, дом, базы, демон, Claude Code
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Начинать с `init` обязательно: плагин домашнего каталога не создаёт — его делают либо эта команда,
|
|
129
|
+
либо лаунчер при первой сессии Claude Code. `doctor` на пустом месте честно ответит `FAIL` в
|
|
130
|
+
строке домашнего каталога, поэтому он и стоит последним; запускать его можно в любой момент.
|
|
131
|
+
|
|
132
|
+
Адрес базы — это адрес публикации OData 1С, он оканчивается на `/odata/standard.odata/`
|
|
133
|
+
(например `https://1c.example.local/ut/odata/standard.odata/`). Пользователь 1С заводится
|
|
134
|
+
отдельный, с правами только на то, что нужно читать, — например `odata_claude`. Роль базы задаёт
|
|
135
|
+
умолчания: `prod` — уровень гейта `identifiers+names` и только чтение, `test` — уровень
|
|
136
|
+
`identifiers`, `dev` — гейт выключен и запись разрешена; любое поле переопределяется явно.
|
|
137
|
+
Пароль ложится в `bases.yaml` домашнего каталога открытым текстом, файл закрывается правами
|
|
138
|
+
владельца (ADR-0014).
|
|
139
|
+
|
|
140
|
+
Первый реиндекс долгий: у типовой УТ `$metadata` — это около 17 МБ описания и больше семи тысяч
|
|
141
|
+
сущностей. Дальше индекс пересобирается, только если у публикации изменилась контрольная сумма
|
|
142
|
+
`$metadata`.
|
|
143
|
+
|
|
144
|
+
Теперь можно спрашивать в Claude Code:
|
|
145
|
+
|
|
146
|
+
- «какие базы 1С мне доступны?» — модель вызовет `odata1c_bases`;
|
|
147
|
+
- «найди справочник контрагентов и покажи состав его полей» — `odata1c_find_entity`,
|
|
148
|
+
затем `odata1c_describe_entity` с классами гейта у каждого поля;
|
|
149
|
+
- «возьми любого контрагента и покажи его пять последних заказов клиента» — `odata1c_query`;
|
|
150
|
+
название контрагента придёт токеном, номера и суммы документов — как есть.
|
|
151
|
+
|
|
152
|
+
Что модель видит и в каком порядке ходит — навык `odata1c` из плагина; справочные темы об
|
|
153
|
+
устройстве OData 1С, токенах, политике и протоколе записи — тул `odata1c_info`.
|
|
154
|
+
|
|
155
|
+
## Что внутри
|
|
156
|
+
|
|
157
|
+
Два процесса из одного пакета: **демон** (`odata1c daemon`) — единственный на машину, держит
|
|
158
|
+
соединения с базами, индекс, словарь и журнал, отвечает по MCP Streamable HTTP на
|
|
159
|
+
`127.0.0.1:7171`; **лаунчер** (`odata1c mcp`) — тонкий stdio-процесс на сессию, который поднимает
|
|
160
|
+
демон при необходимости и проксирует ему вызовы. Собственной логики у лаунчера нет.
|
|
161
|
+
|
|
162
|
+
Тулы чтения: `odata1c_bases`, `odata1c_find_entity`, `odata1c_describe_entity`, `odata1c_query`,
|
|
163
|
+
`odata1c_get`, `odata1c_info`, `odata1c_reindex`, `odata1c_raw_get`, `odata1c_recipe`.
|
|
164
|
+
Тулы записи: `odata1c_create`, `odata1c_update`, `odata1c_mark_for_deletion`, `odata1c_action`
|
|
165
|
+
(проведение и отмена), `odata1c_undo`, `odata1c_commit`, `odata1c_journal`.
|
|
166
|
+
|
|
167
|
+
Рецепт — именованный параметризованный запрос к одной сущности («остатки на складе на дату»,
|
|
168
|
+
«задолженность контрагента»): модель подставляет параметры, шлюз строит запрос сам. Рецепты
|
|
169
|
+
копятся по конфигурации 1С, а не по отдельной базе.
|
|
170
|
+
|
|
171
|
+
## Ограничения
|
|
172
|
+
|
|
173
|
+
- **Физического удаления объектов нет.** «Удаление» для объектов и подчинённых регистров — только
|
|
174
|
+
пометка удаления (`DeletionMark = true`). `PUT` не используется.
|
|
175
|
+
- **Сокращённое название в свободном тексте проходит открытым.** Словарь знает полные написания
|
|
176
|
+
названия; если в комментарии документа человек написал узнаваемое сокращение, которого нет в
|
|
177
|
+
справочнике, гейт его не заменит. Ловить «ядро» названия отвергнуто: ядра — обычные слова, их
|
|
178
|
+
замена портила бы данные ложными срабатываниями.
|
|
179
|
+
- **Аутентификации у демона нет.** Он слушает только `127.0.0.1`; модель угроз — диск и машина
|
|
180
|
+
владельца. Публикация по сети с TLS и токенами — этап M4.
|
|
181
|
+
- **Записи в регистры, подчинённые регистратору, нет** ни при каком флаге разрешений: их пишет
|
|
182
|
+
проведение документа, а не прямая запись.
|
|
183
|
+
- **Шаблоны рецептов заполнены только для УТ.** Для БП и ЗУП шаблоны пока пустые: базы для сверки
|
|
184
|
+
имён нет, а невыверенный рецепт хуже пустого.
|
|
185
|
+
- **Клиент — Claude Code.** Claude Desktop и Cowork не поддерживаются (ADR-0012).
|
|
186
|
+
|
|
187
|
+
## Документы
|
|
188
|
+
|
|
189
|
+
| Файл | Что внутри |
|
|
190
|
+
|---|---|
|
|
191
|
+
| [docs/install.md](docs/install.md) | установка на Windows и Linux, обновление, типовые сбои, раздел сопровождающего |
|
|
192
|
+
| [CHANGELOG.md](CHANGELOG.md) | что вошло в выпуск |
|
|
193
|
+
| [SPEC.md](SPEC.md) | спецификация v0.2, 16 разделов — главный артефакт проекта |
|
|
194
|
+
| [CONTEXT.md](CONTEXT.md) | глоссарий: термины и запрещённые синонимы |
|
|
195
|
+
| [docs/adr/](docs/adr/) | 15 архитектурных решений (0001–0015), статус — во frontmatter |
|
|
196
|
+
| [AGENTS.md](AGENTS.md) | вводная для AI-агентов: архитектура, стек, инварианты, процесс |
|
|
197
|
+
| [CLAUDE.md](CLAUDE.md) | указатель для Claude Code поверх AGENTS.md |
|
|
198
|
+
|
|
199
|
+
## Структура репозитория
|
|
200
|
+
|
|
201
|
+
```text
|
|
202
|
+
src/odata1c/ пакет PyPI odata1c-gate: демон, лаунчер, CLI (SPEC §2.2, §11.1)
|
|
203
|
+
config/ bases.yaml и daemon.yaml, роли, валидация, права файлов
|
|
204
|
+
registry/ реестр баз, статус индекса, видимость по сессии
|
|
205
|
+
client1c/ httpx-пул на базу, IBSession, семафор, маппинг ошибок 1С
|
|
206
|
+
index/ парсер EDMX → metadata.sqlite, реиндекс, нечёткий поиск
|
|
207
|
+
gate/ детекторы реквизитов, словарь, подмена в обе стороны, страж
|
|
208
|
+
write/ разрешения, pending-операции, commit, журнал, undo
|
|
209
|
+
recipes/ загрузка рецептов и рендеринг параметров в OData-литералы
|
|
210
|
+
tools/ регистрация тулов, ресурсов, промптов, server instructions
|
|
211
|
+
templates/ файлы-шаблоны в поставке: конфигурация и рецепты УТ/БП/ЗУП
|
|
212
|
+
cli.py команды odata1c: init, base, reindex, policy, recipe, doctor, reveal, daemon, mcp
|
|
213
|
+
daemon.py демон: тулы, ресурсы, промпт, MCP Streamable HTTP на 127.0.0.1
|
|
214
|
+
launcher.py лаунчер: stdio-прокси демону, подъём демона, проброс elicitation
|
|
215
|
+
plugin/ плагин Claude Code: манифест, .mcp.json, навыки, хук, агент, evals (SPEC §11.2)
|
|
216
|
+
.claude-plugin/ маркетплейс плагина для claude plugin marketplace add
|
|
217
|
+
tests/ unit / property / integration + образцы EDMX (SPEC §12)
|
|
218
|
+
tools/ bump_version.py, plugin_dev_copy.py, probes/ — скрипты проверок и приёмки
|
|
219
|
+
docs/adr/ архитектурные решения
|
|
220
|
+
docs/plans/ планы реализации по этапам
|
|
221
|
+
docs/probes/ отчёты технических проверок P1–P8 и приёмок на живой базе
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Что не попадает в репозиторий
|
|
225
|
+
|
|
226
|
+
`bases.yaml` хранит пароли 1С открытым текстом (SPEC §3.4), поэтому в git не коммитятся
|
|
227
|
+
конфигурация рабочей машины, env-файлы, базы SQLite (словарь, индекс, журнал), выгрузки
|
|
228
|
+
`$metadata` и логи — см. [.gitignore](.gitignore). В поставке живут только файлы-шаблоны
|
|
229
|
+
в `src/odata1c/templates/`, в тестах — урезанные образцы `$metadata`, не полные дампы.
|
|
230
|
+
|
|
231
|
+
## Лицензия
|
|
232
|
+
|
|
233
|
+
MIT.
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# odata1c-gate
|
|
2
|
+
|
|
3
|
+
Локальный MCP-шлюз между Claude Code и стандартным OData-интерфейсом 1С:Предприятие 8.3.
|
|
4
|
+
Модель получает доступ к данным базы — справочникам, документам, регистрам, — но между ней и 1С
|
|
5
|
+
стоит **гейт псевдонимизации**: реквизиты (ИНН, счета, паспорта, телефоны) и, на выбранном уровне,
|
|
6
|
+
названия организаций и ФИО заменяются токенами вида `[[type:tail]]` до того, как данные увидит
|
|
7
|
+
модель. Обратная подмена происходит только внутри шлюза, перед отправкой запроса в 1С.
|
|
8
|
+
|
|
9
|
+
Один пользователь, одна машина, несколько сессий агентов одновременно, несколько баз 1С.
|
|
10
|
+
Клиент — Claude Code (другие клиенты MCP работают, но подтверждение записи у них устроено иначе,
|
|
11
|
+
см. [docs/install.md](docs/install.md)).
|
|
12
|
+
|
|
13
|
+
**Статус: чтение и запись закрыты (M1, M2), идёт этап поставки M3.** Работают демон, лаунчер,
|
|
14
|
+
индекс метаданных, гейт всех уровней, девять тулов чтения и семь тулов записи; приёмка на живой
|
|
15
|
+
базе 1С пройдена и для чтения, и для записи ([docs/probes/M1d-live-check.md](docs/probes/M1d-live-check.md),
|
|
16
|
+
[docs/probes/M2-live-check.md](docs/probes/M2-live-check.md)). Этап M3 собирает всё это в пакет
|
|
17
|
+
PyPI и плагин Claude Code; первый выпуск — `0.1.0` ([CHANGELOG.md](CHANGELOG.md)).
|
|
18
|
+
|
|
19
|
+
## Зачем это
|
|
20
|
+
|
|
21
|
+
Дать модели читать рабочую базу 1С — значит отдать ей персональные данные и коммерческую тайну:
|
|
22
|
+
ИНН контрагентов, расчётные счета, телефоны и адреса физических лиц, названия клиентов.
|
|
23
|
+
Обезличивать выгрузку заранее неудобно (модель должна видеть свежие данные и уметь дозапрашивать),
|
|
24
|
+
а инструктировать модель «не показывай ИНН» бессмысленно — инструкция не механизм.
|
|
25
|
+
|
|
26
|
+
Шлюз решает это подменой на границе: модель работает с живой базой, но защищаемые значения
|
|
27
|
+
заменяются токенами до того, как попадут в её контекст. Токен детерминирован (одно значение — один
|
|
28
|
+
токен), поэтому по нему можно отбирать, связывать записи и вести разговор, не зная исходного
|
|
29
|
+
значения. Разработчик, который читает ответы модели, видит `[[inn:M4T2Q9XZ7K]]`, а не ИНН — и при
|
|
30
|
+
необходимости раскрывает его сам, командой в терминале, мимо модели.
|
|
31
|
+
|
|
32
|
+
## Что видит модель, а что нет
|
|
33
|
+
|
|
34
|
+
**Что уходит модели.** Структура базы (сущности, поля, ключи, навигация) и данные, прошедшие
|
|
35
|
+
гейт. Номера и даты документов, суммы, количества, коды, GUID, значения перечислений не
|
|
36
|
+
защищаются ни на одном уровне — без них работа с базой теряет смысл. Названия организаций и ФИО
|
|
37
|
+
(классы `org` и `person`) и защищаемые реквизиты — ИНН, КПП, ОГРН, счета, БИК, карты, СНИЛС,
|
|
38
|
+
документы, телефоны, почта, даты рождения, адреса — приходят токенами `[[type:tail]]` по правилам
|
|
39
|
+
политики базы. Уровень задаётся на базу: `off` — гейт выключен, `identifiers` — реквизиты,
|
|
40
|
+
`identifiers+names` — реквизиты плюс названия и ФИО.
|
|
41
|
+
|
|
42
|
+
**Что не уходит никогда.** Реальные значения защищаемых классов не выходят через MCP ни в одном
|
|
43
|
+
ответе: ни в данных, ни в текстах ошибок 1С, ни в превью записи, ни в журнале, ни в
|
|
44
|
+
`odata1c_raw_get`, ни в вопросах подтверждения. Это инвариант, а не тест: последний проход по
|
|
45
|
+
готовому ответу делает страж утечек — он ищет в сериализованном ответе известные словарю значения
|
|
46
|
+
и заменяет их токенами, если что-то прошло мимо гейта. Учётные данные 1С модель не получает:
|
|
47
|
+
пароль не покидает домашнего каталога вовсе, имя пользователя 1С не попадает ни в один ответ, а
|
|
48
|
+
адрес публикации базы не возвращает ни один тул. О самой базе модель узнаёт ровно то, что
|
|
49
|
+
перечисляет `odata1c_bases`: имя, подпись, роль, уровень гейта, разрешена ли запись, состояние
|
|
50
|
+
индекса (собран ли, когда, сколько сущностей) и конфигурацию 1С, к которой база отнесена.
|
|
51
|
+
Единственное исключение по адресу — текст сетевого сбоя, в который его может вписать HTTP-клиент.
|
|
52
|
+
Хук плагина вдобавок запрещает модели читать файлы домашнего каталога шлюза. Раскрыть токен может
|
|
53
|
+
только владелец машины, командой `odata1c reveal` в своём терминале.
|
|
54
|
+
|
|
55
|
+
**Кто подтверждает запись.** Тулы записи ничего не пишут в 1С: они готовят операцию, показывают
|
|
56
|
+
превью в токенах и возвращают `pending_id`. Выполняет её отдельный вызов `odata1c_commit`, и
|
|
57
|
+
только после подтверждения человека механизмом клиента — в Claude Code это диалог разрешения,
|
|
58
|
+
у клиентов с elicitation — вопрос шлюза. Реплика «да» в чате подтверждением не считается: модель
|
|
59
|
+
не может подтвердить запись сама себе. Каждая выполненная запись попадает в локальный журнал и
|
|
60
|
+
откатывается тулом `odata1c_undo`. Записи в базах с ролью `prod` по умолчанию нет вовсе, а состав
|
|
61
|
+
разрешённого сужается флагами разрешений в настройках базы.
|
|
62
|
+
|
|
63
|
+
## Установка
|
|
64
|
+
|
|
65
|
+
Нужен [`uv`](https://docs.astral.sh/uv/) — он сам поставит подходящий Python, отдельно ставить
|
|
66
|
+
интерпретатор не нужно. Дальше две команды в терминале ставят плагин Claude Code вместе со шлюзом:
|
|
67
|
+
|
|
68
|
+
```text
|
|
69
|
+
claude plugin marketplace add Romandredan/odata1c-gate
|
|
70
|
+
claude plugin install odata1c@odata1c-gate
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Плагин приносит MCP-сервер шлюза, три навыка, хук подтверждения записи и агента-следователя.
|
|
74
|
+
Версия пакета закреплена в `plugin/.mcp.json`, поэтому `claude plugin update odata1c` обновляет и
|
|
75
|
+
плагин, и шлюз.
|
|
76
|
+
|
|
77
|
+
**Две оговорки.** Первая: обе команды заработают начиная с выпуска `0.1.0` — пока тег не
|
|
78
|
+
опубликован, пакета `odata1c-gate` на PyPI нет, и `uvx` при первом запуске шлюза ответит отказом
|
|
79
|
+
(`.mcp.json` плагина закреплён на версии из репозитория). Вторая: репозиторий пока приватный,
|
|
80
|
+
`claude plugin marketplace add` клонирует его через git, поэтому на машине нужны учётные данные
|
|
81
|
+
git с доступом к нему. Открытие репозитория — отдельное решение владельца.
|
|
82
|
+
|
|
83
|
+
Отдельно ставится командная строка — она нужна владельцу базы, а не модели (описать базу, собрать
|
|
84
|
+
индекс, раскрыть токен, править политику гейта):
|
|
85
|
+
|
|
86
|
+
```text
|
|
87
|
+
uv tool install odata1c-gate
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
После этого команда `odata1c` доступна в терминале. Без установки то же самое запускается как
|
|
91
|
+
`uvx --from odata1c-gate odata1c <команда>`. Подробности, Linux, обновление и разбор типовых
|
|
92
|
+
сбоев — [docs/install.md](docs/install.md).
|
|
93
|
+
|
|
94
|
+
## Первые пять минут
|
|
95
|
+
|
|
96
|
+
```text
|
|
97
|
+
odata1c init # ~/.claude/odata1c/ с шаблонами настроек, права владельца
|
|
98
|
+
odata1c base add ut_test --role test --recipes ut # спросит адрес, подпись, пользователя, пароль
|
|
99
|
+
odata1c base test ut_test # проверить соединение с 1С
|
|
100
|
+
odata1c reindex ut_test # разобрать $metadata и построить индекс метаданных
|
|
101
|
+
odata1c doctor # проверить окружение: uv, дом, базы, демон, Claude Code
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Начинать с `init` обязательно: плагин домашнего каталога не создаёт — его делают либо эта команда,
|
|
105
|
+
либо лаунчер при первой сессии Claude Code. `doctor` на пустом месте честно ответит `FAIL` в
|
|
106
|
+
строке домашнего каталога, поэтому он и стоит последним; запускать его можно в любой момент.
|
|
107
|
+
|
|
108
|
+
Адрес базы — это адрес публикации OData 1С, он оканчивается на `/odata/standard.odata/`
|
|
109
|
+
(например `https://1c.example.local/ut/odata/standard.odata/`). Пользователь 1С заводится
|
|
110
|
+
отдельный, с правами только на то, что нужно читать, — например `odata_claude`. Роль базы задаёт
|
|
111
|
+
умолчания: `prod` — уровень гейта `identifiers+names` и только чтение, `test` — уровень
|
|
112
|
+
`identifiers`, `dev` — гейт выключен и запись разрешена; любое поле переопределяется явно.
|
|
113
|
+
Пароль ложится в `bases.yaml` домашнего каталога открытым текстом, файл закрывается правами
|
|
114
|
+
владельца (ADR-0014).
|
|
115
|
+
|
|
116
|
+
Первый реиндекс долгий: у типовой УТ `$metadata` — это около 17 МБ описания и больше семи тысяч
|
|
117
|
+
сущностей. Дальше индекс пересобирается, только если у публикации изменилась контрольная сумма
|
|
118
|
+
`$metadata`.
|
|
119
|
+
|
|
120
|
+
Теперь можно спрашивать в Claude Code:
|
|
121
|
+
|
|
122
|
+
- «какие базы 1С мне доступны?» — модель вызовет `odata1c_bases`;
|
|
123
|
+
- «найди справочник контрагентов и покажи состав его полей» — `odata1c_find_entity`,
|
|
124
|
+
затем `odata1c_describe_entity` с классами гейта у каждого поля;
|
|
125
|
+
- «возьми любого контрагента и покажи его пять последних заказов клиента» — `odata1c_query`;
|
|
126
|
+
название контрагента придёт токеном, номера и суммы документов — как есть.
|
|
127
|
+
|
|
128
|
+
Что модель видит и в каком порядке ходит — навык `odata1c` из плагина; справочные темы об
|
|
129
|
+
устройстве OData 1С, токенах, политике и протоколе записи — тул `odata1c_info`.
|
|
130
|
+
|
|
131
|
+
## Что внутри
|
|
132
|
+
|
|
133
|
+
Два процесса из одного пакета: **демон** (`odata1c daemon`) — единственный на машину, держит
|
|
134
|
+
соединения с базами, индекс, словарь и журнал, отвечает по MCP Streamable HTTP на
|
|
135
|
+
`127.0.0.1:7171`; **лаунчер** (`odata1c mcp`) — тонкий stdio-процесс на сессию, который поднимает
|
|
136
|
+
демон при необходимости и проксирует ему вызовы. Собственной логики у лаунчера нет.
|
|
137
|
+
|
|
138
|
+
Тулы чтения: `odata1c_bases`, `odata1c_find_entity`, `odata1c_describe_entity`, `odata1c_query`,
|
|
139
|
+
`odata1c_get`, `odata1c_info`, `odata1c_reindex`, `odata1c_raw_get`, `odata1c_recipe`.
|
|
140
|
+
Тулы записи: `odata1c_create`, `odata1c_update`, `odata1c_mark_for_deletion`, `odata1c_action`
|
|
141
|
+
(проведение и отмена), `odata1c_undo`, `odata1c_commit`, `odata1c_journal`.
|
|
142
|
+
|
|
143
|
+
Рецепт — именованный параметризованный запрос к одной сущности («остатки на складе на дату»,
|
|
144
|
+
«задолженность контрагента»): модель подставляет параметры, шлюз строит запрос сам. Рецепты
|
|
145
|
+
копятся по конфигурации 1С, а не по отдельной базе.
|
|
146
|
+
|
|
147
|
+
## Ограничения
|
|
148
|
+
|
|
149
|
+
- **Физического удаления объектов нет.** «Удаление» для объектов и подчинённых регистров — только
|
|
150
|
+
пометка удаления (`DeletionMark = true`). `PUT` не используется.
|
|
151
|
+
- **Сокращённое название в свободном тексте проходит открытым.** Словарь знает полные написания
|
|
152
|
+
названия; если в комментарии документа человек написал узнаваемое сокращение, которого нет в
|
|
153
|
+
справочнике, гейт его не заменит. Ловить «ядро» названия отвергнуто: ядра — обычные слова, их
|
|
154
|
+
замена портила бы данные ложными срабатываниями.
|
|
155
|
+
- **Аутентификации у демона нет.** Он слушает только `127.0.0.1`; модель угроз — диск и машина
|
|
156
|
+
владельца. Публикация по сети с TLS и токенами — этап M4.
|
|
157
|
+
- **Записи в регистры, подчинённые регистратору, нет** ни при каком флаге разрешений: их пишет
|
|
158
|
+
проведение документа, а не прямая запись.
|
|
159
|
+
- **Шаблоны рецептов заполнены только для УТ.** Для БП и ЗУП шаблоны пока пустые: базы для сверки
|
|
160
|
+
имён нет, а невыверенный рецепт хуже пустого.
|
|
161
|
+
- **Клиент — Claude Code.** Claude Desktop и Cowork не поддерживаются (ADR-0012).
|
|
162
|
+
|
|
163
|
+
## Документы
|
|
164
|
+
|
|
165
|
+
| Файл | Что внутри |
|
|
166
|
+
|---|---|
|
|
167
|
+
| [docs/install.md](docs/install.md) | установка на Windows и Linux, обновление, типовые сбои, раздел сопровождающего |
|
|
168
|
+
| [CHANGELOG.md](CHANGELOG.md) | что вошло в выпуск |
|
|
169
|
+
| [SPEC.md](SPEC.md) | спецификация v0.2, 16 разделов — главный артефакт проекта |
|
|
170
|
+
| [CONTEXT.md](CONTEXT.md) | глоссарий: термины и запрещённые синонимы |
|
|
171
|
+
| [docs/adr/](docs/adr/) | 15 архитектурных решений (0001–0015), статус — во frontmatter |
|
|
172
|
+
| [AGENTS.md](AGENTS.md) | вводная для AI-агентов: архитектура, стек, инварианты, процесс |
|
|
173
|
+
| [CLAUDE.md](CLAUDE.md) | указатель для Claude Code поверх AGENTS.md |
|
|
174
|
+
|
|
175
|
+
## Структура репозитория
|
|
176
|
+
|
|
177
|
+
```text
|
|
178
|
+
src/odata1c/ пакет PyPI odata1c-gate: демон, лаунчер, CLI (SPEC §2.2, §11.1)
|
|
179
|
+
config/ bases.yaml и daemon.yaml, роли, валидация, права файлов
|
|
180
|
+
registry/ реестр баз, статус индекса, видимость по сессии
|
|
181
|
+
client1c/ httpx-пул на базу, IBSession, семафор, маппинг ошибок 1С
|
|
182
|
+
index/ парсер EDMX → metadata.sqlite, реиндекс, нечёткий поиск
|
|
183
|
+
gate/ детекторы реквизитов, словарь, подмена в обе стороны, страж
|
|
184
|
+
write/ разрешения, pending-операции, commit, журнал, undo
|
|
185
|
+
recipes/ загрузка рецептов и рендеринг параметров в OData-литералы
|
|
186
|
+
tools/ регистрация тулов, ресурсов, промптов, server instructions
|
|
187
|
+
templates/ файлы-шаблоны в поставке: конфигурация и рецепты УТ/БП/ЗУП
|
|
188
|
+
cli.py команды odata1c: init, base, reindex, policy, recipe, doctor, reveal, daemon, mcp
|
|
189
|
+
daemon.py демон: тулы, ресурсы, промпт, MCP Streamable HTTP на 127.0.0.1
|
|
190
|
+
launcher.py лаунчер: stdio-прокси демону, подъём демона, проброс elicitation
|
|
191
|
+
plugin/ плагин Claude Code: манифест, .mcp.json, навыки, хук, агент, evals (SPEC §11.2)
|
|
192
|
+
.claude-plugin/ маркетплейс плагина для claude plugin marketplace add
|
|
193
|
+
tests/ unit / property / integration + образцы EDMX (SPEC §12)
|
|
194
|
+
tools/ bump_version.py, plugin_dev_copy.py, probes/ — скрипты проверок и приёмки
|
|
195
|
+
docs/adr/ архитектурные решения
|
|
196
|
+
docs/plans/ планы реализации по этапам
|
|
197
|
+
docs/probes/ отчёты технических проверок P1–P8 и приёмок на живой базе
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Что не попадает в репозиторий
|
|
201
|
+
|
|
202
|
+
`bases.yaml` хранит пароли 1С открытым текстом (SPEC §3.4), поэтому в git не коммитятся
|
|
203
|
+
конфигурация рабочей машины, env-файлы, базы SQLite (словарь, индекс, журнал), выгрузки
|
|
204
|
+
`$metadata` и логи — см. [.gitignore](.gitignore). В поставке живут только файлы-шаблоны
|
|
205
|
+
в `src/odata1c/templates/`, в тестах — урезанные образцы `$metadata`, не полные дампы.
|
|
206
|
+
|
|
207
|
+
## Лицензия
|
|
208
|
+
|
|
209
|
+
MIT.
|