From ac72ca6f5293dda78266f57631c5b510e02ff6b6 Mon Sep 17 00:00:00 2001 From: djuka Date: Sat, 21 Feb 2026 04:09:30 +0000 Subject: [PATCH] =?UTF-8?q?Pusti:=20preme=C5=A1ta=20task=20ready=E2=86=92a?= =?UTF-8?q?ctive=20bez=20pokretanja=20claude=20sesije?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - handleRunTask samo premešta task iz ready/ u active/ sa timestampom - Uklonjena zavisnost od console sesija — konzola je nezavisna - Korisnik pokreće claude ručno iz konzole terminala - Ažurirani testovi (6 RunTask testova prolaze) Co-Authored-By: Claude Opus 4.6 --- code/internal/server/server.go | 52 ++++++----------------------- code/internal/server/server_test.go | 41 +++++++++++------------ 2 files changed, 29 insertions(+), 64 deletions(-) diff --git a/code/internal/server/server.go b/code/internal/server/server.go index 65cf8bf..e3b7c27 100644 --- a/code/internal/server/server.go +++ b/code/internal/server/server.go @@ -123,6 +123,9 @@ func (s *Server) setupRoutes() { s.Router.GET("/console/history/:session", s.handleConsoleHistory) s.Router.GET("/console/ws/:session", s.handleConsoleWS) + // Logs route + s.Router.GET("/api/logs/tail", s.handleLogsTail) + // Docs routes s.Router.GET("/docs", s.handleDocsList) s.Router.GET("/docs/*path", s.handleDocsView) @@ -346,54 +349,19 @@ func (s *Server) handleRunTask(c *gin.Context) { task.Status = "ready" } - // Find free session - sessionIdx := -1 - for i := 0; i < 2; i++ { - sess := s.console.getSession(i) - sess.mu.Lock() - if sess.status == "idle" { - sessionIdx = i - sess.mu.Unlock() - break - } - sess.mu.Unlock() - } - - if sessionIdx == -1 { - c.JSON(http.StatusConflict, gin.H{"error": "obe sesije su zauzete"}) + // Move ready → active + if err := supervisor.MoveTask(s.Config.TasksDir, id, "ready", "active"); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } - // Build the prompt - prompt := "Pročitaj CLAUDE.md u root-u projekta. Tvoj task: TASKS/ready/" + id + ".md — Pročitaj task fajl i uradi šta piše. Prati pravila iz CLAUDE.md." - - // Start in the session - session := s.console.getSession(sessionIdx) - execID := s.console.nextExecID() - - session.mu.Lock() - session.status = "running" - session.execID = execID - session.taskID = id - session.output = nil - session.history = append(session.history, historyEntry{ - Command: "pusti " + id, - ExecID: execID, - Timestamp: timeNow(), - Status: "running", - }) - session.mu.Unlock() - // Append "Pokrenut" timestamp - taskPath := filepath.Join(s.Config.TasksDir, "ready", id+".md") - appendTimestamp(taskPath, "Pokrenut") - - go s.runCommand(session, prompt, execID) + taskPath := filepath.Join(s.Config.TasksDir, "active", id+".md") + appendTimestamp(taskPath, "Pokrenut (→active)") c.JSON(http.StatusOK, gin.H{ - "status": "started", - "session": sessionIdx + 1, - "exec_id": execID, + "status": "started", + "task": id, }) } diff --git a/code/internal/server/server_test.go b/code/internal/server/server_test.go index 1027e24..07615bb 100644 --- a/code/internal/server/server_test.go +++ b/code/internal/server/server_test.go @@ -809,8 +809,12 @@ func TestRunTask_Ready(t *testing.T) { if resp["status"] != "started" { t.Errorf("expected status started, got %v", resp["status"]) } - if resp["session"] == nil { - t.Error("expected session number in response") + if resp["task"] != "T08" { + t.Errorf("expected task T08, got %v", resp["task"]) + } + // Verify task moved to active/ + if _, err := os.Stat(filepath.Join(srv.Config.TasksDir, "active", "T08.md")); err != nil { + t.Error("expected T08.md in active/") } } @@ -853,7 +857,7 @@ func TestRunTask_NotFound(t *testing.T) { } } -func TestRunTask_BothSessionsBusy(t *testing.T) { +func TestRunTask_MovesToActive(t *testing.T) { srv := setupTestServer(t) // Move T08 to ready @@ -862,30 +866,18 @@ func TestRunTask_BothSessionsBusy(t *testing.T) { filepath.Join(srv.Config.TasksDir, "ready", "T08.md"), ) - // Occupy both sessions - srv.console.sessions[0].mu.Lock() - srv.console.sessions[0].status = "running" - srv.console.sessions[0].mu.Unlock() - - srv.console.sessions[1].mu.Lock() - srv.console.sessions[1].status = "running" - srv.console.sessions[1].mu.Unlock() - req := httptest.NewRequest(http.MethodPost, "/task/T08/run", nil) w := httptest.NewRecorder() srv.Router.ServeHTTP(w, req) - if w.Code != http.StatusConflict { - t.Fatalf("expected 409 when both sessions busy, got %d: %s", w.Code, w.Body.String()) + if w.Code != http.StatusOK { + t.Fatalf("expected 200, got %d: %s", w.Code, w.Body.String()) } - // Clean up - srv.console.sessions[0].mu.Lock() - srv.console.sessions[0].status = "idle" - srv.console.sessions[0].mu.Unlock() - srv.console.sessions[1].mu.Lock() - srv.console.sessions[1].status = "idle" - srv.console.sessions[1].mu.Unlock() + // Verify task moved to active/ + if _, err := os.Stat(filepath.Join(srv.Config.TasksDir, "active", "T08.md")); err != nil { + t.Error("expected T08.md in active/ after run") + } } func TestDashboardHTML_HasRunButton(t *testing.T) { @@ -1865,11 +1857,16 @@ func TestRunTask_AddsTimestamp(t *testing.T) { t.Fatalf("expected 200, got %d: %s", w.Code, w.Body.String()) } - content, _ := os.ReadFile(filepath.Join(srv.Config.TasksDir, "ready", "T08.md")) + // Task should now be in active/ + content, _ := os.ReadFile(filepath.Join(srv.Config.TasksDir, "active", "T08.md")) text := string(content) if !containsStr(text, "Pokrenut") { t.Error("expected 'Pokrenut' timestamp after run") } + // Verify it's no longer in ready/ + if _, err := os.Stat(filepath.Join(srv.Config.TasksDir, "ready", "T08.md")); err == nil { + t.Error("task should no longer be in ready/") + } } // --- T24: PTY tests ---