@deksden-com/dd-console 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/README.md +154 -2
- package/dist/build.json +1 -0
- package/dist/cache.js +52 -0
- package/dist/cli.js +98 -0
- package/dist/contracts.js +1 -0
- package/dist/daemon.js +102 -0
- package/dist/file-lock.js +33 -0
- package/dist/journal.js +124 -0
- package/dist/reader-pool.js +73 -0
- package/dist/reader-worker.js +21 -0
- package/dist/readers.js +364 -0
- package/dist/safe-files.js +80 -0
- package/dist/server.js +341 -0
- package/dist/sources.js +137 -0
- package/dist/util.js +25 -0
- package/dist/web/app.js +241 -0
- package/dist/web/index.html +14 -0
- package/dist/web/style.css +2 -0
- package/docs/acceptance.md +20 -0
- package/docs/compatibility.md +30 -0
- package/docs/data-contract.md +32 -0
- package/docs/implementation-plan.md +456 -0
- package/docs/implementation-review.md +33 -0
- package/docs/plan-review.md +27 -0
- package/docs/research.md +82 -0
- package/docs/work-plan.md +88 -0
- package/package.json +57 -4
package/docs/research.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Веб-панели dd-eval и dd-flow: исследование и предложение
|
|
2
|
+
|
|
3
|
+
Историческое исследование. Окончательное решение — отдельный репозиторий deksden-com/dd-console; актуальные решения и этапы находятся в [плане реализации](implementation-plan.md). Предложения ниже о размещении внутри dd-flow-cli заменены этим решением.
|
|
4
|
+
|
|
5
|
+
Дата: 2026-09-13. Исследованы локальные чистые checkout: dd-eval `dffd25e`, dd-flow-cli `eb2cb97` (package version 0.9.0-beta.54). Это анализ текущего кода, не проверка всех установленных движков и не испытание работающего UI. Раннеры не запускались и не изменялись.
|
|
6
|
+
|
|
7
|
+
## Рекомендация
|
|
8
|
+
|
|
9
|
+
Одна локальная веб-консоль с двумя разделами — Flows и Evals — и переходом из execution эвала в соответствующий RUN. Существующие раннеры остаются владельцами выполнения. Консоль читает их состояние и журнал; закрытие браузера или перезапуск сервера наблюдения не влияет на выполнение.
|
|
10
|
+
|
|
11
|
+
Начать с наблюдения: список запусков, детали, стадии/работы, сессии, события, проверки, результаты, причины ожидания и свежесть данных. Управление добавить отдельным этапом через существующие команды с их request ID и проверками состояния.
|
|
12
|
+
|
|
13
|
+
## Что уже есть
|
|
14
|
+
|
|
15
|
+
| Область | Источник в репозитории | Что можно использовать |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| Flow dashboards | dd-flow-cli/src/services/dashboard.ts; dashboard-targets.ts | Global/project/protocol HTML и JSON, навигация, состояния, очереди, планы, usage. Это генерируемые локальные страницы; живой HTTP API требует добавления. |
|
|
18
|
+
| Flow RUN | dd-flow-cli/src/services/runs.ts; run-projection.ts | Список RUN, run.json, timeline.jsonl, sessions, works, зависимости, попытки и прогресс плана. |
|
|
19
|
+
| Flow controller | dd-flow-cli/src/services/run-controller-state.ts | Controller ID, generation, status, stage, сессии, ошибка, события в SQLite. |
|
|
20
|
+
| Хранилище Flow | dd-flow-cli/src/storage/database.ts; runtime/context.ts | Уже существует read_existing: SQLite readOnly и query_only. |
|
|
21
|
+
| Eval | dd-eval/lib/runner.mjs: runnerStatus, runnerControlStatus | manifest, результаты executions, pending operations, последняя sequence/time, живое наблюдение и runner attempts. |
|
|
22
|
+
| Eval journal | dd-eval/lib/runner-events.mjs | events.jsonl, нормализованный envelope, sequence, операции, cancel/control и восстановление проекции. |
|
|
23
|
+
| Связь Eval → Flow | runnerControlStatus; executions/<id>/managed-runtime.json | Проверяемые project_root, runtime_root, run_id. Каждый execution использует свой dd-flow-home. |
|
|
24
|
+
|
|
25
|
+
Структуры событий различаются: eval имеет sequence в envelope; flow timeline использует timestamp/event/run_id, без обязательного sequence. Нельзя объявить их одним журналом и сортировкой по времени восстановить причинность.
|
|
26
|
+
|
|
27
|
+
## Какие экраны нужны
|
|
28
|
+
|
|
29
|
+
1. **Обзор.** Активные и завершённые запуски, фильтры по проекту/harness/статусу; текущая работа, последнее событие, длительность, явная причина ожидания. В первую очередь показывать запуски, требующие внимания.
|
|
30
|
+
2. **Flow RUN.** Стадии с попытками и возвратами, дерево работ и зависимостей, связанные сессии и роли, harness и наблюдаемая модель, проверки/ревью, merge-состояние, журнал событий. Для новых flow показывать works даже там, где legacy current_stage отсутствует.
|
|
31
|
+
3. **Eval run.** Case, checkpoint, версии/хеши движка и определения; список executions и их результатов; вложенный flow каждого execution; candidate, Judge и evidence как отдельные состояния. Отсутствующий Judge не равен нулевому score.
|
|
32
|
+
4. **Диагностика.** Что выполнялось последним, активная операция, наблюдаемое состояние провайдера, fallback/recovery, насколько свежи данные, ссылки на разрешённые артефакты. Полные transcripts подгружать только по запросу и с ограничением объёма.
|
|
33
|
+
|
|
34
|
+
Не показывать условные «73% выполнения» без определимого знаменателя: retries и дополнительные работы меняют объём. Полезнее текущая стадия, количество завершённых работ/проверок и время в текущем состоянии.
|
|
35
|
+
|
|
36
|
+
## Архитектура первого выпуска
|
|
37
|
+
|
|
38
|
+
Browser → локальный сервер наблюдения → два адаптера чтения:
|
|
39
|
+
|
|
40
|
+
- Flow: совместимые JSON-проекции и read-only чтение существующего хранилища.
|
|
41
|
+
- Eval: manifest/journal/results и проверенные ссылки на вложенные runtime.
|
|
42
|
+
|
|
43
|
+
Предлагаемая упаковка: сервер и существующий HTML renderer развивать в dd-flow-cli; dd-eval публикует компактный версионируемый контракт наблюдения. Это рекомендация, ещё не существующие команды или API. Не импортировать большой runner.mjs в UI и не делать dd-flow зависимым от исходников dd-eval. Для первого вертикального среза достаточно чтения текущего формата через небольшой адаптер; несовместимую версию явно показывать как unsupported.
|
|
44
|
+
|
|
45
|
+
Пример будущих read endpoints: GET /api/flows, /api/flows/:id, /api/evals, /api/evals/:id, /api/events?cursor=… . Реальная идентичность должна включать runtime/home и project, а не только короткий RUN ID. Сервер выдаёт opaque source ID; браузер не задаёт произвольные пути к БД или shell-команды.
|
|
46
|
+
|
|
47
|
+
Первый работающий срез: polling раз в 2 секунды для выбранного запуска, реже для обзора; общий серверный кэш между вкладками и ограничение параллелизма. Измерить задержки на реальном журнале до выбора окончательных интервалов. runnerStatus вызывает несколько дочерних команд, поэтому его нельзя запускать для каждого RUN каждой вкладкой каждые 2 секунды. Разделить дешёвое чтение журнала и редкие bounded live probes.
|
|
48
|
+
|
|
49
|
+
Затем SSE для доставки изменений: начальный snapshot с revision/cursor, дальнейшие изменения, восстановление после reconnect. Eval cursor может включать sequence; Flow нужен собственный source cursor (например, journal generation + byte offset), поскольку timestamp не уникален. При замене/усечении файла — reset и новый snapshot. Порядок гарантируется внутри источника; общий timeline показывает корреляцию, не выдуманный глобальный порядок.
|
|
50
|
+
|
|
51
|
+
SSE поддерживает переподключение и Last-Event-ID, но сервер сам должен реализовать replay/reset. Источник: [HTML Standard — Server-sent events](https://html.spec.whatwg.org/dev/server-sent-events.html). Один поток на страницу; команды управления позднее идут отдельными HTTP запросами.
|
|
52
|
+
|
|
53
|
+
На старте достаточно Node HTTP, существующего HTML и browser JS. Новая БД, очередь сообщений и UI framework не нужны для проверки ценности. При росте интерактивности решение о компонентах принимать отдельно.
|
|
54
|
+
|
|
55
|
+
## Важные ограничения из кода
|
|
56
|
+
|
|
57
|
+
- refreshRunSessionProjection пишет БД и файлы; recalculateFlowRunUsage пересчитывает usage и вызывает обновление проекции. Просмотр страницы не должен незаметно вызывать такие операции. Для каждого переиспользуемого reader нужен аудит вызовов; read_existing защищает от случайной записи.
|
|
58
|
+
- Глобальный dashboard использует опубликованные project summaries: удобен для обзора, но не гарантирует свежесть отдельного RUN.
|
|
59
|
+
- Eval использует изолированные движки. Новая консоль не должна мигрировать их БД или заменять закреплённый runtime. Нужны проверка версий, read-only доступ и частичная доступность при несовместимости.
|
|
60
|
+
- runnerControlStatus прямо отмечает: независимые snapshots не являются общим доказательством settlement. UI обязан различать requested, observed, settled, unknown; «stop запрошен» не превращается в «остановлен».
|
|
61
|
+
- last_event_at — время последнего события, не heartbeat. Отсутствие новых событий не доказывает зависание.
|
|
62
|
+
- DTO должны выдавать разрешённые поля. Controller и merge записи содержат owner/lease tokens; сырые DB rows и manifest не следует пересылать целиком. Логи экранировать, артефакты отдавать только внутри разрешённых корней с проверкой realpath.
|
|
63
|
+
- По умолчанию loopback, проверка Host/Origin. Удалённый доступ и права пользователей — отдельное расширение. Для будущих mutations потребуются защита запросов, сохранённый request ID, expected generation и durable receipt.
|
|
64
|
+
|
|
65
|
+
## Варианты
|
|
66
|
+
|
|
67
|
+
| Вариант | Выигрыш | Ограничение |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| Расширить статические HTML | Минимум изменений, удобно для завершённых отчётов | Не решает полноценно живое наблюдение и переходы между runtime |
|
|
70
|
+
| Локальная общая консоль — рекомендуется | Переиспользует данные, единая навигация Eval → Flow, небольшой первый выпуск | Требует аккуратных reader contracts и индекса источников |
|
|
71
|
+
| Отдельный центральный сервис | Несколько машин, история и командный доступ | Нужны collectors, доставка, авторизация, хранение и эксплуатация; пока требования не подтверждены |
|
|
72
|
+
|
|
73
|
+
## Последовательность реализации и приёмка
|
|
74
|
+
|
|
75
|
+
1. Проверить readers на одном текущем Flow, одном Eval с вложенными execution и одном старом несовместимом runtime. Зафиксировать компактные DTO, freshness и identity. Проверить отсутствие записей в runtime.
|
|
76
|
+
2. Собрать живой read-only вертикальный срез: overview → Eval → execution → Flow → work/session → event. Polling, фильтры, bounded journal tail, артефакты. Это уже первый полезный выпуск.
|
|
77
|
+
3. Проверить поведение на running/waiting/failed/recovery/completed, повторной попытке стадии и пропавшем runtime; затем SSE и reconnect, если polling недостаточен.
|
|
78
|
+
4. Добавлять pause/resume/stop только через существующую механику раннеров. В UI сначала request receipt, затем подтверждённый результат; повторный запрос не дублирует действие.
|
|
79
|
+
|
|
80
|
+
Критерии первого выпуска: обновления видны с согласованной задержкой; старый/недоступный источник не ломает обзор; eval-child link точен; неизвестные данные не маскируются под успех или ноль; открытие и закрытие панели не меняет ход выполнения; большие журналы читаются порциями; журнал и состояние не меняются из-за просмотра.
|
|
81
|
+
|
|
82
|
+
Перед реализацией остаётся определить продуктовый приоритет: только локальная машина или удалённые раннеры; достаточно ли наблюдения в первом выпуске; нужны ли полные диалоги агентов или события и артефакты. Для данного предложения приняты локальный доступ, наблюдение первым этапом, события/артефакты с подробностями по запросу.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Очередь работ dd-console
|
|
2
|
+
|
|
3
|
+
> Ревью 2026-09-13 и последующие исправления: [отчёт и проверяемые результаты](implementation-review.md).
|
|
4
|
+
|
|
5
|
+
Источник решений: [полный план реализации](implementation-plan.md). Этот файл
|
|
6
|
+
отражает фактический статус первого локального выпуска; дальнейшие пункты —
|
|
7
|
+
очередь для production hardening и масштабирования.
|
|
8
|
+
|
|
9
|
+
## Первый выпуск: локальная консоль наблюдения
|
|
10
|
+
|
|
11
|
+
### 1. Проверить данные и закрепить контракты
|
|
12
|
+
|
|
13
|
+
- [x] Проверить актуальные версии и инструкции dd-flow-cli/dd-eval перед изменениями; закреплены commits и версия в `docs/compatibility.md`.
|
|
14
|
+
- [x] Подготовить обезличенные contract fixtures: самостоятельный Flow, Eval с несколькими executions, повтор стадии, failed/recovery, WAL и недоступный runtime; каталог — `test/fixtures/README.md`.
|
|
15
|
+
- [x] Зафиксировать идентичности source/project/run/work/session и связь Eval → execution → Flow в `docs/compatibility.md`; direct derived link после restart покрыт тестом.
|
|
16
|
+
- [x] Описать DTO, availability/freshness, поддерживаемые версии и доступность полей каждого экрана в `docs/data-contract.md` и `docs/compatibility.md`.
|
|
17
|
+
- [x] Проверить getters на побочные записи: Flow reader использует короткую read-only транзакцию SQLite/WAL; тест подтверждает неизменность основной БД и WAL; Eval использует producer-owned observation export.
|
|
18
|
+
- [x] Проверить, что чтение fixtures не меняет runtime: contract test проверяет основную SQLite и WAL, а реальный Flow прошёл before/after fingerprint без изменений; readers не импортируют runner и не запускают subprocess.
|
|
19
|
+
- [x] Закрепить producer-owned observation export Eval с last_sequence; без него полный live Eval не считать реализованным.
|
|
20
|
+
- [x] Проверить Flow WAL fixture и различить missing store от пустого: transaction reader включает committed WAL; SHM обслуживается SQLite, а empty `runs` store остаётся available. Поддерживаемая revision закреплена в `docs/compatibility.md`.
|
|
21
|
+
|
|
22
|
+
Выход: данные для экранов доступны и проверяемы; пробелы контракта перечислены до разработки интерфейса.
|
|
23
|
+
|
|
24
|
+
### 2. Каркас приложения и навигация
|
|
25
|
+
|
|
26
|
+
- [x] Создать один Node/TypeScript пакет с build/test и упаковкой web assets.
|
|
27
|
+
- [x] Реализовать foreground-команду serve, выбор порта, loopback, URL/JSON receipt и --open.
|
|
28
|
+
- [x] Добавить регистрацию источников и минимальное API чтения.
|
|
29
|
+
- [x] Добавить sources list/add/remove, пустой старт, registry lock и сохранение повреждённого config.
|
|
30
|
+
- [x] Проверить derived source в прямой ссылке после перезапуска сервера.
|
|
31
|
+
- [x] Собрать общий каркас экранов, routes, breadcrumbs, состояния ошибок и пустого списка.
|
|
32
|
+
- [x] Проверить direct links, refresh и Back/Forward на Flow/Eval деталях.
|
|
33
|
+
- [x] Реализовать visual shell: операционный журнал, системная типографика, адаптивные таблицы и статусы.
|
|
34
|
+
|
|
35
|
+
Выход: запускаемый сервер и проходимая навигация на fixtures, без имитации реального выполнения.
|
|
36
|
+
|
|
37
|
+
### 3. Самостоятельные Flows
|
|
38
|
+
|
|
39
|
+
- [x] Подключить список и детали RUN к reader.
|
|
40
|
+
- [x] Сделать детализацию работ, зависимостей и сохранённой стадии.
|
|
41
|
+
- [x] Сделать сессии, проверки, события и зарегистрированные артефакты.
|
|
42
|
+
- [x] Показывать missing/unknown явно; configured/observed model различать. Manifest model маркируется configured, а absent producer fact — «observed: не подтверждена».
|
|
43
|
+
- [x] Пройти полный путь от списка до причины и обратно на реальном сохранённом RUN: 22 works, 21 sessions и 48 checks; результаты — `docs/acceptance.md`.
|
|
44
|
+
|
|
45
|
+
Выход: консоль полезна для исследования самостоятельного Flow.
|
|
46
|
+
|
|
47
|
+
### 4. Evals и вложенные Flows
|
|
48
|
+
|
|
49
|
+
- [x] Подключить список EVAL, параметры запуска и executions.
|
|
50
|
+
- [x] Показать candidate/Judge/evidence отдельно от статуса выполнения Flow, включая безопасные summary и отдельные экраны execution/events.
|
|
51
|
+
- [x] Подключить изолированные runtime по проверенным managed-runtime связям.
|
|
52
|
+
- [x] Сохранить контекст Eval в breadcrumbs при переходе в Flow/Work/Session, включая прямую ссылку и refresh.
|
|
53
|
+
- [x] Проверить одинаковые короткие RUN ID в разных источниках и недоступный вложенный runtime: identity включает source/project/run, а path-escaping execution не создаёт nested Flow link.
|
|
54
|
+
|
|
55
|
+
Выход: единый путь EVAL → execution → Flow → работа → сессия работает на реальных данных.
|
|
56
|
+
|
|
57
|
+
### 5. Живое наблюдение
|
|
58
|
+
|
|
59
|
+
- [x] Добавить polling выбранного экрана и обзора без обращения к runner.
|
|
60
|
+
- [x] Разделить доступность источника, свежесть последнего факта и статус выполнения в API source metadata и header деталей.
|
|
61
|
+
- [x] Добавить общий кэш readers, bounded JSONL tail и pagination списков.
|
|
62
|
+
- [x] Вынести list/detail SQLite чтение в bounded workers; проверить cold start, deadlines, cache/queue limits и snapshot pagination.
|
|
63
|
+
- [x] Обработать неполную последнюю строку и повреждённую строку журнала; rotation/truncation покрыты отдельным тестом.
|
|
64
|
+
- [x] Сохранять focus и прокрутку при polling/Back; события не прокручивают страницу принудительно. Раскрывающихся деталей в текущем UI нет.
|
|
65
|
+
|
|
66
|
+
Выход: ход выполнения виден без ручного обновления страницы и без вмешательства в раннер.
|
|
67
|
+
|
|
68
|
+
### 6. Приёмка и поставка
|
|
69
|
+
|
|
70
|
+
- [x] Пройти сценарии приёмки из основного плана и записать фактические результаты в `docs/acceptance.md`, включая live append <5 s.
|
|
71
|
+
- [x] Проверить чтение без записи, границы доступа к артефактам и экранирование контента; результаты записаны в `docs/acceptance.md`.
|
|
72
|
+
- [x] Проверить три параллельных клиента и 100 МиБ journal: bounded-tail fixture вернула последний event и /healthz за <5 с (фактически ~163 мс на macOS fixture). Задержка появления append проверена в Chromium/WebKit.
|
|
73
|
+
- [x] Проверить клавиатуру, breadcrumbs, прямые Flow/Eval links, возврат позиции чтения и узкое окно в Chromium и WebKit через Playwright.
|
|
74
|
+
- [x] Проверить запуск из упакованного/установленного пакета без соседних checkout через clean tarball install.
|
|
75
|
+
- [x] Описать установку, sources, порты, остановку сервера и ограничения совместимости в README и contract docs.
|
|
76
|
+
- [x] Проверить Node 26/macOS, pack из другого cwd, включение HTML/CSS и preview/download policy через `npm pack --dry-run` и clean install smoke.
|
|
77
|
+
|
|
78
|
+
Выход: первый выпуск готов к использованию; публикация пакета выполняется отдельным согласованным действием.
|
|
79
|
+
|
|
80
|
+
## Порядок интеграции
|
|
81
|
+
|
|
82
|
+
Работать в feature-ветках dd-console, с небольшими PR по этапам. Изменения контрактов раннеров оформлять отдельными PR в соответствующие репозитории и проверять совместимость до подключения в консоли. Не переносить бизнес-логику выполнения в интерфейс. Не менять закреплённые движки исторических eval для удобства чтения.
|
|
83
|
+
|
|
84
|
+
Проверки этого среза и поставки повторяются командами `npm run check` и `npm run pack:check`.
|
|
85
|
+
|
|
86
|
+
## После первого выпуска
|
|
87
|
+
|
|
88
|
+
Pause/resume/stop с точным scope и подтверждённым результатом операции. Затем по потребности — SSE, расширенные transcripts, запуск новых заданий и удалённые источники. Эти пункты не входят в критерии первого выпуска.
|
package/package.json
CHANGED
|
@@ -1,6 +1,59 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deksden-com/dd-console",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": {
|
|
6
|
+
"dd-console": "dist/cli.js"
|
|
7
|
+
},
|
|
8
|
+
"engines": {
|
|
9
|
+
"node": ">=26.0.0"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"prestart": "npm run build",
|
|
13
|
+
"start": "node dist/cli.js serve",
|
|
14
|
+
"prestart:open": "npm run build",
|
|
15
|
+
"start:open": "node dist/cli.js serve --open",
|
|
16
|
+
"start:background": "npm run build && node scripts/start-background.mjs",
|
|
17
|
+
"build": "node scripts/clean.mjs && tsc -p tsconfig.json && node scripts/copy-assets.mjs && node scripts/write-build-info.mjs",
|
|
18
|
+
"typecheck": "tsc --noEmit",
|
|
19
|
+
"test": "npm run build && node --test test/*.test.mjs",
|
|
20
|
+
"test:browser": "npm run build && playwright test",
|
|
21
|
+
"check": "npm run typecheck && npm test && npm run test:browser",
|
|
22
|
+
"pack:check": "node scripts/pack-smoke.mjs",
|
|
23
|
+
"stop": "node dist/cli.js stop",
|
|
24
|
+
"restart": "npm run build && node dist/cli.js restart",
|
|
25
|
+
"status": "node dist/cli.js status",
|
|
26
|
+
"changeset": "changeset",
|
|
27
|
+
"version:release": "changeset version && npm install --package-lock-only",
|
|
28
|
+
"release": "npm run build && changeset publish",
|
|
29
|
+
"prepack": "npm run build"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist",
|
|
33
|
+
"README.md",
|
|
34
|
+
"docs",
|
|
35
|
+
"CHANGELOG.md"
|
|
36
|
+
],
|
|
37
|
+
"license": "UNLICENSED",
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@changesets/cli": "^3.0.3",
|
|
40
|
+
"@playwright/test": "^1.63.0",
|
|
41
|
+
"@types/node": "^24.10.0",
|
|
42
|
+
"typescript": "^5.9.3"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"koffi": "^3.2.1"
|
|
46
|
+
},
|
|
47
|
+
"os": [
|
|
48
|
+
"darwin",
|
|
49
|
+
"linux"
|
|
50
|
+
],
|
|
51
|
+
"description": "Local web console for dd-flow and dd-eval runners",
|
|
52
|
+
"repository": {
|
|
53
|
+
"type": "git",
|
|
54
|
+
"url": "git+https://github.com/deksden-com/dd-console.git"
|
|
55
|
+
},
|
|
56
|
+
"publishConfig": {
|
|
57
|
+
"access": "public"
|
|
58
|
+
}
|
|
59
|
+
}
|