# CLI sparku

> Все команды sparku, их флаги, порядок поиска токена и коды выхода.

## Установка

Настройки SparkU → Свои интеграции → строка «sparku» → «Установить…». Ставится
символическая ссылка `/usr/local/bin/sparku`, указывающая на утилиту внутри
`SparkU.app/Contents/Helpers/sparku`; ссылка обновляется вместе с приложением.

```bash
sparku version
sparku help
```

## Токен

Токен ищется по порядку, пока не найдётся непустое значение:

1. `--token <токен>`
2. `--token-file <путь>`
3. `SPARKU_TOKEN_<АДРЕС>` (адрес заглавными буквами, дефисы → `_`)
4. `SPARKU_TOKEN`
5. `SPARKU_TOKEN_FILE` (путь к файлу с токеном)

Адрес сокета можно переопределить переменной `SPARKU_SOCKET` или флагом `--socket`
(по умолчанию `~/.sparku/run/api.sock`).

> [!NOTE]
> Недоступность SparkU проверяется **до** проверки токена: `sparku push … || [ $?
> -eq 69 ]` в скрипте надёжно ловит «SparkU не запущен», даже если токен вдобавок не
> настроен.

## push

Записывает поля (upsert — частичное обновление, старые значения не заявленных
ключей не трогаются).

```
sparku push <адрес> поле=значение … [поле:=json …] [--ttl 5m] [--bind]
```

- `поле=значение` — строка, сервер сама приводит её к типу поля;
- `поле:=json` — значение как есть, распарсенное как JSON;
- `--ttl` — срок жизни значений для этой записи: число секунд или `5m` / `1h30m`
  (иначе — срок по умолчанию из настроек интеграции);
- `--bind` — значения живут, пока жив скрипт, который вызвал `sparku`: он завершился
  или упал — значения сняты (см. [привязку к процессу](/docs/api/ru/concepts.md#привязка-к-процессу)).

```bash
sparku push deploy progress=0.4 stage=build
sparku push deploy progress=70% --ttl 10m
sparku push deploy stage=build --bind
sparku push queue items:='[{"title": "Сборка"}]'
```

## end

Снимает все значения интеграции (как истечение TTL, только сразу).

```
sparku end <адрес>
```

```bash
sparku end deploy
```

## notify

Вспышка индикатора и строка на несколько секунд (не чаще раза в 2 секунды на
интеграцию).

```
sparku notify <адрес> ["текст"] [--state значение] [--color red] [--duration 4]
```

- текст — позиционный аргумент, до 120 символов (длиннее обрезается);
- `--state` — значение поля-состояния (берёт из него подпись, значок и цвет);
- `--color` — семантический цвет (`blue`, `green`, `orange`, `red`, `purple`, `pink`,
  `yellow`, `teal`, `indigo`, `gray`, `success`, `warning`, `error`);
- `--duration` — 1…10 секунд, по умолчанию 4.

Нужен хотя бы `текст` или `--state`.

```bash
sparku notify deploy "Сборка упала" --state failed
sparku notify server "CPU 95%" --color red --duration 6
```

## glow

Координатная подсветка: пятна света в заданных местах контура островка. Каждый вызов
заменяет кадр целиком.

```
sparku glow <адрес> позиция:цвет[:яркость[:ширина]] … [--intensity 1.2] [--ttl 5]
sparku glow <адрес> --off
```

- позиция — 0…1 слева направо по ширине островка, 0.5 — середина под вырезом;
- цвет — семантическое имя (`blue`, `red`, `success`, …) или `#RRGGBB`;
- яркость — 0…1, по умолчанию 1; ширина — полуширина пятна в долях ширины островка,
  по умолчанию 0.08;
- `--intensity` — толщина обводки и сила свечения, 0.2…3;
- `--ttl` — сколько кадр горит без следующего, по умолчанию 5 секунд;
- `--off` — погасить.

```bash
sparku glow deploy 0.2:green 0.5:orange:0.6 0.8:#ff3b30
sparku glow build 0.5:blue:1:0.5 --ttl 1h      # широкая полоса на час
sparku glow deploy --off
```

Для визуализаций, где кадры идут десятками в секунду, шлите `POST …/glow` в сокет
напрямую, без запуска процесса на каждый кадр — см. [HTTP API](/docs/api/ru/http.md).

## ask

Вопрос человеку на островке. Ждёт ответа (соединение держится, пока не ответят или
не истечёт `--timeout`).

```
sparku ask <адрес> "вопрос" [-o id:подпись …] [--multi] [--custom]
           [--accept Да --decline Нет --comment] [--title …]
           [--timeout 10m] [--attach файл]
```

- `-o id:подпись` (повторяемый) — вариант ответа; без `-o` и без `--custom` вопрос
  становится подтверждением двумя кнопками;
- `--multi` — можно выбрать несколько вариантов (нужно ≥ 2 вариантов);
- `--custom` — добавляет поле свободного ответа;
- `--accept` / `--decline` — подписи кнопок подтверждения (по умолчанию «Да» / «Нет»);
- `--comment` — у отказа можно оставить комментарий;
- `--title` — заголовок вопроса;
- `--timeout` — от 5 секунд до суток, по умолчанию 10 минут; формат — число секунд
  или `90s` / `10m` / `2h`;
- `--attach` — абсолютный (или относительный от текущей директории) путь к файлу,
  который можно открыть из вопроса.

Ответ печатается в stdout: выбранные варианты — id по одному на строку, свой ответ —
текстом, причина отказа (`--comment`) — тоже текстом.

```bash
if sparku ask deploy "Деплоить?"; then ./deploy.sh; fi
env=$(sparku ask deploy "Куда?" -o prod:Прод -o stage:Стейджинг)
sparku ask deploy "Удалить ветку?" --accept Удалить --decline Оставить --comment
```

У интеграции может быть не больше одного вопроса без ответа одновременно —
повторный `ask` получит `409 dialog_pending`.

## listen

Печатает нажатия элементов карточки.

```
sparku listen <адрес> [--exec "команда"] [--reconnect]
```

- без `--exec` — каждое событие построчно в stdout в виде NDJSON (удобно для `jq`,
  `while read`);
- с `--exec` — на каждое событие запускается команда; данные приходят ей **только**
  через окружение (`SPARKU_SLUG`, `SPARKU_CONTROL`, `SPARKU_VALUE`, `SPARKU_EVENT`),
  в текст команды ничего не подставляется;
- `--reconnect` — переподключаться, если SparkU закрыл соединение (например,
  перезапускается), вместо того чтобы завершиться с ошибкой.

```bash
sparku listen deploy --exec './on-click.sh'   # $SPARKU_CONTROL, $SPARKU_VALUE
sparku listen deploy --reconnect | jq .
```

## import

Предлагает интеграцию из файла `.sparku` человеку и ждёт согласия в настройках
SparkU.

```
sparku import <файл.sparku>
```

При согласии печатает в stdout `export SPARKU_TOKEN_<АДРЕС>=…`, поэтому установщик
может сделать:

```bash
eval "$(sparku import deploy.sparku)"
```

Отказ человека — код выхода `77`.

## doctor

Проверяет окружение по шагам: сокет, версия SparkU, (если указан адрес) токен и
существование интеграции.

```
sparku doctor [адрес]
```

```bash
sparku doctor
sparku doctor deploy
```

## openapi

Описание API в формате OpenAPI 3.1 (JSON) — для генераторов клиентов и ИИ-агентов.

```
sparku openapi [адрес]
```

Без адреса — общая схема всех маршрутов `/v1`; SparkU для неё не нужен, она же
лежит на сайте: [/openapi.json](/openapi.json). С адресом — схема этой интеграции:
тело `push` перечисляет её поля с типами, границами и значениями состояний, так что
сгенерированный клиент не пропустит опечатку в имени поля.

```bash
sparku openapi deploy > deploy.openapi.json
```

## version / help

```
sparku version
sparku help
```

## Коды выхода

### `push`, `end`, `doctor`, `notify`, `listen`, `import`

Коды — из `<sysexits.h>`, чтобы не пересекаться с кодами `ask`:

| Код | Значение | Когда |
|---|---|---|
| `0` | успех | |
| `64` | неверные аргументы (`EX_USAGE`) | опечатка в флаге, не хватает обязательного аргумента |
| `65` | значения не прошли проверку (`EX_DATAERR`) | HTTP 400, 411, 413, 422 |
| `67` | нет интеграции с таким адресом (`EX_NOUSER`) | HTTP 404 |
| `69` | SparkU недоступен или API выключен (`EX_UNAVAILABLE`) | нет сокета, HTTP 409, 503 |
| `70` | внутренняя ошибка SparkU (`EX_SOFTWARE`) | HTTP 5xx |
| `75` | слишком часто, повторите позже (`EX_TEMPFAIL`) | HTTP 429 (`notify` чаще раза в 2 с) |
| `76` | непонятный ответ (`EX_PROTOCOL`) | версии CLI и приложения разошлись |
| `77` | нет токена или он не подходит (`EX_NOPERM`) | HTTP 401, 403; отказ `sparku import` |

`69` проверяется первым: скрипт может надёжно отличить «SparkU не запущен» от любой
другой ошибки, даже если токен тоже не настроен.

### `ask`

Отдельная схема — не пересекается с `<sysexits.h>`, поэтому в shell работает
`if sparku ask deploy "Деплоить?"; then …`:

| Код | Значение |
|---|---|
| `0` | ответ получен (выбор или свой текст — в stdout) |
| `1` | отказ (`declined`) |
| `2` | время вышло, вопрос сняли на островке («Скрыть») или SparkU закрылся |

`409 dialog_pending` (у интеграции уже есть вопрос без ответа) возвращается как код
`69`, как и остальные ошибки недоступности.
