From e9a47ac02aafc2d6d381116141650d574a2f2d2a Mon Sep 17 00:00:00 2001 From: LPF Date: Tue, 10 Mar 2026 00:00:01 +0800 Subject: [PATCH 1/2] fix whatsapp --- Dockerfile | 35 +++++ cmd/clawgo/cmd_gateway.go | 95 +++++++++++++- docker-compose.yml | 14 ++ pkg/api/server.go | 48 +++++++ pkg/api/server_test.go | 47 +++++++ pkg/channels/whatsapp_bridge.go | 187 ++++++++++++++++++++------- pkg/channels/whatsapp_bridge_test.go | 10 ++ 7 files changed, 384 insertions(+), 52 deletions(-) create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ec22176 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,35 @@ +FROM golang:1.25.5-bookworm AS builder + +WORKDIR /src + +COPY go.mod go.sum ./ +RUN go mod download + +COPY . ./ + +RUN rm -rf cmd/clawgo/workspace \ + && mkdir -p cmd/clawgo/workspace \ + && cp -a workspace/. cmd/clawgo/workspace/ + +RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -buildvcs=false -ldflags="-s -w" -o /out/clawgo ./cmd/clawgo + +FROM debian:bookworm-slim + +RUN apt-get update \ + && apt-get install -y --no-install-recommends ca-certificates tzdata \ + && rm -rf /var/lib/apt/lists/* + +RUN useradd --create-home --shell /bin/sh clawgo + +USER clawgo +WORKDIR /home/clawgo + +COPY --from=builder /out/clawgo /usr/local/bin/clawgo + +ENV CLAWGO_CONFIG=/home/clawgo/.clawgo/config.json + +EXPOSE 18790 + +VOLUME ["/home/clawgo/.clawgo"] + +ENTRYPOINT ["/bin/sh", "-c", "if [ ! -f \"$CLAWGO_CONFIG\" ]; then /usr/local/bin/clawgo onboard; fi; exec /usr/local/bin/clawgo gateway run --config \"$CLAWGO_CONFIG\""] diff --git a/cmd/clawgo/cmd_gateway.go b/cmd/clawgo/cmd_gateway.go index ec12e12..adcb77a 100644 --- a/cmd/clawgo/cmd_gateway.go +++ b/cmd/clawgo/cmd_gateway.go @@ -3,6 +3,7 @@ package main import ( "context" "fmt" + "net/url" "os" "os/exec" "os/signal" @@ -86,6 +87,9 @@ func gatewayCmd() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() + if shouldEmbedWhatsAppBridge(cfg) { + cfg.Channels.WhatsApp.BridgeURL = embeddedWhatsAppBridgeURL(cfg) + } agentLoop, channelManager, err := buildGatewayRuntime(ctx, cfg, msgBus, cronService) if err != nil { @@ -125,10 +129,6 @@ func gatewayCmd() { fmt.Println("✓ Sentinel service started") } - if err := channelManager.StartAll(ctx); err != nil { - fmt.Printf("Error starting channels: %v\n", err) - } - registryServer := api.NewServer(cfg.Gateway.Host, cfg.Gateway.Port, cfg.Gateway.Token, nodes.DefaultManager()) configureGatewayNodeP2P := func(loop *agent.AgentLoop, server *api.Server, runtimeCfg *config.Config) { if loop == nil || server == nil || runtimeCfg == nil { @@ -223,6 +223,10 @@ func gatewayCmd() { registryServer.SetToolsCatalogHandler(func() interface{} { return agentLoop.GetToolCatalog() }) + whatsAppBridge, whatsAppEmbedded := setupEmbeddedWhatsAppBridge(ctx, cfg) + if whatsAppBridge != nil { + registryServer.SetWhatsAppBridge(whatsAppBridge, embeddedWhatsAppBridgeBasePath) + } registryServer.SetCronHandler(func(action string, args map[string]interface{}) (interface{}, error) { getStr := func(k string) string { v, _ := args[k].(string) @@ -366,6 +370,10 @@ func gatewayCmd() { fmt.Printf("✓ Node registry server started on %s:%d\n", cfg.Gateway.Host, cfg.Gateway.Port) } + if err := channelManager.StartAll(ctx); err != nil { + fmt.Printf("Error starting channels: %v\n", err) + } + go agentLoop.Run(ctx) go runGatewayStartupCompactionCheck(ctx, agentLoop) go runGatewayBootstrapInit(ctx, cfg, agentLoop) @@ -394,6 +402,10 @@ func gatewayCmd() { return } + if shouldEmbedWhatsAppBridge(newCfg) { + newCfg.Channels.WhatsApp.BridgeURL = embeddedWhatsAppBridgeURL(newCfg) + } + runtimeSame := reflect.DeepEqual(cfg.Agents, newCfg.Agents) && reflect.DeepEqual(cfg.Providers, newCfg.Providers) && reflect.DeepEqual(cfg.Tools, newCfg.Tools) && @@ -435,14 +447,22 @@ func gatewayCmd() { return } + newWhatsAppBridge, _ := setupEmbeddedWhatsAppBridge(ctx, newCfg) + channelManager.StopAll(ctx) agentLoop.Stop() + if whatsAppBridge != nil { + whatsAppBridge.Stop() + } channelManager = newChannelManager agentLoop = newAgentLoop cfg = newCfg + whatsAppBridge = newWhatsAppBridge + whatsAppEmbedded = newWhatsAppBridge != nil runtimecfg.Set(cfg) configureGatewayNodeP2P(agentLoop, registryServer, cfg) + registryServer.SetWhatsAppBridge(whatsAppBridge, embeddedWhatsAppBridgeBasePath) sentinelService.Stop() sentinelService = sentinel.NewService( getConfigPath(), @@ -483,6 +503,9 @@ func gatewayCmd() { default: fmt.Println("\nShutting down...") cancel() + if whatsAppEmbedded && whatsAppBridge != nil { + whatsAppBridge.Stop() + } heartbeatService.Stop() sentinelService.Stop() cronService.Stop() @@ -495,6 +518,8 @@ func gatewayCmd() { } } +const embeddedWhatsAppBridgeBasePath = "/whatsapp" + func runGatewayStartupCompactionCheck(parent context.Context, agentLoop *agent.AgentLoop) { if agentLoop == nil { return @@ -843,3 +868,65 @@ func buildHeartbeatService(cfg *config.Config, msgBus *bus.MessageBus) *heartbea return "queued", nil }, hbInterval, cfg.Agents.Defaults.Heartbeat.Enabled, cfg.Agents.Defaults.Heartbeat.PromptTemplate) } + +func setupEmbeddedWhatsAppBridge(ctx context.Context, cfg *config.Config) (*channels.WhatsAppBridgeService, bool) { + if cfg == nil || !cfg.Channels.WhatsApp.Enabled || !shouldEmbedWhatsAppBridge(cfg) { + return nil, false + } + cfg.Channels.WhatsApp.BridgeURL = embeddedWhatsAppBridgeURL(cfg) + stateDir := filepath.Join(filepath.Dir(getConfigPath()), "channels", "whatsapp") + svc := channels.NewWhatsAppBridgeService(fmt.Sprintf("%s:%d", cfg.Gateway.Host, cfg.Gateway.Port), stateDir, false) + if err := svc.StartEmbedded(ctx); err != nil { + fmt.Printf("Error starting embedded WhatsApp bridge: %v\n", err) + return nil, false + } + return svc, true +} + +func shouldEmbedWhatsAppBridge(cfg *config.Config) bool { + raw := strings.TrimSpace(cfg.Channels.WhatsApp.BridgeURL) + if raw == "" { + return true + } + hostPort := comparableBridgeHostPort(raw) + if hostPort == "" { + return false + } + if hostPort == "127.0.0.1:3001" || hostPort == "localhost:3001" { + return true + } + return hostPort == comparableGatewayHostPort(cfg.Gateway.Host, cfg.Gateway.Port) +} + +func embeddedWhatsAppBridgeURL(cfg *config.Config) string { + host := strings.TrimSpace(cfg.Gateway.Host) + switch host { + case "", "0.0.0.0", "::", "[::]": + host = "127.0.0.1" + } + return fmt.Sprintf("ws://%s:%d%s/ws", host, cfg.Gateway.Port, embeddedWhatsAppBridgeBasePath) +} + +func comparableBridgeHostPort(raw string) string { + raw = strings.TrimSpace(raw) + if raw == "" { + return "" + } + if !strings.Contains(raw, "://") { + return strings.ToLower(raw) + } + u, err := url.Parse(raw) + if err != nil { + return "" + } + return strings.ToLower(strings.TrimSpace(u.Host)) +} + +func comparableGatewayHostPort(host string, port int) string { + host = strings.TrimSpace(strings.ToLower(host)) + switch host { + case "", "0.0.0.0", "::", "[::]": + host = "127.0.0.1" + } + return fmt.Sprintf("%s:%d", host, port) +} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..c9de9b1 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,14 @@ +services: + clawgo: + build: + context: . + dockerfile: Dockerfile + container_name: clawgo + restart: unless-stopped + ports: + - "18790:18790" + environment: + TZ: Asia/Shanghai + CLAWGO_CONFIG: /home/clawgo/.clawgo/config.json + volumes: + - ./.clawgo:/home/clawgo/.clawgo diff --git a/pkg/api/server.go b/pkg/api/server.go index a54a270..708ebe7 100644 --- a/pkg/api/server.go +++ b/pkg/api/server.go @@ -71,6 +71,8 @@ type Server struct { liveRuntimeOn bool liveSubagentMu sync.Mutex liveSubagents map[string]*liveSubagentGroup + whatsAppBridge *channels.WhatsAppBridgeService + whatsAppBase string } var nodesWebsocketUpgrader = websocket.Upgrader{ @@ -311,6 +313,42 @@ func (s *Server) SetNodeWebRTCTransport(t *nodes.WebRTCTransport) { func (s *Server) SetNodeP2PStatusHandler(fn func() map[string]interface{}) { s.nodeP2PStatus = fn } +func (s *Server) SetWhatsAppBridge(service *channels.WhatsAppBridgeService, basePath string) { + s.whatsAppBridge = service + s.whatsAppBase = strings.TrimSpace(basePath) +} + +func (s *Server) handleWhatsAppBridgeWS(w http.ResponseWriter, r *http.Request) { + if s.whatsAppBridge == nil { + http.Error(w, "whatsapp bridge unavailable", http.StatusServiceUnavailable) + return + } + s.whatsAppBridge.ServeWS(w, r) +} + +func (s *Server) handleWhatsAppBridgeStatus(w http.ResponseWriter, r *http.Request) { + if s.whatsAppBridge == nil { + http.Error(w, "whatsapp bridge unavailable", http.StatusServiceUnavailable) + return + } + s.whatsAppBridge.ServeStatus(w, r) +} + +func (s *Server) handleWhatsAppBridgeLogout(w http.ResponseWriter, r *http.Request) { + if s.whatsAppBridge == nil { + http.Error(w, "whatsapp bridge unavailable", http.StatusServiceUnavailable) + return + } + s.whatsAppBridge.ServeLogout(w, r) +} + +func joinServerRoute(base, endpoint string) string { + base = strings.TrimRight(strings.TrimSpace(base), "/") + if base == "" || base == "/" { + return "/" + strings.TrimPrefix(endpoint, "/") + } + return base + "/" + strings.TrimPrefix(endpoint, "/") +} func (s *Server) rememberNodeConnection(nodeID, connID string) { nodeID = strings.TrimSpace(nodeID) @@ -440,6 +478,16 @@ func (s *Server) Start(ctx context.Context) error { mux.HandleFunc("/webui/api/logs/stream", s.handleWebUILogsStream) mux.HandleFunc("/webui/api/logs/live", s.handleWebUILogsLive) mux.HandleFunc("/webui/api/logs/recent", s.handleWebUILogsRecent) + if strings.TrimSpace(s.whatsAppBase) != "" { + base := strings.TrimRight(strings.TrimSpace(s.whatsAppBase), "/") + if base == "" { + base = "/whatsapp" + } + mux.HandleFunc(base, s.handleWhatsAppBridgeWS) + mux.HandleFunc(joinServerRoute(base, "ws"), s.handleWhatsAppBridgeWS) + mux.HandleFunc(joinServerRoute(base, "status"), s.handleWhatsAppBridgeStatus) + mux.HandleFunc(joinServerRoute(base, "logout"), s.handleWhatsAppBridgeLogout) + } s.server = &http.Server{Addr: s.addr, Handler: mux} go func() { <-ctx.Done() diff --git a/pkg/api/server_test.go b/pkg/api/server_test.go index ebf58c5..3f0fee2 100644 --- a/pkg/api/server_test.go +++ b/pkg/api/server_test.go @@ -120,6 +120,53 @@ func TestHandleWebUIWhatsAppQR(t *testing.T) { } } +func TestHandleWebUIWhatsAppStatusWithNestedBridgePath(t *testing.T) { + t.Parallel() + + bridge := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case "/whatsapp/status": + _ = json.NewEncoder(w).Encode(map[string]interface{}{ + "state": "connected", + "connected": true, + "logged_in": true, + "bridge_addr": "127.0.0.1:7788", + "user_jid": "8613012345678@s.whatsapp.net", + "qr_available": false, + "last_event": "connected", + "updated_at": "2026-03-09T12:00:00+08:00", + }) + default: + http.NotFound(w, r) + } + })) + defer bridge.Close() + + tmp := t.TempDir() + cfgPath := filepath.Join(tmp, "config.json") + cfg := cfgpkg.DefaultConfig() + cfg.Logging.Enabled = false + cfg.Channels.WhatsApp.Enabled = true + cfg.Channels.WhatsApp.BridgeURL = "ws" + strings.TrimPrefix(bridge.URL, "http") + "/whatsapp/ws" + if err := cfgpkg.SaveConfig(cfgPath, cfg); err != nil { + t.Fatalf("save config: %v", err) + } + + srv := NewServer("127.0.0.1", 0, "", nil) + srv.SetConfigPath(cfgPath) + + req := httptest.NewRequest(http.MethodGet, "/webui/api/whatsapp/status", nil) + rec := httptest.NewRecorder() + srv.handleWebUIWhatsAppStatus(rec, req) + + if rec.Code != http.StatusOK { + t.Fatalf("expected 200, got %d: %s", rec.Code, rec.Body.String()) + } + if !strings.Contains(rec.Body.String(), `"bridge_running":true`) { + t.Fatalf("expected bridge_running=true, got: %s", rec.Body.String()) + } +} + func TestHandleWebUIConfigRequiresConfirmForProviderAPIBaseChange(t *testing.T) { t.Parallel() diff --git a/pkg/channels/whatsapp_bridge.go b/pkg/channels/whatsapp_bridge.go index 7eade47..dedab8a 100644 --- a/pkg/channels/whatsapp_bridge.go +++ b/pkg/channels/whatsapp_bridge.go @@ -67,6 +67,7 @@ type WhatsAppBridgeService struct { status WhatsAppBridgeStatus wsClientsMu sync.Mutex markReadFn func(ctx context.Context, ids []types.MessageID, timestamp time.Time, chat, sender types.JID) error + localOnly bool } type whatsappBridgeWSMessage struct { @@ -100,6 +101,34 @@ func NewWhatsAppBridgeService(addr, stateDir string, printQR bool) *WhatsAppBrid } func (s *WhatsAppBridgeService) Start(ctx context.Context) error { + if err := s.startRuntime(ctx); err != nil { + return err + } + + mux := http.NewServeMux() + s.RegisterRoutes(mux, "") + s.httpServer = &http.Server{ + Addr: s.addr, + Handler: mux, + } + + ln, err := net.Listen("tcp", s.addr) + if err != nil { + return fmt.Errorf("listen whatsapp bridge: %w", err) + } + + if err := s.httpServer.Serve(ln); err != nil && !errors.Is(err, http.ErrServerClosed) { + return err + } + return nil +} + +func (s *WhatsAppBridgeService) StartEmbedded(ctx context.Context) error { + s.localOnly = true + return s.startRuntime(ctx) +} + +func (s *WhatsAppBridgeService) startRuntime(ctx context.Context) error { if strings.TrimSpace(s.addr) == "" { return fmt.Errorf("bridge address is required") } @@ -116,26 +145,13 @@ func (s *WhatsAppBridgeService) Start(ctx context.Context) error { runCtx, cancel := context.WithCancel(ctx) s.cancel = cancel - mux := http.NewServeMux() - mux.HandleFunc("/", s.handleWS) - mux.HandleFunc("/ws", s.handleWS) - mux.HandleFunc("/status", s.handleStatus) - mux.HandleFunc("/logout", s.handleLogout) - s.httpServer = &http.Server{ - Addr: s.addr, - Handler: mux, - } - - ln, err := net.Listen("tcp", s.addr) - if err != nil { - return fmt.Errorf("listen whatsapp bridge: %w", err) - } - go func() { <-runCtx.Done() - shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - _ = s.httpServer.Shutdown(shutdownCtx) + if s.httpServer != nil { + shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + _ = s.httpServer.Shutdown(shutdownCtx) + } s.closeWSClients() if s.client != nil { s.client.Disconnect() @@ -148,10 +164,6 @@ func (s *WhatsAppBridgeService) Start(ctx context.Context) error { go func() { _ = s.connectClient(runCtx) }() - - if err := s.httpServer.Serve(ln); err != nil && !errors.Is(err, http.ErrServerClosed) { - return err - } return nil } @@ -161,6 +173,17 @@ func (s *WhatsAppBridgeService) Stop() { } } +func (s *WhatsAppBridgeService) RegisterRoutes(mux *http.ServeMux, basePath string) { + if mux == nil { + return + } + basePath = normalizeBridgeBasePath(basePath) + mux.HandleFunc(basePath, s.ServeWS) + mux.HandleFunc(joinBridgeRoute(basePath, "ws"), s.ServeWS) + mux.HandleFunc(joinBridgeRoute(basePath, "status"), s.ServeStatus) + mux.HandleFunc(joinBridgeRoute(basePath, "logout"), s.ServeLogout) +} + func (s *WhatsAppBridgeService) StatusSnapshot() WhatsAppBridgeStatus { s.statusMu.RLock() defer s.statusMu.RUnlock() @@ -421,11 +444,29 @@ func (s *WhatsAppBridgeService) handleWS(w http.ResponseWriter, r *http.Request) } } +func (s *WhatsAppBridgeService) ServeWS(w http.ResponseWriter, r *http.Request) { + s.wrapHandler(s.handleWS)(w, r) +} + +func (s *WhatsAppBridgeService) wrapHandler(next http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + if s.localOnly && !isLoopbackRequest(r) { + http.Error(w, "forbidden", http.StatusForbidden) + return + } + next(w, r) + } +} + func (s *WhatsAppBridgeService) handleStatus(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(w).Encode(s.StatusSnapshot()) } +func (s *WhatsAppBridgeService) ServeStatus(w http.ResponseWriter, r *http.Request) { + s.wrapHandler(s.handleStatus)(w, r) +} + func (s *WhatsAppBridgeService) handleLogout(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "method not allowed", http.StatusMethodNotAllowed) @@ -795,36 +836,16 @@ func ParseWhatsAppBridgeListenAddr(raw string) (string, error) { return raw, nil } +func (s *WhatsAppBridgeService) ServeLogout(w http.ResponseWriter, r *http.Request) { + s.wrapHandler(s.handleLogout)(w, r) +} + func BridgeStatusURL(raw string) (string, error) { - raw = strings.TrimSpace(raw) - if raw == "" { - return "", fmt.Errorf("bridge url is required") - } - if !strings.Contains(raw, "://") { - raw = "ws://" + raw - } - u, err := url.Parse(raw) - if err != nil { - return "", fmt.Errorf("parse bridge url: %w", err) - } - switch u.Scheme { - case "wss": - u.Scheme = "https" - default: - u.Scheme = "http" - } - u.Path = "/status" - u.RawQuery = "" - u.Fragment = "" - return u.String(), nil + return bridgeEndpointURL(raw, "status") } func BridgeLogoutURL(raw string) (string, error) { - statusURL, err := BridgeStatusURL(raw) - if err != nil { - return "", err - } - return strings.TrimSuffix(statusURL, "/status") + "/logout", nil + return bridgeEndpointURL(raw, "logout") } func normalizeWhatsAppRecipientJID(raw string) (types.JID, error) { @@ -874,3 +895,73 @@ func extractWhatsAppMessageText(msg *waProto.Message) string { return "" } } + +func bridgeEndpointURL(raw, endpoint string) (string, error) { + raw = strings.TrimSpace(raw) + if raw == "" { + return "", fmt.Errorf("bridge url is required") + } + if !strings.Contains(raw, "://") { + raw = "ws://" + raw + } + u, err := url.Parse(raw) + if err != nil { + return "", fmt.Errorf("parse bridge url: %w", err) + } + switch u.Scheme { + case "wss": + u.Scheme = "https" + default: + u.Scheme = "http" + } + u.Path = bridgeSiblingPath(u.Path, endpoint) + u.RawQuery = "" + u.Fragment = "" + return u.String(), nil +} + +func bridgeSiblingPath(pathValue, endpoint string) string { + pathValue = strings.TrimSpace(pathValue) + if endpoint == "" { + endpoint = "status" + } + if pathValue == "" || pathValue == "/" { + return "/" + endpoint + } + trimmed := strings.TrimSuffix(pathValue, "/") + if strings.HasSuffix(trimmed, "/ws") { + return strings.TrimSuffix(trimmed, "/ws") + "/" + endpoint + } + return trimmed + "/" + endpoint +} + +func normalizeBridgeBasePath(basePath string) string { + basePath = strings.TrimSpace(basePath) + if basePath == "" || basePath == "/" { + return "/" + } + if !strings.HasPrefix(basePath, "/") { + basePath = "/" + basePath + } + return strings.TrimSuffix(basePath, "/") +} + +func joinBridgeRoute(basePath, endpoint string) string { + basePath = normalizeBridgeBasePath(basePath) + if basePath == "/" { + return "/" + strings.TrimPrefix(endpoint, "/") + } + return basePath + "/" + strings.TrimPrefix(endpoint, "/") +} + +func isLoopbackRequest(r *http.Request) bool { + if r == nil { + return false + } + host, _, err := net.SplitHostPort(strings.TrimSpace(r.RemoteAddr)) + if err != nil { + host = strings.TrimSpace(r.RemoteAddr) + } + ip := net.ParseIP(host) + return ip != nil && ip.IsLoopback() +} diff --git a/pkg/channels/whatsapp_bridge_test.go b/pkg/channels/whatsapp_bridge_test.go index 8b2fd6b..8855dbe 100644 --- a/pkg/channels/whatsapp_bridge_test.go +++ b/pkg/channels/whatsapp_bridge_test.go @@ -53,6 +53,16 @@ func TestBridgeStatusURL(t *testing.T) { } } +func TestBridgeStatusURLWithNestedPath(t *testing.T) { + got, err := BridgeStatusURL("ws://localhost:7788/whatsapp/ws") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if got != "http://localhost:7788/whatsapp/status" { + t.Fatalf("got %q", got) + } +} + func TestNormalizeWhatsAppRecipientJID(t *testing.T) { tests := []struct { input string From c18fdb690e2d93b5c3c1daf44985bd3969064fd9 Mon Sep 17 00:00:00 2001 From: LPF Date: Tue, 10 Mar 2026 00:33:23 +0800 Subject: [PATCH 2/2] fix package --- Dockerfile | 8 +-- Makefile | 8 +-- cmd/{clawgo => }/cli_common.go | 4 +- cmd/{clawgo => }/cmd_agent.go | 12 ++-- cmd/{clawgo => }/cmd_channel.go | 12 ++-- cmd/{clawgo => }/cmd_config.go | 18 +++--- cmd/{clawgo => }/cmd_cron.go | 12 ++-- cmd/{clawgo => }/cmd_gateway.go | 62 +++++++++---------- cmd/{clawgo => }/cmd_node.go | 34 +++++------ cmd/{clawgo => }/cmd_node_test.go | 8 +-- cmd/{clawgo => }/cmd_onboard.go | 2 +- cmd/{clawgo => }/cmd_onboard_test.go | 2 +- cmd/{clawgo => }/cmd_skills.go | 4 +- cmd/{clawgo => }/cmd_status.go | 14 ++--- cmd/{clawgo => }/cmd_status_test.go | 4 +- cmd/{clawgo => }/cmd_uninstall.go | 0 cmd/{clawgo => }/main.go | 6 +- cmd/{clawgo => }/reload_unix.go | 0 cmd/{clawgo => }/reload_windows.go | 0 cmd/{clawgo => }/signals_unix.go | 0 cmd/{clawgo => }/signals_windows.go | 0 go.mod | 69 +++++++++++----------- go.sum | 65 ++++++++++++++++++++ pkg/agent/context.go | 6 +- pkg/agent/loop.go | 22 +++---- pkg/agent/loop_nodes_p2p_test.go | 4 +- pkg/agent/loop_skill_exec_test.go | 6 +- pkg/agent/loop_system_notify_test.go | 2 +- pkg/agent/memory_log_test.go | 6 +- pkg/agent/router_dispatch.go | 8 +-- pkg/agent/router_dispatch_test.go | 14 ++--- pkg/agent/runtime_admin.go | 6 +- pkg/agent/runtime_admin_test.go | 6 +- pkg/agent/session_planner.go | 8 +-- pkg/agent/session_planner_split_test.go | 4 +- pkg/agent/session_scheduler.go | 2 +- pkg/agent/subagent_config_intent.go | 4 +- pkg/agent/subagent_node_test.go | 4 +- pkg/agent/subagent_prompt_test.go | 2 +- pkg/agent/trigger_audit.go | 18 +++--- pkg/api/server.go | 8 +-- pkg/api/server_test.go | 4 +- pkg/bus/bus.go | 2 +- pkg/channels/base.go | 4 +- pkg/channels/dedupe_regression_test.go | 15 +++-- pkg/channels/dingtalk.go | 6 +- pkg/channels/discord.go | 6 +- pkg/channels/feishu.go | 12 ++-- pkg/channels/maixcam.go | 8 +-- pkg/channels/manager.go | 6 +- pkg/channels/qq.go | 6 +- pkg/channels/telegram.go | 12 ++-- pkg/channels/utils.go | 2 +- pkg/channels/whatsapp.go | 6 +- pkg/channels/whatsapp_bridge_test.go | 2 +- pkg/channels/whatsapp_test.go | 2 +- pkg/configops/configops.go | 2 +- pkg/cron/service.go | 2 +- pkg/heartbeat/service.go | 2 +- pkg/providers/http_provider.go | 4 +- pkg/runtimecfg/snapshot.go | 2 +- pkg/sentinel/service.go | 8 +-- pkg/server/server.go | 4 +- pkg/session/manager.go | 2 +- pkg/tools/browser.go | 2 +- pkg/tools/camera.go | 4 +- pkg/tools/cron_tool.go | 2 +- pkg/tools/mcp.go | 2 +- pkg/tools/mcp_test.go | 2 +- pkg/tools/message.go | 2 +- pkg/tools/nodes_tool.go | 2 +- pkg/tools/process_manager.go | 2 +- pkg/tools/registry.go | 2 +- pkg/tools/remind.go | 2 +- pkg/tools/remind_test.go | 4 +- pkg/tools/sessions_tool.go | 2 +- pkg/tools/shell.go | 2 +- pkg/tools/skill_exec.go | 2 +- pkg/tools/subagent.go | 6 +- pkg/tools/subagent_config_manager.go | 42 ++++++------- pkg/tools/subagent_config_tool_test.go | 6 +- pkg/tools/subagent_profile.go | 6 +- pkg/tools/subagent_profile_test.go | 6 +- pkg/tools/subagent_runtime_control_test.go | 4 +- pkg/tools/web.go | 2 +- 85 files changed, 381 insertions(+), 316 deletions(-) rename cmd/{clawgo => }/cli_common.go (98%) rename cmd/{clawgo => }/cmd_agent.go (93%) rename cmd/{clawgo => }/cmd_channel.go (97%) rename cmd/{clawgo => }/cmd_config.go (95%) rename cmd/{clawgo => }/cmd_cron.go (93%) rename cmd/{clawgo => }/cmd_gateway.go (94%) rename cmd/{clawgo => }/cmd_node.go (98%) rename cmd/{clawgo => }/cmd_node_test.go (99%) rename cmd/{clawgo => }/cmd_onboard.go (98%) rename cmd/{clawgo => }/cmd_onboard_test.go (95%) rename cmd/{clawgo => }/cmd_skills.go (98%) rename cmd/{clawgo => }/cmd_status.go (97%) rename cmd/{clawgo => }/cmd_status_test.go (95%) rename cmd/{clawgo => }/cmd_uninstall.go (100%) rename cmd/{clawgo => }/main.go (93%) rename cmd/{clawgo => }/reload_unix.go (100%) rename cmd/{clawgo => }/reload_windows.go (100%) rename cmd/{clawgo => }/signals_unix.go (100%) rename cmd/{clawgo => }/signals_windows.go (100%) diff --git a/Dockerfile b/Dockerfile index ec22176..6bce05e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,11 +7,11 @@ RUN go mod download COPY . ./ -RUN rm -rf cmd/clawgo/workspace \ - && mkdir -p cmd/clawgo/workspace \ - && cp -a workspace/. cmd/clawgo/workspace/ +RUN rm -rf cmd/workspace \ + && mkdir -p cmd/workspace \ + && cp -a workspace/. cmd/workspace/ -RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -buildvcs=false -ldflags="-s -w" -o /out/clawgo ./cmd/clawgo +RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -buildvcs=false -ldflags="-s -w" -o /out/clawgo ./cmd FROM debian:bookworm-slim diff --git a/Makefile b/Makefile index 574c7a9..d41a6fc 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ # Build variables BINARY_NAME=clawgo BUILD_DIR=build -CMD_DIR=cmd/$(BINARY_NAME) +CMD_DIR=cmd MAIN_GO=$(CMD_DIR)/main.go # Version @@ -46,7 +46,7 @@ WORKSPACE_DIR?=$(CLAWGO_HOME)/workspace WORKSPACE_SKILLS_DIR=$(WORKSPACE_DIR)/skills BUILTIN_SKILLS_DIR=$(CURDIR)/skills WORKSPACE_SOURCE_DIR=$(CURDIR)/workspace -EMBED_WORKSPACE_DIR=$(CURDIR)/cmd/$(BINARY_NAME)/workspace +EMBED_WORKSPACE_DIR=$(CURDIR)/cmd/workspace EMBED_WEBUI_DIR=$(EMBED_WORKSPACE_DIR)/webui DEV_CONFIG?=$(if $(wildcard $(CURDIR)/config.json),$(CURDIR)/config.json,$(CLAWGO_HOME)/config.json) DEV_ARGS?=--debug gateway run @@ -189,11 +189,11 @@ package-all: build-all fi @echo "Package complete: $(BUILD_DIR)" -## sync-embed-workspace: Sync workspace seed files and built WebUI into cmd/clawgo/workspace for go:embed +## sync-embed-workspace: Sync workspace seed files and built WebUI into cmd/workspace for go:embed sync-embed-workspace: sync-embed-workspace-base sync-embed-webui @echo "✓ Embed assets ready in $(EMBED_WORKSPACE_DIR)" -## sync-embed-workspace-base: Sync root workspace files into cmd/clawgo/workspace for go:embed +## sync-embed-workspace-base: Sync root workspace files into cmd/workspace for go:embed sync-embed-workspace-base: @echo "Syncing workspace seed files for embedding..." @if [ ! -d "$(WORKSPACE_SOURCE_DIR)" ]; then \ diff --git a/cmd/clawgo/cli_common.go b/cmd/cli_common.go similarity index 98% rename from cmd/clawgo/cli_common.go rename to cmd/cli_common.go index 7164837..745ae74 100644 --- a/cmd/clawgo/cli_common.go +++ b/cmd/cli_common.go @@ -7,8 +7,8 @@ import ( "path/filepath" "strings" - "clawgo/pkg/config" - "clawgo/pkg/logger" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/logger" ) func copyDirectory(src, dst string) error { diff --git a/cmd/clawgo/cmd_agent.go b/cmd/cmd_agent.go similarity index 93% rename from cmd/clawgo/cmd_agent.go rename to cmd/cmd_agent.go index d02c78d..43b835a 100644 --- a/cmd/clawgo/cmd_agent.go +++ b/cmd/cmd_agent.go @@ -9,11 +9,11 @@ import ( "path/filepath" "strings" - "clawgo/pkg/agent" - "clawgo/pkg/bus" - "clawgo/pkg/cron" - "clawgo/pkg/logger" - "clawgo/pkg/providers" + "github.com/YspCoder/clawgo/pkg/agent" + "github.com/YspCoder/clawgo/pkg/bus" + "github.com/YspCoder/clawgo/pkg/cron" + "github.com/YspCoder/clawgo/pkg/logger" + "github.com/YspCoder/clawgo/pkg/providers" "github.com/chzyer/readline" ) @@ -27,7 +27,7 @@ func agentCmd() { switch args[i] { case "--debug", "-d": logger.SetLevel(logger.DEBUG) - fmt.Println("🔍 Debug mode enabled") + fmt.Println("馃攳 Debug mode enabled") case "-m", "--message": if i+1 < len(args) { message = args[i+1] diff --git a/cmd/clawgo/cmd_channel.go b/cmd/cmd_channel.go similarity index 97% rename from cmd/clawgo/cmd_channel.go rename to cmd/cmd_channel.go index 3a22b54..25ff44d 100644 --- a/cmd/clawgo/cmd_channel.go +++ b/cmd/cmd_channel.go @@ -10,9 +10,9 @@ import ( "strings" "time" - "clawgo/pkg/bus" - "clawgo/pkg/channels" - "clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/bus" + "github.com/YspCoder/clawgo/pkg/channels" + "github.com/YspCoder/clawgo/pkg/config" qrterminal "github.com/mdp/qrterminal/v3" ) @@ -55,7 +55,7 @@ func channelHelp() { func channelTestCmd() { to := "" channelName := "" - message := "This is a test message from ClawGo 🦞" + message := "This is a test message from ClawGo 馃" args := os.Args[3:] for i := 0; i < len(args); i++ { @@ -104,11 +104,11 @@ func channelTestCmd() { fmt.Printf("Sending test message to %s (%s)...\n", channelName, to) if err := mgr.SendToChannel(ctx, channelName, to, message); err != nil { - fmt.Printf("✗ Failed to send message: %v\n", err) + fmt.Printf("鉁?Failed to send message: %v\n", err) os.Exit(1) } - fmt.Println("✓ Test message sent successfully!") + fmt.Println("鉁?Test message sent successfully!") } func whatsAppChannelCmd() { diff --git a/cmd/clawgo/cmd_config.go b/cmd/cmd_config.go similarity index 95% rename from cmd/clawgo/cmd_config.go rename to cmd/cmd_config.go index 5e4d1d8..8e99fb1 100644 --- a/cmd/clawgo/cmd_config.go +++ b/cmd/cmd_config.go @@ -9,8 +9,8 @@ import ( "strconv" "strings" - "clawgo/pkg/config" - "clawgo/pkg/configops" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/configops" ) func configCmd() { @@ -100,7 +100,7 @@ func configSetCmd() { return } - fmt.Printf("✓ Updated %s = %v\n", path, value) + fmt.Printf("鉁?Updated %s = %v\n", path, value) running, err := triggerGatewayReload() if err != nil { if running { @@ -113,7 +113,7 @@ func configSetCmd() { } fmt.Printf("Updated config file. Hot reload not applied: %v\n", err) } else { - fmt.Println("✓ Gateway hot reload signal sent") + fmt.Println("鉁?Gateway hot reload signal sent") } } @@ -150,7 +150,7 @@ func configReloadCmd() { fmt.Printf("Hot reload not applied: %v\n", err) return } - fmt.Println("✓ Gateway hot reload signal sent") + fmt.Println("鉁?Gateway hot reload signal sent") } func configCheckCmd() { @@ -161,11 +161,11 @@ func configCheckCmd() { } validationErrors := config.Validate(cfg) if len(validationErrors) == 0 { - fmt.Println("✓ Config validation passed") + fmt.Println("鉁?Config validation passed") return } - fmt.Println("✗ Config validation failed:") + fmt.Println("鉁?Config validation failed:") for _, ve := range validationErrors { fmt.Printf(" - %v\n", ve) } @@ -265,7 +265,7 @@ func providerCmd() { os.Exit(1) } - fmt.Println("✓ Provider configuration saved.") + fmt.Println("鉁?Provider configuration saved.") running, err := triggerGatewayReload() if err != nil { if running { @@ -275,7 +275,7 @@ func providerCmd() { fmt.Printf("Gateway not running, reload skipped: %v\n", err) return } - fmt.Println("✓ Gateway hot reload signal sent") + fmt.Println("鉁?Gateway hot reload signal sent") } func providerNames(cfg *config.Config) []string { diff --git a/cmd/clawgo/cmd_cron.go b/cmd/cmd_cron.go similarity index 93% rename from cmd/clawgo/cmd_cron.go rename to cmd/cmd_cron.go index bc8602a..836602a 100644 --- a/cmd/clawgo/cmd_cron.go +++ b/cmd/cmd_cron.go @@ -6,7 +6,7 @@ import ( "path/filepath" "time" - "clawgo/pkg/cron" + "github.com/YspCoder/clawgo/pkg/cron" ) func cronCmd() { @@ -177,15 +177,15 @@ func cronAddCmd(storePath string) { return } - fmt.Printf("✓ Added job '%s' (%s)\n", job.Name, job.ID) + fmt.Printf("鉁?Added job '%s' (%s)\n", job.Name, job.ID) } func cronRemoveCmd(storePath, jobID string) { cs := cron.NewCronService(storePath, nil) if cs.RemoveJob(jobID) { - fmt.Printf("✓ Removed job %s\n", jobID) + fmt.Printf("鉁?Removed job %s\n", jobID) } else { - fmt.Printf("✗ Job %s not found\n", jobID) + fmt.Printf("鉁?Job %s not found\n", jobID) } } @@ -205,8 +205,8 @@ func cronEnableCmd(storePath string, disable bool) { if disable { status = "disabled" } - fmt.Printf("✓ Job '%s' %s\n", job.Name, status) + fmt.Printf("鉁?Job '%s' %s\n", job.Name, status) } else { - fmt.Printf("✗ Job %s not found\n", jobID) + fmt.Printf("鉁?Job %s not found\n", jobID) } } diff --git a/cmd/clawgo/cmd_gateway.go b/cmd/cmd_gateway.go similarity index 94% rename from cmd/clawgo/cmd_gateway.go rename to cmd/cmd_gateway.go index adcb77a..b8a4f76 100644 --- a/cmd/clawgo/cmd_gateway.go +++ b/cmd/cmd_gateway.go @@ -13,18 +13,18 @@ import ( "strings" "time" - "clawgo/pkg/agent" - "clawgo/pkg/api" - "clawgo/pkg/bus" - "clawgo/pkg/channels" - "clawgo/pkg/config" - "clawgo/pkg/cron" - "clawgo/pkg/heartbeat" - "clawgo/pkg/logger" - "clawgo/pkg/nodes" - "clawgo/pkg/providers" - "clawgo/pkg/runtimecfg" - "clawgo/pkg/sentinel" + "github.com/YspCoder/clawgo/pkg/agent" + "github.com/YspCoder/clawgo/pkg/api" + "github.com/YspCoder/clawgo/pkg/bus" + "github.com/YspCoder/clawgo/pkg/channels" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/cron" + "github.com/YspCoder/clawgo/pkg/heartbeat" + "github.com/YspCoder/clawgo/pkg/logger" + "github.com/YspCoder/clawgo/pkg/nodes" + "github.com/YspCoder/clawgo/pkg/providers" + "github.com/YspCoder/clawgo/pkg/runtimecfg" + "github.com/YspCoder/clawgo/pkg/sentinel" "github.com/pion/webrtc/v4" ) @@ -107,26 +107,26 @@ func gatewayCmd() { enabledChannels := channelManager.GetEnabledChannels() if len(enabledChannels) > 0 { - fmt.Printf("✓ Channels enabled: %s\n", enabledChannels) + fmt.Printf("鉁?Channels enabled: %s\n", enabledChannels) } else { - fmt.Println("⚠ Warning: No channels enabled") + fmt.Println("鈿?Warning: No channels enabled") } - fmt.Printf("✓ Gateway started on %s:%d\n", cfg.Gateway.Host, cfg.Gateway.Port) + fmt.Printf("鉁?Gateway started on %s:%d\n", cfg.Gateway.Host, cfg.Gateway.Port) fmt.Println("Press Ctrl+C to stop. Send SIGHUP to hot-reload config.") if err := cronService.Start(); err != nil { fmt.Printf("Error starting cron service: %v\n", err) } - fmt.Println("✓ Cron service started") + fmt.Println("鉁?Cron service started") if err := heartbeatService.Start(); err != nil { fmt.Printf("Error starting heartbeat service: %v\n", err) } - fmt.Println("✓ Heartbeat service started") + fmt.Println("鉁?Heartbeat service started") if cfg.Sentinel.Enabled { sentinelService.Start() - fmt.Println("✓ Sentinel service started") + fmt.Println("鉁?Sentinel service started") } registryServer := api.NewServer(cfg.Gateway.Host, cfg.Gateway.Port, cfg.Gateway.Token, nodes.DefaultManager()) @@ -367,7 +367,7 @@ func gatewayCmd() { if err := registryServer.Start(ctx); err != nil { fmt.Printf("Error starting node registry server: %v\n", err) } else { - fmt.Printf("✓ Node registry server started on %s:%d\n", cfg.Gateway.Host, cfg.Gateway.Port) + fmt.Printf("鉁?Node registry server started on %s:%d\n", cfg.Gateway.Host, cfg.Gateway.Port) } if err := channelManager.StartAll(ctx); err != nil { @@ -381,10 +381,10 @@ func gatewayCmd() { sigChan := make(chan os.Signal, 1) signal.Notify(sigChan, gatewayNotifySignals()...) applyReload := func() { - fmt.Println("\n↻ Reloading config...") + fmt.Println("\n鈫?Reloading config...") newCfg, err := config.LoadConfig(getConfigPath()) if err != nil { - fmt.Printf("✗ Reload failed (load config): %v\n", err) + fmt.Printf("鉁?Reload failed (load config): %v\n", err) return } if strings.EqualFold(strings.TrimSpace(os.Getenv(envRootGranted)), "1") || strings.EqualFold(strings.TrimSpace(os.Getenv(envRootGranted)), "true") { @@ -398,7 +398,7 @@ func gatewayCmd() { } if reflect.DeepEqual(cfg, newCfg) { - fmt.Println("✓ Config unchanged, skip reload") + fmt.Println("鉁?Config unchanged, skip reload") return } @@ -437,13 +437,13 @@ func gatewayCmd() { cfg = newCfg runtimecfg.Set(cfg) configureGatewayNodeP2P(agentLoop, registryServer, cfg) - fmt.Println("✓ Config hot-reload applied (logging/metadata only)") + fmt.Println("鉁?Config hot-reload applied (logging/metadata only)") return } newAgentLoop, newChannelManager, err := buildGatewayRuntime(ctx, newCfg, msgBus, cronService) if err != nil { - fmt.Printf("✗ Reload failed (init runtime): %v\n", err) + fmt.Printf("鉁?Reload failed (init runtime): %v\n", err) return } @@ -485,11 +485,11 @@ func gatewayCmd() { sentinelService.SetManager(channelManager) if err := channelManager.StartAll(ctx); err != nil { - fmt.Printf("✗ Reload failed (start channels): %v\n", err) + fmt.Printf("鉁?Reload failed (start channels): %v\n", err) return } go agentLoop.Run(ctx) - fmt.Println("✓ Config hot-reload applied") + fmt.Println("鉁?Config hot-reload applied") } for { @@ -511,7 +511,7 @@ func gatewayCmd() { cronService.Stop() agentLoop.Stop() channelManager.StopAll(ctx) - fmt.Println("✓ Gateway stopped") + fmt.Println("鉁?Gateway stopped") return } } @@ -606,7 +606,7 @@ func gatewayInstallServiceCmd() error { return err } - fmt.Printf("✓ Gateway service registered: %s (%s)\n", gatewayServiceName, scope) + fmt.Printf("鉁?Gateway service registered: %s (%s)\n", gatewayServiceName, scope) fmt.Printf(" Unit file: %s\n", unitPath) fmt.Println(" Start service: clawgo gateway start") fmt.Println(" Restart service: clawgo gateway restart") @@ -766,9 +766,9 @@ func buildGatewayRuntime(ctx context.Context, cfg *config.Config, msgBus *bus.Me startupInfo := agentLoop.GetStartupInfo() toolsInfo := startupInfo["tools"].(map[string]interface{}) skillsInfo := startupInfo["skills"].(map[string]interface{}) - fmt.Println("\n📦 Agent Status:") - fmt.Printf(" • Tools: %d loaded\n", toolsInfo["count"]) - fmt.Printf(" • Skills: %d/%d available\n", skillsInfo["available"], skillsInfo["total"]) + fmt.Println("\n馃摝 Agent Status:") + fmt.Printf(" 鈥?Tools: %d loaded\n", toolsInfo["count"]) + fmt.Printf(" 鈥?Skills: %d/%d available\n", skillsInfo["available"], skillsInfo["total"]) logger.InfoCF("agent", logger.C0098, map[string]interface{}{ diff --git a/cmd/clawgo/cmd_node.go b/cmd/cmd_node.go similarity index 98% rename from cmd/clawgo/cmd_node.go rename to cmd/cmd_node.go index d7ab616..3f452f3 100644 --- a/cmd/clawgo/cmd_node.go +++ b/cmd/cmd_node.go @@ -19,14 +19,14 @@ import ( "sync" "time" - "clawgo/pkg/agent" - "clawgo/pkg/bus" - "clawgo/pkg/config" - "clawgo/pkg/cron" - "clawgo/pkg/nodes" - "clawgo/pkg/providers" - "clawgo/pkg/runtimecfg" - "clawgo/pkg/tools" + "github.com/YspCoder/clawgo/pkg/agent" + "github.com/YspCoder/clawgo/pkg/bus" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/cron" + "github.com/YspCoder/clawgo/pkg/nodes" + "github.com/YspCoder/clawgo/pkg/providers" + "github.com/YspCoder/clawgo/pkg/runtimecfg" + "github.com/YspCoder/clawgo/pkg/tools" "github.com/gorilla/websocket" "github.com/pion/webrtc/v4" ) @@ -151,11 +151,11 @@ func nodeRegisterCmd(args []string) { fmt.Printf("Error registering node: %v\n", err) os.Exit(1) } - fmt.Printf("✓ Node registered: %s -> %s\n", info.ID, opts.GatewayBase) + fmt.Printf("鉁?Node registered: %s -> %s\n", info.ID, opts.GatewayBase) if !opts.Watch { return } - fmt.Printf("✓ Heartbeat loop started: every %ds\n", opts.HeartbeatSec) + fmt.Printf("鉁?Heartbeat loop started: every %ds\n", opts.HeartbeatSec) if err := runNodeHeartbeatLoop(client, opts, info); err != nil { fmt.Printf("Heartbeat loop stopped: %v\n", err) os.Exit(1) @@ -175,7 +175,7 @@ func nodeHeartbeatCmd(args []string) { fmt.Printf("Error sending heartbeat: %v\n", err) os.Exit(1) } - fmt.Printf("✓ Heartbeat sent: %s -> %s\n", opts.ID, opts.GatewayBase) + fmt.Printf("鉁?Heartbeat sent: %s -> %s\n", opts.ID, opts.GatewayBase) } func parseNodeRegisterArgs(args []string, cfg *config.Config) (nodeRegisterOptions, error) { @@ -409,23 +409,23 @@ func runNodeHeartbeatLoop(client *http.Client, opts nodeRegisterOptions, info no for { if err := runNodeHeartbeatSocket(ctx, opts, info); err != nil { if ctx.Err() != nil { - fmt.Println("✓ Node heartbeat stopped") + fmt.Println("鉁?Node heartbeat stopped") return nil } fmt.Printf("Warning: node socket closed for %s: %v\n", info.ID, err) } if ctx.Err() != nil { - fmt.Println("✓ Node heartbeat stopped") + fmt.Println("鉁?Node heartbeat stopped") return nil } if regErr := postNodeRegister(ctx, client, opts.GatewayBase, opts.Token, info); regErr != nil { fmt.Printf("Warning: re-register failed for %s: %v\n", info.ID, regErr) } else { - fmt.Printf("✓ Node re-registered: %s\n", info.ID) + fmt.Printf("鉁?Node re-registered: %s\n", info.ID) } select { case <-ctx.Done(): - fmt.Println("✓ Node heartbeat stopped") + fmt.Println("鉁?Node heartbeat stopped") return nil case <-time.After(2 * time.Second): } @@ -466,7 +466,7 @@ func runNodeHeartbeatSocket(ctx context.Context, opts nodeRegisterOptions, info if err := waitNodeAck(ctx, acks, errs, "registered", info.ID); err != nil { return err } - fmt.Printf("✓ Node socket connected: %s\n", info.ID) + fmt.Printf("鉁?Node socket connected: %s\n", info.ID) ticker := time.NewTicker(time.Duration(opts.HeartbeatSec) * time.Second) pingTicker := time.NewTicker(nodeSocketPingInterval(opts.HeartbeatSec)) @@ -493,7 +493,7 @@ func runNodeHeartbeatSocket(ctx context.Context, opts nodeRegisterOptions, info if err := waitNodeAck(ctx, acks, errs, "heartbeat", info.ID); err != nil { return err } - fmt.Printf("✓ Heartbeat ok: %s\n", info.ID) + fmt.Printf("鉁?Heartbeat ok: %s\n", info.ID) } } } diff --git a/cmd/clawgo/cmd_node_test.go b/cmd/cmd_node_test.go similarity index 99% rename from cmd/clawgo/cmd_node_test.go rename to cmd/cmd_node_test.go index 8274f77..e1333c4 100644 --- a/cmd/clawgo/cmd_node_test.go +++ b/cmd/cmd_node_test.go @@ -11,10 +11,10 @@ import ( "testing" "time" - "clawgo/pkg/agent" - "clawgo/pkg/config" - "clawgo/pkg/nodes" - "clawgo/pkg/providers" + "github.com/YspCoder/clawgo/pkg/agent" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/nodes" + "github.com/YspCoder/clawgo/pkg/providers" ) type stubNodeProvider struct { diff --git a/cmd/clawgo/cmd_onboard.go b/cmd/cmd_onboard.go similarity index 98% rename from cmd/clawgo/cmd_onboard.go rename to cmd/cmd_onboard.go index 79990ae..88c1e82 100644 --- a/cmd/clawgo/cmd_onboard.go +++ b/cmd/cmd_onboard.go @@ -7,7 +7,7 @@ import ( "path/filepath" "strings" - "clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/config" ) type onboardOptions struct { diff --git a/cmd/clawgo/cmd_onboard_test.go b/cmd/cmd_onboard_test.go similarity index 95% rename from cmd/clawgo/cmd_onboard_test.go rename to cmd/cmd_onboard_test.go index d4d794e..a38ad3f 100644 --- a/cmd/clawgo/cmd_onboard_test.go +++ b/cmd/cmd_onboard_test.go @@ -3,7 +3,7 @@ package main import ( "testing" - "clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/config" ) func TestParseOnboardOptionsSyncWebUI(t *testing.T) { diff --git a/cmd/clawgo/cmd_skills.go b/cmd/cmd_skills.go similarity index 98% rename from cmd/clawgo/cmd_skills.go rename to cmd/cmd_skills.go index 91237f9..f25f03d 100644 --- a/cmd/clawgo/cmd_skills.go +++ b/cmd/cmd_skills.go @@ -8,8 +8,8 @@ import ( "strings" "time" - "clawgo/pkg/config" - "clawgo/pkg/skills" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/skills" ) func skillsCmd() { diff --git a/cmd/clawgo/cmd_status.go b/cmd/cmd_status.go similarity index 97% rename from cmd/clawgo/cmd_status.go rename to cmd/cmd_status.go index c22615e..ab07a46 100644 --- a/cmd/clawgo/cmd_status.go +++ b/cmd/cmd_status.go @@ -8,8 +8,8 @@ import ( "sort" "strings" - "clawgo/pkg/nodes" - "clawgo/pkg/providers" + "github.com/YspCoder/clawgo/pkg/nodes" + "github.com/YspCoder/clawgo/pkg/providers" ) func statusCmd() { @@ -24,16 +24,16 @@ func statusCmd() { fmt.Printf("%s clawgo Status\n\n", logo) if _, err := os.Stat(configPath); err == nil { - fmt.Println("Config:", configPath, "✓") + fmt.Println("Config:", configPath, "[ok]") } else { - fmt.Println("Config:", configPath, "✗") + fmt.Println("Config:", configPath, "[missing]") } workspace := cfg.WorkspacePath() if _, err := os.Stat(workspace); err == nil { - fmt.Println("Workspace:", workspace, "✓") + fmt.Println("Workspace:", workspace, "[ok]") } else { - fmt.Println("Workspace:", workspace, "✗") + fmt.Println("Workspace:", workspace, "[missing]") } if _, err := os.Stat(configPath); err == nil { @@ -59,7 +59,7 @@ func statusCmd() { hasKey := strings.TrimSpace(activeProvider.APIKey) != "" status := "not set" if hasKey { - status = "✓" + status = "configured" } fmt.Printf("Provider API Key: %s\n", status) fmt.Printf("Logging: %v\n", cfg.Logging.Enabled) diff --git a/cmd/clawgo/cmd_status_test.go b/cmd/cmd_status_test.go similarity index 95% rename from cmd/clawgo/cmd_status_test.go rename to cmd/cmd_status_test.go index e8fe402..2dec050 100644 --- a/cmd/clawgo/cmd_status_test.go +++ b/cmd/cmd_status_test.go @@ -8,7 +8,7 @@ import ( "strings" "testing" - "clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/config" ) func TestStatusCmdUsesActiveProviderDetails(t *testing.T) { @@ -71,7 +71,7 @@ func TestStatusCmdUsesActiveProviderDetails(t *testing.T) { if !strings.Contains(out, "Provider API Base: https://backup.example/v1") { t.Fatalf("expected active provider api base in output, got: %s", out) } - if !strings.Contains(out, "Provider API Key: ✓") { + if !strings.Contains(out, "Provider API Key: configured") { t.Fatalf("expected active provider api key status in output, got: %s", out) } if !strings.Contains(out, "Nodes P2P: enabled=true transport=webrtc") { diff --git a/cmd/clawgo/cmd_uninstall.go b/cmd/cmd_uninstall.go similarity index 100% rename from cmd/clawgo/cmd_uninstall.go rename to cmd/cmd_uninstall.go diff --git a/cmd/clawgo/main.go b/cmd/main.go similarity index 93% rename from cmd/clawgo/main.go rename to cmd/main.go index bf326e0..0babb61 100644 --- a/cmd/clawgo/main.go +++ b/cmd/main.go @@ -12,8 +12,8 @@ import ( "fmt" "os" - "clawgo/pkg/config" - "clawgo/pkg/logger" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/logger" ) //go:embed workspace @@ -22,7 +22,7 @@ var embeddedFiles embed.FS var version = "dev" var buildTime = "unknown" -const logo = "🦞" +const logo = "馃" const gatewayServiceName = "clawgo-gateway.service" const envRootGranted = "CLAWGO_ROOT_GRANTED" diff --git a/cmd/clawgo/reload_unix.go b/cmd/reload_unix.go similarity index 100% rename from cmd/clawgo/reload_unix.go rename to cmd/reload_unix.go diff --git a/cmd/clawgo/reload_windows.go b/cmd/reload_windows.go similarity index 100% rename from cmd/clawgo/reload_windows.go rename to cmd/reload_windows.go diff --git a/cmd/clawgo/signals_unix.go b/cmd/signals_unix.go similarity index 100% rename from cmd/clawgo/signals_unix.go rename to cmd/signals_unix.go diff --git a/cmd/clawgo/signals_windows.go b/cmd/signals_windows.go similarity index 100% rename from cmd/clawgo/signals_windows.go rename to cmd/signals_windows.go diff --git a/go.mod b/go.mod index d9be4b3..1e634bd 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ -module clawgo +module github.com/YspCoder/clawgo -go 1.25.5 +go 1.25.7 require ( github.com/bwmarrin/discordgo v0.29.0 @@ -9,20 +9,22 @@ require ( github.com/gorilla/websocket v1.5.3 github.com/larksuite/oapi-sdk-go/v3 v3.5.3 github.com/mdp/qrterminal/v3 v3.2.1 - github.com/mymmrac/telego v1.6.0 + github.com/mymmrac/telego v1.7.0 github.com/open-dingtalk/dingtalk-stream-sdk-go v0.9.1 - github.com/pion/webrtc/v4 v4.1.6 + github.com/pion/webrtc/v4 v4.2.9 github.com/robfig/cron/v3 v3.0.1 github.com/tencent-connect/botgo v0.2.1 go.mau.fi/whatsmeow v0.0.0-20260305215846-fc65416c22c4 - golang.org/x/oauth2 v0.35.0 - golang.org/x/sync v0.19.0 - golang.org/x/time v0.14.0 + golang.org/x/oauth2 v0.36.0 + golang.org/x/sync v0.20.0 + golang.org/x/time v0.15.0 + google.golang.org/protobuf v1.36.11 modernc.org/sqlite v1.46.1 + rsc.io/qr v0.2.0 ) require ( - filippo.io/edwards25519 v1.1.0 // indirect + filippo.io/edwards25519 v1.2.0 // indirect github.com/andybalholm/brotli v1.2.0 // indirect github.com/beeper/argo-go v1.1.2 // indirect github.com/bytedance/gopkg v0.1.3 // indirect @@ -32,31 +34,32 @@ require ( github.com/coder/websocket v1.8.14 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/elliotchance/orderedmap/v3 v3.1.0 // indirect - github.com/go-resty/resty/v2 v2.17.1 // indirect + github.com/go-resty/resty/v2 v2.17.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/uuid v1.6.0 // indirect github.com/grbit/go-json v0.11.0 // indirect - github.com/klauspost/compress v1.18.2 // indirect - github.com/klauspost/cpuid/v2 v2.2.9 // indirect + github.com/klauspost/compress v1.18.4 // indirect + github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/ncruces/go-strftime v1.0.0 // indirect - github.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741 // indirect - github.com/pion/datachannel v1.5.10 // indirect - github.com/pion/dtls/v3 v3.0.7 // indirect - github.com/pion/ice/v4 v4.0.10 // indirect - github.com/pion/interceptor v0.1.41 // indirect + github.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6 // indirect + github.com/pion/datachannel v1.6.0 // indirect + github.com/pion/dtls/v3 v3.1.2 // indirect + github.com/pion/ice/v4 v4.2.1 // indirect + github.com/pion/interceptor v0.1.44 // indirect github.com/pion/logging v0.2.4 // indirect - github.com/pion/mdns/v2 v2.0.7 // indirect + github.com/pion/mdns/v2 v2.1.0 // indirect github.com/pion/randutil v0.1.0 // indirect - github.com/pion/rtcp v1.2.15 // indirect - github.com/pion/rtp v1.8.23 // indirect - github.com/pion/sctp v1.8.40 // indirect - github.com/pion/sdp/v3 v3.0.16 // indirect - github.com/pion/srtp/v3 v3.0.8 // indirect - github.com/pion/stun/v3 v3.0.0 // indirect - github.com/pion/transport/v3 v3.0.8 // indirect - github.com/pion/turn/v4 v4.1.1 // indirect + github.com/pion/rtcp v1.2.16 // indirect + github.com/pion/rtp v1.10.1 // indirect + github.com/pion/sctp v1.9.2 // indirect + github.com/pion/sdp/v3 v3.0.18 // indirect + github.com/pion/srtp/v3 v3.0.10 // indirect + github.com/pion/stun/v3 v3.1.1 // indirect + github.com/pion/transport/v3 v3.1.1 // indirect + github.com/pion/transport/v4 v4.0.1 // indirect + github.com/pion/turn/v4 v4.1.4 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rs/zerolog v1.34.0 // indirect github.com/tidwall/gjson v1.18.0 // indirect @@ -65,21 +68,19 @@ require ( github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.69.0 // indirect - github.com/valyala/fastjson v1.6.7 // indirect - github.com/vektah/gqlparser/v2 v2.5.27 // indirect + github.com/valyala/fastjson v1.6.10 // indirect + github.com/vektah/gqlparser/v2 v2.5.32 // indirect github.com/wlynxg/anet v0.0.5 // indirect go.mau.fi/libsignal v0.2.1 // indirect go.mau.fi/util v0.9.6 // indirect - golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect + golang.org/x/arch v0.25.0 // indirect golang.org/x/crypto v0.48.0 // indirect - golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a // indirect - golang.org/x/net v0.50.0 // indirect - golang.org/x/sys v0.41.0 // indirect + golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa // indirect + golang.org/x/net v0.51.0 // indirect + golang.org/x/sys v0.42.0 // indirect golang.org/x/term v0.40.0 // indirect golang.org/x/text v0.34.0 // indirect - google.golang.org/protobuf v1.36.11 // indirect - modernc.org/libc v1.67.6 // indirect + modernc.org/libc v1.70.0 // indirect modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.11.0 // indirect - rsc.io/qr v0.2.0 // indirect ) diff --git a/go.sum b/go.sum index 739edd6..93b4132 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,8 @@ cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +filippo.io/edwards25519 v1.2.0 h1:crnVqOiS4jqYleHd9vaKZ+HKtHfllngJIiOpNpoJsjo= +filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc= github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= github.com/agnivade/levenshtein v1.2.1 h1:EHBY3UOn1gwdy/VbFwgo4cxecRznFk7fKWN1KOX7eoM= @@ -49,6 +51,8 @@ github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Px github.com/go-resty/resty/v2 v2.6.0/go.mod h1:PwvJS6hvaPkjtjNg9ph+VrSD92bi5Zq73w/BIH7cC3Q= github.com/go-resty/resty/v2 v2.17.1 h1:x3aMpHK1YM9e4va/TMDRlusDDoZiQ+ViDu/WpA6xTM4= github.com/go-resty/resty/v2 v2.17.1/go.mod h1:kCKZ3wWmwJaNc7S29BRtUhJwy7iqmn+2mLtQrOyQlVA= +github.com/go-resty/resty/v2 v2.17.2 h1:FQW5oHYcIlkCNrMD2lloGScxcHJ0gkjshV3qcQAyHQk= +github.com/go-resty/resty/v2 v2.17.2/go.mod h1:kCKZ3wWmwJaNc7S29BRtUhJwy7iqmn+2mLtQrOyQlVA= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -88,8 +92,12 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= +github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= +github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= +github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= @@ -111,6 +119,8 @@ github.com/mdp/qrterminal/v3 v3.2.1 h1:6+yQjiiOsSuXT5n9/m60E54vdgFsw0zhADHhHLrFe github.com/mdp/qrterminal/v3 v3.2.1/go.mod h1:jOTmXvnBsMy5xqLniO0R++Jmjs2sTm9dFSuQ5kpz/SU= github.com/mymmrac/telego v1.6.0 h1:Zc8rgyHozvd/7ZgyrigyHdAF9koHYMfilYfyB6wlFC0= github.com/mymmrac/telego v1.6.0/go.mod h1:xt6ZWA8zi8KmuzryE1ImEdl9JSwjHNpM4yhC7D8hU4Y= +github.com/mymmrac/telego v1.7.0 h1:yRO/l00tFGG4nY66ufUKb4ARqv7qx9+LsjQv/b0NEyo= +github.com/mymmrac/telego v1.7.0/go.mod h1:pdLV346EgVuq7Xrh3kMggeBiazeHhsdEoK0RTEOPXRM= github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w= github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= @@ -125,38 +135,70 @@ github.com/open-dingtalk/dingtalk-stream-sdk-go v0.9.1 h1:Lb/Uzkiw2Ugt2Xf03J5wmv github.com/open-dingtalk/dingtalk-stream-sdk-go v0.9.1/go.mod h1:ln3IqPYYocZbYvl9TAOrG/cxGR9xcn4pnZRLdCTEGEU= github.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741 h1:KPpdlQLZcHfTMQRi6bFQ7ogNO0ltFT4PmtwTLW4W+14= github.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= +github.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6 h1:rh2lKw/P/EqHa724vYH2+VVQ1YnW4u6EOXl0PMAovZE= +github.com/petermattis/goid v0.0.0-20260226131333-17d1149c6ac6/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pion/datachannel v1.5.10 h1:ly0Q26K1i6ZkGf42W7D4hQYR90pZwzFOjTq5AuCKk4o= github.com/pion/datachannel v1.5.10/go.mod h1:p/jJfC9arb29W7WrxyKbepTU20CFgyx5oLo8Rs4Py/M= +github.com/pion/datachannel v1.6.0 h1:XecBlj+cvsxhAMZWFfFcPyUaDZtd7IJvrXqlXD/53i0= +github.com/pion/datachannel v1.6.0/go.mod h1:ur+wzYF8mWdC+Mkis5Thosk+u/VOL287apDNEbFpsIk= github.com/pion/dtls/v3 v3.0.7 h1:bItXtTYYhZwkPFk4t1n3Kkf5TDrfj6+4wG+CZR8uI9Q= github.com/pion/dtls/v3 v3.0.7/go.mod h1:uDlH5VPrgOQIw59irKYkMudSFprY9IEFCqz/eTz16f8= +github.com/pion/dtls/v3 v3.1.2 h1:gqEdOUXLtCGW+afsBLO0LtDD8GnuBBjEy6HRtyofZTc= +github.com/pion/dtls/v3 v3.1.2/go.mod h1:Hw/igcX4pdY69z1Hgv5x7wJFrUkdgHwAn/Q/uo7YHRo= github.com/pion/ice/v4 v4.0.10 h1:P59w1iauC/wPk9PdY8Vjl4fOFL5B+USq1+xbDcN6gT4= github.com/pion/ice/v4 v4.0.10/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw= +github.com/pion/ice/v4 v4.2.1 h1:XPRYXaLiFq3LFDG7a7bMrmr3mFr27G/gtXN3v/TVfxY= +github.com/pion/ice/v4 v4.2.1/go.mod h1:2quLV1S5v1tAx3VvAJaH//KGitRXvo4RKlX6D3tnN+c= github.com/pion/interceptor v0.1.41 h1:NpvX3HgWIukTf2yTBVjVGFXtpSpWgXjqz7IIpu7NsOw= github.com/pion/interceptor v0.1.41/go.mod h1:nEt4187unvRXJFyjiw00GKo+kIuXMWQI9K89fsosDLY= +github.com/pion/interceptor v0.1.44 h1:sNlZwM8dWXU9JQAkJh8xrarC0Etn8Oolcniukmuy0/I= +github.com/pion/interceptor v0.1.44/go.mod h1:4atVlBkcgXuUP+ykQF0qOCGU2j7pQzX2ofvPRFsY5RY= github.com/pion/logging v0.2.4 h1:tTew+7cmQ+Mc1pTBLKH2puKsOvhm32dROumOZ655zB8= github.com/pion/logging v0.2.4/go.mod h1:DffhXTKYdNZU+KtJ5pyQDjvOAh/GsNSyv1lbkFbe3so= github.com/pion/mdns/v2 v2.0.7 h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM= github.com/pion/mdns/v2 v2.0.7/go.mod h1:vAdSYNAT0Jy3Ru0zl2YiW3Rm/fJCwIeM0nToenfOJKA= +github.com/pion/mdns/v2 v2.1.0 h1:3IJ9+Xio6tWYjhN6WwuY142P/1jA0D5ERaIqawg/fOY= +github.com/pion/mdns/v2 v2.1.0/go.mod h1:pcez23GdynwcfRU1977qKU0mDxSeucttSHbCSfFOd9A= github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= github.com/pion/rtcp v1.2.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo= github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0= +github.com/pion/rtcp v1.2.16 h1:fk1B1dNW4hsI78XUCljZJlC4kZOPk67mNRuQ0fcEkSo= +github.com/pion/rtcp v1.2.16/go.mod h1:/as7VKfYbs5NIb4h6muQ35kQF/J0ZVNz2Z3xKoCBYOo= github.com/pion/rtp v1.8.23 h1:kxX3bN4nM97DPrVBGq5I/Xcl332HnTHeP1Swx3/MCnU= github.com/pion/rtp v1.8.23/go.mod h1:rF5nS1GqbR7H/TCpKwylzeq6yDM+MM6k+On5EgeThEM= +github.com/pion/rtp v1.10.1 h1:xP1prZcCTUuhO2c83XtxyOHJteISg6o8iPsE2acaMtA= +github.com/pion/rtp v1.10.1/go.mod h1:rF5nS1GqbR7H/TCpKwylzeq6yDM+MM6k+On5EgeThEM= github.com/pion/sctp v1.8.40 h1:bqbgWYOrUhsYItEnRObUYZuzvOMsVplS3oNgzedBlG8= github.com/pion/sctp v1.8.40/go.mod h1:SPBBUENXE6ThkEksN5ZavfAhFYll+h+66ZiG6IZQuzo= +github.com/pion/sctp v1.9.2 h1:HxsOzEV9pWoeggv7T5kewVkstFNcGvhMPx0GvUOUQXo= +github.com/pion/sctp v1.9.2/go.mod h1:OTOlsQ5EDQ6mQ0z4MUGXt2CgQmKyafBEXhUVqLRB6G8= github.com/pion/sdp/v3 v3.0.16 h1:0dKzYO6gTAvuLaAKQkC02eCPjMIi4NuAr/ibAwrGDCo= github.com/pion/sdp/v3 v3.0.16/go.mod h1:9tyKzznud3qiweZcD86kS0ff1pGYB3VX+Bcsmkx6IXo= +github.com/pion/sdp/v3 v3.0.18 h1:l0bAXazKHpepazVdp+tPYnrsy9dfh7ZbT8DxesH5ZnI= +github.com/pion/sdp/v3 v3.0.18/go.mod h1:ZREGo6A9ZygQ9XkqAj5xYCQtQpif0i6Pa81HOiAdqQ8= github.com/pion/srtp/v3 v3.0.8 h1:RjRrjcIeQsilPzxvdaElN0CpuQZdMvcl9VZ5UY9suUM= github.com/pion/srtp/v3 v3.0.8/go.mod h1:2Sq6YnDH7/UDCvkSoHSDNDeyBcFgWL0sAVycVbAsXFg= +github.com/pion/srtp/v3 v3.0.10 h1:tFirkpBb3XccP5VEXLi50GqXhv5SKPxqrdlhDCJlZrQ= +github.com/pion/srtp/v3 v3.0.10/go.mod h1:3mOTIB0cq9qlbn59V4ozvv9ClW/BSEbRp4cY0VtaR7M= github.com/pion/stun/v3 v3.0.0 h1:4h1gwhWLWuZWOJIJR9s2ferRO+W3zA/b6ijOI6mKzUw= github.com/pion/stun/v3 v3.0.0/go.mod h1:HvCN8txt8mwi4FBvS3EmDghW6aQJ24T+y+1TKjB5jyU= +github.com/pion/stun/v3 v3.1.1 h1:CkQxveJ4xGQjulGSROXbXq94TAWu8gIX2dT+ePhUkqw= +github.com/pion/stun/v3 v3.1.1/go.mod h1:qC1DfmcCTQjl9PBaMa5wSn3x9IPmKxSdcCsxBcDBndM= github.com/pion/transport/v3 v3.0.8 h1:oI3myyYnTKUSTthu/NZZ8eu2I5sHbxbUNNFW62olaYc= github.com/pion/transport/v3 v3.0.8/go.mod h1:+c2eewC5WJQHiAA46fkMMzoYZSuGzA/7E2FPrOYHctQ= +github.com/pion/transport/v3 v3.1.1 h1:Tr684+fnnKlhPceU+ICdrw6KKkTms+5qHMgw6bIkYOM= +github.com/pion/transport/v3 v3.1.1/go.mod h1:+c2eewC5WJQHiAA46fkMMzoYZSuGzA/7E2FPrOYHctQ= +github.com/pion/transport/v4 v4.0.1 h1:sdROELU6BZ63Ab7FrOLn13M6YdJLY20wldXW2Cu2k8o= +github.com/pion/transport/v4 v4.0.1/go.mod h1:nEuEA4AD5lPdcIegQDpVLgNoDGreqM/YqmEx3ovP4jM= github.com/pion/turn/v4 v4.1.1 h1:9UnY2HB99tpDyz3cVVZguSxcqkJ1DsTSZ+8TGruh4fc= github.com/pion/turn/v4 v4.1.1/go.mod h1:2123tHk1O++vmjI5VSD0awT50NywDAq5A2NNNU4Jjs8= +github.com/pion/turn/v4 v4.1.4 h1:EU11yMXKIsK43FhcUnjLlrhE4nboHZq+TXBIi3QpcxQ= +github.com/pion/turn/v4 v4.1.4/go.mod h1:ES1DXVFKnOhuDkqn9hn5VJlSWmZPaRJLyBXoOeO/BmQ= github.com/pion/webrtc/v4 v4.1.6 h1:srHH2HwvCGwPba25EYJgUzgLqCQoXl1VCUnrGQMSzUw= github.com/pion/webrtc/v4 v4.1.6/go.mod h1:wKecGRlkl3ox/As/MYghJL+b/cVXMEhoPMJWPuGQFhU= +github.com/pion/webrtc/v4 v4.2.9 h1:DZIh1HAhPIL3RvwEDFsmL5hfPSLEpxsQk9/Jir2vkJE= +github.com/pion/webrtc/v4 v4.2.9/go.mod h1:9EmLZve0H76eTzf8v2FmchZ6tcBXtDgpfTEu+drW6SY= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -203,8 +245,12 @@ github.com/valyala/fasthttp v1.69.0 h1:fNLLESD2SooWeh2cidsuFtOcrEi4uB4m1mPrkJMZy github.com/valyala/fasthttp v1.69.0/go.mod h1:4wA4PfAraPlAsJ5jMSqCE2ug5tqUPwKXxVj8oNECGcw= github.com/valyala/fastjson v1.6.7 h1:ZE4tRy0CIkh+qDc5McjatheGX2czdn8slQjomexVpBM= github.com/valyala/fastjson v1.6.7/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= +github.com/valyala/fastjson v1.6.10 h1:/yjJg8jaVQdYR3arGxPE2X5z89xrlhS0eGXdv+ADTh4= +github.com/valyala/fastjson v1.6.10/go.mod h1:e6FubmQouUNP73jtMLmcbxS6ydWIpOfhz34TSfO3JaE= github.com/vektah/gqlparser/v2 v2.5.27 h1:RHPD3JOplpk5mP5JGX8RKZkt2/Vwj/PZv0HxTdwFp0s= github.com/vektah/gqlparser/v2 v2.5.27/go.mod h1:D1/VCZtV3LPnQrcPBeR/q5jkSQIPti0uYCP/RI0gIeo= +github.com/vektah/gqlparser/v2 v2.5.32 h1:k9QPJd4sEDTL+qB4ncPLflqTJ3MmjB9SrVzJrawpFSc= +github.com/vektah/gqlparser/v2 v2.5.32/go.mod h1:c1I28gSOVNzlfc4WuDlqU7voQnsqI6OG2amkBAFmgts= github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU= github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= @@ -222,6 +268,8 @@ go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.25.0 h1:qnk6Ksugpi5Bz32947rkUgDt9/s5qvqDPl/gBKdMJLE= +golang.org/x/arch v0.25.0/go.mod h1:0X+GdSIP+kL5wPmpK7sdkEVTt2XoYP0cSjQSbZBwOi8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -232,6 +280,8 @@ golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a h1:ovFr6Z0MNmU7nH8VaX5xqw+05ST2uO1exVfZPVqRC5o= golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA= +golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa h1:Zt3DZoOFFYkKhDT3v7Lm9FDMEV06GpzjG2jrqW+QTE0= +golang.org/x/exp v0.0.0-20260218203240-3dfff04db8fa/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -253,9 +303,13 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= +golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo= +golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ= golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= +golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -264,6 +318,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -288,6 +344,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -306,6 +364,8 @@ golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= +golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -346,16 +406,21 @@ modernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis= modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= modernc.org/ccgo/v4 v4.30.1 h1:4r4U1J6Fhj98NKfSjnPUN7Ze2c6MnAdL0hWw6+LrJpc= modernc.org/ccgo/v4 v4.30.1/go.mod h1:bIOeI1JL54Utlxn+LwrFyjCx2n2RDiYEaJVSrgdrRfM= +modernc.org/ccgo/v4 v4.32.0 h1:hjG66bI/kqIPX1b2yT6fr/jt+QedtP2fqojG2VrFuVw= modernc.org/fileutil v1.3.40 h1:ZGMswMNc9JOCrcrakF1HrvmergNLAmxOPjizirpfqBA= modernc.org/fileutil v1.3.40/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc= +modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM= modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= modernc.org/gc/v3 v3.1.1 h1:k8T3gkXWY9sEiytKhcgyiZ2L0DTyCQ/nvX+LoCljoRE= modernc.org/gc/v3 v3.1.1/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY= +modernc.org/gc/v3 v3.1.2 h1:ZtDCnhonXSZexk/AYsegNRV1lJGgaNZJuKjJSWKyEqo= modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= modernc.org/libc v1.67.6 h1:eVOQvpModVLKOdT+LvBPjdQqfrZq+pC39BygcT+E7OI= modernc.org/libc v1.67.6/go.mod h1:JAhxUVlolfYDErnwiqaLvUqc8nfb2r6S6slAgZOnaiE= +modernc.org/libc v1.70.0 h1:U58NawXqXbgpZ/dcdS9kMshu08aiA6b7gusEusqzNkw= +modernc.org/libc v1.70.0/go.mod h1:OVmxFGP1CI/Z4L3E0Q3Mf1PDE0BucwMkcXjjLntvHJo= modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= diff --git a/pkg/agent/context.go b/pkg/agent/context.go index d309950..2124a02 100644 --- a/pkg/agent/context.go +++ b/pkg/agent/context.go @@ -8,9 +8,9 @@ import ( "strings" "time" - "clawgo/pkg/logger" - "clawgo/pkg/providers" - "clawgo/pkg/skills" + "github.com/YspCoder/clawgo/pkg/logger" + "github.com/YspCoder/clawgo/pkg/providers" + "github.com/YspCoder/clawgo/pkg/skills" ) type ContextBuilder struct { diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index 701bea8..5d5e996 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -23,17 +23,17 @@ import ( "time" "unicode/utf8" - "clawgo/pkg/bus" - "clawgo/pkg/config" - "clawgo/pkg/cron" - "clawgo/pkg/ekg" - "clawgo/pkg/logger" - "clawgo/pkg/nodes" - "clawgo/pkg/providers" - "clawgo/pkg/runtimecfg" - "clawgo/pkg/scheduling" - "clawgo/pkg/session" - "clawgo/pkg/tools" + "github.com/YspCoder/clawgo/pkg/bus" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/cron" + "github.com/YspCoder/clawgo/pkg/ekg" + "github.com/YspCoder/clawgo/pkg/logger" + "github.com/YspCoder/clawgo/pkg/nodes" + "github.com/YspCoder/clawgo/pkg/providers" + "github.com/YspCoder/clawgo/pkg/runtimecfg" + "github.com/YspCoder/clawgo/pkg/scheduling" + "github.com/YspCoder/clawgo/pkg/session" + "github.com/YspCoder/clawgo/pkg/tools" ) type AgentLoop struct { diff --git a/pkg/agent/loop_nodes_p2p_test.go b/pkg/agent/loop_nodes_p2p_test.go index d026c85..2d11472 100644 --- a/pkg/agent/loop_nodes_p2p_test.go +++ b/pkg/agent/loop_nodes_p2p_test.go @@ -3,8 +3,8 @@ package agent import ( "testing" - "clawgo/pkg/bus" - "clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/bus" + "github.com/YspCoder/clawgo/pkg/config" ) func TestNewAgentLoopDisablesNodeP2PByDefault(t *testing.T) { diff --git a/pkg/agent/loop_skill_exec_test.go b/pkg/agent/loop_skill_exec_test.go index 00adddc..0de146d 100644 --- a/pkg/agent/loop_skill_exec_test.go +++ b/pkg/agent/loop_skill_exec_test.go @@ -4,9 +4,9 @@ import ( "context" "testing" - "clawgo/pkg/bus" - "clawgo/pkg/config" - "clawgo/pkg/providers" + "github.com/YspCoder/clawgo/pkg/bus" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/providers" ) type stubLLMProvider struct{} diff --git a/pkg/agent/loop_system_notify_test.go b/pkg/agent/loop_system_notify_test.go index ec845f9..4004c9b 100644 --- a/pkg/agent/loop_system_notify_test.go +++ b/pkg/agent/loop_system_notify_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - "clawgo/pkg/bus" + "github.com/YspCoder/clawgo/pkg/bus" ) func TestPrepareOutboundSubagentNoReplyFallback(t *testing.T) { diff --git a/pkg/agent/memory_log_test.go b/pkg/agent/memory_log_test.go index 7d40385..2073aae 100644 --- a/pkg/agent/memory_log_test.go +++ b/pkg/agent/memory_log_test.go @@ -7,9 +7,9 @@ import ( "testing" "time" - "clawgo/pkg/bus" - "clawgo/pkg/config" - "clawgo/pkg/runtimecfg" + "github.com/YspCoder/clawgo/pkg/bus" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/runtimecfg" ) func TestAppendDailySummaryLogUsesSubagentNamespaceAndTitle(t *testing.T) { diff --git a/pkg/agent/router_dispatch.go b/pkg/agent/router_dispatch.go index c755d99..b00d245 100644 --- a/pkg/agent/router_dispatch.go +++ b/pkg/agent/router_dispatch.go @@ -5,10 +5,10 @@ import ( "strings" "time" - "clawgo/pkg/bus" - "clawgo/pkg/config" - "clawgo/pkg/runtimecfg" - "clawgo/pkg/tools" + "github.com/YspCoder/clawgo/pkg/bus" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/runtimecfg" + "github.com/YspCoder/clawgo/pkg/tools" ) func (al *AgentLoop) maybeAutoRoute(ctx context.Context, msg bus.InboundMessage) (string, bool, error) { diff --git a/pkg/agent/router_dispatch_test.go b/pkg/agent/router_dispatch_test.go index a14ae83..0b03221 100644 --- a/pkg/agent/router_dispatch_test.go +++ b/pkg/agent/router_dispatch_test.go @@ -4,10 +4,10 @@ import ( "context" "testing" - "clawgo/pkg/bus" - "clawgo/pkg/config" - "clawgo/pkg/runtimecfg" - "clawgo/pkg/tools" + "github.com/YspCoder/clawgo/pkg/bus" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/runtimecfg" + "github.com/YspCoder/clawgo/pkg/tools" ) func TestResolveAutoRouteTarget(t *testing.T) { @@ -27,9 +27,9 @@ func TestResolveAutoRouteTargetRulesFirst(t *testing.T) { cfg.Agents.Router.Strategy = "rules_first" cfg.Agents.Subagents["coder"] = config.SubagentConfig{Enabled: true, Role: "coding", SystemPromptFile: "agents/coder/AGENT.md"} cfg.Agents.Subagents["tester"] = config.SubagentConfig{Enabled: true, Role: "testing", SystemPromptFile: "agents/tester/AGENT.md"} - cfg.Agents.Router.Rules = []config.AgentRouteRule{{AgentID: "coder", Keywords: []string{"登录", "bug"}}} + cfg.Agents.Router.Rules = []config.AgentRouteRule{{AgentID: "coder", Keywords: []string{"鐧诲綍", "bug"}}} - agentID, task := resolveAutoRouteTarget(cfg, "请帮我修复登录接口的 bug 并改代码") + agentID, task := resolveAutoRouteTarget(cfg, "璇峰府鎴戜慨澶嶇櫥褰曟帴鍙g殑 bug 骞舵敼浠g爜") if agentID != "coder" || task == "" { t.Fatalf("expected coder route, got %s / %s", agentID, task) } @@ -113,7 +113,7 @@ func TestMaybeAutoRouteDispatchesRulesFirstMatch(t *testing.T) { Channel: "cli", ChatID: "direct", SessionKey: "main", - Content: "请做一次回归测试并验证这个修复", + Content: "璇峰仛涓€娆″洖褰掓祴璇曞苟楠岃瘉杩欎釜淇", }) if err != nil { t.Fatalf("rules-first auto route failed: %v", err) diff --git a/pkg/agent/runtime_admin.go b/pkg/agent/runtime_admin.go index dee2387..66a02ee 100644 --- a/pkg/agent/runtime_admin.go +++ b/pkg/agent/runtime_admin.go @@ -10,9 +10,9 @@ import ( "strings" "time" - "clawgo/pkg/config" - "clawgo/pkg/runtimecfg" - "clawgo/pkg/tools" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/runtimecfg" + "github.com/YspCoder/clawgo/pkg/tools" ) func (al *AgentLoop) HandleSubagentRuntime(ctx context.Context, action string, args map[string]interface{}) (interface{}, error) { diff --git a/pkg/agent/runtime_admin_test.go b/pkg/agent/runtime_admin_test.go index ae2927d..042eb06 100644 --- a/pkg/agent/runtime_admin_test.go +++ b/pkg/agent/runtime_admin_test.go @@ -7,9 +7,9 @@ import ( "testing" "time" - "clawgo/pkg/config" - "clawgo/pkg/runtimecfg" - "clawgo/pkg/tools" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/runtimecfg" + "github.com/YspCoder/clawgo/pkg/tools" ) func TestHandleSubagentRuntimeDispatchAndWait(t *testing.T) { diff --git a/pkg/agent/session_planner.go b/pkg/agent/session_planner.go index 21a1f39..48c2a55 100644 --- a/pkg/agent/session_planner.go +++ b/pkg/agent/session_planner.go @@ -14,10 +14,10 @@ import ( "sync" "time" - "clawgo/pkg/bus" - "clawgo/pkg/ekg" - "clawgo/pkg/providers" - "clawgo/pkg/scheduling" + "github.com/YspCoder/clawgo/pkg/bus" + "github.com/YspCoder/clawgo/pkg/ekg" + "github.com/YspCoder/clawgo/pkg/providers" + "github.com/YspCoder/clawgo/pkg/scheduling" ) type plannedTask struct { diff --git a/pkg/agent/session_planner_split_test.go b/pkg/agent/session_planner_split_test.go index 9e0606a..9d03462 100644 --- a/pkg/agent/session_planner_split_test.go +++ b/pkg/agent/session_planner_split_test.go @@ -4,8 +4,8 @@ import ( "context" "testing" - "clawgo/pkg/bus" - "clawgo/pkg/providers" + "github.com/YspCoder/clawgo/pkg/bus" + "github.com/YspCoder/clawgo/pkg/providers" ) func TestSplitPlannedSegmentsDoesNotSplitPlainNewlines(t *testing.T) { diff --git a/pkg/agent/session_scheduler.go b/pkg/agent/session_scheduler.go index 2eb461e..7a28467 100644 --- a/pkg/agent/session_scheduler.go +++ b/pkg/agent/session_scheduler.go @@ -7,7 +7,7 @@ import ( "sync" "sync/atomic" - "clawgo/pkg/scheduling" + "github.com/YspCoder/clawgo/pkg/scheduling" ) const ( diff --git a/pkg/agent/subagent_config_intent.go b/pkg/agent/subagent_config_intent.go index 94a74c0..d8244a4 100644 --- a/pkg/agent/subagent_config_intent.go +++ b/pkg/agent/subagent_config_intent.go @@ -6,8 +6,8 @@ import ( "path/filepath" "strings" - "clawgo/pkg/bus" - "clawgo/pkg/tools" + "github.com/YspCoder/clawgo/pkg/bus" + "github.com/YspCoder/clawgo/pkg/tools" ) func (al *AgentLoop) maybeHandleSubagentConfigIntent(ctx context.Context, msg bus.InboundMessage) (string, bool, error) { diff --git a/pkg/agent/subagent_node_test.go b/pkg/agent/subagent_node_test.go index 04cd82c..9c5106d 100644 --- a/pkg/agent/subagent_node_test.go +++ b/pkg/agent/subagent_node_test.go @@ -5,8 +5,8 @@ import ( "strings" "testing" - "clawgo/pkg/nodes" - "clawgo/pkg/tools" + "github.com/YspCoder/clawgo/pkg/nodes" + "github.com/YspCoder/clawgo/pkg/tools" ) func TestDispatchNodeSubagentTaskUsesNodeAgentTask(t *testing.T) { diff --git a/pkg/agent/subagent_prompt_test.go b/pkg/agent/subagent_prompt_test.go index c8d18bd..23f8c39 100644 --- a/pkg/agent/subagent_prompt_test.go +++ b/pkg/agent/subagent_prompt_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "clawgo/pkg/tools" + "github.com/YspCoder/clawgo/pkg/tools" ) func TestBuildSubagentTaskInputPrefersPromptFile(t *testing.T) { diff --git a/pkg/agent/trigger_audit.go b/pkg/agent/trigger_audit.go index 25145df..8364d05 100644 --- a/pkg/agent/trigger_audit.go +++ b/pkg/agent/trigger_audit.go @@ -19,12 +19,12 @@ type triggerAudit struct { } type triggerEvent struct { - Time string `json:"time"` - Trigger string `json:"trigger"` - Channel string `json:"channel"` - Session string `json:"session"` + Time string `json:"time"` + Trigger string `json:"trigger"` + Channel string `json:"channel"` + Session string `json:"session"` Suppressed bool `json:"suppressed,omitempty"` - Error string `json:"error,omitempty"` + Error string `json:"error,omitempty"` } func newTriggerAudit(workspace string) *triggerAudit { @@ -37,10 +37,10 @@ func (ta *triggerAudit) Record(trigger, channel, session string, suppressed bool } trigger = normalizeTrigger(trigger) e := triggerEvent{ - Time: time.Now().UTC().Format(time.RFC3339), - Trigger: trigger, - Channel: channel, - Session: session, + Time: time.Now().UTC().Format(time.RFC3339), + Trigger: trigger, + Channel: channel, + Session: session, Suppressed: suppressed, } if err != nil { diff --git a/pkg/api/server.go b/pkg/api/server.go index 708ebe7..e05c0f5 100644 --- a/pkg/api/server.go +++ b/pkg/api/server.go @@ -28,10 +28,10 @@ import ( "sync" "time" - "clawgo/pkg/channels" - cfgpkg "clawgo/pkg/config" - "clawgo/pkg/nodes" - "clawgo/pkg/tools" + "github.com/YspCoder/clawgo/pkg/channels" + cfgpkg "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/nodes" + "github.com/YspCoder/clawgo/pkg/tools" "github.com/gorilla/websocket" "rsc.io/qr" ) diff --git a/pkg/api/server_test.go b/pkg/api/server_test.go index 3f0fee2..744e5a4 100644 --- a/pkg/api/server_test.go +++ b/pkg/api/server_test.go @@ -15,8 +15,8 @@ import ( "testing" "time" - cfgpkg "clawgo/pkg/config" - "clawgo/pkg/nodes" + cfgpkg "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/nodes" "github.com/gorilla/websocket" ) diff --git a/pkg/bus/bus.go b/pkg/bus/bus.go index c458def..0134c73 100644 --- a/pkg/bus/bus.go +++ b/pkg/bus/bus.go @@ -1,8 +1,8 @@ package bus import ( - "clawgo/pkg/logger" "context" + "github.com/YspCoder/clawgo/pkg/logger" "sync" "time" ) diff --git a/pkg/channels/base.go b/pkg/channels/base.go index 7c6ad7d..23af234 100644 --- a/pkg/channels/base.go +++ b/pkg/channels/base.go @@ -10,8 +10,8 @@ import ( "sync/atomic" "time" - "clawgo/pkg/bus" - "clawgo/pkg/logger" + "github.com/YspCoder/clawgo/pkg/bus" + "github.com/YspCoder/clawgo/pkg/logger" ) type Channel interface { diff --git a/pkg/channels/dedupe_regression_test.go b/pkg/channels/dedupe_regression_test.go index d15b229..169d772 100644 --- a/pkg/channels/dedupe_regression_test.go +++ b/pkg/channels/dedupe_regression_test.go @@ -6,8 +6,8 @@ import ( "testing" "time" - "clawgo/pkg/bus" - "clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/bus" + "github.com/YspCoder/clawgo/pkg/config" ) type recordingChannel struct { @@ -15,11 +15,11 @@ type recordingChannel struct { sent []bus.OutboundMessage } -func (r *recordingChannel) Name() string { return "test" } -func (r *recordingChannel) Start(ctx context.Context) error { return nil } -func (r *recordingChannel) Stop(ctx context.Context) error { return nil } -func (r *recordingChannel) IsRunning() bool { return true } -func (r *recordingChannel) IsAllowed(senderID string) bool { return true } +func (r *recordingChannel) Name() string { return "test" } +func (r *recordingChannel) Start(ctx context.Context) error { return nil } +func (r *recordingChannel) Stop(ctx context.Context) error { return nil } +func (r *recordingChannel) IsRunning() bool { return true } +func (r *recordingChannel) IsAllowed(senderID string) bool { return true } func (r *recordingChannel) HealthCheck(ctx context.Context) error { return nil } func (r *recordingChannel) Send(ctx context.Context, msg bus.OutboundMessage) error { r.mu.Lock() @@ -78,7 +78,6 @@ func TestBaseChannel_HandleMessage_ContentHashFallbackDedupe(t *testing.T) { } } - func TestDispatchOutbound_DifferentButtonsShouldNotDeduplicate(t *testing.T) { mb := bus.NewMessageBus() mgr, err := NewManager(&config.Config{}, mb) diff --git a/pkg/channels/dingtalk.go b/pkg/channels/dingtalk.go index b4e0398..4ba73ca 100644 --- a/pkg/channels/dingtalk.go +++ b/pkg/channels/dingtalk.go @@ -8,9 +8,9 @@ import ( "fmt" "sync" - "clawgo/pkg/bus" - "clawgo/pkg/config" - "clawgo/pkg/logger" + "github.com/YspCoder/clawgo/pkg/bus" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/logger" "github.com/open-dingtalk/dingtalk-stream-sdk-go/chatbot" "github.com/open-dingtalk/dingtalk-stream-sdk-go/client" ) diff --git a/pkg/channels/discord.go b/pkg/channels/discord.go index f820120..47b70a8 100644 --- a/pkg/channels/discord.go +++ b/pkg/channels/discord.go @@ -1,11 +1,11 @@ package channels import ( - "clawgo/pkg/bus" - "clawgo/pkg/config" - "clawgo/pkg/logger" "context" "fmt" + "github.com/YspCoder/clawgo/pkg/bus" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/logger" "io" "net/http" "os" diff --git a/pkg/channels/feishu.go b/pkg/channels/feishu.go index 5339a58..af6188e 100644 --- a/pkg/channels/feishu.go +++ b/pkg/channels/feishu.go @@ -22,9 +22,9 @@ import ( larksheets "github.com/larksuite/oapi-sdk-go/v3/service/sheets/v3" larkws "github.com/larksuite/oapi-sdk-go/v3/ws" - "clawgo/pkg/bus" - "clawgo/pkg/config" - "clawgo/pkg/logger" + "github.com/YspCoder/clawgo/pkg/bus" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/logger" ) type FeishuChannel struct { @@ -135,7 +135,7 @@ func (c *FeishuChannel) Send(ctx context.Context, msg bus.OutboundMessage) error logger.WarnCF("feishu", logger.C0045, map[string]interface{}{logger.FieldError: lerr.Error(), logger.FieldChatID: msg.ChatID}) continue } - links = append(links, fmt.Sprintf("表格%d: %s", i+1, link)) + links = append(links, fmt.Sprintf("琛ㄦ牸%d: %s", i+1, link)) } if len(links) > 0 { if strings.TrimSpace(workMsg.Content) != "" { @@ -903,9 +903,9 @@ func normalizeFeishuText(s string) string { // Headers: "## title" -> "title" s = regexp.MustCompile(`(?m)^#{1,6}\s+`).ReplaceAllString(s, "") // Bullet styles - s = regexp.MustCompile(`(?m)^[-*]\s+`).ReplaceAllString(s, "• ") + s = regexp.MustCompile(`(?m)^[-*]\s+`).ReplaceAllString(s, "鈥?") // Ordered list to bullet for readability - s = regexp.MustCompile(`(?m)^\d+\.\s+`).ReplaceAllString(s, "• ") + s = regexp.MustCompile(`(?m)^\d+\.\s+`).ReplaceAllString(s, "鈥?") // Bold/italic/strike markers s = regexp.MustCompile(`\*\*(.*?)\*\*`).ReplaceAllString(s, `$1`) s = regexp.MustCompile(`__(.*?)__`).ReplaceAllString(s, `$1`) diff --git a/pkg/channels/maixcam.go b/pkg/channels/maixcam.go index e97e713..0520ff8 100644 --- a/pkg/channels/maixcam.go +++ b/pkg/channels/maixcam.go @@ -7,9 +7,9 @@ import ( "net" "sync" - "clawgo/pkg/bus" - "clawgo/pkg/config" - "clawgo/pkg/logger" + "github.com/YspCoder/clawgo/pkg/bus" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/logger" ) type MaixCamChannel struct { @@ -161,7 +161,7 @@ func (c *MaixCamChannel) handlePersonDetection(msg MaixCamMessage) { w, _ := msg.Data["w"].(float64) h, _ := msg.Data["h"].(float64) - content := fmt.Sprintf("📷 Person detected!\nClass: %s\nConfidence: %.2f%%\nPosition: (%.0f, %.0f)\nSize: %.0fx%.0f", + content := fmt.Sprintf("馃摲 Person detected!\nClass: %s\nConfidence: %.2f%%\nPosition: (%.0f, %.0f)\nSize: %.0fx%.0f", classInfo, score*100, x, y, w, h) metadata := map[string]string{ diff --git a/pkg/channels/manager.go b/pkg/channels/manager.go index 3670b0f..34dbc38 100644 --- a/pkg/channels/manager.go +++ b/pkg/channels/manager.go @@ -16,9 +16,9 @@ import ( "sync/atomic" "time" - "clawgo/pkg/bus" - "clawgo/pkg/config" - "clawgo/pkg/logger" + "github.com/YspCoder/clawgo/pkg/bus" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/logger" "golang.org/x/sync/errgroup" "golang.org/x/time/rate" ) diff --git a/pkg/channels/qq.go b/pkg/channels/qq.go index 9399645..1e9bb59 100644 --- a/pkg/channels/qq.go +++ b/pkg/channels/qq.go @@ -13,9 +13,9 @@ import ( "github.com/tencent-connect/botgo/token" "golang.org/x/oauth2" - "clawgo/pkg/bus" - "clawgo/pkg/config" - "clawgo/pkg/logger" + "github.com/YspCoder/clawgo/pkg/bus" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/logger" ) type QQChannel struct { diff --git a/pkg/channels/telegram.go b/pkg/channels/telegram.go index 7bae6a7..113d7d0 100644 --- a/pkg/channels/telegram.go +++ b/pkg/channels/telegram.go @@ -20,9 +20,9 @@ import ( "github.com/mymmrac/telego/telegoutil" "golang.org/x/time/rate" - "clawgo/pkg/bus" - "clawgo/pkg/config" - "clawgo/pkg/logger" + "github.com/YspCoder/clawgo/pkg/bus" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/logger" ) const ( @@ -1144,15 +1144,15 @@ func markdownToTelegramHTML(text string) string { text = escapeHTML(text) text = regexp.MustCompile("(?m)^#{1,6}\\s+(.+)$").ReplaceAllString(text, "$1") - text = regexp.MustCompile("(?m)^>\\s*(.*)$").ReplaceAllString(text, "│ $1") + text = regexp.MustCompile("(?m)^>\\s*(.*)$").ReplaceAllString(text, "鈹?$1") text = regexp.MustCompile("\\[([^\\]]+)\\]\\(([^)]+)\\)").ReplaceAllString(text, `$1`) text = regexp.MustCompile("\\*\\*(.+?)\\*\\*").ReplaceAllString(text, "$1") text = regexp.MustCompile("__(.+?)__").ReplaceAllString(text, "$1") text = regexp.MustCompile("\\*([^*\\n]+)\\*").ReplaceAllString(text, "$1") text = regexp.MustCompile("_([^_\\n]+)_").ReplaceAllString(text, "$1") text = regexp.MustCompile("~~(.+?)~~").ReplaceAllString(text, "$1") - text = regexp.MustCompile("(?m)^[-*]\\s+").ReplaceAllString(text, "• ") - text = regexp.MustCompile("(?m)^\\d+\\.\\s+").ReplaceAllString(text, "• ") + text = regexp.MustCompile("(?m)^[-*]\\s+").ReplaceAllString(text, "鈥?") + text = regexp.MustCompile("(?m)^\\d+\\.\\s+").ReplaceAllString(text, "鈥?") for i, code := range inlineCodes.codes { escaped := escapeHTML(code) diff --git a/pkg/channels/utils.go b/pkg/channels/utils.go index 1704e36..a1f38ea 100644 --- a/pkg/channels/utils.go +++ b/pkg/channels/utils.go @@ -5,7 +5,7 @@ import ( "errors" "sync" - "clawgo/pkg/logger" + "github.com/YspCoder/clawgo/pkg/logger" ) func truncateString(s string, maxLen int) string { diff --git a/pkg/channels/whatsapp.go b/pkg/channels/whatsapp.go index 9708a9c..5463470 100644 --- a/pkg/channels/whatsapp.go +++ b/pkg/channels/whatsapp.go @@ -13,9 +13,9 @@ import ( "github.com/gorilla/websocket" - "clawgo/pkg/bus" - "clawgo/pkg/config" - "clawgo/pkg/logger" + "github.com/YspCoder/clawgo/pkg/bus" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/logger" ) type WhatsAppChannel struct { diff --git a/pkg/channels/whatsapp_bridge_test.go b/pkg/channels/whatsapp_bridge_test.go index 8855dbe..7b5779d 100644 --- a/pkg/channels/whatsapp_bridge_test.go +++ b/pkg/channels/whatsapp_bridge_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - "clawgo/pkg/bus" + "github.com/YspCoder/clawgo/pkg/bus" waProto "go.mau.fi/whatsmeow/proto/waE2E" "go.mau.fi/whatsmeow/types" "google.golang.org/protobuf/proto" diff --git a/pkg/channels/whatsapp_test.go b/pkg/channels/whatsapp_test.go index cf444ed..35293c3 100644 --- a/pkg/channels/whatsapp_test.go +++ b/pkg/channels/whatsapp_test.go @@ -3,7 +3,7 @@ package channels import ( "testing" - "clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/config" ) func TestWhatsAppShouldHandleIncomingMessage(t *testing.T) { diff --git a/pkg/configops/configops.go b/pkg/configops/configops.go index 371c954..17c468d 100644 --- a/pkg/configops/configops.go +++ b/pkg/configops/configops.go @@ -9,7 +9,7 @@ import ( "strings" "syscall" - "clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/config" ) func LoadConfigAsMap(path string) (map[string]interface{}, error) { diff --git a/pkg/cron/service.go b/pkg/cron/service.go index cb8236a..52a45db 100644 --- a/pkg/cron/service.go +++ b/pkg/cron/service.go @@ -10,7 +10,7 @@ import ( "sync" "time" - "clawgo/pkg/lifecycle" + "github.com/YspCoder/clawgo/pkg/lifecycle" robcron "github.com/robfig/cron/v3" ) diff --git a/pkg/heartbeat/service.go b/pkg/heartbeat/service.go index 8d27069..9cd2e0a 100644 --- a/pkg/heartbeat/service.go +++ b/pkg/heartbeat/service.go @@ -7,7 +7,7 @@ import ( "strings" "time" - "clawgo/pkg/lifecycle" + "github.com/YspCoder/clawgo/pkg/lifecycle" ) type HeartbeatService struct { diff --git a/pkg/providers/http_provider.go b/pkg/providers/http_provider.go index bdc31ab..af5963a 100644 --- a/pkg/providers/http_provider.go +++ b/pkg/providers/http_provider.go @@ -3,11 +3,11 @@ package providers import ( "bufio" "bytes" - "clawgo/pkg/config" - "clawgo/pkg/logger" "context" "encoding/json" "fmt" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/logger" "io" "net/http" "net/url" diff --git a/pkg/runtimecfg/snapshot.go b/pkg/runtimecfg/snapshot.go index 12db9a6..409fbcc 100644 --- a/pkg/runtimecfg/snapshot.go +++ b/pkg/runtimecfg/snapshot.go @@ -3,7 +3,7 @@ package runtimecfg import ( "sync/atomic" - "clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/config" ) var current atomic.Value // *config.Config diff --git a/pkg/sentinel/service.go b/pkg/sentinel/service.go index d13ad9d..e18651c 100644 --- a/pkg/sentinel/service.go +++ b/pkg/sentinel/service.go @@ -8,10 +8,10 @@ import ( "sync" "time" - "clawgo/pkg/channels" - "clawgo/pkg/config" - "clawgo/pkg/lifecycle" - "clawgo/pkg/logger" + "github.com/YspCoder/clawgo/pkg/channels" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/lifecycle" + "github.com/YspCoder/clawgo/pkg/logger" ) type AlertFunc func(msg string) diff --git a/pkg/server/server.go b/pkg/server/server.go index d834ec3..eeae76c 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -6,8 +6,8 @@ import ( "net/http" "time" - "clawgo/pkg/config" - "clawgo/pkg/logger" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/logger" ) type Server struct { diff --git a/pkg/session/manager.go b/pkg/session/manager.go index cf79088..9dd9d67 100644 --- a/pkg/session/manager.go +++ b/pkg/session/manager.go @@ -12,7 +12,7 @@ import ( "sync" "time" - "clawgo/pkg/providers" + "github.com/YspCoder/clawgo/pkg/providers" ) type Session struct { diff --git a/pkg/tools/browser.go b/pkg/tools/browser.go index ad76373..19cfe88 100644 --- a/pkg/tools/browser.go +++ b/pkg/tools/browser.go @@ -6,7 +6,7 @@ import ( "path/filepath" "time" - "clawgo/pkg/browser" + "github.com/YspCoder/clawgo/pkg/browser" ) type BrowserTool struct { diff --git a/pkg/tools/camera.go b/pkg/tools/camera.go index b28e6e0..686b789 100644 --- a/pkg/tools/camera.go +++ b/pkg/tools/camera.go @@ -46,13 +46,13 @@ func (t *CameraTool) Execute(ctx context.Context, args map[string]interface{}) ( } else { filename = fmt.Sprintf("snap_%d.jpg", time.Now().Unix()) } - + // Ensure filename is safe and within workspace filename = filepath.Clean(filename) if filepath.IsAbs(filename) { return "", fmt.Errorf("filename must be relative to workspace") } - + outputPath := filepath.Join(t.workspace, filename) // Check if video device exists diff --git a/pkg/tools/cron_tool.go b/pkg/tools/cron_tool.go index 9ce6f56..d865118 100644 --- a/pkg/tools/cron_tool.go +++ b/pkg/tools/cron_tool.go @@ -6,7 +6,7 @@ import ( "fmt" "strings" - "clawgo/pkg/cron" + "github.com/YspCoder/clawgo/pkg/cron" ) type CronTool struct { diff --git a/pkg/tools/mcp.go b/pkg/tools/mcp.go index db183f2..3680b65 100644 --- a/pkg/tools/mcp.go +++ b/pkg/tools/mcp.go @@ -21,7 +21,7 @@ import ( "sync/atomic" "time" - "clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/config" ) const mcpProtocolVersion = "2025-06-18" diff --git a/pkg/tools/mcp_test.go b/pkg/tools/mcp_test.go index dd7a334..577279a 100644 --- a/pkg/tools/mcp_test.go +++ b/pkg/tools/mcp_test.go @@ -15,7 +15,7 @@ import ( "testing" "time" - "clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/config" ) func TestMCPToolListServers(t *testing.T) { diff --git a/pkg/tools/message.go b/pkg/tools/message.go index 13faaf9..38d4a91 100644 --- a/pkg/tools/message.go +++ b/pkg/tools/message.go @@ -6,7 +6,7 @@ import ( "strings" "sync" - "clawgo/pkg/bus" + "github.com/YspCoder/clawgo/pkg/bus" ) type SendCallback func(channel, chatID, action, content, media, messageID, emoji string, buttons [][]bus.Button) error diff --git a/pkg/tools/nodes_tool.go b/pkg/tools/nodes_tool.go index fcc4900..f8f89e8 100644 --- a/pkg/tools/nodes_tool.go +++ b/pkg/tools/nodes_tool.go @@ -9,7 +9,7 @@ import ( "strings" "time" - "clawgo/pkg/nodes" + "github.com/YspCoder/clawgo/pkg/nodes" ) // NodesTool provides an OpenClaw-style control surface for paired nodes. diff --git a/pkg/tools/process_manager.go b/pkg/tools/process_manager.go index 01b12d0..83fee9c 100644 --- a/pkg/tools/process_manager.go +++ b/pkg/tools/process_manager.go @@ -15,7 +15,7 @@ import ( "sync/atomic" "time" - "clawgo/pkg/events" + "github.com/YspCoder/clawgo/pkg/events" ) type processSession struct { diff --git a/pkg/tools/registry.go b/pkg/tools/registry.go index 174aabe..b17136a 100644 --- a/pkg/tools/registry.go +++ b/pkg/tools/registry.go @@ -7,7 +7,7 @@ import ( "sync/atomic" "time" - "clawgo/pkg/logger" + "github.com/YspCoder/clawgo/pkg/logger" ) type ToolRegistry struct { diff --git a/pkg/tools/remind.go b/pkg/tools/remind.go index fd8fde9..145e468 100644 --- a/pkg/tools/remind.go +++ b/pkg/tools/remind.go @@ -6,7 +6,7 @@ import ( "sync" "time" - "clawgo/pkg/cron" + "github.com/YspCoder/clawgo/pkg/cron" ) type RemindTool struct { diff --git a/pkg/tools/remind_test.go b/pkg/tools/remind_test.go index 3302649..5827885 100644 --- a/pkg/tools/remind_test.go +++ b/pkg/tools/remind_test.go @@ -5,7 +5,7 @@ import ( "path/filepath" "testing" - "clawgo/pkg/cron" + "github.com/YspCoder/clawgo/pkg/cron" ) func TestRemindTool_UsesToolContextForDeliveryTarget(t *testing.T) { @@ -15,7 +15,7 @@ func TestRemindTool_UsesToolContextForDeliveryTarget(t *testing.T) { tool.SetContext("telegram", "chat-123") _, err := tool.Execute(context.Background(), map[string]interface{}{ - "message": "喝水", + "message": "鍠濇按", "time_expr": "10m", }) if err != nil { diff --git a/pkg/tools/sessions_tool.go b/pkg/tools/sessions_tool.go index 757d835..2594300 100644 --- a/pkg/tools/sessions_tool.go +++ b/pkg/tools/sessions_tool.go @@ -7,7 +7,7 @@ import ( "strings" "time" - "clawgo/pkg/providers" + "github.com/YspCoder/clawgo/pkg/providers" ) type SessionInfo struct { diff --git a/pkg/tools/shell.go b/pkg/tools/shell.go index 4be5617..816de96 100644 --- a/pkg/tools/shell.go +++ b/pkg/tools/shell.go @@ -12,7 +12,7 @@ import ( "strings" "time" - "clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/config" ) type ExecTool struct { diff --git a/pkg/tools/skill_exec.go b/pkg/tools/skill_exec.go index 23237be..ff26ce7 100644 --- a/pkg/tools/skill_exec.go +++ b/pkg/tools/skill_exec.go @@ -10,7 +10,7 @@ import ( "strings" "time" - "clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/config" ) type SkillExecTool struct { diff --git a/pkg/tools/subagent.go b/pkg/tools/subagent.go index dcada2a..c368fe5 100644 --- a/pkg/tools/subagent.go +++ b/pkg/tools/subagent.go @@ -10,9 +10,9 @@ import ( "sync" "time" - "clawgo/pkg/bus" - "clawgo/pkg/ekg" - "clawgo/pkg/providers" + "github.com/YspCoder/clawgo/pkg/bus" + "github.com/YspCoder/clawgo/pkg/ekg" + "github.com/YspCoder/clawgo/pkg/providers" ) type SubagentTask struct { diff --git a/pkg/tools/subagent_config_manager.go b/pkg/tools/subagent_config_manager.go index 2ad197d..9aad9f7 100644 --- a/pkg/tools/subagent_config_manager.go +++ b/pkg/tools/subagent_config_manager.go @@ -5,9 +5,9 @@ import ( "fmt" "strings" - "clawgo/pkg/config" - "clawgo/pkg/configops" - "clawgo/pkg/runtimecfg" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/configops" + "github.com/YspCoder/clawgo/pkg/runtimecfg" ) func DraftConfigSubagent(description, agentIDHint string) map[string]interface{} { @@ -287,11 +287,11 @@ func normalizeKeywords(items []string) []string { func inferDraftRole(lower string) string { switch { - case containsDraftKeyword(lower, "test", "regression", "qa", "回归", "测试", "验证"): + case containsDraftKeyword(lower, "test", "regression", "qa", "鍥炲綊", "娴嬭瘯", "楠岃瘉"): return "testing" - case containsDraftKeyword(lower, "doc", "docs", "readme", "文档", "说明"): + case containsDraftKeyword(lower, "doc", "docs", "readme", "鏂囨。", "璇存槑"): return "docs" - case containsDraftKeyword(lower, "research", "investigate", "analyze", "调研", "分析", "研究"): + case containsDraftKeyword(lower, "research", "investigate", "analyze", "璋冪爺", "鍒嗘瀽", "鐮旂┒"): return "research" default: return "coding" @@ -301,7 +301,7 @@ func inferDraftRole(lower string) string { func inferDraftAgentID(role, lower string) string { switch role { case "testing": - if containsDraftKeyword(lower, "review", "审查", "reviewer") { + if containsDraftKeyword(lower, "review", "瀹℃煡", "reviewer") { return "reviewer" } return "tester" @@ -310,10 +310,10 @@ func inferDraftAgentID(role, lower string) string { case "research": return "researcher" default: - if containsDraftKeyword(lower, "frontend", "ui", "前端") { + if containsDraftKeyword(lower, "frontend", "ui", "鍓嶇") { return "frontend-coder" } - if containsDraftKeyword(lower, "backend", "api", "后端") { + if containsDraftKeyword(lower, "backend", "api", "鍚庣") { return "backend-coder" } return "coder" @@ -356,19 +356,19 @@ func inferDraftKeywords(role, lower string) []string { seed := []string{} switch role { case "testing": - seed = []string{"test", "regression", "verify", "回归", "测试", "验证"} + seed = []string{"test", "regression", "verify", "鍥炲綊", "娴嬭瘯", "楠岃瘉"} case "docs": - seed = []string{"docs", "readme", "document", "文档", "说明"} + seed = []string{"docs", "readme", "document", "鏂囨。", "璇存槑"} case "research": - seed = []string{"research", "analyze", "investigate", "调研", "分析", "研究"} + seed = []string{"research", "analyze", "investigate", "璋冪爺", "鍒嗘瀽", "鐮旂┒"} default: - seed = []string{"code", "implement", "fix", "refactor", "代码", "实现", "修复", "重构"} + seed = []string{"code", "implement", "fix", "refactor", "浠g爜", "瀹炵幇", "淇", "閲嶆瀯"} } - if containsDraftKeyword(lower, "frontend", "前端", "ui") { - seed = append(seed, "frontend", "ui", "前端") + if containsDraftKeyword(lower, "frontend", "鍓嶇", "ui") { + seed = append(seed, "frontend", "ui", "鍓嶇") } - if containsDraftKeyword(lower, "backend", "后端", "api") { - seed = append(seed, "backend", "api", "后端") + if containsDraftKeyword(lower, "backend", "鍚庣", "api") { + seed = append(seed, "backend", "api", "鍚庣") } return normalizeKeywords(seed) } @@ -376,13 +376,13 @@ func inferDraftKeywords(role, lower string) []string { func inferDraftSystemPrompt(role, description string) string { switch role { case "testing": - return "你负责测试、验证、回归检查与风险反馈。任务描述:" + description + return "浣犺礋璐f祴璇曘€侀獙璇併€佸洖褰掓鏌ヤ笌椋庨櫓鍙嶉銆備换鍔℃弿杩帮細" + description case "docs": - return "你负责文档编写、结构整理和说明补全。任务描述:" + description + return "浣犺礋璐f枃妗g紪鍐欍€佺粨鏋勬暣鐞嗗拰璇存槑琛ュ叏銆備换鍔℃弿杩帮細" + description case "research": - return "你负责调研、分析、比较方案,并输出结论与依据。任务描述:" + description + return "浣犺礋璐h皟鐮斻€佸垎鏋愩€佹瘮杈冩柟妗堬紝骞惰緭鍑虹粨璁轰笌渚濇嵁銆備换鍔℃弿杩帮細" + description default: - return "你负责代码实现与重构,输出具体修改建议和变更结果。任务描述:" + description + return "浣犺礋璐d唬鐮佸疄鐜颁笌閲嶆瀯锛岃緭鍑哄叿浣撲慨鏀瑰缓璁拰鍙樻洿缁撴灉銆備换鍔℃弿杩帮細" + description } } diff --git a/pkg/tools/subagent_config_tool_test.go b/pkg/tools/subagent_config_tool_test.go index a0f2cab..59e44b7 100644 --- a/pkg/tools/subagent_config_tool_test.go +++ b/pkg/tools/subagent_config_tool_test.go @@ -6,8 +6,8 @@ import ( "path/filepath" "testing" - "clawgo/pkg/config" - "clawgo/pkg/runtimecfg" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/runtimecfg" ) func TestSubagentConfigToolUpsert(t *testing.T) { @@ -34,7 +34,7 @@ func TestSubagentConfigToolUpsert(t *testing.T) { "role": "testing", "notify_main_policy": "internal_only", "display_name": "Review Agent", - "description": "负责回归与评审", + "description": "handles review and regression checks", "system_prompt_file": "agents/reviewer/AGENT.md", "routing_keywords": []interface{}{"review", "regression"}, "tool_allowlist": []interface{}{"shell", "sessions"}, diff --git a/pkg/tools/subagent_profile.go b/pkg/tools/subagent_profile.go index 0abe584..08f5f12 100644 --- a/pkg/tools/subagent_profile.go +++ b/pkg/tools/subagent_profile.go @@ -11,9 +11,9 @@ import ( "sync" "time" - "clawgo/pkg/config" - "clawgo/pkg/nodes" - "clawgo/pkg/runtimecfg" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/nodes" + "github.com/YspCoder/clawgo/pkg/runtimecfg" ) type SubagentProfile struct { diff --git a/pkg/tools/subagent_profile_test.go b/pkg/tools/subagent_profile_test.go index f538e97..070ee69 100644 --- a/pkg/tools/subagent_profile_test.go +++ b/pkg/tools/subagent_profile_test.go @@ -6,9 +6,9 @@ import ( "testing" "time" - "clawgo/pkg/config" - "clawgo/pkg/nodes" - "clawgo/pkg/runtimecfg" + "github.com/YspCoder/clawgo/pkg/config" + "github.com/YspCoder/clawgo/pkg/nodes" + "github.com/YspCoder/clawgo/pkg/runtimecfg" ) func TestSubagentProfileStoreNormalization(t *testing.T) { diff --git a/pkg/tools/subagent_runtime_control_test.go b/pkg/tools/subagent_runtime_control_test.go index 818a0fc..f2761c5 100644 --- a/pkg/tools/subagent_runtime_control_test.go +++ b/pkg/tools/subagent_runtime_control_test.go @@ -9,8 +9,8 @@ import ( "testing" "time" - "clawgo/pkg/bus" - "clawgo/pkg/providers" + "github.com/YspCoder/clawgo/pkg/bus" + "github.com/YspCoder/clawgo/pkg/providers" ) func TestSubagentSpawnEnforcesTaskQuota(t *testing.T) { diff --git a/pkg/tools/web.go b/pkg/tools/web.go index faef9a4..835dd5a 100644 --- a/pkg/tools/web.go +++ b/pkg/tools/web.go @@ -11,7 +11,7 @@ import ( "strings" "time" - "clawgo/pkg/logger" + "github.com/YspCoder/clawgo/pkg/logger" ) const (