ktalk-cli 3.0.2__tar.gz → 4.0.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.
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/.gitignore +2 -1
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/PKG-INFO +57 -32
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/README.md +56 -31
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/pyproject.toml +1 -1
- ktalk_cli-4.0.0/src/ktalk_cli/CLAUDE.md +39 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/auth.py +15 -3
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/cli.py +23 -54
- ktalk_cli-4.0.0/src/ktalk_cli/cli_config.py +128 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/cli_doctor.py +38 -8
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/cli_meetings_read.py +9 -2
- ktalk_cli-4.0.0/src/ktalk_cli/cli_sync.py +233 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/client.py +9 -2
- ktalk_cli-4.0.0/src/ktalk_cli/config.py +270 -0
- ktalk_cli-4.0.0/src/ktalk_cli/fs_guard.py +58 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/reconciliation.py +22 -12
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/registry.py +1 -19
- ktalk_cli-4.0.0/src/ktalk_cli/talk_config.py +123 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/token_file.py +12 -9
- ktalk_cli-4.0.0/tests/conftest.py +56 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_adr022_ktalk_cli_rename.py +13 -1
- ktalk_cli-4.0.0/tests/test_calendar_window_iso8601.py +142 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_cli.py +12 -14
- ktalk_cli-4.0.0/tests/test_cli_config_set.py +138 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_cli_content.py +6 -7
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_cli_meeting.py +24 -3
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_cli_meeting_sanctioned.py +24 -3
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_cli_meetings_surface.py +24 -3
- ktalk_cli-4.0.0/tests/test_code_review_dev003.py +295 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_config.py +51 -20
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_diagnostics.py +37 -4
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_fr19_auth_status.py +9 -10
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_fr39_calendar_inclusive_end.py +24 -3
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_fr40_timezone_format.py +24 -3
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_fr41_last_synced.py +24 -5
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_fr42_single_credential_source.py +32 -27
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_fr43_legacy_key_removal_warning.py +31 -27
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_fr44_auth_status_accepted_rejected.py +20 -35
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_fr48_doctor_summary_diagnostics.py +44 -93
- ktalk_cli-4.0.0/tests/test_legacy_config_detection.py +425 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_nfr17_identity_verification.py +4 -4
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_pagination.py +6 -20
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_reconciliation.py +11 -20
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_registry.py +4 -18
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_search_contacts.py +1 -4
- ktalk_cli-4.0.0/tests/test_sec001_control_char.py +36 -0
- ktalk_cli-4.0.0/tests/test_sec001_legacy_var_401.py +44 -0
- ktalk_cli-4.0.0/tests/test_sec001_symlink_guard.py +67 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_secret_masking.py +45 -32
- ktalk_cli-4.0.0/tests/test_settings_config_sources.py +237 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_store.py +24 -11
- ktalk_cli-4.0.0/tests/test_sync_honest_window.py +315 -0
- ktalk_cli-4.0.0/tests/test_talk_config.py +132 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_token_file.py +12 -4
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_write_journal.py +20 -3
- ktalk_cli-3.0.2/src/ktalk_cli/CLAUDE.md +0 -30
- ktalk_cli-3.0.2/src/ktalk_cli/cli_sync.py +0 -154
- ktalk_cli-3.0.2/src/ktalk_cli/config.py +0 -187
- ktalk_cli-3.0.2/tests/conftest.py +0 -16
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/LICENSE +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/__init__.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/calendar_reader.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/cli_contacts.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/cli_content.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/cli_meeting.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/cli_meeting_args.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/cli_meeting_confirm.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/cli_sanction.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/cli_store.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/cli_token.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/confirmation.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/contacts.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/contour_diagnostics.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/download.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/endpoints.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/enrichment.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/formatters.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/host_config.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/meeting_body.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/meeting_cancel.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/meeting_scheduling.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/pagination.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/rooms.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/store.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/store_migration.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/transcript_identity.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/write_journal.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/src/ktalk_cli/write_sanction.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/fixtures/access-info-expired.json +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/fixtures/access-info-full.json +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/fixtures/archive-8col.md +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/fixtures/archive-dup-id.md +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/fixtures/archive-escaped-pipe-7col.md +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/fixtures/archive-page1.json +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/fixtures/archive-page2-empty.json +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/fixtures/archive-pipe-in-name.md +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/fixtures/calendar-item-session.json +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/fixtures/chat-messages-session.json +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/fixtures/conference-history-session-oversized.json +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/fixtures/conference-history-session.json +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/fixtures/error-body-problem-json.json +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/fixtures/error-body-validation.json +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/fixtures/recording-detail-session-full-participants.json +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/fixtures/recording-detail-session-oversized-partial.json +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/fixtures/recording-detail-with-qualities.json +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/fixtures/recording-list-item-session.json +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/fixtures/recordings-list-apikey-page1.json +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/fixtures/recordings-list-apikey-page2.json +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/fixtures/registry-archive-2026-04.md +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/fixtures/registry.md +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/fixtures/room-detail-session.json +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_archive.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_auth_modes.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_calendar.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_chat.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_cli_config_show.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_cli_export_store_isolation.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_cli_host_config_wiring.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_cli_migrate_to_central_store.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_client.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_concurrency.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_confirmation.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_contour_diagnostics.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_download.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_enrichment.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_formatters.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_fr21_no_vault_layout.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_fr47_missing_fields_completeness.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_host_config.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_issue3_null_id_fallback.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_meeting_body.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_meeting_cancel.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_meeting_scheduling.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_migration.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_rooms.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_store_migration.py +0 -0
- {ktalk_cli-3.0.2 → ktalk_cli-4.0.0}/tests/test_write_sanction.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: ktalk-cli
|
|
3
|
-
Version:
|
|
3
|
+
Version: 4.0.0
|
|
4
4
|
Summary: CLI for accessing Kontur Talk (KTalk) recordings, transcripts and summaries
|
|
5
5
|
Project-URL: Homepage, https://github.com/mdemyanov/ktalk-cli
|
|
6
6
|
Project-URL: Repository, https://github.com/mdemyanov/ktalk-cli
|
|
@@ -90,6 +90,14 @@ uv tool upgrade ktalk-cli
|
|
|
90
90
|
|
|
91
91
|
## Авторизация
|
|
92
92
|
|
|
93
|
+
**С версии 4.0.0 конфигурация каждого значения имеет ровно один источник**
|
|
94
|
+
(ADR-027): session token — только файл, записанный `ktalk token set`; адрес
|
|
95
|
+
стенда — только `config.toml`, записанный `ktalk config set base-url`. Ни одна
|
|
96
|
+
переменная `KTALK_*` и ни один `.env` в рабочем каталоге больше не читаются как
|
|
97
|
+
источник значения — их присутствие не проходит молча: `ktalk auth-status`,
|
|
98
|
+
`ktalk doctor` и тексты отказов называют обнаруженную снятую переменную по
|
|
99
|
+
имени (значение не печатается никогда) и советуют её убрать.
|
|
100
|
+
|
|
93
101
|
**С версии 3.0.0 CLI работает только через session token** (кука браузера) — режим
|
|
94
102
|
персонального API-ключа (`KTALK_PERSONAL_API_KEY`) снят целиком (ADR-025): он
|
|
95
103
|
конкурировал с сессией молча (при обеих заданных переменных побеждал ключ без
|
|
@@ -101,9 +109,11 @@ uv tool upgrade ktalk-cli
|
|
|
101
109
|
ручного обновления токена по мере его протухания (`ktalk token set -`, см. ниже) —
|
|
102
110
|
это не восстанавливается автоматически снятием ключа.
|
|
103
111
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
112
|
+
Переменные `KTALK_PERSONAL_API_KEY`, `KTALK_SESSION_TOKEN` и остальные
|
|
113
|
+
`KTALK_*`, если они всё ещё заданы в окружении (частая причина — блок `env` в
|
|
114
|
+
`~/.claude/settings.json`), не читаются ни на одном шаге — CLI печатает об этом
|
|
115
|
+
одно предупреждение на stderr при каждом вызове и продолжает работу на файле
|
|
116
|
+
токена/`config.toml`.
|
|
107
117
|
|
|
108
118
|
### Session token
|
|
109
119
|
|
|
@@ -134,14 +144,20 @@ ktalk token status # есть ли файл, права, маска знач
|
|
|
134
144
|
ktalk auth-status # жива ли авторизация — реальный запрос, не имитация
|
|
135
145
|
```
|
|
136
146
|
|
|
137
|
-
Путь
|
|
147
|
+
Путь файла — `${XDG_CONFIG_HOME:-~/.config}/ktalk-mcp/token`; переменной-
|
|
148
|
+
переопределения нет (снятая `KTALK_TOKEN_FILE` не читается, ADR-027).
|
|
138
149
|
|
|
139
|
-
|
|
150
|
+
**Единственный источник токена** — этот файл (ADR-027). Переменная
|
|
151
|
+
`KTALK_SESSION_TOKEN` и `.env` в рабочем каталоге не читаются вовсе: заданная
|
|
152
|
+
переменная больше не перекрывает файл ни молча, ни с предупреждением — она
|
|
153
|
+
просто не участвует в разрешении credential, а CLI называет её в выводе
|
|
154
|
+
`auth-status`/`doctor` как снятую.
|
|
140
155
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
156
|
+
> Ротация больше не может «застрять» на невидимой переменной: `ktalk token set -`
|
|
157
|
+
> перезаписывает файл, и следующий же вызов читает новое значение. Разводка
|
|
158
|
+
> источников из старых установок (переменная против файла, рунбук
|
|
159
|
+
> [OPS-003](content/70-operations/OPS-003-env-var-shadows-token-file.md)) снята
|
|
160
|
+
> самим устройством 4.0.0 — переменную достаточно убрать из окружения.
|
|
145
161
|
|
|
146
162
|
Ни один запрос не несёт заголовок `X-Auth-Token` — единственный транспорт credential
|
|
147
163
|
теперь query-параметр `sessionToken`.
|
|
@@ -165,22 +181,25 @@ ktalk auth-status # жива ли авторизация — реальны
|
|
|
165
181
|
> ошибку авторизации, повторите те же два шага — `ktalk token set -` перезаписывает
|
|
166
182
|
> файл, права переставлять не нужно.
|
|
167
183
|
|
|
168
|
-
###
|
|
184
|
+
### Конфигурация: адрес стенда (`config.toml`)
|
|
185
|
+
|
|
186
|
+
Адрес контура задаётся один раз, машинной командой:
|
|
169
187
|
|
|
170
188
|
```bash
|
|
171
|
-
|
|
172
|
-
export KTALK_BASE_URL="https://your-domain.ktalk.ru"
|
|
189
|
+
ktalk config set base-url https://your-domain.ktalk.ru
|
|
173
190
|
```
|
|
174
191
|
|
|
175
|
-
|
|
176
|
-
|
|
192
|
+
Команда пишет `${XDG_CONFIG_HOME:-~/.config}/ktalk-mcp/config.toml` (рядом с
|
|
193
|
+
файлом токена, права `0644` — адрес не секрет) и отвергает значение без схемы
|
|
194
|
+
http(s) или без хоста до записи. Проверка — `ktalk config show`: секция
|
|
195
|
+
`## Толк` называет адрес, путь `config.toml` и статус файла токена.
|
|
177
196
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
197
|
+
**Переменные окружения и `.env` больше не читаются вовсе (4.0.0, ADR-027).**
|
|
198
|
+
`KTALK_BASE_URL`, `KTALK_SESSION_TOKEN`, `KTALK_PERSONAL_API_KEY`,
|
|
199
|
+
`KTALK_REGISTRY_DB`, `KTALK_TOKEN_FILE` и `.env` в рабочем каталоге не
|
|
200
|
+
участвуют в разрешении ни одного значения. Если какая-то из них всё ещё задана,
|
|
201
|
+
`ktalk auth-status` и `ktalk doctor` называют её по имени и советуют убрать —
|
|
202
|
+
значение при этом не печатается никогда.
|
|
184
203
|
|
|
185
204
|
## Диагностика авторизации
|
|
186
205
|
|
|
@@ -193,10 +212,12 @@ ktalk auth-status
|
|
|
193
212
|
Диагностика различает два случая, которые снаружи выглядят одинаково — просто ошибка, —
|
|
194
213
|
но чинятся по-разному:
|
|
195
214
|
|
|
196
|
-
- **401** — токен невалиден либо истёк.
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
215
|
+
- **401** — токен невалиден либо истёк. Вердикт `alive: false`, код возврата `1`.
|
|
216
|
+
Обновите токен: `ktalk token set -` — файл перезаписывается, права переставлять
|
|
217
|
+
не нужно.
|
|
218
|
+
- **403** — токен рабочий, но у текущей сессии нет прав на эту операцию. Вердикт
|
|
219
|
+
`alive: true`, код возврата `0`: нехватка прав не является отказом токена, и
|
|
220
|
+
перевыпускать его не нужно.
|
|
200
221
|
|
|
201
222
|
У session token понятия scope и срока действия нет — диагностика выполняет реальный
|
|
202
223
|
пробный запрос (список записей), а не имитацию без сети.
|
|
@@ -320,15 +341,15 @@ CLI работает с KTalk Web API через единственный (sessi
|
|
|
320
341
|
|
|
321
342
|
Та же команда `ktalk` ведёт операционный реестр обработки записей на SQLite.
|
|
322
343
|
Вся детерминированная механика (синхронизация списка записей, дедуп,
|
|
323
|
-
|
|
344
|
+
смена статусов, рендер дашборда и markdown-зеркала, разовая
|
|
324
345
|
миграция) живёт в коде, а не в рассуждениях модели.
|
|
325
346
|
|
|
326
347
|
**SQLite — операционный source of truth.** Markdown-файл `registry.md` —
|
|
327
348
|
генерируемое read-only зеркало для git (`ktalk export`), руками не редактируется.
|
|
328
349
|
|
|
329
|
-
Путь к базе: флаг `--db PATH` >
|
|
330
|
-
|
|
331
|
-
|
|
350
|
+
Путь к базе: флаг `--db PATH` > `registry.db_path` из `.ktalk.toml`
|
|
351
|
+
проекта-хозяина > машинный дефолт централизованного хранилища (ADR-013;
|
|
352
|
+
переменная `KTALK_REGISTRY_DB` снята в 4.0.0 и не читается, ADR-027).
|
|
332
353
|
|
|
333
354
|
`ktalk auth-status`, `ktalk create-meeting-preview` и `ktalk create-meeting-confirm`
|
|
334
355
|
реестр не открывают вовсе — им он не нужен. В частности, `auth-status` работает
|
|
@@ -337,10 +358,12 @@ CLI работает с KTalk Web API через единственный (sessi
|
|
|
337
358
|
|
|
338
359
|
| Команда | Назначение |
|
|
339
360
|
|---|---|
|
|
340
|
-
| `ktalk sync [--days
|
|
361
|
+
| `ktalk sync [--days N] [--json] [--dry-run]` | Загрузить записи из KTalk и upsert'нуть их в реестр (новые — `new`, существующие — с обновлёнными не-статусными полями; статус ни одной записи не меняется). Без `--days` окно — от момента последней синхронизации минус 1 день запаса (первый запуск — 90 дней); `--days N` — явное переопределение нижней границы. Идемпотентно. `--dry-run` — сверить id с реестром без записи, ничего не пишет. В `--json`-ответе ключа `expired` больше нет (4.0.0): смены статуса как побочного эффекта чтения не происходит. |
|
|
341
362
|
| `ktalk token set <значение\|->` | Записать session-токен в `~/.config/ktalk-mcp/token` (`0600`). `-` — прочитать из stdin: `pbpaste \| ktalk token set -`. Значение не печатается. |
|
|
342
363
|
| `ktalk token status [--json]` | Есть ли файл токена, его права и маска значения. |
|
|
343
364
|
| `ktalk auth-status [--json]` | Диагностика активной авторизации — жив ли токен. См. «Диагностика авторизации». |
|
|
365
|
+
| `ktalk config set base-url <url>` | Записать адрес стенда в `~/.config/ktalk-mcp/config.toml` (`0644`). См. «Конфигурация: адрес стенда». |
|
|
366
|
+
| `ktalk config show [--json]` | Машинная конфигурация оператора (адрес, путь `config.toml`, статус файла токена) и резолвленный `.ktalk.toml` проекта-хозяина. |
|
|
344
367
|
| `ktalk dashboard [--json]` | Дашборд: новые записи, статистика по статусам. |
|
|
345
368
|
| `ktalk list [--status S] [--json]` | Список записей с фильтром по статусу. |
|
|
346
369
|
| `ktalk show <id> [--json]` | Детали записи: участники, статус, пути, длительность. |
|
|
@@ -368,8 +391,10 @@ uv run pytest -v
|
|
|
368
391
|
# Линтинг
|
|
369
392
|
uv run ruff check .
|
|
370
393
|
|
|
371
|
-
# Локальный запуск CLI (
|
|
372
|
-
|
|
394
|
+
# Локальный запуск CLI (токен и адрес — файлами, см. «Авторизация»)
|
|
395
|
+
pbpaste | uv run ktalk token set -
|
|
396
|
+
uv run ktalk config set base-url https://your-domain.ktalk.ru
|
|
397
|
+
uv run ktalk auth-status
|
|
373
398
|
```
|
|
374
399
|
|
|
375
400
|
## Пакет и плагин Claude Code
|
|
@@ -67,6 +67,14 @@ uv tool upgrade ktalk-cli
|
|
|
67
67
|
|
|
68
68
|
## Авторизация
|
|
69
69
|
|
|
70
|
+
**С версии 4.0.0 конфигурация каждого значения имеет ровно один источник**
|
|
71
|
+
(ADR-027): session token — только файл, записанный `ktalk token set`; адрес
|
|
72
|
+
стенда — только `config.toml`, записанный `ktalk config set base-url`. Ни одна
|
|
73
|
+
переменная `KTALK_*` и ни один `.env` в рабочем каталоге больше не читаются как
|
|
74
|
+
источник значения — их присутствие не проходит молча: `ktalk auth-status`,
|
|
75
|
+
`ktalk doctor` и тексты отказов называют обнаруженную снятую переменную по
|
|
76
|
+
имени (значение не печатается никогда) и советуют её убрать.
|
|
77
|
+
|
|
70
78
|
**С версии 3.0.0 CLI работает только через session token** (кука браузера) — режим
|
|
71
79
|
персонального API-ключа (`KTALK_PERSONAL_API_KEY`) снят целиком (ADR-025): он
|
|
72
80
|
конкурировал с сессией молча (при обеих заданных переменных побеждал ключ без
|
|
@@ -78,9 +86,11 @@ uv tool upgrade ktalk-cli
|
|
|
78
86
|
ручного обновления токена по мере его протухания (`ktalk token set -`, см. ниже) —
|
|
79
87
|
это не восстанавливается автоматически снятием ключа.
|
|
80
88
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
89
|
+
Переменные `KTALK_PERSONAL_API_KEY`, `KTALK_SESSION_TOKEN` и остальные
|
|
90
|
+
`KTALK_*`, если они всё ещё заданы в окружении (частая причина — блок `env` в
|
|
91
|
+
`~/.claude/settings.json`), не читаются ни на одном шаге — CLI печатает об этом
|
|
92
|
+
одно предупреждение на stderr при каждом вызове и продолжает работу на файле
|
|
93
|
+
токена/`config.toml`.
|
|
84
94
|
|
|
85
95
|
### Session token
|
|
86
96
|
|
|
@@ -111,14 +121,20 @@ ktalk token status # есть ли файл, права, маска знач
|
|
|
111
121
|
ktalk auth-status # жива ли авторизация — реальный запрос, не имитация
|
|
112
122
|
```
|
|
113
123
|
|
|
114
|
-
Путь
|
|
124
|
+
Путь файла — `${XDG_CONFIG_HOME:-~/.config}/ktalk-mcp/token`; переменной-
|
|
125
|
+
переопределения нет (снятая `KTALK_TOKEN_FILE` не читается, ADR-027).
|
|
115
126
|
|
|
116
|
-
|
|
127
|
+
**Единственный источник токена** — этот файл (ADR-027). Переменная
|
|
128
|
+
`KTALK_SESSION_TOKEN` и `.env` в рабочем каталоге не читаются вовсе: заданная
|
|
129
|
+
переменная больше не перекрывает файл ни молча, ни с предупреждением — она
|
|
130
|
+
просто не участвует в разрешении credential, а CLI называет её в выводе
|
|
131
|
+
`auth-status`/`doctor` как снятую.
|
|
117
132
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
133
|
+
> Ротация больше не может «застрять» на невидимой переменной: `ktalk token set -`
|
|
134
|
+
> перезаписывает файл, и следующий же вызов читает новое значение. Разводка
|
|
135
|
+
> источников из старых установок (переменная против файла, рунбук
|
|
136
|
+
> [OPS-003](content/70-operations/OPS-003-env-var-shadows-token-file.md)) снята
|
|
137
|
+
> самим устройством 4.0.0 — переменную достаточно убрать из окружения.
|
|
122
138
|
|
|
123
139
|
Ни один запрос не несёт заголовок `X-Auth-Token` — единственный транспорт credential
|
|
124
140
|
теперь query-параметр `sessionToken`.
|
|
@@ -142,22 +158,25 @@ ktalk auth-status # жива ли авторизация — реальны
|
|
|
142
158
|
> ошибку авторизации, повторите те же два шага — `ktalk token set -` перезаписывает
|
|
143
159
|
> файл, права переставлять не нужно.
|
|
144
160
|
|
|
145
|
-
###
|
|
161
|
+
### Конфигурация: адрес стенда (`config.toml`)
|
|
162
|
+
|
|
163
|
+
Адрес контура задаётся один раз, машинной командой:
|
|
146
164
|
|
|
147
165
|
```bash
|
|
148
|
-
|
|
149
|
-
export KTALK_BASE_URL="https://your-domain.ktalk.ru"
|
|
166
|
+
ktalk config set base-url https://your-domain.ktalk.ru
|
|
150
167
|
```
|
|
151
168
|
|
|
152
|
-
|
|
153
|
-
|
|
169
|
+
Команда пишет `${XDG_CONFIG_HOME:-~/.config}/ktalk-mcp/config.toml` (рядом с
|
|
170
|
+
файлом токена, права `0644` — адрес не секрет) и отвергает значение без схемы
|
|
171
|
+
http(s) или без хоста до записи. Проверка — `ktalk config show`: секция
|
|
172
|
+
`## Толк` называет адрес, путь `config.toml` и статус файла токена.
|
|
154
173
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
174
|
+
**Переменные окружения и `.env` больше не читаются вовсе (4.0.0, ADR-027).**
|
|
175
|
+
`KTALK_BASE_URL`, `KTALK_SESSION_TOKEN`, `KTALK_PERSONAL_API_KEY`,
|
|
176
|
+
`KTALK_REGISTRY_DB`, `KTALK_TOKEN_FILE` и `.env` в рабочем каталоге не
|
|
177
|
+
участвуют в разрешении ни одного значения. Если какая-то из них всё ещё задана,
|
|
178
|
+
`ktalk auth-status` и `ktalk doctor` называют её по имени и советуют убрать —
|
|
179
|
+
значение при этом не печатается никогда.
|
|
161
180
|
|
|
162
181
|
## Диагностика авторизации
|
|
163
182
|
|
|
@@ -170,10 +189,12 @@ ktalk auth-status
|
|
|
170
189
|
Диагностика различает два случая, которые снаружи выглядят одинаково — просто ошибка, —
|
|
171
190
|
но чинятся по-разному:
|
|
172
191
|
|
|
173
|
-
- **401** — токен невалиден либо истёк.
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
192
|
+
- **401** — токен невалиден либо истёк. Вердикт `alive: false`, код возврата `1`.
|
|
193
|
+
Обновите токен: `ktalk token set -` — файл перезаписывается, права переставлять
|
|
194
|
+
не нужно.
|
|
195
|
+
- **403** — токен рабочий, но у текущей сессии нет прав на эту операцию. Вердикт
|
|
196
|
+
`alive: true`, код возврата `0`: нехватка прав не является отказом токена, и
|
|
197
|
+
перевыпускать его не нужно.
|
|
177
198
|
|
|
178
199
|
У session token понятия scope и срока действия нет — диагностика выполняет реальный
|
|
179
200
|
пробный запрос (список записей), а не имитацию без сети.
|
|
@@ -297,15 +318,15 @@ CLI работает с KTalk Web API через единственный (sessi
|
|
|
297
318
|
|
|
298
319
|
Та же команда `ktalk` ведёт операционный реестр обработки записей на SQLite.
|
|
299
320
|
Вся детерминированная механика (синхронизация списка записей, дедуп,
|
|
300
|
-
|
|
321
|
+
смена статусов, рендер дашборда и markdown-зеркала, разовая
|
|
301
322
|
миграция) живёт в коде, а не в рассуждениях модели.
|
|
302
323
|
|
|
303
324
|
**SQLite — операционный source of truth.** Markdown-файл `registry.md` —
|
|
304
325
|
генерируемое read-only зеркало для git (`ktalk export`), руками не редактируется.
|
|
305
326
|
|
|
306
|
-
Путь к базе: флаг `--db PATH` >
|
|
307
|
-
|
|
308
|
-
|
|
327
|
+
Путь к базе: флаг `--db PATH` > `registry.db_path` из `.ktalk.toml`
|
|
328
|
+
проекта-хозяина > машинный дефолт централизованного хранилища (ADR-013;
|
|
329
|
+
переменная `KTALK_REGISTRY_DB` снята в 4.0.0 и не читается, ADR-027).
|
|
309
330
|
|
|
310
331
|
`ktalk auth-status`, `ktalk create-meeting-preview` и `ktalk create-meeting-confirm`
|
|
311
332
|
реестр не открывают вовсе — им он не нужен. В частности, `auth-status` работает
|
|
@@ -314,10 +335,12 @@ CLI работает с KTalk Web API через единственный (sessi
|
|
|
314
335
|
|
|
315
336
|
| Команда | Назначение |
|
|
316
337
|
|---|---|
|
|
317
|
-
| `ktalk sync [--days
|
|
338
|
+
| `ktalk sync [--days N] [--json] [--dry-run]` | Загрузить записи из KTalk и upsert'нуть их в реестр (новые — `new`, существующие — с обновлёнными не-статусными полями; статус ни одной записи не меняется). Без `--days` окно — от момента последней синхронизации минус 1 день запаса (первый запуск — 90 дней); `--days N` — явное переопределение нижней границы. Идемпотентно. `--dry-run` — сверить id с реестром без записи, ничего не пишет. В `--json`-ответе ключа `expired` больше нет (4.0.0): смены статуса как побочного эффекта чтения не происходит. |
|
|
318
339
|
| `ktalk token set <значение\|->` | Записать session-токен в `~/.config/ktalk-mcp/token` (`0600`). `-` — прочитать из stdin: `pbpaste \| ktalk token set -`. Значение не печатается. |
|
|
319
340
|
| `ktalk token status [--json]` | Есть ли файл токена, его права и маска значения. |
|
|
320
341
|
| `ktalk auth-status [--json]` | Диагностика активной авторизации — жив ли токен. См. «Диагностика авторизации». |
|
|
342
|
+
| `ktalk config set base-url <url>` | Записать адрес стенда в `~/.config/ktalk-mcp/config.toml` (`0644`). См. «Конфигурация: адрес стенда». |
|
|
343
|
+
| `ktalk config show [--json]` | Машинная конфигурация оператора (адрес, путь `config.toml`, статус файла токена) и резолвленный `.ktalk.toml` проекта-хозяина. |
|
|
321
344
|
| `ktalk dashboard [--json]` | Дашборд: новые записи, статистика по статусам. |
|
|
322
345
|
| `ktalk list [--status S] [--json]` | Список записей с фильтром по статусу. |
|
|
323
346
|
| `ktalk show <id> [--json]` | Детали записи: участники, статус, пути, длительность. |
|
|
@@ -345,8 +368,10 @@ uv run pytest -v
|
|
|
345
368
|
# Линтинг
|
|
346
369
|
uv run ruff check .
|
|
347
370
|
|
|
348
|
-
# Локальный запуск CLI (
|
|
349
|
-
|
|
371
|
+
# Локальный запуск CLI (токен и адрес — файлами, см. «Авторизация»)
|
|
372
|
+
pbpaste | uv run ktalk token set -
|
|
373
|
+
uv run ktalk config set base-url https://your-domain.ktalk.ru
|
|
374
|
+
uv run ktalk auth-status
|
|
350
375
|
```
|
|
351
376
|
|
|
352
377
|
## Пакет и плагин Claude Code
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# ktalk-cli — API Контур.Толк
|
|
2
|
+
|
|
3
|
+
Справочник вынесен из корневого `CLAUDE.md`: грузится только при работе под `src/`.
|
|
4
|
+
|
|
5
|
+
## Контракт API
|
|
6
|
+
- OpenAPI спецификация (справочник, **есть расхождения с реальностью**): `talk.public.api-api-2.json`
|
|
7
|
+
- Base URL: https://your-domain.ktalk.ru
|
|
8
|
+
- **Режим авторизации один — сессионный токен** ([ADR-025](content/00-project/adr/ADR-025-single-auth-mode.md)
|
|
9
|
+
снял двухрежимность [ADR-003](content/00-project/adr/ADR-003-auth-modes.md) в 3.0.0):
|
|
10
|
+
`sessionToken=` в query при чтении, заголовок `Authorization: Session <token>` при записи
|
|
11
|
+
(`meeting_scheduling.py`). `X-Auth-Token` не шлётся ни одним запросом. `KTALK_PERSONAL_API_KEY`
|
|
12
|
+
не читается ни на одном шаге: заданная, она даёт однократное предупреждение в stderr
|
|
13
|
+
(`config.py:181-187`) и больше ничего.
|
|
14
|
+
- **Порядок источников токена, он же ловушка эксплуатации** — первый непустой выигрывает:
|
|
15
|
+
`KTALK_SESSION_TOKEN` (окружение или `.env` рабочего каталога) > `~/.config/ktalk-mcp/token`
|
|
16
|
+
(`token_file.py`, DEV-018). Файл читается валидатором `Settings` **только когда переменная
|
|
17
|
+
пуста** (`config.py:111-130`) — поэтому переменная переживает `ktalk token set` и делает
|
|
18
|
+
ротацию токена невидимой: `auth-status` печатает `alive: false` на свежезаписанный рабочий
|
|
19
|
+
файл. Разведение — `env -u KTALK_SESSION_TOKEN ktalk auth-status` против обычного вызова;
|
|
20
|
+
процедура — [OPS-003](content/70-operations/OPS-003-env-var-shadows-token-file.md). Права
|
|
21
|
+
шире `0600` — файла как будто нет. Запись — `ktalk token set -`, формат проверяется до записи.
|
|
22
|
+
- **Путь есть не у каждой операции** — интеграторский контур (`/api/Domain/*`, `/api/Recordings/*`,
|
|
23
|
+
`/api/ConferenceReports/*`) отдаёт 401/403 по сессии, поэтому пути живут в таблице
|
|
24
|
+
`OPERATION_PROFILES` (`endpoints.py`, реэкспорт через `auth.py`), а не хардкодом в методах.
|
|
25
|
+
Профиль `None` (`list_archive`) — отказ до сети, код возврата 1.
|
|
26
|
+
- Пути под сессией: `GET /api/recordings`, `/api/recordings/{id}`, `/api/conferencesHistory/{key}`,
|
|
27
|
+
`/api/recordings/{key}/transcript`, `/api/recordings/v2/{key}/summary`,
|
|
28
|
+
`/api/recordings/{key}/summary/{type}`
|
|
29
|
+
|
|
30
|
+
### Поведение API, проверенное эмпирически (спеке здесь верить нельзя)
|
|
31
|
+
- `top` максимум **100**, не 1000: `400 «The field Top must be between 1 and 100»`.
|
|
32
|
+
- `nextPageToken` во внутреннем контуре **не существует** — пагинация только через `skip`.
|
|
33
|
+
- `startFrom`/`startTo` **игнорируются**: окно дат обеспечивает клиент (`clip_to_window`),
|
|
34
|
+
обход прекращается на первой странице за порогом. Выдача отсортирована от новых к старым.
|
|
35
|
+
- `maxParticipantCount` в списке имеет максимум 10 и дефолт 6 — полный состав участников
|
|
36
|
+
берётся дообогащением по каждой записи, а не из списка.
|
|
37
|
+
- Чат требует необъявленный в спеке параметр `channel` (рабочее значение `general`).
|
|
38
|
+
- **401 ≠ 403**: 401 — ключ/токен невалиден, 403 — валиден, но не хватает scope. Тело 403
|
|
39
|
+
обычно пустое, диагностика строится на коде ответа и требуемом scope операции.
|
|
@@ -69,8 +69,14 @@ def classify_response(response: object) -> None:
|
|
|
69
69
|
`contour_diagnostics._status_hint`."""
|
|
70
70
|
status = response.status_code # type: ignore[attr-defined]
|
|
71
71
|
if status == 401:
|
|
72
|
+
from ktalk_cli.config import _with_legacy_notice
|
|
73
|
+
|
|
72
74
|
raise _auth_error(
|
|
73
|
-
|
|
75
|
+
_with_legacy_notice(
|
|
76
|
+
"Токен сессии истёк или невалиден. Обновите его: "
|
|
77
|
+
"`ktalk token set -` (см. README)."
|
|
78
|
+
),
|
|
79
|
+
401,
|
|
74
80
|
)
|
|
75
81
|
if status == 403:
|
|
76
82
|
# У сессионного токена нет понятия scope, но 403 — это не 401. ADR-003
|
|
@@ -101,9 +107,15 @@ class AuthContext:
|
|
|
101
107
|
def resolve(*, session_token: str | None) -> AuthContext:
|
|
102
108
|
if session_token:
|
|
103
109
|
return AuthContext(session_token)
|
|
110
|
+
# ADR-027: тот же текст отказа, что `Settings.auth_credential` (FR-E —
|
|
111
|
+
# только инструкция, переменная окружения больше не предлагается).
|
|
112
|
+
from ktalk_cli.config import _with_legacy_notice
|
|
113
|
+
|
|
104
114
|
raise KTalkConfigError(
|
|
105
|
-
|
|
106
|
-
|
|
115
|
+
_with_legacy_notice(
|
|
116
|
+
"Сессионный токен не задан: файла токена нет. Выполните "
|
|
117
|
+
"`ktalk token set -` (см. README)."
|
|
118
|
+
)
|
|
107
119
|
)
|
|
108
120
|
|
|
109
121
|
|
|
@@ -10,6 +10,8 @@ from pathlib import Path
|
|
|
10
10
|
|
|
11
11
|
from ktalk_cli.cli_contacts import cmd_search_contacts
|
|
12
12
|
from ktalk_cli.cli_contacts import register_subparsers as register_contacts_subparsers
|
|
13
|
+
from ktalk_cli.cli_config import cmd_config
|
|
14
|
+
from ktalk_cli.cli_config import register_subparsers as register_config_subparsers
|
|
13
15
|
from ktalk_cli.cli_content import (
|
|
14
16
|
cmd_download_recording,
|
|
15
17
|
cmd_get_participants,
|
|
@@ -45,8 +47,8 @@ from ktalk_cli.cli_token import register_subparsers as register_token_subparsers
|
|
|
45
47
|
from ktalk_cli.cli_store import cmd_migrate_to_central_store
|
|
46
48
|
from ktalk_cli.cli_store import register_subparsers as register_store_subparsers
|
|
47
49
|
from ktalk_cli.cli_sync import cmd_auth_status, cmd_sync
|
|
48
|
-
from ktalk_cli.config import redact_secrets, resolve_db_path
|
|
49
|
-
from ktalk_cli.host_config import
|
|
50
|
+
from ktalk_cli.config import legacy_config_notice, redact_secrets, resolve_db_path
|
|
51
|
+
from ktalk_cli.host_config import discover_host_config
|
|
50
52
|
from ktalk_cli.registry import Registry, migrate_from_vault, render_markdown_mirror
|
|
51
53
|
|
|
52
54
|
_STATUSES = ("new", "processing", "done", "skipped", "partial")
|
|
@@ -108,18 +110,20 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
108
110
|
p_mig.add_argument("--json", action="store_true")
|
|
109
111
|
|
|
110
112
|
p_sync = sub.add_parser("sync", help="Синхронизация с KTalk")
|
|
111
|
-
p_sync.add_argument(
|
|
113
|
+
p_sync.add_argument(
|
|
114
|
+
"--days",
|
|
115
|
+
type=int,
|
|
116
|
+
default=None,
|
|
117
|
+
help="Явное переопределение нижней границы окна (N дней назад от сегодня); "
|
|
118
|
+
"без флага — от момента последней синхронизации (ADR-027)",
|
|
119
|
+
)
|
|
112
120
|
p_sync.add_argument("--json", action="store_true")
|
|
113
121
|
p_sync.add_argument("--dry-run", action="store_true", help="Сверка id без записи (FR-15)")
|
|
114
122
|
|
|
115
123
|
p_auth = sub.add_parser("auth-status", help="Диагностика авторизации (FR-11)")
|
|
116
124
|
p_auth.add_argument("--json", action="store_true")
|
|
117
125
|
|
|
118
|
-
|
|
119
|
-
config_sub = p_config.add_subparsers(dest="config_command")
|
|
120
|
-
p_config_show = config_sub.add_parser("show", help="Показать резолвленный .ktalk.toml")
|
|
121
|
-
p_config_show.add_argument("--json", action="store_true")
|
|
122
|
-
|
|
126
|
+
register_config_subparsers(sub)
|
|
123
127
|
register_meeting_subparsers(sub)
|
|
124
128
|
register_meeting_confirm_subparsers(sub)
|
|
125
129
|
register_sanction_subparsers(sub)
|
|
@@ -272,45 +276,6 @@ def _cmd_migrate(reg: Registry, args) -> int:
|
|
|
272
276
|
return 0
|
|
273
277
|
|
|
274
278
|
|
|
275
|
-
def _host_config_to_dict(host_config: HostConfig | None) -> dict:
|
|
276
|
-
if host_config is None:
|
|
277
|
-
return {"registry": {}, "directories": {}, "routing": {}, "integrations": {}}
|
|
278
|
-
return {
|
|
279
|
-
"registry": host_config.registry,
|
|
280
|
-
"directories": host_config.directories,
|
|
281
|
-
"routing": host_config.routing,
|
|
282
|
-
"integrations": host_config.integrations,
|
|
283
|
-
# FR-48: `doctor` и `config show` называют один и тот же путь одним
|
|
284
|
-
# значением (ADR-026 spec §2) — ключ появляется только когда конфиг
|
|
285
|
-
# найден, отсутствие файла не путь, а нормальная ветка.
|
|
286
|
-
"path": str(host_config.path),
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
def _cmd_config(reg: Registry | None, args) -> int:
|
|
291
|
-
if getattr(args, "config_command", None) != "show":
|
|
292
|
-
print("Неизвестная подкоманда config (доступно: show)", file=sys.stderr)
|
|
293
|
-
return 2
|
|
294
|
-
host_config = discover_host_config()
|
|
295
|
-
data = _host_config_to_dict(host_config)
|
|
296
|
-
if args.json:
|
|
297
|
-
_print_json(data)
|
|
298
|
-
return 0
|
|
299
|
-
print("# Конфигурация проекта-хозяина (.ktalk.toml)\n")
|
|
300
|
-
if host_config is None:
|
|
301
|
-
print("(конфиг не найден — машинные дефолты)")
|
|
302
|
-
return 0
|
|
303
|
-
for section_name in ("registry", "directories", "routing", "integrations"):
|
|
304
|
-
section = data[section_name]
|
|
305
|
-
print(f"## {section_name}")
|
|
306
|
-
if not section:
|
|
307
|
-
print("(не объявлено)")
|
|
308
|
-
else:
|
|
309
|
-
for key, value in section.items():
|
|
310
|
-
print(f"- {key} = {value}")
|
|
311
|
-
return 0
|
|
312
|
-
|
|
313
|
-
|
|
314
279
|
_REGISTRY_FREE_COMMANDS = {
|
|
315
280
|
"auth-status",
|
|
316
281
|
"config",
|
|
@@ -361,7 +326,7 @@ _HANDLERS = {
|
|
|
361
326
|
"migrate": _cmd_migrate,
|
|
362
327
|
"sync": cmd_sync,
|
|
363
328
|
"auth-status": cmd_auth_status,
|
|
364
|
-
"config":
|
|
329
|
+
"config": cmd_config,
|
|
365
330
|
"create-meeting-preview": cmd_create_meeting_preview,
|
|
366
331
|
"create-meeting-confirm": cmd_create_meeting_confirm,
|
|
367
332
|
"cancel-meeting-preview": cmd_cancel_meeting_preview,
|
|
@@ -386,9 +351,13 @@ _HANDLERS = {
|
|
|
386
351
|
|
|
387
352
|
|
|
388
353
|
def main(argv: list[str] | None = None) -> int:
|
|
389
|
-
# FR-
|
|
390
|
-
#
|
|
391
|
-
|
|
354
|
+
# FR-D (ADR-027 п.3, обобщение FR-43 с одной переменной на пять): обнаружение
|
|
355
|
+
# снятых переменных конфигурации не проходит молча — ровно одна строка на
|
|
356
|
+
# процесс, до диспетчеризации любой команды, через барьер маскирования;
|
|
357
|
+
# уведомление информационно, команду не блокирует.
|
|
358
|
+
notice = legacy_config_notice()
|
|
359
|
+
if notice is not None:
|
|
360
|
+
print(redact_secrets(notice), file=sys.stderr)
|
|
392
361
|
parser = build_parser()
|
|
393
362
|
args = parser.parse_args(argv)
|
|
394
363
|
if getattr(args, "version", False):
|
|
@@ -431,15 +400,15 @@ def main(argv: list[str] | None = None) -> int:
|
|
|
431
400
|
# дефолту, пока сам реестр читался из `.ktalk.toml`.
|
|
432
401
|
args.db = str(db_path)
|
|
433
402
|
# Code review (epic-capability-pairing, Р5): признак «путь резолвился к
|
|
434
|
-
# машинному дефолту централизованного хранилища», а не к --db/
|
|
403
|
+
# машинному дефолту централизованного хранилища», а не к --db/
|
|
435
404
|
# конфигу хозяина — считается ДО перезаписи `args.db` выше, той же
|
|
436
|
-
# логикой приоритета, что `resolve_db_path` (ADR-013 §3
|
|
405
|
+
# логикой приоритета, что `resolve_db_path` (ADR-013 §3 в редакции
|
|
406
|
+
# ADR-027: среднего члена KTALK_REGISTRY_DB больше нет), без повторного
|
|
437
407
|
# вызова `resolve_store_root()` (не создавать хранилище стороны ради
|
|
438
408
|
# одной проверки). Использует только `_cmd_export`, чтобы не положить
|
|
439
409
|
# зеркало проекта-хозяина внутрь хранилища (NFR-16 AC).
|
|
440
410
|
args.db_from_machine_default = not (
|
|
441
411
|
raw_cli_db
|
|
442
|
-
or os.environ.get("KTALK_REGISTRY_DB")
|
|
443
412
|
or (host_config is not None and host_config.registry.get("db_path"))
|
|
444
413
|
)
|
|
445
414
|
reg = Registry(db_path)
|