Files
agentik/agentik-cli/build.gradle.kts
subochev b0bbc57880 feat(agentik-cli): REPL-клиент на базе :client для всех KMP-целей
Новый KMP-модуль :agentik-cli — REPL поверх HTTP-фасада :server.

commonMain (~900 строк):
- Main.kt — точка входа + парсинг --server/--id/--no-history/--help
- CliPlatform.kt — expect-фабрика Agent + CliTerminal + SessionIo + env()
- SlashCommand.kt — 11 slash-команд: /help /new /list /sw /rename /rm
  /interrupt /history /pwd /exit /quit
- AgentikCli.kt (~350 строк) — главный REPL-цикл: readLine → parse →
  send → render events. Сохраняет lastEventAt в ~/.agentik/cli-state.json.
- EventRenderer.kt — печатает SSE-события (StartResponse/AppendText/AppendImage/
  End/Interrupted/Error) с правильным разделением text/image и переводом
  строки на end.
- SessionRepository.kt — JSON-state (conversationId, lastEventAt) +
  IO-интерфейс SessionIo.

jvmMain — JLine-терминал (LineReader+history, стрелки, Ctrl-D/E, автосейв
истории), java.io-based atomic-IO для state-файла, real System.getenv.

nativeMain — stub actuals (kotlin.Result-error с подсказкой куда копать):
подключение native ktor-движков (darwin/curl/okhttp) и termios через
kotlinx.cinterop — отдельная задача. Все 8 KMP-целей (jvm/macosX64/macosArm64/
iosX64/iosArm64/iosSimulatorArm64/linuxX64/linuxArm64/mingwX64) компилируются.

shadowJar собирает self-contained fatjar (~8.5 MB). 23 unit-теста зелёные.

Заодно фикс бага в :client — InstantSerializer.descriptor имел имя
'kotlin.time.Instant', которое kotlinx-serialization 1.6+ резервирует за
встроенным сериализатором, из-за чего client падал на старте с
'there already exists InstantSerializer'. Переименовано в
'pw.binom.agentik.Instant' — зеркально с :server.

Smoke-тест на 192.168.76.166: /new + 'привет'/'2+2' отвечает корректно,
state-файл создаётся в /root/.agentik/cli-state.json, /list возвращает
125 диалогов.
2026-09-16 13:42:12 +03:00

103 lines
3.7 KiB
Kotlin
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.gradle.api.artifacts.ConfigurationContainer
plugins {
alias(libs.plugins.kotlin.multiplatform)
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.shadow)
}
kotlin {
jvmToolchain(21)
// Suppress Beta-предупреждения от expect/actual объектов — фича стабильна с Kotlin 1.9,
// но компилятор всё ещё требует -Xexpect-actual-classes, чтобы не ныть.
compilerOptions {
freeCompilerArgs.add("-Xexpect-actual-classes")
}
// "Все возможные цели сборки": jvm + весь натив. Зеркалит набор :server/:proto.
// commonMain зависит только от :proto (KMP). jvmMain подключает :client (JVM-only)
// и JLine — там же и `:client`'s AgentClient. nativeMain пока получает stub actual,
// расширять будем через ktor-client-* {curl,darwin,winhttp} когда дойдёт очередь.
jvm()
macosX64()
macosArm64()
iosX64()
iosArm64()
iosSimulatorArm64()
linuxX64()
linuxArm64()
mingwX64()
sourceSets {
commonMain.dependencies {
implementation(project(":proto"))
implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.serialization.core)
implementation(libs.kotlinx.serialization.json)
}
jvmMain.dependencies {
// :client JVM-only (ktor-cio). Подключаем только в jvmMain.
implementation(project(":client"))
// JLine для readline с историей и completion.
implementation(libs.jline)
}
commonTest.dependencies {
implementation(kotlin("test"))
implementation(libs.kotlinx.coroutines.core)
// runTest { } — suspend test runner для commonTest.
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.11.0")
}
jvmTest.dependencies {
// JUnit нужен в jvmTest — kotlin-test на JVM = JUnit4.
implementation("junit:junit:4.13.2")
}
}
@OptIn(ExperimentalKotlinGradlePluginApi::class)
jvm {
binaries {
executable {
mainClass.set("pw.binom.agentik.cli.MainKt")
}
}
}
}
// --- Fatjar (uberjar) ---
//
// По аналогии с :standalone: shadowJar берёт `jvmJar` + `jvmRuntimeClasspath`.
// Shadow 8.x не авторегистрирует shadowJar в KMP-проектах — нужно явно register.
val shadowJarTask = tasks.register<ShadowJar>("shadowJar") {
archiveBaseName.set("agentik-cli")
archiveClassifier.set("all")
description = "Self-contained fatjar with all runtime dependencies bundled."
group = "build"
from(tasks.named("jvmJar"))
val cc = try {
@Suppress("UNCHECKED_CAST")
configurations as org.gradle.api.artifacts.ConfigurationContainer
} catch (_: ClassCastException) {
@Suppress("UNCHECKED_CAST")
(project as org.gradle.api.Project).configurations as org.gradle.api.artifacts.ConfigurationContainer
}
from(cc.getByName("jvmRuntimeClasspath"))
mergeServiceFiles()
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
manifest {
attributes["Main-Class"] = "pw.binom.agentik.cli.MainKt"
attributes["Implementation-Title"] = "agentik-cli"
attributes["Implementation-Version"] = project.version.toString()
}
includeEmptyDirs = false
}