源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
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

This commit is contained in:
agent-radar
2026-09-01 20:17:27 +08:00
commit 2ed3415fb7
8018 changed files with 1936476 additions and 0 deletions
+306
View File
@@ -0,0 +1,306 @@
package daemon
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"os"
"strings"
"time"
)
type Client struct {
baseURL string
token string
httpClient *http.Client
}
const (
// Built-in commands use this broad fallback budget. App commands publish
// their handler timeout through capability metadata and override it per
// invocation, including the transport margin owned by the terminal CLI.
defaultClientTimeout = 360 * time.Second
healthPath = "/v1/health"
cliCapabilitiesPath = "/v1/cli/capabilities"
cliCommandInvokePattern = "/v1/cli/commands/{commandID}/invoke"
)
type HealthStatus struct {
Service string `json:"service"`
Status string `json:"status"`
}
type CapabilityList struct {
Commands []Capability `json:"commands"`
}
type Capability struct {
ID string `json:"id"`
Path []string `json:"path"`
Summary string `json:"summary"`
Description string `json:"description,omitempty"`
Visibility string `json:"visibility,omitempty"`
InputSchema map[string]any `json:"inputSchema,omitempty"`
Output CapabilityOutput `json:"output"`
Execution *CommandExecution `json:"execution,omitempty"`
HandlerTimeoutMs int `json:"handlerTimeoutMs,omitempty"`
Source CapabilitySource `json:"source"`
}
type CommandExecution struct {
Mode string `json:"mode"`
}
type CapabilityListOptions struct {
IncludeHidden bool
IncludeIntegration bool
AgentSessionID string
}
type CapabilitySource struct {
Kind string `json:"kind"`
AppID string `json:"appId,omitempty"`
AppName string `json:"appName,omitempty"`
CLIDescription string `json:"cliDescription,omitempty"`
AppDescription string `json:"appDescription,omitempty"`
DocumentationFile string `json:"documentationFile,omitempty"`
DocumentationPath string `json:"documentationPath,omitempty"`
}
type CapabilityOutput struct {
DefaultMode string `json:"defaultMode"`
JSON bool `json:"json"`
Table *struct {
Columns []TableColumn `json:"columns"`
} `json:"table"`
}
type TableColumn struct {
Key string `json:"key"`
Label string `json:"label"`
}
type InvokeRequest struct {
Input map[string]any `json:"input,omitempty"`
OutputMode string `json:"outputMode,omitempty"`
Context InvokeContext `json:"context"`
}
type InvokeContext struct {
AppID string `json:"appId,omitempty"`
Source string `json:"source"`
WorkspaceID string `json:"workspaceID,omitempty"`
ParentCommandID string `json:"parentCommandId,omitempty"`
AgentSessionID string `json:"agentSessionId,omitempty"`
AgentCWD string `json:"agentCwd,omitempty"`
AgentRailPlacementJSON string `json:"agentRailPlacementJSON,omitempty"`
}
type InvokeResponse struct {
OK bool `json:"ok"`
Output *CommandOutput `json:"output,omitempty"`
}
type CommandOutput struct {
Kind string `json:"kind"`
Columns []TableColumn `json:"columns,omitempty"`
Rows []map[string]any `json:"rows,omitempty"`
Value map[string]any `json:"value,omitempty"`
Text string `json:"text,omitempty"`
Warnings []CommandWarning `json:"warnings,omitempty"`
Continuation *CommandContinuation `json:"continuation,omitempty"`
}
type CommandContinuation struct {
State string `json:"state"`
RetryAfterMs int `json:"retryAfterMs"`
}
type CommandWarning struct {
Code string `json:"code"`
Message string `json:"message"`
}
type apiErrorEnvelope struct {
Error struct {
Code string `json:"code"`
Reason string `json:"reason"`
Retryable bool `json:"retryable"`
DeveloperMessage string `json:"developerMessage"`
CorrelationID string `json:"correlationId"`
} `json:"error"`
}
func NewClient(endpoint Endpoint) (*Client, error) {
baseURL, err := endpoint.BaseURL()
if err != nil {
return nil, err
}
return &Client{
baseURL: baseURL,
token: endpoint.Token,
httpClient: &http.Client{
Timeout: defaultClientTimeout,
},
}, nil
}
func (client *Client) GetHealth(ctx context.Context) (HealthStatus, error) {
var result HealthStatus
if err := client.DoJSON(ctx, http.MethodGet, healthPath, nil, &result); err != nil {
return HealthStatus{}, err
}
return result, nil
}
func (client *Client) ListCapabilitiesForWorkspaceWithOptions(ctx context.Context, workspaceID string, options CapabilityListOptions) (CapabilityList, error) {
var result CapabilityList
path := cliCapabilitiesPath
query := url.Values{}
if strings.TrimSpace(workspaceID) != "" {
query.Set("workspaceID", strings.TrimSpace(workspaceID))
}
if strings.TrimSpace(options.AgentSessionID) != "" {
query.Set("agentSessionID", strings.TrimSpace(options.AgentSessionID))
}
if options.IncludeHidden {
query.Set("includeHidden", "true")
}
if options.IncludeIntegration {
query.Set("includeIntegration", "true")
}
if len(query) > 0 {
path += "?" + query.Encode()
}
if err := client.DoJSON(ctx, http.MethodGet, path, nil, &result); err != nil {
return CapabilityList{}, err
}
return result, nil
}
func (client *Client) Invoke(ctx context.Context, commandID string, request InvokeRequest) (InvokeResponse, error) {
return client.InvokeWithTimeout(ctx, commandID, request, defaultClientTimeout)
}
func (client *Client) InvokeWithTimeout(ctx context.Context, commandID string, request InvokeRequest, timeout time.Duration) (InvokeResponse, error) {
var result InvokeResponse
path := strings.Replace(cliCommandInvokePattern, "{commandID}", urlPathEscape(commandID), 1)
httpClient := client.httpClient
if timeout > 0 {
cloned := *client.httpClient
cloned.Timeout = timeout
httpClient = &cloned
}
if err := client.doJSON(ctx, httpClient, http.MethodPost, path, request, &result); err != nil {
return InvokeResponse{}, err
}
return result, nil
}
func (client *Client) DoJSON(ctx context.Context, method string, path string, body any, result any) error {
return client.doJSON(ctx, client.httpClient, method, path, body, result)
}
func (client *Client) doJSON(ctx context.Context, httpClient *http.Client, method string, path string, body any, result any) error {
var requestBody io.Reader
if body != nil {
encoded, err := json.Marshal(body)
if err != nil {
return newRequestError(ErrorDetails{ReasonCode: "daemon_request_invalid", Message: fmt.Sprintf("encode request body: %v", err)})
}
requestBody = bytes.NewReader(encoded)
}
url := client.baseURL + path
request, err := http.NewRequestWithContext(ctx, method, url, requestBody)
if err != nil {
return newRequestError(ErrorDetails{ReasonCode: "daemon_request_invalid", Message: fmt.Sprintf("create daemon request: %v", err)})
}
request.Header.Set("Accept", "application/json")
request.Header.Set("Authorization", "Bearer "+client.token)
if body != nil {
request.Header.Set("Content-Type", "application/json")
}
response, err := httpClient.Do(request)
if err != nil {
return daemonRequestError(err)
}
defer response.Body.Close()
content, err := io.ReadAll(response.Body)
if err != nil {
return newRequestError(ErrorDetails{ReasonCode: "daemon_response_read_failed", Message: fmt.Sprintf("read daemon response: %v", err)})
}
if response.StatusCode < 200 || response.StatusCode >= 300 {
return daemonResponseError(response.StatusCode, response.Status, content)
}
if result == nil {
return nil
}
if err := json.Unmarshal(content, result); err != nil {
return newRequestError(ErrorDetails{ReasonCode: "daemon_response_invalid", Message: fmt.Sprintf("decode daemon response: %v", err)})
}
return nil
}
func daemonResponseError(statusCode int, status string, content []byte) error {
var envelope apiErrorEnvelope
if err := json.Unmarshal(content, &envelope); err == nil {
reasonCode := strings.TrimSpace(envelope.Error.Reason)
if reasonCode == "" {
reasonCode = strings.TrimSpace(envelope.Error.Code)
}
if reasonCode != "" {
message := strings.TrimSpace(envelope.Error.DeveloperMessage)
if message == "" {
message = reasonCode
}
return newRequestError(ErrorDetails{
ReasonCode: reasonCode, Message: message, Retryable: envelope.Error.Retryable,
CorrelationID: strings.TrimSpace(envelope.Error.CorrelationID), StatusCode: statusCode,
})
}
}
if statusCode == http.StatusUnauthorized {
return newRequestError(ErrorDetails{ReasonCode: "unauthorized", Message: "daemon authentication failed", StatusCode: statusCode})
}
message := strings.TrimSpace(string(content))
if message == "" {
message = strings.TrimSpace(status)
}
return newRequestError(ErrorDetails{
ReasonCode: "daemon_request_failed", Message: "daemon request failed: " + message, StatusCode: statusCode,
})
}
func daemonRequestError(err error) error {
if errors.Is(err, context.Canceled) {
return newRequestError(ErrorDetails{ReasonCode: "daemon_request_canceled", Message: "daemon request canceled"})
}
if errors.Is(err, context.DeadlineExceeded) || os.IsTimeout(err) {
return newRequestError(ErrorDetails{ReasonCode: "daemon_request_timed_out", Message: "daemon request timed out", Retryable: true})
}
if runningInAgentEnvironment() {
return newRequestError(ErrorDetails{
ReasonCode: "daemon_unavailable", Retryable: true,
Message: "daemon is not reachable from this agent execution environment; rerun the command in an execution environment with localhost/IPC access",
})
}
return newRequestError(ErrorDetails{ReasonCode: "daemon_unavailable", Message: "daemon is not reachable", Retryable: true})
}
func runningInAgentEnvironment() bool {
return strings.TrimSpace(os.Getenv("TUTTI_AGENT_SESSION_ID")) != "" ||
strings.TrimSpace(os.Getenv("TUTTI_AGENT_ROUTING")) != ""
}
func urlPathEscape(value string) string {
replacer := strings.NewReplacer("%", "%25", "/", "%2F", "?", "%3F", "#", "%23")
return replacer.Replace(value)
}
+134
View File
@@ -0,0 +1,134 @@
package daemon
import (
"context"
"errors"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
)
func TestNewClientUsesStartupFriendlyTimeout(t *testing.T) {
client, err := NewClient(Endpoint{Addr: "127.0.0.1:1", Token: "token-1"})
if err != nil {
t.Fatalf("NewClient: %v", err)
}
if client.httpClient.Timeout < 30*time.Second {
t.Fatalf("timeout = %s, want at least 30s", client.httpClient.Timeout)
}
}
func TestInvokeWithTimeoutOverridesDefaultClientBudget(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
time.Sleep(40 * time.Millisecond)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"ok":true,"output":{"kind":"json","value":{"ok":true}}}`))
}))
defer server.Close()
client := &Client{
baseURL: server.URL,
token: "token-1",
httpClient: &http.Client{
Timeout: 10 * time.Millisecond,
},
}
response, err := client.InvokeWithTimeout(context.Background(), "wait.command", InvokeRequest{}, 100*time.Millisecond)
if err != nil {
t.Fatalf("InvokeWithTimeout() error = %v", err)
}
if response.Output == nil || response.Output.Value["ok"] != true {
t.Fatalf("response = %#v", response)
}
if client.httpClient.Timeout != 10*time.Millisecond {
t.Fatalf("shared client timeout mutated to %s", client.httpClient.Timeout)
}
}
func TestDoJSONReportsTimeoutSeparatelyFromUnreachable(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
time.Sleep(50 * time.Millisecond)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"service":"tuttid","status":"ok"}`))
}))
defer server.Close()
client := &Client{
baseURL: server.URL,
token: "token-1",
httpClient: &http.Client{
Timeout: 10 * time.Millisecond,
},
}
var result HealthStatus
err := client.DoJSON(context.Background(), http.MethodGet, healthPath, nil, &result)
if err == nil {
t.Fatal("expected timeout error")
}
if !strings.Contains(err.Error(), "daemon request timed out") {
t.Fatalf("error = %q, want timeout message", err.Error())
}
if strings.Contains(err.Error(), "daemon is not reachable") {
t.Fatalf("error = %q, should not report daemon as unreachable", err.Error())
}
details, ok := RequestErrorDetails(err)
if !ok || details.ReasonCode != "daemon_request_timed_out" || !details.Retryable {
t.Fatalf("details = %#v ok=%t", details, ok)
}
}
func TestDoJSONPreservesStructuredDaemonError(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusNotFound)
_, _ = w.Write([]byte(`{"error":{"code":"workspace_not_found","reason":"workspace_agent_session_not_found","retryable":true,"developerMessage":"agent session was not found","correlationId":"corr-1"}}`))
}))
defer server.Close()
client := &Client{baseURL: server.URL, token: "token-1", httpClient: server.Client()}
err := client.DoJSON(context.Background(), http.MethodGet, healthPath, nil, &HealthStatus{})
details, ok := RequestErrorDetails(err)
if !ok {
t.Fatalf("RequestErrorDetails(%v) did not match", err)
}
if details.ReasonCode != "workspace_agent_session_not_found" || details.Message != "agent session was not found" ||
!details.Retryable || details.CorrelationID != "corr-1" || details.StatusCode != http.StatusNotFound {
t.Fatalf("details = %#v", details)
}
}
func TestDaemonRequestErrorKeepsPlainUnreachableOutsideAgent(t *testing.T) {
t.Setenv("TUTTI_AGENT_SESSION_ID", "")
t.Setenv("TUTTI_AGENT_ROUTING", "")
err := daemonRequestError(errors.New("dial tcp failed"))
if got, want := err.Error(), "daemon is not reachable"; got != want {
t.Fatalf("error = %q, want %q", got, want)
}
}
func TestDaemonRequestErrorHintsLocalDaemonAccessInsideAgent(t *testing.T) {
t.Setenv("TUTTI_AGENT_SESSION_ID", "session-1")
t.Setenv("TUTTI_AGENT_ROUTING", "")
err := daemonRequestError(errors.New("dial tcp failed"))
message := err.Error()
for _, expected := range []string{
"daemon is not reachable from this agent execution environment",
"execution environment with localhost/IPC access",
"localhost/IPC",
} {
if !strings.Contains(message, expected) {
t.Fatalf("error = %q, want to contain %q", message, expected)
}
}
if strings.Contains(message, "sandbox_permissions=require_escalated") {
t.Fatalf("error = %q, should not contain provider-specific Codex escalation syntax", message)
}
}
+82
View File
@@ -0,0 +1,82 @@
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
}
+48
View File
@@ -0,0 +1,48 @@
package daemon
import (
"os"
"path/filepath"
"testing"
)
func TestReadEndpointFile(t *testing.T) {
path := filepath.Join(t.TempDir(), "tuttid.listener.json")
if err := os.WriteFile(path, []byte(`{"version":1,"addr":"127.0.0.1:4545","auth":{"scheme":"bearer","token":"token-1"}}`), 0o600); err != nil {
t.Fatalf("write endpoint: %v", err)
}
endpoint, err := ReadEndpointFile(path)
if err != nil {
t.Fatalf("ReadEndpointFile: %v", err)
}
if endpoint.Addr != "127.0.0.1:4545" {
t.Fatalf("addr = %q", endpoint.Addr)
}
if endpoint.Token != "token-1" {
t.Fatalf("token = %q", endpoint.Token)
}
}
func TestReadEndpointFileRejectsMissingAuth(t *testing.T) {
path := filepath.Join(t.TempDir(), "tuttid.listener.json")
if err := os.WriteFile(path, []byte(`{"addr":"127.0.0.1:4545"}`), 0o600); err != nil {
t.Fatalf("write endpoint: %v", err)
}
if _, err := ReadEndpointFile(path); err == nil {
t.Fatal("expected missing auth to fail")
}
}
func TestListenerInfoPathUsesStateRoot(t *testing.T) {
stateDir := t.TempDir()
t.Setenv("TUTTI_STATE_DIR", stateDir)
t.Setenv("TUTTID_RUN_DIR", "")
t.Setenv("TUTTID_LISTENER_INFO_PATH", "")
want := filepath.Join(stateDir, "run", "tuttid.listener.json")
if got := ListenerInfoPath(); got != want {
t.Fatalf("ListenerInfoPath() = %q, want %q", got, want)
}
}
+45
View File
@@ -0,0 +1,45 @@
package daemon
import (
"errors"
"strings"
)
type ErrorDetails struct {
ReasonCode string
Message string
Retryable bool
CorrelationID string
StatusCode int
}
type requestError struct {
details ErrorDetails
}
func (e *requestError) Error() string {
if e == nil {
return ""
}
return e.details.Message
}
func RequestErrorDetails(err error) (ErrorDetails, bool) {
var requestErr *requestError
if !errors.As(err, &requestErr) || requestErr == nil {
return ErrorDetails{}, false
}
return requestErr.details, true
}
func newRequestError(details ErrorDetails) error {
details.ReasonCode = strings.TrimSpace(details.ReasonCode)
details.Message = strings.TrimSpace(details.Message)
if details.ReasonCode == "" {
details.ReasonCode = "daemon_request_failed"
}
if details.Message == "" {
details.Message = details.ReasonCode
}
return &requestError{details: details}
}