From 12d0bc25142e3feb0a7536e1976c7b939057a938 Mon Sep 17 00:00:00 2001 From: Alix-007 <267018309+Alix-007@users.noreply.github.com> Date: Thu, 26 Mar 2026 02:01:23 +0800 Subject: [PATCH] fix(weixin): fallback sync cursor store when home is unusable --- pkg/channels/weixin/state.go | 19 ++++++++++++++++++- pkg/channels/weixin/weixin_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/pkg/channels/weixin/state.go b/pkg/channels/weixin/state.go index 8fbdd00dd..c27483b5c 100644 --- a/pkg/channels/weixin/state.go +++ b/pkg/channels/weixin/state.go @@ -41,7 +41,24 @@ type contextTokensFile struct { } func picoclawHomeDir() string { - return config.GetHome() + if home := os.Getenv(config.EnvHome); home != "" { + return home + } + + if userHome, err := os.UserHomeDir(); err == nil && userHome != "" { + home := filepath.Join(userHome, ".picoclaw") + syncDir := filepath.Join(home, "channels", "weixin", "sync") + mkErr := os.MkdirAll(syncDir, 0o700) + if mkErr == nil { + return home + } + logger.WarnCF("weixin", "Default picoclaw home is not writable; using temp directory for sync cursor", map[string]any{ + "path": home, + "error": mkErr.Error(), + }) + } + + return filepath.Join(os.TempDir(), "picoclaw") } func genWeixinAccountKey(cfg config.WeixinConfig) string { diff --git a/pkg/channels/weixin/weixin_test.go b/pkg/channels/weixin/weixin_test.go index b41b930db..3bac9822b 100644 --- a/pkg/channels/weixin/weixin_test.go +++ b/pkg/channels/weixin/weixin_test.go @@ -7,7 +7,9 @@ import ( "errors" "io" "net/http" + "os" "path/filepath" + "runtime" "testing" "time" @@ -269,6 +271,29 @@ func TestBuildWeixinSyncBufPathUsesPicoclawHome(t *testing.T) { } } +func TestBuildWeixinSyncBufPathFallsBackWhenHomeIsUnusable(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("HOME handling differs on windows") + } + + t.Setenv(config.EnvHome, "") + unusableHome := filepath.Join(t.TempDir(), "home-file") + if err := os.WriteFile(unusableHome, []byte("not-a-dir"), 0o600); err != nil { + t.Fatalf("WriteFile(unusableHome) error = %v", err) + } + t.Setenv("HOME", unusableHome) + + wxCfg := config.WeixinConfig{ + BaseURL: "https://ilinkai.weixin.qq.com/", + } + wxCfg.SetToken("token-123") + got := buildWeixinSyncBufPath(wxCfg) + wantDir := filepath.Join(os.TempDir(), "picoclaw", "channels", "weixin", "sync") + if filepath.Dir(got) != wantDir { + t.Fatalf("sync path dir = %q, want %q", filepath.Dir(got), wantDir) + } +} + func TestSessionPauseGuard(t *testing.T) { ch := &WeixinChannel{ typingCache: make(map[string]typingTicketCacheEntry),