Files
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

83 lines
2.1 KiB
Go

package daemon
import (
"encoding/json"
"errors"
"fmt"
"net/url"
"os"
"strings"
"github.com/tutti-os/tutti/apps/cli/internal/defaults"
)
type Endpoint struct {
Addr string
Token string
}
type endpointFile struct {
Version int `json:"version"`
Addr string `json:"addr"`
Auth endpointFileAuth `json:"auth"`
}
type endpointFileAuth struct {
Scheme string `json:"scheme"`
Token string `json:"token"`
}
func DiscoverEndpoint() (Endpoint, error) {
return ReadEndpointFile(ListenerInfoPath())
}
func ReadEndpointFile(path string) (Endpoint, error) {
content, err := os.ReadFile(path)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
return Endpoint{}, fmt.Errorf("daemon endpoint is not available; start the Tutti desktop app")
}
return Endpoint{}, fmt.Errorf("read daemon endpoint: %w", err)
}
var payload endpointFile
if err := json.Unmarshal(content, &payload); err != nil {
return Endpoint{}, fmt.Errorf("daemon endpoint file is invalid JSON")
}
addr := strings.TrimSpace(payload.Addr)
if addr == "" {
return Endpoint{}, fmt.Errorf("daemon endpoint file does not contain addr")
}
if payload.Version != 0 && payload.Version != 1 {
return Endpoint{}, fmt.Errorf("daemon endpoint file version is not supported")
}
scheme := strings.ToLower(strings.TrimSpace(payload.Auth.Scheme))
token := strings.TrimSpace(payload.Auth.Token)
if scheme != "bearer" || token == "" {
return Endpoint{}, fmt.Errorf("daemon endpoint file does not contain bearer auth")
}
return Endpoint{Addr: addr, Token: token}, nil
}
func (endpoint Endpoint) BaseURL() (string, error) {
addr := strings.TrimSpace(endpoint.Addr)
if addr == "" {
return "", fmt.Errorf("daemon address is empty")
}
if strings.HasPrefix(addr, "http://") || strings.HasPrefix(addr, "https://") {
parsed, err := url.Parse(addr)
if err != nil || parsed.Host == "" {
return "", fmt.Errorf("daemon address is invalid")
}
return strings.TrimRight(addr, "/"), nil
}
return "http://" + strings.TrimRight(addr, "/"), nil
}
func ListenerInfoPath() string {
return defaults.ResolveDefaultsFromEnv().State.TuttidListenerInfoPath
}