Files
ratatoskr-go/internal/config/types.go
Hermes 9c5f38698c
All checks were successful
CI / test (push) Successful in 56s
CI / build-and-package (amd64, linux) (push) Successful in 42s
CI / build-and-package (amd64, windows) (push) Successful in 40s
fix: idle-таймер сбрасывается по live-стриму LLM + дефолт 5м; агенты opencode в agents/ с mode: primary
- opencode ищет кастомных агентов в поддиректории agents/ (как .opencode),
  а не в корне OPENCODE_CONFIG_DIR → распаковка теперь в <dir>/agents/*.md
- markdown-агентам добавлен mode: primary (иначе subagent по умолчанию)
- idle-детекция сбрасывает таймер при live-строках (text/tool/agent/reasoning),
  а не только по росту БД → «LLM думает и стримит» не считается зависанием
- дефолт idle_timeout поднят с 2м до 5м
2026-08-17 10:57:19 +05:00

103 lines
4.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Package config — загрузка конфигурации Ratatoskr-go.
//
// Источники (каждый следующий имеет приоритет над предыдущим):
// 1. Файл config.yaml (с подстановкой ${VAR:-default})
// 2. Переменные окружения (env-теги в структуре)
//
// Порядок: Load("config.yaml") → YAML → os.Expand → env override → Validate.
package config
import (
"errors"
"fmt"
"time"
)
// Duration — time.Duration с YAML-сериализацией (строка "5s", "10m").
type Duration time.Duration
func (d Duration) Duration() time.Duration { return time.Duration(d) }
func (d Duration) String() string { return time.Duration(d).String() }
func (d *Duration) UnmarshalYAML(unmarshal func(any) error) error {
var s string
if err := unmarshal(&s); err != nil {
return fmt.Errorf("%w: %v", ErrInvalidFormat, err)
}
td, err := time.ParseDuration(s)
if err != nil {
return fmt.Errorf("%w: parse duration %q: %v", ErrInvalidFormat, s, err)
}
*d = Duration(td)
return nil
}
// Config — полная конфигурация бинаря.
type Config struct {
Telegram TelegramCfg `yaml:"telegram"`
OpenCode OpenCodeCfg `yaml:"opencode"`
Git GitCfg `yaml:"git"`
Chat ChatCfg `yaml:"chat"`
Paths PathsCfg `yaml:"paths"`
Update UpdateCfg `yaml:"update"`
}
// GitCfg — источник репозиториев (для git clone).
type GitCfg struct {
BaseURL string `yaml:"base_url" env:"GIT_BASE_URL"`
Token string `yaml:"token" env:"GIT_TOKEN"`
}
// UpdateCfg — автообновление.
// Enabled=false отключает и авто-проверку, и /update.
// BaseURL — хост Gitea для обновления (обязателен: без него update отключён,
// фоллбэк на git.base_url НЕ используется).
// Token — токен read:package. Приоритет: вшитый -X main.updateToken > этот.
// Package — имя пакета-хранилища (по умолчанию ratatoskr). Владелец пакета —
// жёсткая константа (packageOwner в app).
// CheckInterval — как часто авто-проверять наличие обновления
// (по умолчанию 24h). Авто-режим ТОЛЬКО уведомляет; замена — по /update.
type UpdateCfg struct {
Enabled bool `yaml:"enabled" default:"false"`
BaseURL string `yaml:"base_url" env:"UPDATE_BASE_URL"`
Token string `yaml:"token" env:"UPDATE_TOKEN"`
Package string `yaml:"package" default:"ratatoskr"`
CheckInterval Duration `yaml:"check_interval" default:"24h"`
}
type TelegramCfg struct {
Token string `yaml:"token" env:"TG_TOKEN"`
ChatID string `yaml:"chat_id" env:"TG_CHAT_ID"`
}
type OpenCodeCfg struct {
Bin string `yaml:"bin" default:"opencode"`
DBPath string `yaml:"db_path" default:""`
Config string `yaml:"config" env:"OPENCODE_CONFIG"`
ConfigDir string `yaml:"config_dir" env:"OPENCODE_CONFIG_DIR"`
HardTimeout Duration `yaml:"hard_timeout" default:"20m"`
IdleTimeout Duration `yaml:"idle_timeout" default:"5m"`
PollMs Duration `yaml:"poll_ms" default:"2s"`
}
type ChatCfg struct {
PollInterval Duration `yaml:"poll_interval" default:"30s"`
}
type PathsCfg struct {
Worktree string `yaml:"worktree" default:"./worktrees"`
DB string `yaml:"db" default:"./ratatoskr.db" env:"RATATOSKR_DB"`
}
// Validate проверяет обязательные поля. Возвращает C1 MissingField
// (склеенную, все ошибки сразу) или C2 InvalidFormat.
func (c *Config) Validate() error {
var errs []error
if c.Telegram.Token == "" {
errs = append(errs, fmt.Errorf("%w: telegram.token", ErrMissingField))
}
if c.Telegram.ChatID == "" {
errs = append(errs, fmt.Errorf("%w: telegram.chat_id", ErrMissingField))
}
return errors.Join(errs...)
}