296a1bdb71
Co-authored-by: Carlos Florencio <carlosmflorencio@gmail.com>
77 lines
2.9 KiB
Go
77 lines
2.9 KiB
Go
package api
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/kandev/kandev/internal/agentctl/server/process"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
const defaultWorkspaceRefreshTrigger = "manual_refresh"
|
|
|
|
// SetPollModeRequest is the body for POST /api/v1/workspace/poll-mode.
|
|
type SetPollModeRequest struct {
|
|
Mode string `json:"mode"`
|
|
}
|
|
|
|
// RefreshWorkspaceRequest is the body for POST /api/v1/workspace/refresh.
|
|
type RefreshWorkspaceRequest struct {
|
|
Trigger string `json:"trigger,omitempty"`
|
|
}
|
|
|
|
// handleSetPollMode updates the workspace tracker's poll mode based on the
|
|
// gateway's view of UI subscription/focus state for sessions in this workspace.
|
|
//
|
|
// See plan: focus-gated git polling. The gateway computes a workspace-level
|
|
// mode (fast if any session focused, slow if any subscribed, paused otherwise)
|
|
// and pushes it here so the tracker can throttle expensive git scans.
|
|
//
|
|
// Multi-repo: the per-repo trackers also need the mode update — otherwise they
|
|
// keep their construction-time default (fast) and never throttle, AND they
|
|
// miss the focus-triggered immediate scan that handleMonitorModeChange does
|
|
// on a transition INTO fast. Fanning out keeps every repo in lockstep.
|
|
//
|
|
// Snapshot-on-focus: a transition to fast/slow forces a RefreshGitStatus on
|
|
// every tracker so a fresh git status reaches subscribers. monitorTick
|
|
// otherwise only pushes on detected change; without this, a page opened
|
|
// after the agent has been idle would see no events until the user makes
|
|
// a file change. Multi-repo amplifies it: per-repo state is a Map and the
|
|
// aggregator only renders the repos that have published — missing events
|
|
// = missing files in the Changes panel, not just stale data.
|
|
func (s *Server) handleSetPollMode(c *gin.Context) {
|
|
var req SetPollModeRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
mode := process.PollMode(req.Mode)
|
|
if !mode.IsValid() {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid mode: must be one of fast, slow, paused"})
|
|
return
|
|
}
|
|
|
|
s.procMgr.SetWorkspacePollMode(c.Request.Context(), mode)
|
|
s.logger.Debug("workspace poll mode updated", zap.String("mode", req.Mode))
|
|
|
|
c.JSON(http.StatusOK, gin.H{"mode": req.Mode})
|
|
}
|
|
|
|
// handleRefreshWorkspace performs one explicit file and Git scan. Lifecycle
|
|
// callers use the turn_complete trigger; browser callers use the default
|
|
// manual_refresh trigger, which also retries a tracker paused by denial.
|
|
func (s *Server) handleRefreshWorkspace(c *gin.Context) {
|
|
var req RefreshWorkspaceRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request: " + err.Error()})
|
|
return
|
|
}
|
|
trigger := req.Trigger
|
|
if trigger == "" {
|
|
trigger = defaultWorkspaceRefreshTrigger
|
|
}
|
|
s.procMgr.RefreshWorkspace(c.Request.Context(), trigger)
|
|
c.JSON(http.StatusOK, gin.H{"trigger": process.NormalizeWorkspaceTrigger(trigger)})
|
|
}
|