Files

5.9 KiB
Raw Permalink Blame History

Проект: /root/WORK/memo (Kotlin/JVM). Заказ по CLI — руками проверяемые команды.

Правки:

  • memo-cli/build.gradle.kts: добавить application-плагин и зависимость на :memo-core
  • новый файл memo-cli/src/main/kotlin/memo/cli/Main.kt
  • новый файл memo-cli/src/test/kotlin/memo/cli/CliArgsTest.kt

Настройка модуля memo-cli

build.gradle.kts модуля: plugins { kotlin("jvm"); application } application { mainClass.set("memo.cli.MainKt") } dependencies { implementation(project(":memo-core")) }

Main.kt — контракт команд

fun main(args: Array)

Разбор аргументов вынести в чистую функцию (тестируемую без процесса): sealed interface Cmd data class IndexCmd(val path: String) : Cmd data class SearchCmd(val path: String, val query: String, val k: Int, val mode: SearchMode, val json: Boolean) : Cmd data class StatusCmd(val path: String) : Cmd data class McpProbeCmd(val tool: String, val argsJson: String) : Cmd object HelpCmd : Cmd fun parseArgs(args: Array): Cmd // при ошибке — HelpCmd

Правила разбора:

  • index <path> → IndexCmd
  • search <path> <query> [--k N] [--mode hybrid|lex|vec] [--json] → SearchCmd (по умолчанию k = 8, mode = HYBRID); неизвестный флаг или нечисловой --k → HelpCmd
  • status <path> → StatusCmd
  • mcp-probe --tool <name> [--args <json>] → McpProbeCmd (args по умолчанию "{}")
  • нет аргументов, --help, -h, неизвестная команда → HelpCmd

Поведение команд:

  1. index <path>: определить корень так — если path оканчивается на "/.memo" или содержит его, взять родителя; каталог X считается коллекцией, если в нём есть файлы *.md (искать на глубине до 2 от path). Для каждой найденной коллекции: создать каталог <коллекция>/.memo, базу <коллекция>/.memo/index.db, Db(...).init(), затем Indexer(db, embedder).indexTree(коллекция). Путь к модели: переменная окружения MEMO_MODEL_DIR, иначе /root/WORK/memo/models/siglip2. Печатать по строке на коллекцию: индексировано: <N> обновлено, <файлов всего> и в конце итого: <сумма> обновлено в <число коллекций> коллекциях.
  2. search <path> <query>: path — ЛИБО коллекция, ЛИБО файл *.md (тогда коллекция = его каталог), ЛИБО корень, содержащий коллекции (тогда искать по всем коллекциям внутри, объединив результаты по убыванию score и обрезав до k). Модель/эмбеддер обязателен: без него базы не откроются — это нормально. Refresh-хук передавать обязательно: он делает Indexer(db, embedder).indexTree(root) перед поиском. Без --json печатать человекочитаемо: <score с 3 знаками> <path>:<line> <heading> далее текст чанка с отступом 4 пробела, обрезанный до 300 символов. С --json печатать ОДИН JSON-массив, без пояснений и без лишних строк: [{"path":"...","line":12,"heading":"...","score":0.51,"text":"..."}] Если ничего не найдено — пустой JSON-массив [] (в режиме --json) и код возврата 0.
  3. status <path>: по каждой коллекции печатать <<коллекция>>: файлов <N>, чанков <M>, индекс <дата ISO> (дата — максимальный indexed_at из files).
  4. mcp-probe --tool <name> --args <json>: выполнить то же, что делает MCP-инструмент, и напечатать результат в формате MCP-ответа: {"content":[{"type":"text","text":"<результат>"}],"isError":false} Поддерживаемые инструменты на этом шаге: memo_search (аргументы path, query, k, mode) и memo_status (path). memo_reindex — вернуть isError: true с текстом "not implemented yet".

CliArgsTest.kt — ровно 5 тестов, имена ровно такие

  1. indexCommandParsed — ["index", "/tmp/x"] → IndexCmd с path "/tmp/x".
  2. searchDefaultsAreK8HybridNoJson — ["search", "/tmp/x", "вопрос"] → SearchCmd(k = 8, mode = HYBRID, json = false).
  3. searchFlagsParsed — ["search", "/tmp/x", "вопрос", "--k", "3", "--mode", "lex", "--json"] → k = 3, mode = LEX, json = true.
  4. badKValueFallsBackToHelp — ["search", "/tmp/x", "вопрос", "--k", "abc"] → HelpCmd.
  5. unknownCommandFallsBackToHelp — ["сломать"] → HelpCmd.

После: ./gradlew :memo-cli:test --rerun-tasks и ./gradlew :memo-cli:installDist — обе команды зелёные. Проверь руками, что бинарь появился: ls memo-cli/build/install/memo-cli/bin/memo Коммит: git add -A && git commit -m "cli: index/search/status/mcp-probe"

СТРОГИЕ ЗАПРЕТЫ:

  • Не выводить план текстом; сразу правь файлы.
  • Не трогать memo-core (ни src/main, ни src/test), кроме использования его публичного API.
  • Не добавлять зависимости, кроме :memo-core.
  • Не создавать другие файлы.