feat(agentik-cli): one-shot subcommand CLI; client: streaming SSE via prepareGet
ci / JVM build + tests (push) Failing after 2m11s

- :agentik-cli переписан с REPL на one-shot subcommands:
  conv-ls / conv-new / conv-show / conv-delete / conv-rename /
  msgs / send / interrupt / info. Аргумент-парсер — kotlinx.cli 0.3.6
  (clikt 5.x отвергнут из-за upstream-бага duplicate symbol
  selfAndAncestors между clikt и clikt-mordant, issue #598).
- :client: events() переведён с httpClient.get() на
  prepareGet()+execute{} — get() дожидается полного тела, а SSE
  не закрывается никогда, поэтому подписка висела вечно. (Это
  же объясняет, почему TUI agent.events() фактически был
  нерабочим на реальном сервере.)
- :client KMP-конверсия (jvm + 5 desktop-native) уже была в
  коммите 9d826a4, здесь она просто подтверждена в статусе
  green по всем таргетам.
- REPL-инфраструктура (CliPlatform, EventRenderer, Main,
  SessionRepository, SlashCommand + 3 теста) удалена.
- agentik-cli/README переписан под subcommand-формат,
  root README обновлён (убран дубликат строки, agentik-tui
  убран из 'Запускаемые модули').

Smoke (на 192.168.76.166): info / conv-ls / conv-new /
conv-rename / conv-show / conv-delete / msgs / send
(стримит response-events до event End) / interrupt
(выводит event Interrupted).
This commit is contained in:
2026-09-17 23:05:25 +03:00
parent ee0b9d8341
commit b5b21d146a
37 changed files with 595 additions and 1427 deletions
+90 -51
View File
@@ -2,83 +2,122 @@
## Что это
JVM-only REPL-клиент к серверу `:standalone` через `:client`
над HTTP+SSE:
JVM-only **one-shot subcommand CLI** к серверу `:standalone` через
`:client` по HTTP+SSE. Один вызов — одна команда: стримы ответа
`send` идёт в stdout построчно, никакого embedded-REPL.
- Нативный REPL с JLine (стрелки влево/вправо/вверх, история,
Ctrl-D/E).
- Подписка на live-стрим событий агента.
- Slash-команды: `/new /list /switch /rename /rm /interrupt /history
/pwd /help /exit /quit`.
- Persistent session id в `~/.agentik/cli-state.json`.
Решает: быстрый способ дёрнуть агента из shell-скрипта или руками,
не поднимая отдельную TUI-сессию.
Решает: быстрый способ проверить агента руками из терминала.
Используется в CI-смоук-тестах и для daily-driver.
## Подкоманды
```
agentik-cli <subcommand> [options]
Subcommands:
conv-ls Список диалогов агента
conv-new Создать диалог; печатает id
conv-show Метаданные диалога
conv-delete Удалить диалог
conv-rename Переименовать диалог
msgs Показать сообщения диалога
send Отправить user-ход и стримить ответ
interrupt Прервать текущий ход диалога
info Показать server URL и agent id
```
`--server URL` и `--id ID` (env: `AGENTIK_SERVER`, `AGENTIK_AGENT_ID`)
задаются **после** имени subcommand'а — kotlinx.cli не шарит опции
родителя в subcommand. Пример:
```bash
agentik-cli conv-ls --server http://192.168.76.166:8080/agentik
agentik-cli conv-new --server http://localhost:8080/agentik
agentik-cli send --server http://localhost:8080/agentik conv-abc "привет"
```
## Как запустить
### Требования
- JVM 21+ (на машине должна быть JAVA_HOME или `java` в PATH).
- Запущенный `:standalone` (по умолчанию `http://localhost:8080/agentik`).
### Запуск из готового fatjar
### Из готового fatjar
```bash
java --enable-native-access=ALL-UNNAMED -jar agentik-cli-0.1.0-all.jar \
--server http://192.168.76.166:8080/agentik
java --enable-native-access=ALL-UNNAMED \
-jar agentik-cli-0.1.0-SNAPSHOT-all.jar --help
```
### Запуск через Gradle (dev)
### Через Gradle
```bash
./gradlew :agentik-cli:run --args="--server http://localhost:8080/agentik"
./gradlew :agentik-cli:shadowJar
java -jar agentik-cli/build/libs/agentik-cli-0.1.0-SNAPSHOT-all.jar info
```
## Параметры CLI
## Примеры
| Флаг | ENV | Что делает |
|---|---|---|
| `--server URL` | `AGENTIK_SERVER` | URL `/agentik` (default `http://localhost:8080/agentik`) |
| `--id ID` | `USER`/`USERNAME` | Имя агента (default — текущий пользователь) |
| `--no-history` | — | Не восстанавливать последнюю диалог после запуска |
| `--help` | — | Показывает help и выходит |
```bash
# Список диалогов (таблица)
agentik-cli conv-ls --server http://localhost:8080/agentik
## Slash-команды (внутри REPL)
# Создать диалог
ID=$(agentik-cli conv-new --server http://localhost:8080/agentik)
echo "new conv: $ID"
| Команда | Синонимы | Что делает |
|---|---|---|
| `/help` | | Показывает help |
| `/new [title]` | | Создать диалог |
| `/list` | `/ls` | Список диалогов |
| `/switch <id>` | `/sw`, `/cd` | Переключиться на диалог |
| `/rename <title>` | | Переименовать текущий диалог |
| `/rm [id]` | `/delete` | Удалить (текущий или по id) |
| `/interrupt` | `/stop`, `/cancel` | Прервать текущий ход |
| `/history` | `/h`, `/hist` | Показывает историю текущего диалога |
| `/pwd` | | Путь к state-file |
| `/exit`, `/quit` | | Выйти |
# Переименовать
agentik-cli conv-rename --server http://localhost:8080/agentik "$ID" "мой чат"
## Переменные среды (пробрасываются серверу через `--server`)
# Отправить ход и стримить ответ
agentik-cli send --server http://localhost:8080/agentik "$ID" "2+2"
См. [`../standalone/README.md`](../standalone/README.md). На стороне
клиента они **не** интерпретируются — это лишь настройки запуска
агента. CLI только знает, по какому URL стучаться.
# Показать последние N сообщений
agentik-cli msgs --server http://localhost:8080/agentik "$ID" --limit 10
## Известное ограничение
# Прервать активный ход
agentik-cli interrupt --server http://localhost:8080/agentik "$ID"
SSE event-stream в не-TTY ssh-сессии (без `-tt`) закрывается на
default-таймауте Ktor. Используйте либо `ssh -tt`, либо нативный
terminal. Это upstream-особенность Ktor SSE.
# Удалить
agentik-cli conv-delete --server http://localhost:8080/agentik "$ID"
```
## Формат вывода `send`
Каждое SSE-событие печатается отдельной строкой `event <Type> ...` —
пригодно для парсинга через `awk`/`jq`-обёртки:
```
event StartReasoning
event StartResponse TEXT
event AppendText \n\n
event AppendText Привет!
event End
```
Терминальные события (`End`, `Interrupted`, `Error`) тоже
печатаются; CLI выходит сразу после `End`.
## Почему JVM-only (а не KMP)
Аргумент-парсер: `kotlinx.cli` 0.3.6 (JetBrains, KMP) — единственный
зрелый вариант, который линкуется нативно под `linuxX64`/`linuxArm64`
без upstream-багов. Альтернативы:
- **clikt-multiplatform 5.x** имеет upstream-баг: `clikt` и
`clikt-mordant` оба объявляют `selfAndAncestors` в commonMain, и
Kotlin/Native linker падает на дубликате символа
(issue [ajalt/clikt#598](https://github.com/ajalt/clikt/issues/598),
workaround — `kotlin.native.cacheKind.linuxX64=none`, что замедляет
сборку на порядки). Поэтому clikt отвергнут в пользу kotlinx.cli.
- **picocli** — JVM-only.
- **kotlinx-args** — мёртвый репозиторий.
Нативные бинари `:agentik-cli` отложены до стабилизации
arg-parser-ситуации.
## Тесты
```
```bash
./gradlew :agentik-cli:jvmTest
```
23 теста: парсер slash-команд, event-рендер, state-repository.
## Версии
`gradle/libs.versions.toml` → `[versions] agentik-agentik-cli`.