ratatoskr-go: стартовый каркас (Go-бинарь, CI, structure)
All checks were successful
build-test / build (push) Successful in 47s
All checks were successful
build-test / build (push) Successful in 47s
This commit is contained in:
16
.gitea/workflows/build.yml
Normal file
16
.gitea/workflows/build.yml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
name: build-test
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: '1.23'
|
||||||
|
- run: go vet ./...
|
||||||
|
- run: go build ./...
|
||||||
|
- run: go test ./...
|
||||||
18
.gitignore
vendored
Normal file
18
.gitignore
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Binaries
|
||||||
|
/bin/
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
|
||||||
|
# Go build/test artifacts
|
||||||
|
/testbin/
|
||||||
|
*.test
|
||||||
|
|
||||||
|
# Env / secrets
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!/.env.example
|
||||||
|
secrets/
|
||||||
|
|
||||||
|
# Local scratch
|
||||||
|
.tmp/
|
||||||
|
.db/
|
||||||
49
README.md
Normal file
49
README.md
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# Ratatoskr-go
|
||||||
|
|
||||||
|
Ratatoskr на Go — **оркестратор в единый статический бинарь** + субагенты через
|
||||||
|
[opencode](https://opencode.ai) как внешний процесс. Переезд с Python-версии.
|
||||||
|
|
||||||
|
## Почему Go
|
||||||
|
|
||||||
|
Агентный конвейер — это клей (HTTP/JSON к LLM, SQLite, Gitea API, Telegram), а не
|
||||||
|
горячие вычисления. Цель — **один статический бинарь без runtime-зависимостей**
|
||||||
|
(CGO_ENABLED=0), который решает проблему доставки/деплоя. Go: горизонт
|
||||||
|
HTTP/JSON + goroutine-параллелизм research/feedback/notify + SQLite без CGO
|
||||||
|
(`modernc.org/sqlite`).
|
||||||
|
|
||||||
|
## Структура
|
||||||
|
|
||||||
|
```
|
||||||
|
cmd/ratatoskr/ # точка входа, сборка бинаря
|
||||||
|
internal/
|
||||||
|
app/ # компоновка (composition root), конфиг, DI
|
||||||
|
dialog/ # state-machine диалога: collect→confirm→created
|
||||||
|
decide/ # аналитик: промпт + разбор JSON-решения (opencode agent)
|
||||||
|
research/ # исследователь: FACTS о репозитории
|
||||||
|
feedback/ # feedback: транскрипт→proposals (opencode agent)
|
||||||
|
opencode/ # обёртка запуска opencode-процесса, парсинг вердикта
|
||||||
|
gitea/ # Gitea API-клиент: issues, labels, PR, webhook
|
||||||
|
webhook/ # digest-ответы и статус в Telegram
|
||||||
|
issue/ # issue: формирование тела задачи, task-tag
|
||||||
|
```
|
||||||
|
|
||||||
|
## Сборка
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go build -o bin/ratatoskr ./cmd/ratatoskr # обычная
|
||||||
|
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \
|
||||||
|
-o bin/ratatoskr-linux-amd64 ./cmd/ratatoskr # статический бинарь
|
||||||
|
```
|
||||||
|
|
||||||
|
## Контракты (не ломать)
|
||||||
|
|
||||||
|
- `process_turn` всегда возвращает **3 значения**: `(reply, action, session)`.
|
||||||
|
- `decide_fn` возвращает кортеж/структуру `(decision, err)`.
|
||||||
|
- `/proposal` передаёт аналитику **полный комплект**, а не digest.
|
||||||
|
- Вердикты агентов — строгий JSON; `_extract_json` устойчив к мусору.
|
||||||
|
|
||||||
|
## Eval
|
||||||
|
|
||||||
|
Eval-suite (парсинг A / контракты B / качество C) — см.
|
||||||
|
[дизайн в вики](../wiki/concepts/ratatoskr-evals.md). Запуск после внедрения:
|
||||||
|
`go test ./...` для детерминированных уровней A+B.
|
||||||
44
cmd/ratatoskr/main.go
Normal file
44
cmd/ratatoskr/main.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
// Command ratatoskr — оркестратор конвейера Ratatoskr (единственный бинарь).
|
||||||
|
//
|
||||||
|
// Стартовый каркас: точка входа + заглушки пакетов. Полная логика
|
||||||
|
// (диалог, аналитик, research, feedback, webhook) наполняется по мере
|
||||||
|
// переезда с Python.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/kamelion/ratatoskr-go/internal/app"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cfg := flag.String("config", "", "путь к config файлу (по умолчанию — env)")
|
||||||
|
version := flag.Bool("version", false, "показать версию и выйти")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if *version {
|
||||||
|
fmt.Println("ratatoskr-go dev (переезд с Ratatoskr Python)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Composition root: читает конфиг (env/config), настраивает DI.
|
||||||
|
a, err := app.New(*cfg)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("app init: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Пока: заглушка. Здесь будет:
|
||||||
|
// - запуск Telegram-gateway (диалог)
|
||||||
|
// - http-сервер webhook (+ /feedback, /status)
|
||||||
|
// - воркер: обработка issues → opencode-субагенты → PR
|
||||||
|
_ = a
|
||||||
|
os.Exit(run())
|
||||||
|
}
|
||||||
|
|
||||||
|
func run() int {
|
||||||
|
fmt.Fprintln(os.Stderr, "ratatoskr-go: каркас готов, конвейер не подключён")
|
||||||
|
return 0
|
||||||
|
}
|
||||||
26
internal/app/app.go
Normal file
26
internal/app/app.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// Package app — composition root: конфигурация, DI, жизненный цикл процесса.
|
||||||
|
package app
|
||||||
|
|
||||||
|
// Config — конфигурация конвейера (env или config-файл).
|
||||||
|
type Config struct {
|
||||||
|
GiteaURL string
|
||||||
|
GiteaToken string
|
||||||
|
IssueRepo string
|
||||||
|
// TODO: Telegram, LiteLLM, SQLite (opencode.db), gateway, webhook secret.
|
||||||
|
}
|
||||||
|
|
||||||
|
// App — собранный конвейер (все зависимости).
|
||||||
|
type App struct {
|
||||||
|
Config Config
|
||||||
|
// TODO: *dialog.Controller, *gitea.Client, *opencode.Runner, ...
|
||||||
|
}
|
||||||
|
|
||||||
|
// New читает конфиг и собирает приложение. Стартовая заглушка.
|
||||||
|
func New(configPath string) (*App, error) {
|
||||||
|
var c Config
|
||||||
|
_ = configPath // TODO: загрузка из env/config
|
||||||
|
// TODO: слой failures/classes ошибок по конвенции проекта.
|
||||||
|
// Использовать в рантайме (например, лимиты диалога):
|
||||||
|
c.IssueRepo = "kamelion/ratatoskr-go" // placeholder
|
||||||
|
return &App{Config: c}, nil
|
||||||
|
}
|
||||||
15
internal/app/app_test.go
Normal file
15
internal/app/app_test.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package app
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
// Контракт: process_turn (после внедрения) должен возвращать 3 значения.
|
||||||
|
// Здесь — placeholder-проверка, что composition root собирается без сбоев.
|
||||||
|
func TestNew(t *testing.T) {
|
||||||
|
a, err := New("")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("New() err = %v", err)
|
||||||
|
}
|
||||||
|
if a.Config.IssueRepo == "" {
|
||||||
|
t.Fatal("IssueRepo пуст — каркас не инициализирован")
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user