Metadata-Version: 2.4
Name: s-clikit
Version: 0.1.3
Summary: Стандартная библиотека построения CLI: transport+retry, config+профили, session(keyring+fallback), output-контракт, errors, command-kit, локальные сессии.
Author: Dmitry
License: MIT
License-File: LICENSE
Requires-Python: >=3.11
Requires-Dist: httpx>=0.28
Requires-Dist: keyring>=25.0
Requires-Dist: platformdirs>=4.0
Requires-Dist: pydantic-settings>=2.0
Requires-Dist: rich>=13.9
Requires-Dist: s-librarykit
Requires-Dist: stamina>=24.3
Requires-Dist: tomli-w>=1.0
Requires-Dist: typer>=0.15
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest>=8.3; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Requires-Dist: ruff>=0.8; extra == 'dev'
Provides-Extra: socks
Requires-Dist: httpx[socks]>=0.28; extra == 'socks'
Description-Content-Type: text/markdown

# clikit

**Стандартная библиотека построения CLI поверх [librarykit](https://gitlab.com/S-kits/librarykit).**
Новый CLI собирается за ~10 строк: единый root-app с `--json/--text/--profile/--version`,
4-слойный конфиг с валидацией, JSON-first вывод для агентов и скриптов,
структурированные команды. Сетевой слой — транспорт, retry, секреты, пути — это
зона КОРНЯ `librarykit`; clikit на нём построен и тянет его как зависимость, но
больше НЕ фасадит (строгие зоны). Единая иерархия ошибок (`errors`) — общий
контракт между слоями.

```
librarykit   ← КОРЕНЬ: errors · retry · transport · sessions · paths · config_util
   ▲
clikit       ← ЭТОТ КИТ: command_kit · config · output · scaffold + errors.
                        transport/retry/session/paths — бери из librarykit напрямую.
```

## Установка

```bash
uv add s-clikit
```

Имя дистрибутива — `s-clikit`, имя для импорта — `clikit`. `librarykit` подтянется
автоматически как зависимость.

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

CLI за 10 строк — `build_root_app` даёт root с флагами `--json/--text/--profile/--version`:

```python
from clikit import build_root_app, command, AppConfig, emit_data
from librarykit.transport import RestHttpClient  # транспорт — зона librarykit

app = build_root_app(brand="acme", help="ACME CLI")

@app.command()
@command
def items():
    cfg = AppConfig.load("acme")
    client = RestHttpClient(cfg.base_url, access_token=...)
    emit_data(..., text_renderer=...)
```

Запуск: `acme items` отдаёт машинный JSON; `acme items --text` — человеко-читаемый
вывод. Скаффолд нового проекта: `clikit new <name>` (см. `clikit.scaffold`).

## JSON по умолчанию

Дефолтный режим вывода — **json** (для AI-агентов и скриптинга): без флагов команда
печатает машинный JSON Lines в stdout. Человек переключается в текст:

- флагом `--text` / `--plain`;
- env `{BRAND}_OUTPUT=text`;
- в `config.toml` → `output_format = "text"`.

`--json` форсит json (перебивает `--text`, если переданы оба).

## Слои конфига: global + project + local

`AppConfig.load(brand)` собирает значения по слоям (низ→верх приоритета), **per-key
мерж** (верхний слой переопределяет только заданные ключи, не заменяет объект целиком):

```
defaults(модель) < global(config_dir/config.toml)
    < project(.<brand>.toml | .<brand>/config.toml — найден ВВЕРХ от cwd до .git)
    < local(*.local.toml рядом с project, gitignored)
    < ENV({BRAND}_<FIELD>) < init-kwargs
```

- **project-discovery**: подъём от cwd до маркера `.git`; ищется `.<brand>.toml` в
  корне ИЛИ `.<brand>/config.toml` — «конфиг рядом с проектом».
- **local-оверрайд**: `.<brand>.local.toml` — приватные правки поверх командного
  конфига (в `.gitignore`).
- Профили (`{BRAND}_PROFILE` → `profiles/<p>/`) — на уровне global.

`AppConfig` построен на `pydantic-settings` (типизация + fail-fast валидация). Пути
по ОС (`librarykit.config_util.AppPaths`) — на `platformdirs` (`%APPDATA%` /
`~/Library` / `~/.config`), ENV-override `{BRAND}_HOME`.

### env-интерполяция секретов

Строковые значения резолвятся из окружения при `load` (секрет не лежит в git):

```toml
api_token = "${ACME_TOKEN}"                        # из env ACME_TOKEN
base_url  = "${ACME_HOST:-http://localhost:8000}"  # с дефолтом
```

Поддержаны `${VAR}` и `${VAR:-default}`. Подстановка команд `$(...)` **не**
поддержана (поверхность атаки). Заряжать env можно `load_dotenv_file` или keyring
(`librarykit.secret_store.SecretStore`).

### MCP-секция

`AppConfig.mcp: dict[str, McpServer]` — единая форма манифеста MCP-сервера
(`transport`/`command`/`args`/`env`/`url`/`headers`/`enabled`):

```toml
[mcp.skills-hub]
transport = "stdio"
command = "skills-hub-mcp"
args = ["--stdio"]
env = { TOKEN = "${SH_TOKEN}" }
```

### `$schema` для редактора

`AppConfig.json_schema()` отдаёт JSON Schema модели. Команда для CLI —
`make_schema_command(MyConfig)`:

```python
from clikit import make_schema_command, AppConfig
app.command(name="schema")(make_schema_command(MyConfig))   # `acme schema` печатает схему
```

## Публичный API

Зона clikit (`clikit.__all__`): `CliError`, `AuthRequired`, `SessionExpired`,
`RateLimited`, `NotImplementedYet`, `ValidationError`, `init_output_mode`, `is_json`,
`console`, `emit_data`, `emit_message`, `emit_error`, `AppConfig`, `McpServer`,
`AdapterConfig`, `validate_adapters_installed`, `load_dotenv_file`, `interpolate_env`,
`discover_project_config`, `build_root_app`, `command`, `async_command`, `gated`,
`make_schema_command`, `scaffold_cli`.

**Депрекейт (строгие зоны):** `HttpClient` / `ApiError` / `RefreshCallback`,
`RetryPolicy` / `DEFAULT_RETRY`, `SecretStore`, `AppPaths` / `atomic_write_text` /
`chmod_600` / `slugify` ещё доступны из `clikit` (back-compat), но кидают
`DeprecationWarning`. Бери их канон напрямую из `librarykit.transport` /
`librarykit.retry` / `librarykit.secret_store` / `librarykit.config_util`.

## Разработка

```bash
uv sync --extra dev
uv run --extra dev pytest -q
uv run --extra dev ruff check clikit
```

## Лицензия

MIT © 2026 Dmitry.
