feat(analyst): этапы задачи — аналитик раскладывает на steps с критериями готовности, dev идёт по ним
Some checks failed
CI / test (push) Failing after 1m52s
CI / build-and-package (amd64, linux) (push) Failing after 1m3s
CI / build-and-package (amd64, windows) (push) Successful in 30s

This commit is contained in:
ki.sagidullin
2026-08-24 18:05:06 +05:00
parent 6546f18348
commit 6c0b903794
10 changed files with 286 additions and 50 deletions

View File

@@ -14,17 +14,17 @@ 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
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 — все возможные статусы для валидации.
@@ -40,17 +40,24 @@ func IsTerminal(s Status) bool {
return model.IsTerminal(s)
}
// Step — этап задачи с собственным критерием готовности.
type Step struct {
Title string `json:"title"`
AC string `json:"ac"` // acceptance criterion этапа
}
// Task — запись задачи в БД.
type Task struct {
ID int64 `json:"id"`
ChatID string `json:"chat_id"` // tg://<id>
ChatID string `json:"chat_id"` // tg://<id>
Title string `json:"title"`
Goal string `json:"goal"`
Repo string `json:"repo"` // обратная совместимость: одиночный репозиторий
Repos []string `json:"repos"` // список репозиториев (основной)
Repo string `json:"repo"` // обратная совместимость: одиночный репозиторий
Repos []string `json:"repos"` // список репозиториев (основной)
Why string `json:"why"`
AC string `json:"ac"` // acceptance criteria
TaskTag string `json:"task_tag"` // UUID, стабильный на всю жизнь
AC string `json:"ac"` // acceptance criteria
Steps []Step `json:"steps"` // этапы задачи (опционально)
TaskTag string `json:"task_tag"` // UUID, стабильный на всю жизнь
Status Status `json:"status"`
CreatedAt SQLiteTime `json:"created_at"`
UpdatedAt SQLiteTime `json:"updated_at"`
@@ -88,6 +95,25 @@ func (t *Task) SetReposFromDB(repos string) {
_ = json.Unmarshal([]byte(repos), &t.Repos)
}
// StepsJoined возвращает steps как одну строку (JSON-массив) для хранения в БД.
// Пустой список → пустая строка.
func (t *Task) StepsJoined() string {
if len(t.Steps) == 0 {
return ""
}
b, _ := json.Marshal(t.Steps)
return string(b)
}
// SetStepsFromDB заполняет Steps из сохранённой строки (JSON).
func (t *Task) SetStepsFromDB(steps string) {
if steps == "" {
t.Steps = nil
return
}
_ = json.Unmarshal([]byte(steps), &t.Steps)
}
// TraceStatus — алиас доменного статуса трассировки.
type TraceStatus = model.TraceStatus
@@ -105,7 +131,7 @@ type Trace struct {
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
Output string `json:"output"` // полный NDJSON или summary
Status TraceStatus `json:"status"`
StartedAt SQLiteTime `json:"started_at"`
FinishedAt NullSQLiteTime `json:"finished_at,omitempty"`
@@ -113,8 +139,8 @@ type Trace struct {
// TaskFilter — параметры фильтрации списка задач.
type TaskFilter struct {
ChatID string
Status Status
Limit int
Offset int
}
ChatID string
Status Status
Limit int
Offset int
}