# `:agentik-cli` — one-shot CLI клиент к `/agentik` ## Что это **One-shot subcommand CLI** (Kotlin Multiplatform) к серверу `:standalone` через `:client` по HTTP+SSE. Один вызов — одна команда: стрим ответа `send` идёт в stdout построчно, никакого embedded-REPL. Решает: быстрый способ дёрнуть агента из shell-скрипта или руками, не поднимая отдельную TUI-сессии. ## Платформы | Платформа | Артефакт | Размер | Статус | |---|---|---|---| | `jvm` (JRE 21) | `*-all.jar` | ~7 МБ | ✓ собирается и работает | | `linuxX64` | `.kexe` | ~5 МБ | ✓ собирается и работает на этом хосте | | `macosX64` | `.kexe` | — | собирается на macOS-раннере | | `macosArm64` | `.kexe` | — | собирается на macOS-arm64-раннере | | `mingwX64` | `.exe` | ~6 МБ | ✓ собирается (cross-compile с Linux) | | `linuxArm64` | — | — | **нет** — kotlinx-cli 0.3.6 не публикует klib для linuxArm64 | | `iOS` | — | — | нет смысла на iOS | ## Подкоманды ``` agentik-cli [args...] Команды верхнего уровня: conv операции над диалогами (см. ниже) msgs [--limit N] показать сообщения send отправить ход, стримит response-события в stdout interrupt прервать текущий ход info показать конфиг (server URL + agent id) Подкоманды `conv`: conv ls список диалогов conv new [--temp] создать диалог, печатает id conv show метаданные диалога conv delete удалить диалог conv rename переименовать ``` `--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 "привет" agentik-cli info # через AGENTIK_SERVER env-переменную ``` ## Как запустить ### JVM (fatjar) ```bash ./gradlew :agentik-cli:shadowJar java --enable-native-access=ALL-UNNAMED \ -jar agentik-cli/build/libs/agentik-cli-0.1.0-SNAPSHOT-all.jar conv --help ``` ### Native linuxX64 ```bash ./gradlew :agentik-cli:linkReleaseExecutableLinuxX64 ./agentik-cli/build/bin/linuxX64/releaseExecutable/agentik-cli.kexe conv --help ``` ### Native macOS / Windows На Linux-хосте `macosX64`/`macosArm64` линкуются пустыми (нужен macOS-раннер, Apple Mach-O формат). `mingwX64` собирается через кросс-компиляцию. CI-ноут: запускать `./gradlew :agentik-cli:linkReleaseExecutableMacosX64 :agentik-cli:linkReleaseExecutableMacosArm64` на `macos-latest` раннере Gitea Actions. ## Примеры ```bash # Список диалогов (таблица) agentik-cli conv ls --server http://localhost:8080/agentik # Создать диалог ID=$(agentik-cli conv new --server http://localhost:8080/agentik) echo "new conv: $ID" # Переименовать agentik-cli conv rename --server http://localhost:8080/agentik "$ID" "мой чат" # Отправить ход и стримить ответ agentik-cli send --server http://localhost:8080/agentik "$ID" "2+2" # Показать последние N сообщений agentik-cli msgs --server http://localhost:8080/agentik "$ID" --limit 10 # Прервать активный ход agentik-cli interrupt --server http://localhost:8080/agentik "$ID" # Удалить agentik-cli conv delete --server http://localhost:8080/agentik "$ID" # Через env-переменную AGENTIK_SERVER=http://localhost:8080/agentik agentik-cli info ``` ## Формат вывода `send` Каждое SSE-событие печатается отдельной строкой `event <Type> ...` — пригодно для парсинга через `awk`/`jq`-обёртки: ``` event StartReasoning event StartResponse TEXT event AppendText \n\n event AppendText Привет! event End ``` Терминальные события (`End`, `Interrupted`, `Error`) тоже печатаются; CLI выходит сразу после `End`. ## Почему kotlinx.cli (а не clikt) - **kotlinx.cli 0.3.6** (JetBrains, KMP) — единственный зрелый arg-parser, который стабильно линкуется под `linux_x64` + `macos_x64`/`macos_arm64` + `mingw_x64`. Минус: нет `linux_arm64`. - **clikt-multiplatform 5.x** (ajalt) — имеет linuxArm64, но ломается на native linker: `duplicate symbol selfAndAncestors` между `clikt` и `clikt-mordant` commonMain (issue [ajalt/clikt#598](https://github.com/ajalt/clikt/issues/598)). Workaround `kotlin.native.cacheKind.linuxX64=none` замедляет сборку на порядки и не решает проблему до конца. Поэтому clikt отвергнут. ## Платформенные детали - **entryPoint на K/N** — это FQN функции **без** суффикса `Kt` (т.е. `pw.binom.agentik.cli.main`, а не `MainKt.main`). JVM convention `MainKt.main` тут не работает — K/N линкер ищет функцию по `package.main`. - **`platformEnv(key)`** для чтения env-переменных: - JVM: `System.getenv(key)` через `jvmMain` actual. - Native: `getenv(key)` из `platform.posix` через `kotlinx.cinterop.toKString()` (`nativeMain` actual, требует `@OptIn(ExperimentalForeignApi::class)`). - **Stdout / exit code** — работают на K/N через корутины. ## Готчасы kotlinx.cli - **Вложенные subcommands + parent.execute().** В kotlinx.cli 0.3.6 `parent.execute()` вызывается ПОСЛЕ `leaf.execute()` всегда, когда leaf был достигнут через parent. Поэтому `ConvCommand.execute()` сделан no-op (`override fun execute() = Unit`), иначе вывод дочерней команды дублируется выводом родителя. Дочерние команды смотрятся через `agentik-cli conv --help`. - **strictSubcommandOptionsOrder.** Без этого флага `conv new --server ...` парсится как `conv [--server ...]` + позиционный аргумент `new` на уровне родителя — и дочерняя команда не запускается. В `ArgParser` сразу включается `strictSubcommandOptionsOrder = true`. ## Тесты Тесты для подкоманд пока не написаны (TODO). Базовый smoke покрывается руками против живого сервера. ```bash ./gradlew :agentik-cli:jvmTest # 0/0 — пока пусто ``` ## Версии `gradle/libs.versions.toml` → `[versions] agentik-agentik-cli`.