kenn-io--agentsview
f99010fae1
CI / lint (push) Failing after 1s
CI / frontend (push) Failing after 1s
CI / scripts (push) Failing after 1s
CI / Go Test (ubuntu-latest) (push) Failing after 0s
CI / frontend-node-25 (push) Failing after 1s
CI / docs (push) Failing after 0s
CI / coverage (push) Failing after 0s
CI / e2e (push) Failing after 0s
Docker / build-and-push (push) Failing after 1s
CI / integration (push) Failing after 4m43s
CI / Go Test (windows-latest) (push) Has been cancelled
CI / Desktop Unit Tests (Windows) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Linux (arm64)) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Linux) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Windows) (push) Has been cancelled
Desktop Artifacts (macOS) / Desktop Build (macOS (aarch64)) (push) Has been cancelled
Desktop Artifacts (macOS) / Desktop Build (macOS (x86_64)) (push) Has been cancelled
157 行
4.3 KiB
Go
157 行
4.3 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/google/shlex"
|
|
"go.kenn.io/agentsview/internal/config"
|
|
)
|
|
|
|
func (s *Server) registerConfigRoutes() {
|
|
group := newRouteGroup(s.api, "/api/v1/config", "Config")
|
|
|
|
get(s, group, "/github", "Get GitHub config", s.humaGetGithubConfig)
|
|
post(s, group, "/github", "Set GitHub config", s.humaSetGithubConfig)
|
|
get(s, group, "/terminal", "Get terminal config", s.humaGetTerminalConfig)
|
|
post(s, group, "/terminal", "Set terminal config", s.humaSetTerminalConfig)
|
|
}
|
|
|
|
type terminalMode string
|
|
|
|
const (
|
|
terminalModeAuto terminalMode = "auto"
|
|
terminalModeCustom terminalMode = "custom"
|
|
terminalModeClipboard terminalMode = "clipboard"
|
|
)
|
|
|
|
type githubConfigResponse struct {
|
|
Configured bool `json:"configured"`
|
|
}
|
|
|
|
type setGithubConfigInput struct {
|
|
Body struct {
|
|
Token string `json:"token" required:"true" minLength:"1" doc:"GitHub token"`
|
|
}
|
|
}
|
|
|
|
type setGithubConfigResponse struct {
|
|
Success bool `json:"success"`
|
|
Username string `json:"username"`
|
|
}
|
|
|
|
type terminalConfigInput struct {
|
|
Body terminalConfigBody
|
|
}
|
|
|
|
type terminalConfigBody struct {
|
|
Mode terminalMode `json:"mode" enum:"auto,custom,clipboard" doc:"Terminal launch mode"`
|
|
CustomBin string `json:"custom_bin,omitempty" doc:"Terminal binary path when mode is custom"`
|
|
CustomArgs string `json:"custom_args,omitempty" doc:"Argument template containing {cmd} when mode is custom"`
|
|
}
|
|
|
|
func terminalConfigBodyFromConfig(tc config.TerminalConfig) terminalConfigBody {
|
|
mode := terminalMode(tc.Mode)
|
|
if mode == "" {
|
|
mode = terminalModeAuto
|
|
}
|
|
return terminalConfigBody{
|
|
Mode: mode,
|
|
CustomBin: tc.CustomBin,
|
|
CustomArgs: tc.CustomArgs,
|
|
}
|
|
}
|
|
|
|
func (b terminalConfigBody) config() config.TerminalConfig {
|
|
return config.TerminalConfig{
|
|
Mode: string(b.Mode),
|
|
CustomBin: b.CustomBin,
|
|
CustomArgs: b.CustomArgs,
|
|
}
|
|
}
|
|
|
|
func (s *Server) humaGetGithubConfig(
|
|
ctx context.Context,
|
|
_ *emptyInput,
|
|
) (*jsonOutput[githubConfigResponse], error) {
|
|
return &jsonOutput[githubConfigResponse]{
|
|
Body: githubConfigResponse{Configured: s.githubToken(ctx) != ""},
|
|
}, nil
|
|
}
|
|
|
|
func (s *Server) humaSetGithubConfig(
|
|
ctx context.Context,
|
|
in *setGithubConfigInput,
|
|
) (*jsonOutput[setGithubConfigResponse], error) {
|
|
token := strings.TrimSpace(in.Body.Token)
|
|
if token == "" {
|
|
return nil, apiError(http.StatusBadRequest, "token required")
|
|
}
|
|
username, err := validateGithubToken(ctx, token)
|
|
if err != nil {
|
|
return nil, apiError(http.StatusUnauthorized, err.Error())
|
|
}
|
|
s.mu.Lock()
|
|
err = s.cfg.SaveGithubToken(token)
|
|
s.mu.Unlock()
|
|
if err != nil {
|
|
return nil, apiError(http.StatusInternalServerError, "failed to save token")
|
|
}
|
|
return &jsonOutput[setGithubConfigResponse]{
|
|
Body: setGithubConfigResponse{Success: true, Username: username},
|
|
}, nil
|
|
}
|
|
|
|
func (s *Server) humaGetTerminalConfig(
|
|
_ context.Context,
|
|
_ *emptyInput,
|
|
) (*jsonOutput[terminalConfigBody], error) {
|
|
s.mu.RLock()
|
|
tc := s.cfg.Terminal
|
|
s.mu.RUnlock()
|
|
return &jsonOutput[terminalConfigBody]{
|
|
Body: terminalConfigBodyFromConfig(tc),
|
|
}, nil
|
|
}
|
|
|
|
func (s *Server) humaSetTerminalConfig(
|
|
_ context.Context,
|
|
in *terminalConfigInput,
|
|
) (*jsonOutput[terminalConfigBody], error) {
|
|
body := in.Body
|
|
tc := body.config()
|
|
switch terminalMode(tc.Mode) {
|
|
case terminalModeAuto, terminalModeCustom, terminalModeClipboard:
|
|
default:
|
|
return nil, apiError(http.StatusBadRequest,
|
|
`mode must be "auto", "custom", or "clipboard"`)
|
|
}
|
|
if tc.Mode == string(terminalModeCustom) && tc.CustomBin == "" {
|
|
return nil, apiError(http.StatusBadRequest,
|
|
`custom_bin is required when mode is "custom"`)
|
|
}
|
|
if tc.Mode == string(terminalModeCustom) {
|
|
if tc.CustomArgs != "" && !strings.Contains(tc.CustomArgs, "{cmd}") {
|
|
return nil, apiError(http.StatusBadRequest,
|
|
`custom_args must contain the {cmd} placeholder so the resume command is passed to the terminal`)
|
|
}
|
|
if tc.CustomArgs != "" {
|
|
if _, splitErr := shlex.Split(tc.CustomArgs); splitErr != nil {
|
|
return nil, apiError(http.StatusBadRequest,
|
|
fmt.Sprintf("custom_args has invalid shell syntax: %v", splitErr))
|
|
}
|
|
}
|
|
}
|
|
s.mu.Lock()
|
|
err := s.cfg.SaveTerminalConfig(tc)
|
|
s.mu.Unlock()
|
|
if err != nil {
|
|
return nil, internalError("save terminal config", err)
|
|
}
|
|
return &jsonOutput[terminalConfigBody]{
|
|
Body: terminalConfigBodyFromConfig(tc),
|
|
}, nil
|
|
}
|