feat: наблюдение за живой opencode-сессией (/status N показывает что делает агент)
LiveRegistry собирает live-шаги из stdout процесса opencode по taskID (через контекст, без изменения интерфейса Runner). /status N для running-задачи прикладывает живое состояние: активный субагент, давность последнего шага, последние text-шаги агента. Ничего не перезапускается и не убивается — только наблюдение по запросу.
This commit is contained in:
@@ -9,9 +9,10 @@ import (
|
||||
)
|
||||
|
||||
// fakeOpenCode создаёт shell-скрипт, имитирующий opencode run:
|
||||
// $FAKE_MODE=ok -> мгновенный успех, печатает NDJSON c session_id
|
||||
// $FAKE_MODE=slow-> спит долго (для idle/hard timeout)
|
||||
// $FAKE_MODE=fail-> exit 7 (resume-fallback)
|
||||
//
|
||||
// $FAKE_MODE=ok -> мгновенный успех, печатает NDJSON c session_id
|
||||
// $FAKE_MODE=slow-> спит долго (для idle/hard timeout)
|
||||
// $FAKE_MODE=fail-> exit 7 (resume-fallback)
|
||||
func fakeOpenCode(t *testing.T, workdir string) string {
|
||||
t.Helper()
|
||||
bin := filepath.Join(workdir, "opencode")
|
||||
@@ -59,6 +60,28 @@ func TestRun_Success(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRun_LiveRegistry(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
bin := fakeOpenCode(t, dir)
|
||||
t.Setenv("FAKE_MODE", "ok")
|
||||
|
||||
reg := NewLiveRegistry()
|
||||
ctx := WithLive(context.Background(), reg, 42)
|
||||
|
||||
r := &Runner{Bin: bin, PollInterval: 20 * time.Millisecond}
|
||||
res, err := r.Run(ctx, "task", dir, "dev", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Run err: %v", err)
|
||||
}
|
||||
if res.RC != 0 {
|
||||
t.Fatalf("RC = %d, want 0", res.RC)
|
||||
}
|
||||
// После завершения Finish удаляет сессию → Snap не найден.
|
||||
if _, ok := reg.Snap(42); ok {
|
||||
t.Error("сессия не удалена после Finish (должна быть, т.к. задача завершилась)")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRun_IdleTimeout(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
bin := fakeOpenCode(t, dir)
|
||||
|
||||
Reference in New Issue
Block a user