- internal/model: единый источник статусов задачи (Status, TraceStatus, машина переходов), без зависимости от storage. - internal/storage: совместимый мост (type Status = model.Status, re-export констант) — внешний код не меняется. - internal/events: шина событий (fan-out, блокирующий Publish с гарантией порядка), события задач/трейсов, отдельная логовая шина + LogWriter, Publisher/NilPublisher для внедрения в Core/Worker. - docs/ui-spec.md: спецификация десктопного UI (Fyne).
120 lines
4.2 KiB
Go
120 lines
4.2 KiB
Go
package storage
|
|
|
|
import (
|
|
"encoding/json"
|
|
|
|
"github.com/kamelion/ratatoskr-go/internal/model"
|
|
)
|
|
|
|
// Status — алиас доменного статуса задачи.
|
|
//
|
|
// Совместимый мост: весь внешний код продолжает использовать storage.Status
|
|
// (например «storage.StatusRunning»), но единый источник истины — model.Status.
|
|
type Status = model.Status
|
|
|
|
// Статусы задачи — re-export из model.
|
|
const (
|
|
StatusDraft = model.StatusDraft
|
|
StatusCollecting = model.StatusCollecting
|
|
StatusReady = model.StatusReady
|
|
StatusApproved = model.StatusApproved
|
|
StatusRunning = model.StatusRunning
|
|
StatusSuccess = model.StatusSuccess
|
|
StatusFailed = model.StatusFailed
|
|
StatusTimeout = model.StatusTimeout
|
|
StatusCancelled = model.StatusCancelled
|
|
StatusAborted = model.StatusAborted
|
|
StatusClosed = model.StatusClosed
|
|
)
|
|
|
|
// AllStatuses — все возможные статусы для валидации.
|
|
var AllStatuses = model.AllStatuses
|
|
|
|
// IsValidTransition проверяет, допустим ли переход from → to.
|
|
func IsValidTransition(from, to Status) bool {
|
|
return model.IsValidTransition(from, to)
|
|
}
|
|
|
|
// IsTerminal возвращает true, если статус терминальный.
|
|
func IsTerminal(s Status) bool {
|
|
return model.IsTerminal(s)
|
|
}
|
|
|
|
// Task — запись задачи в БД.
|
|
type Task struct {
|
|
ID int64 `json:"id"`
|
|
ChatID string `json:"chat_id"` // tg://<id>
|
|
Title string `json:"title"`
|
|
Goal string `json:"goal"`
|
|
Repo string `json:"repo"` // обратная совместимость: одиночный репозиторий
|
|
Repos []string `json:"repos"` // список репозиториев (основной)
|
|
Why string `json:"why"`
|
|
AC string `json:"ac"` // acceptance criteria
|
|
TaskTag string `json:"task_tag"` // UUID, стабильный на всю жизнь
|
|
Status Status `json:"status"`
|
|
CreatedAt SQLiteTime `json:"created_at"`
|
|
UpdatedAt SQLiteTime `json:"updated_at"`
|
|
}
|
|
|
|
// ReposJoined возвращает repos как одну строку (JSON-массив) для хранения в БД.
|
|
// Пустой список → пустая строка.
|
|
func (t *Task) ReposJoined() string {
|
|
if len(t.Repos) == 0 {
|
|
return ""
|
|
}
|
|
b, _ := json.Marshal(t.Repos)
|
|
return string(b)
|
|
}
|
|
|
|
// EffectiveRepos возвращает сам репо: если Repos пуст, но Repo задан —
|
|
// подтягивает одиночный (обратная совместимость).
|
|
func (t *Task) EffectiveRepos() []string {
|
|
if len(t.Repos) > 0 {
|
|
return t.Repos
|
|
}
|
|
if t.Repo != "" {
|
|
return []string{t.Repo}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// SetReposFromDB заполняет Repos из сохранённой строки (JSON), либо
|
|
// из одиночного repo (обратная совместимость).
|
|
func (t *Task) SetReposFromDB(repos string) {
|
|
if repos == "" {
|
|
t.Repos = nil
|
|
return
|
|
}
|
|
_ = json.Unmarshal([]byte(repos), &t.Repos)
|
|
}
|
|
|
|
// TraceStatus — алиас доменного статуса трассировки.
|
|
type TraceStatus = model.TraceStatus
|
|
|
|
const (
|
|
TraceRunning TraceStatus = model.TraceRunning
|
|
TraceSuccess TraceStatus = model.TraceSuccess
|
|
TraceFailed TraceStatus = model.TraceFailed
|
|
TraceTimeout TraceStatus = model.TraceTimeout
|
|
)
|
|
|
|
// Trace — лог одного субагента.
|
|
type Trace struct {
|
|
ID int64 `json:"id"`
|
|
TaskID int64 `json:"task_id"`
|
|
Agent string `json:"agent"` // analyst | researcher | dev | reviewer
|
|
SessionID string `json:"session_id"` // opencode session_id
|
|
Prompt string `json:"prompt"`
|
|
Output string `json:"output"` // полный NDJSON или summary
|
|
Status TraceStatus `json:"status"`
|
|
StartedAt SQLiteTime `json:"started_at"`
|
|
FinishedAt NullSQLiteTime `json:"finished_at,omitempty"`
|
|
}
|
|
|
|
// TaskFilter — параметры фильтрации списка задач.
|
|
type TaskFilter struct {
|
|
ChatID string
|
|
Status Status
|
|
Limit int
|
|
Offset int
|
|
} |