mirror of
https://github.com/chenhg5/cc-connect.git
synced 2026-10-25 17:36:43 +08:00
fix(core): derive workspace session store from the engine store path (#1926)
getOrCreateWorkspaceAgent built the per-workspace session file as
filepath.Join(filepath.Dir(e.sessions.StorePath()), ...). With no store
path configured — which is how every engine in the test suite is built —
filepath.Dir("") is ".", so the path collapsed to a bare relative
"<engine>_ws_<hash>.json" and the session manager wrote it into the
process working directory. That is what littered core/ with test_ws_*.json
during `go test ./core/`.
An empty store path already means "no persistence" everywhere else in the
session manager (saveLocked returns early), so it now means the same here:
the workspace manager is built unpersisted instead of inventing a path.
A configured store path still derives the workspace file beside it, as
before.
Regressions: an engine without a store path yields a workspace manager
whose StorePath() is empty, and a configured one still derives
test_ws_<hash>.json in the store's directory.
Also ignores the stale files contributors already have on disk.
Co-authored-by: Claude Code <noreply@anthropic.com>
This commit is contained in:
1 parent
f8acb2c6c6
commit
1d38af3fe3
3 files changed
+83
-3
No files matched your search
@@ -82,6 +82,13 @@ temp/
|
||||
*.pid
|
||||
*.log
|
||||
|
||||
# Per-workspace session stores (<engine>_ws_<hash>.json, see
|
||||
# Engine.getOrCreateWorkspaceAgent). They are derived from the engine's own
|
||||
# session store, so they belong next to it — never in the working tree. This
|
||||
# is a guard for files already on disk from before that derivation was
|
||||
# corrected; the derivation itself no longer produces them.
|
||||
*_ws_????????.json
|
||||
|
||||
# ============================================================================
|
||||
# IDE & Editor
|
||||
# ============================================================================
|
||||
|
||||
+10
-3
@@ -4180,10 +4180,17 @@ func (e *Engine) getOrCreateWorkspaceAgent(workspace string) (Agent, *SessionMan
|
||||
}
|
||||
}
|
||||
|
||||
// Create per-workspace session manager
|
||||
// Create per-workspace session manager. An empty store path means "no
|
||||
// persistence" everywhere else in the session manager, so it has to mean
|
||||
// the same here: filepath.Dir("") is ".", which would otherwise drop
|
||||
// "<engine>_ws_<hash>.json" into the process working directory — that is
|
||||
// what littered core/ with test_ws_*.json during `go test ./core/`.
|
||||
h := sha256.Sum256([]byte(workspace))
|
||||
sessionFile := filepath.Join(filepath.Dir(e.sessions.StorePath()),
|
||||
fmt.Sprintf("%s_ws_%s.json", e.name, hex.EncodeToString(h[:4])))
|
||||
sessionFile := ""
|
||||
if storePath := e.sessions.StorePath(); storePath != "" {
|
||||
sessionFile = filepath.Join(filepath.Dir(storePath),
|
||||
fmt.Sprintf("%s_ws_%s.json", e.name, hex.EncodeToString(h[:4])))
|
||||
}
|
||||
sessions := NewSessionManager(sessionFile)
|
||||
sessions.InvalidateForAgent(agent.Name())
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// registerWorkspaceStoreAgent registers a throwaway agent type so
|
||||
// getOrCreateWorkspaceAgent can build a per-workspace instance.
|
||||
func registerWorkspaceStoreAgent(t *testing.T, agentName string) {
|
||||
t.Helper()
|
||||
RegisterAgent(agentName, func(opts map[string]any) (Agent, error) {
|
||||
workDir, _ := opts["work_dir"].(string)
|
||||
return &sendWorkDirAgent{
|
||||
name: agentName,
|
||||
workDir: workDir,
|
||||
session: newResultAgentSession("workspace session"),
|
||||
}, nil
|
||||
})
|
||||
}
|
||||
|
||||
// A workspace session manager has to inherit the engine's "no store path means
|
||||
// no persistence" contract. filepath.Dir("") is ".", so deriving a path from an
|
||||
// empty store path used to drop "<engine>_ws_<hash>.json" into the process
|
||||
// working directory — that is how `go test ./core/` littered core/ with
|
||||
// test_ws_*.json files.
|
||||
func TestGetOrCreateWorkspaceAgent_EmptyStorePathStaysUnpersisted(t *testing.T) {
|
||||
agentName := "test-ws-store-unpersisted"
|
||||
registerWorkspaceStoreAgent(t, agentName)
|
||||
|
||||
p := &stubPlatformEngine{n: "telegram"}
|
||||
e := NewEngine("test", &sendWorkDirAgent{name: agentName}, []Platform{p}, "", LangEnglish)
|
||||
|
||||
_, sessions, err := e.getOrCreateWorkspaceAgent(t.TempDir())
|
||||
if err != nil {
|
||||
t.Fatalf("getOrCreateWorkspaceAgent() error = %v", err)
|
||||
}
|
||||
if got := sessions.StorePath(); got != "" {
|
||||
t.Fatalf("workspace store path = %q, want empty when the engine has no store path", got)
|
||||
}
|
||||
}
|
||||
|
||||
// The derived path keeps living beside the engine's own store, so a configured
|
||||
// deployment still persists workspace sessions.
|
||||
func TestGetOrCreateWorkspaceAgent_DerivesStorePathBesideEngineStore(t *testing.T) {
|
||||
agentName := "test-ws-store-derived"
|
||||
registerWorkspaceStoreAgent(t, agentName)
|
||||
|
||||
dir := t.TempDir()
|
||||
p := &stubPlatformEngine{n: "telegram"}
|
||||
e := NewEngine("test", &sendWorkDirAgent{name: agentName}, []Platform{p},
|
||||
filepath.Join(dir, "sessions.json"), LangEnglish)
|
||||
|
||||
_, sessions, err := e.getOrCreateWorkspaceAgent(t.TempDir())
|
||||
if err != nil {
|
||||
t.Fatalf("getOrCreateWorkspaceAgent() error = %v", err)
|
||||
}
|
||||
got := sessions.StorePath()
|
||||
if filepath.Dir(got) != dir {
|
||||
t.Fatalf("workspace store dir = %q, want %q", filepath.Dir(got), dir)
|
||||
}
|
||||
if base := filepath.Base(got); !strings.HasPrefix(base, "test_ws_") || !strings.HasSuffix(base, ".json") {
|
||||
t.Fatalf("workspace store name = %q, want test_ws_<hash>.json", base)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user