feat: наблюдение за живой opencode-сессией (/status N показывает что делает агент)
All checks were successful
CI / test (push) Successful in 54s
CI / build-and-package (amd64, linux) (push) Successful in 35s
CI / build-and-package (amd64, windows) (push) Successful in 43s

LiveRegistry собирает live-шаги из stdout процесса opencode по taskID
(через контекст, без изменения интерфейса Runner). /status N для running-задачи
прикладывает живое состояние: активный субагент, давность последнего шага,
последние text-шаги агента. Ничего не перезапускается и не убивается —
только наблюдение по запросу.
This commit is contained in:
Hermes
2026-08-17 08:05:15 +05:00
parent 2255917949
commit da775ac227
9 changed files with 329 additions and 26 deletions

39
internal/app/live_test.go Normal file
View File

@@ -0,0 +1,39 @@
package app
import (
"strings"
"testing"
"time"
"github.com/kamelion/ratatoskr-go/internal/opencode"
)
func TestLiveProbe_Fmt(t *testing.T) {
reg := opencode.NewLiveRegistry()
p := &liveProbe{reg: reg}
// Нет сессии — Probe должен вернуть ok=false.
if _, ok := p.Probe(1); ok {
t.Error("Probe без сессии вернул ok=true")
}
reg.Start(7, "dev")
reg.Observe(7, opencode.LiveStep{Type: "text", Text: "анализирую код", At: time.Now()})
reg.Observe(7, opencode.LiveStep{Type: "tool", At: time.Now()})
reg.Observe(7, opencode.LiveStep{Type: "text", Text: "пишу фичу по задаче номер триста семь", At: time.Now()})
desc, ok := p.Probe(7)
if !ok {
t.Fatal("Probe с сессией вернул ok=false")
}
if !strings.Contains(desc, "dev") {
t.Errorf("описание не содержит агента: %q", desc)
}
if !strings.Contains(desc, "пишу фичу") {
t.Errorf("описание не содержит последний text-шаг: %q", desc)
}
// text-шаги: оба, tools пропущен
if n := strings.Count(desc, "▸"); n != 2 {
t.Errorf("ожидал 2 text-шага (▸), вижу %d: %q", n, desc)
}
}