5.3 KiB
Проект: Kotlin/JVM, Gradle 8.14 (wrapper уже в репо), JDK 21. Рабочая копия: /root/WORK/memo.
Задача — ТОЛЬКО каркас сборки и четыре теста. НЕ пиши чанкер, поиск, watcher, MCP, CLI-логику.
-
settings.gradle.kts: rootProject.name = "memo"; include(":memo-core", ":memo-cli", ":memo-watch", ":memo-mcp"). В dependencyResolutionManagement { repositories { mavenCentral(); maven(url = "http://nexus.xx/repository/caffeine/") { isAllowInsecureProtocol = true } } }.
-
build.gradle.kts (корень): plugins { kotlin("jvm") version "2.4.10" apply false }; ext: kotlinVersion "2.4.10", onnxVersion "1.16.0"; во всех модулях jvmTarget 17.
-
memo-core/build.gradle.kts: plugins { kotlin("jvm") }; зависимости: implementation("pw.binom.db:ksqlite:0.1.4") implementation("pw.binom.ai.embeddingtext:api:5") runtimeOnly("pw.binom.ai.embeddingtext:siglip-jvm:5") testImplementation(kotlin("test")) Тестовый фреймворк не менять (дефолтный JUnit4), useJUnitPlatform() НЕ добавлять.
-
Модули memo-cli, memo-watch, memo-mcp — только build.gradle.kts с plugins { kotlin("jvm") } и пустой src. Логику не писать.
-
memo-core/src/main/kotlin/memo/core/Embedder.kt: class Embedder(private val modelPath: String, private val tokenizerPath: String) : AutoCloseable
- лениво, при первом embed, создаёт pw.binom.voice.embeddingtext.createSiglip2TextExtractor(modelPath, tokenizerPath)
- fun embed(text: String): FloatArray — возвращает ex.embed(text).values; если размерность != 768, бросить IllegalStateException с фактической размерностью
- override fun close() — идемпотентно, закрывает экстрактор Импорты: pw.binom.voice.embeddingtext.createSiglip2TextExtractor, pw.binom.voice.embeddingtext.TextEmbeddingExtractor
-
memo-core/src/main/kotlin/memo/core/Db.kt: class Db(val path: String) : AutoCloseable
- при создании открывает SQLiteConnection.open(path) (pw.binom.db.ksqlite.SQLiteConnection)
- сразу выполняет: "PRAGMA journal_mode=WAL" и "PRAGMA synchronous=NORMAL"
- fun init() — идемпотентно создаёт схему (ровно эти SQL): CREATE TABLE IF NOT EXISTS files(path TEXT PRIMARY KEY, mtime REAL, size INTEGER, hash TEXT, indexed_at REAL); CREATE TABLE IF NOT EXISTS chunks(id INTEGER PRIMARY KEY, path TEXT NOT NULL, heading TEXT, line INTEGER NOT NULL, ord INTEGER NOT NULL, text TEXT NOT NULL, hash TEXT NOT NULL); CREATE INDEX IF NOT EXISTS idx_chunks_path ON chunks(path); CREATE VIRTUAL TABLE IF NOT EXISTS chunks_fts USING fts5(text, heading, tokenize='unicode61'); CREATE VIRTUAL TABLE IF NOT EXISTS chunks_vec USING vec0(embedding float[768]);
- val conn даёт доступ к соединению
- close() закрывает соединение
-
memo-core/src/test/kotlin/memo/core/ — ровно 4 теста, отдельные @Test функции, имена ровно такие:
- ksqliteSmoke — временный файл БД, CREATE TABLE t(a INTEGER), INSERT 42, SELECT, значение совпало.
- vec0KnnRoundTrip — CREATE VIRTUAL TABLE v USING vec0(embedding float[4]); вставить 3 вектора с rowid 1, 2, 3 (привязка FloatArray: stmt.bind(1, id); stmt.bind(2, floatArrayOf(...))); запрос "SELECT rowid FROM v WHERE embedding MATCH ? ORDER BY distance LIMIT 1" с вектором, ближайшим к rowid=2, обязан вернуть 2.
- fts5FindsCyrillic — FTS5-таблица, вставка строки "внутренний домен траефик", поиск MATCH 'траефик' находит ровно 1 строку.
- embedderProduces768 — путь к модели: env MEMO_MODEL_DIR, иначе /root/WORK/memo/models/siglip2; если text_model_int8.onnx или tokenizer.model отсутствуют — тест падает с сообщением "модель не найдена: <путь>"; иначе embed("привет мир") → dim == 768 и ни одного NaN.
-
Прогони ./gradlew :memo-core:test и добейся, чтобы все 4 теста были зелёными (файлы модели уже скачиваются в models/siglip2, дождись их; если их ещё нет — тест embedderProduces768 может упасть, тогда перезапусти прогон позже). В конце: git add -A && git commit -m "core: каркас сборки, embedder, схема БД, 4 теста".
СТРОГИЕ ЗАПРЕТЫ:
- НЕ выводи план текстом. Сразу правь файлы инструментами. Задача не выполнена, пока файлы не изменены и ./gradlew :memo-core:test не зелёный.
- НЕ добавляй зависимости, которых нет в списке выше.
- НЕ трогай docs/SPEC.md, TASK.md, TESTING.md, README.md, LICENSE, scripts/, .gitignore.
- НЕ создавай Android/KMP-модули и platform-таргеты.
- НЕ коммить папку models/ и файлы *.db.