style: fix golines formatting for CI compliance

This commit is contained in:
Edouard CLAUDE 2026-02-21 16:00:33 +04:00
parent 26da5defe8
commit 08e7bd5965
8 changed files with 175 additions and 33 deletions

View file

@ -193,20 +193,32 @@ func gatewayCmd() {
cfg.Dashboard.Password = dashboard.GeneratePassword() cfg.Dashboard.Password = dashboard.GeneratePassword()
configPath := getConfigPath() configPath := getConfigPath()
if saveErr := config.SaveConfig(configPath, cfg); saveErr != nil { if saveErr := config.SaveConfig(configPath, cfg); saveErr != nil {
logger.ErrorCF("dashboard", "Failed to save generated password", map[string]any{"error": saveErr.Error()}) logger.ErrorCF(
"dashboard",
"Failed to save generated password",
map[string]any{"error": saveErr.Error()},
)
} }
fmt.Printf("🔑 Dashboard password generated: %s\n", cfg.Dashboard.Password) fmt.Printf("🔑 Dashboard password generated: %s\n", cfg.Dashboard.Password)
} }
dashConfigPath := getConfigPath() dashConfigPath := getConfigPath()
dashboard.Mount(healthServer, cfg, agentLoop, channelManager, dashConfigPath) dashboard.Mount(healthServer, cfg, agentLoop, channelManager, dashConfigPath)
fmt.Printf("✓ Dashboard available at http://%s:%d/dashboard\n", cfg.Gateway.Host, cfg.Gateway.Port) fmt.Printf(
"✓ Dashboard available at http://%s:%d/dashboard\n",
cfg.Gateway.Host,
cfg.Gateway.Port,
)
} }
go func() { go func() {
if err := healthServer.Start(); err != nil && err != http.ErrServerClosed { if err := healthServer.Start(); err != nil && err != http.ErrServerClosed {
logger.ErrorCF("health", "Health server error", map[string]any{"error": err.Error()}) logger.ErrorCF("health", "Health server error", map[string]any{"error": err.Error()})
} }
}() }()
fmt.Printf("✓ Health endpoints available at http://%s:%d/health and /ready\n", cfg.Gateway.Host, cfg.Gateway.Port) fmt.Printf(
"✓ Health endpoints available at http://%s:%d/health and /ready\n",
cfg.Gateway.Host,
cfg.Gateway.Port,
)
go agentLoop.Run(ctx) go agentLoop.Run(ctx)
@ -239,7 +251,15 @@ func setupCronTool(
cronService := cron.NewCronService(cronStorePath, nil) cronService := cron.NewCronService(cronStorePath, nil)
// Create and register CronTool // Create and register CronTool
cronTool := tools.NewCronTool(cronService, agentLoop, msgBus, workspace, restrict, execTimeout, cfg) cronTool := tools.NewCronTool(
cronService,
agentLoop,
msgBus,
workspace,
restrict,
execTimeout,
cfg,
)
agentLoop.RegisterTool(cronTool) agentLoop.RegisterTool(cronTool)
// Set the onJob handler // Set the onJob handler

View file

@ -11,7 +11,12 @@ import (
"github.com/sipeed/picoclaw/pkg/config" "github.com/sipeed/picoclaw/pkg/config"
) )
func statusHandler(cfg *config.Config, al *agent.AgentLoop, cm *channels.Manager, startTime time.Time) http.HandlerFunc { func statusHandler(
cfg *config.Config,
al *agent.AgentLoop,
cm *channels.Manager,
startTime time.Time,
) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
info := al.GetStartupInfo() info := al.GetStartupInfo()
channelStatus := cm.GetStatus() channelStatus := cm.GetStatus()

View file

@ -13,7 +13,12 @@ import (
"github.com/sipeed/picoclaw/pkg/health" "github.com/sipeed/picoclaw/pkg/health"
) )
func registerAgentsCRUD(srv *health.Server, cfg *config.Config, configPath string, auth func(http.HandlerFunc) http.HandlerFunc) { func registerAgentsCRUD(
srv *health.Server,
cfg *config.Config,
configPath string,
auth func(http.HandlerFunc) http.HandlerFunc,
) {
srv.HandleFunc("/dashboard/fragments/agent-edit", auth(fragmentAgentEdit(cfg))) srv.HandleFunc("/dashboard/fragments/agent-edit", auth(fragmentAgentEdit(cfg)))
srv.HandleFunc("/dashboard/fragments/agent-add", auth(fragmentAgentAdd())) srv.HandleFunc("/dashboard/fragments/agent-add", auth(fragmentAgentAdd()))
srv.HandleFunc("/dashboard/crud/agents/create", auth(agentCreateHandler(cfg, configPath))) srv.HandleFunc("/dashboard/crud/agents/create", auth(agentCreateHandler(cfg, configPath)))
@ -256,7 +261,11 @@ func agentCreateHandler(cfg *config.Config, configPath string) http.HandlerFunc
if instructions := r.FormValue("instructions"); strings.TrimSpace(instructions) != "" { if instructions := r.FormValue("instructions"); strings.TrimSpace(instructions) != "" {
ws := resolveAgentWorkspace(cfg, &agent) ws := resolveAgentWorkspace(cfg, &agent)
if err := writeAgentInstructions(ws, instructions); err != nil { if err := writeAgentInstructions(ws, instructions); err != nil {
jsonError(w, "agent created but failed to write AGENT.md: "+err.Error(), http.StatusInternalServerError) jsonError(
w,
"agent created but failed to write AGENT.md: "+err.Error(),
http.StatusInternalServerError,
)
return return
} }
} }
@ -318,7 +327,11 @@ func agentUpdateHandler(cfg *config.Config, configPath string) http.HandlerFunc
instructions := r.FormValue("instructions") instructions := r.FormValue("instructions")
ws := resolveAgentWorkspace(cfg, found) ws := resolveAgentWorkspace(cfg, found)
if err := writeAgentInstructions(ws, instructions); err != nil { if err := writeAgentInstructions(ws, instructions); err != nil {
jsonError(w, "agent updated but failed to write AGENT.md: "+err.Error(), http.StatusInternalServerError) jsonError(
w,
"agent updated but failed to write AGENT.md: "+err.Error(),
http.StatusInternalServerError,
)
return return
} }

View file

@ -11,7 +11,12 @@ import (
"github.com/sipeed/picoclaw/pkg/health" "github.com/sipeed/picoclaw/pkg/health"
) )
func registerChannelsCRUD(srv *health.Server, cfg *config.Config, configPath string, auth func(http.HandlerFunc) http.HandlerFunc) { func registerChannelsCRUD(
srv *health.Server,
cfg *config.Config,
configPath string,
auth func(http.HandlerFunc) http.HandlerFunc,
) {
srv.HandleFunc("/dashboard/fragments/channel-edit", auth(fragmentChannelEdit(cfg))) srv.HandleFunc("/dashboard/fragments/channel-edit", auth(fragmentChannelEdit(cfg)))
srv.HandleFunc("/dashboard/crud/channels/update", auth(channelUpdateHandler(cfg, configPath))) srv.HandleFunc("/dashboard/crud/channels/update", auth(channelUpdateHandler(cfg, configPath)))
srv.HandleFunc("/dashboard/crud/channels/toggle", auth(channelToggleHandler(cfg, configPath))) srv.HandleFunc("/dashboard/crud/channels/toggle", auth(channelToggleHandler(cfg, configPath)))
@ -100,7 +105,11 @@ func channelEditFormHTML(name string, cfg *config.Config) string {
allowFrom = ch.AllowFrom allowFrom = ch.AllowFrom
fields = textField("ws_url", "WebSocket URL", ch.WSUrl) + fields = textField("ws_url", "WebSocket URL", ch.WSUrl) +
textField("access_token", "Access Token", ch.AccessToken) + textField("access_token", "Access Token", ch.AccessToken) +
textField("reconnect_interval", "Reconnect Interval", strconv.Itoa(ch.ReconnectInterval)) textField(
"reconnect_interval",
"Reconnect Interval",
strconv.Itoa(ch.ReconnectInterval),
)
default: default:
return "" return ""
} }
@ -160,7 +169,11 @@ func fragmentChannelEdit(cfg *config.Config) http.HandlerFunc {
if html == "" { if html == "" {
w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(w, `<p class="error">Unknown channel: %s</p>`, template.HTMLEscapeString(name)) fmt.Fprintf(
w,
`<p class="error">Unknown channel: %s</p>`,
template.HTMLEscapeString(name),
)
return return
} }
w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Set("Content-Type", "text/html; charset=utf-8")
@ -263,7 +276,11 @@ func channelUpdateHandler(cfg *config.Config, configPath string) http.HandlerFun
configMu.Unlock() configMu.Unlock()
w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(w, `<p class="error">Unknown channel: %s</p>`, template.HTMLEscapeString(name)) fmt.Fprintf(
w,
`<p class="error">Unknown channel: %s</p>`,
template.HTMLEscapeString(name),
)
return return
} }
configMu.Unlock() configMu.Unlock()
@ -272,7 +289,11 @@ func channelUpdateHandler(cfg *config.Config, configPath string) http.HandlerFun
if err := saveConfig(configPath, cfg); err != nil { if err := saveConfig(configPath, cfg); err != nil {
w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, `<p class="error">Failed to save: %s</p>`, template.HTMLEscapeString(err.Error())) fmt.Fprintf(
w,
`<p class="error">Failed to save: %s</p>`,
template.HTMLEscapeString(err.Error()),
)
return return
} }
} }
@ -321,7 +342,11 @@ func channelToggleHandler(cfg *config.Config, configPath string) http.HandlerFun
configMu.Unlock() configMu.Unlock()
w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(w, `<p class="error">Unknown channel: %s</p>`, template.HTMLEscapeString(name)) fmt.Fprintf(
w,
`<p class="error">Unknown channel: %s</p>`,
template.HTMLEscapeString(name),
)
return return
} }
configMu.Unlock() configMu.Unlock()
@ -330,7 +355,11 @@ func channelToggleHandler(cfg *config.Config, configPath string) http.HandlerFun
if err := saveConfig(configPath, cfg); err != nil { if err := saveConfig(configPath, cfg); err != nil {
w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, `<p class="error">Failed to save: %s</p>`, template.HTMLEscapeString(err.Error())) fmt.Fprintf(
w,
`<p class="error">Failed to save: %s</p>`,
template.HTMLEscapeString(err.Error()),
)
return return
} }
} }

View file

@ -10,7 +10,12 @@ import (
"github.com/sipeed/picoclaw/pkg/health" "github.com/sipeed/picoclaw/pkg/health"
) )
func registerModelsCRUD(srv *health.Server, cfg *config.Config, configPath string, auth func(http.HandlerFunc) http.HandlerFunc) { func registerModelsCRUD(
srv *health.Server,
cfg *config.Config,
configPath string,
auth func(http.HandlerFunc) http.HandlerFunc,
) {
srv.HandleFunc("/dashboard/fragments/model-edit", auth(fragmentModelEdit(cfg))) srv.HandleFunc("/dashboard/fragments/model-edit", auth(fragmentModelEdit(cfg)))
srv.HandleFunc("/dashboard/fragments/model-add", auth(fragmentModelAdd())) srv.HandleFunc("/dashboard/fragments/model-add", auth(fragmentModelAdd()))
srv.HandleFunc("/dashboard/crud/models/create", auth(modelCreateHandler(cfg, configPath))) srv.HandleFunc("/dashboard/crud/models/create", auth(modelCreateHandler(cfg, configPath)))
@ -159,7 +164,11 @@ func modelCreateHandler(cfg *config.Config, configPath string) http.HandlerFunc
if err := saveConfig(configPath, cfg); err != nil { if err := saveConfig(configPath, cfg); err != nil {
w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, `<p class="error">Failed to save: %s</p>`, template.HTMLEscapeString(err.Error())) fmt.Fprintf(
w,
`<p class="error">Failed to save: %s</p>`,
template.HTMLEscapeString(err.Error()),
)
return return
} }
} }
@ -200,7 +209,11 @@ func modelUpdateHandler(cfg *config.Config, configPath string) http.HandlerFunc
if err := saveConfig(configPath, cfg); err != nil { if err := saveConfig(configPath, cfg); err != nil {
w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, `<p class="error">Failed to save: %s</p>`, template.HTMLEscapeString(err.Error())) fmt.Fprintf(
w,
`<p class="error">Failed to save: %s</p>`,
template.HTMLEscapeString(err.Error()),
)
return return
} }
} }
@ -237,7 +250,11 @@ func modelDeleteHandler(cfg *config.Config, configPath string) http.HandlerFunc
if err := saveConfig(configPath, cfg); err != nil { if err := saveConfig(configPath, cfg); err != nil {
w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, `<p class="error">Failed to save: %s</p>`, template.HTMLEscapeString(err.Error())) fmt.Fprintf(
w,
`<p class="error">Failed to save: %s</p>`,
template.HTMLEscapeString(err.Error()),
)
return return
} }
} }

View file

@ -10,11 +10,23 @@ import (
"github.com/sipeed/picoclaw/pkg/health" "github.com/sipeed/picoclaw/pkg/health"
) )
func registerSettingsCRUD(srv *health.Server, cfg *config.Config, configPath string, currentPassword string, auth func(http.HandlerFunc) http.HandlerFunc) { func registerSettingsCRUD(
srv *health.Server,
cfg *config.Config,
configPath string,
currentPassword string,
auth func(http.HandlerFunc) http.HandlerFunc,
) {
srv.HandleFunc("/dashboard/fragments/settings", auth(fragmentSettings(cfg, currentPassword))) srv.HandleFunc("/dashboard/fragments/settings", auth(fragmentSettings(cfg, currentPassword)))
srv.HandleFunc("/dashboard/crud/settings/password", auth(passwordChangeHandler(cfg, configPath))) srv.HandleFunc(
"/dashboard/crud/settings/password",
auth(passwordChangeHandler(cfg, configPath)),
)
srv.HandleFunc("/dashboard/crud/settings/gateway", auth(gatewayUpdateHandler(cfg, configPath))) srv.HandleFunc("/dashboard/crud/settings/gateway", auth(gatewayUpdateHandler(cfg, configPath)))
srv.HandleFunc("/dashboard/crud/settings/heartbeat", auth(heartbeatUpdateHandler(cfg, configPath))) srv.HandleFunc(
"/dashboard/crud/settings/heartbeat",
auth(heartbeatUpdateHandler(cfg, configPath)),
)
srv.HandleFunc("/dashboard/crud/settings/devices", auth(devicesUpdateHandler(cfg, configPath))) srv.HandleFunc("/dashboard/crud/settings/devices", auth(devicesUpdateHandler(cfg, configPath)))
} }

View file

@ -22,7 +22,11 @@ func TestPasswordChange(t *testing.T) {
form.Set("current_password", "oldpassword") form.Set("current_password", "oldpassword")
form.Set("new_password", "newpassword123") form.Set("new_password", "newpassword123")
req := httptest.NewRequest(http.MethodPost, "/dashboard/crud/settings/password", strings.NewReader(form.Encode())) req := httptest.NewRequest(
http.MethodPost,
"/dashboard/crud/settings/password",
strings.NewReader(form.Encode()),
)
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
w := httptest.NewRecorder() w := httptest.NewRecorder()
@ -68,7 +72,11 @@ func TestPasswordChangeWrongCurrent(t *testing.T) {
form.Set("current_password", "wrongpassword") form.Set("current_password", "wrongpassword")
form.Set("new_password", "newpassword123") form.Set("new_password", "newpassword123")
req := httptest.NewRequest(http.MethodPost, "/dashboard/crud/settings/password", strings.NewReader(form.Encode())) req := httptest.NewRequest(
http.MethodPost,
"/dashboard/crud/settings/password",
strings.NewReader(form.Encode()),
)
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
w := httptest.NewRecorder() w := httptest.NewRecorder()
@ -99,7 +107,11 @@ func TestPasswordChangeTooShort(t *testing.T) {
form.Set("current_password", "oldpassword") form.Set("current_password", "oldpassword")
form.Set("new_password", "short") form.Set("new_password", "short")
req := httptest.NewRequest(http.MethodPost, "/dashboard/crud/settings/password", strings.NewReader(form.Encode())) req := httptest.NewRequest(
http.MethodPost,
"/dashboard/crud/settings/password",
strings.NewReader(form.Encode()),
)
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
w := httptest.NewRecorder() w := httptest.NewRecorder()
@ -129,7 +141,11 @@ func TestGatewayUpdate(t *testing.T) {
form.Set("host", "127.0.0.1") form.Set("host", "127.0.0.1")
form.Set("port", "9090") form.Set("port", "9090")
req := httptest.NewRequest(http.MethodPost, "/dashboard/crud/settings/gateway", strings.NewReader(form.Encode())) req := httptest.NewRequest(
http.MethodPost,
"/dashboard/crud/settings/gateway",
strings.NewReader(form.Encode()),
)
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
w := httptest.NewRecorder() w := httptest.NewRecorder()
@ -174,7 +190,11 @@ func TestGatewayUpdateBadPort(t *testing.T) {
form.Set("host", "localhost") form.Set("host", "localhost")
form.Set("port", tt.port) form.Set("port", tt.port)
req := httptest.NewRequest(http.MethodPost, "/dashboard/crud/settings/gateway", strings.NewReader(form.Encode())) req := httptest.NewRequest(
http.MethodPost,
"/dashboard/crud/settings/gateway",
strings.NewReader(form.Encode()),
)
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
w := httptest.NewRecorder() w := httptest.NewRecorder()
@ -197,7 +217,11 @@ func TestHeartbeatUpdate(t *testing.T) {
form.Set("enabled", "on") form.Set("enabled", "on")
form.Set("interval", "15") form.Set("interval", "15")
req := httptest.NewRequest(http.MethodPost, "/dashboard/crud/settings/heartbeat", strings.NewReader(form.Encode())) req := httptest.NewRequest(
http.MethodPost,
"/dashboard/crud/settings/heartbeat",
strings.NewReader(form.Encode()),
)
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
w := httptest.NewRecorder() w := httptest.NewRecorder()
@ -230,7 +254,11 @@ func TestDevicesUpdate(t *testing.T) {
form.Set("enabled", "on") form.Set("enabled", "on")
form.Set("monitor_usb", "on") form.Set("monitor_usb", "on")
req := httptest.NewRequest(http.MethodPost, "/dashboard/crud/settings/devices", strings.NewReader(form.Encode())) req := httptest.NewRequest(
http.MethodPost,
"/dashboard/crud/settings/devices",
strings.NewReader(form.Encode()),
)
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
w := httptest.NewRecorder() w := httptest.NewRecorder()

View file

@ -15,7 +15,13 @@ import (
"github.com/sipeed/picoclaw/pkg/logger" "github.com/sipeed/picoclaw/pkg/logger"
) )
func Mount(srv *health.Server, cfg *config.Config, al *agent.AgentLoop, cm *channels.Manager, configPath ...string) { func Mount(
srv *health.Server,
cfg *config.Config,
al *agent.AgentLoop,
cm *channels.Manager,
configPath ...string,
) {
startTime := time.Now() startTime := time.Now()
broker := NewBroker() broker := NewBroker()
password := cfg.Dashboard.Password password := cfg.Dashboard.Password
@ -34,7 +40,10 @@ func Mount(srv *health.Server, cfg *config.Config, al *agent.AgentLoop, cm *chan
logger.ErrorCF("dashboard", "Failed to create sub FS", map[string]any{"error": err.Error()}) logger.ErrorCF("dashboard", "Failed to create sub FS", map[string]any{"error": err.Error()})
return return
} }
srv.Handle("/dashboard/static/", http.StripPrefix("/dashboard/static/", http.FileServer(http.FS(staticFS)))) srv.Handle(
"/dashboard/static/",
http.StripPrefix("/dashboard/static/", http.FileServer(http.FS(staticFS))),
)
// Auth routes (public) // Auth routes (public)
srv.HandleFunc("/dashboard/login", func(w http.ResponseWriter, r *http.Request) { srv.HandleFunc("/dashboard/login", func(w http.ResponseWriter, r *http.Request) {
@ -115,7 +124,12 @@ var funcMap = template.FuncMap{
"extractProvider": extractProvider, "extractProvider": extractProvider,
} }
func fragmentStatus(cfg *config.Config, al *agent.AgentLoop, cm *channels.Manager, startTime time.Time) http.HandlerFunc { func fragmentStatus(
cfg *config.Config,
al *agent.AgentLoop,
cm *channels.Manager,
startTime time.Time,
) http.HandlerFunc {
const tmpl = `<div id="status-bar" class="status-bar"> const tmpl = `<div id="status-bar" class="status-bar">
<span class="indicator {{if .Running}}running{{else}}stopped{{end}}"></span> <span class="indicator {{if .Running}}running{{else}}stopped{{end}}"></span>
<span>{{.Model}}</span> <span>{{.Model}}</span>
@ -252,7 +266,11 @@ func fragmentAgentDetail(cfg *config.Config) http.HandlerFunc {
} }
} }
w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Set("Content-Type", "text/html; charset=utf-8")
fmt.Fprintf(w, `<div><h3>Agent not found</h3><p>No agent with ID "%s"</p></div>`, template.HTMLEscapeString(agentID)) fmt.Fprintf(
w,
`<div><h3>Agent not found</h3><p>No agent with ID "%s"</p></div>`,
template.HTMLEscapeString(agentID),
)
} }
} }