From efbbd85d8e662e8fb0ab061566bf09eaeebf2143 Mon Sep 17 00:00:00 2001 From: Grivn Date: Sun, 31 May 2026 10:22:08 +0000 Subject: [PATCH] fix(setup): align OpenClaw prompt path with MNEMON_DATA_DIR Resolve the OpenClaw prime hook guide path from MNEMON_DATA_DIR with the same legacy ~/.mnemon fallback used by the Claude and Codex hooks. This keeps OpenClaw setup output and runtime guide injection aligned after prompt files move under the data root. Validation: go test ./internal/setup; go test ./... --- .../openclaw/hooks/mnemon-prime/handler.js | 15 ++++++++++++--- internal/setup/claude.go | 4 ++-- internal/setup/openclaw_test.go | 17 +++++++++++++++++ 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/internal/setup/assets/openclaw/hooks/mnemon-prime/handler.js b/internal/setup/assets/openclaw/hooks/mnemon-prime/handler.js index a1d79ac..52b9aeb 100644 --- a/internal/setup/assets/openclaw/hooks/mnemon-prime/handler.js +++ b/internal/setup/assets/openclaw/hooks/mnemon-prime/handler.js @@ -1,9 +1,18 @@ -import { readFileSync } from "fs"; +import { existsSync, readFileSync } from "fs"; import { homedir } from "os"; import { join } from "path"; import { execSync } from "child_process"; -const GUIDE_PATH = join(homedir(), ".mnemon", "prompt", "guide.md"); +const LEGACY_GUIDE_PATH = join(homedir(), ".mnemon", "prompt", "guide.md"); + +function guidePath() { + const dataRoot = process.env.MNEMON_DATA_DIR || join(homedir(), ".mnemon"); + const scopedPath = join(dataRoot, "prompt", "guide.md"); + if (!existsSync(scopedPath) && existsSync(LEGACY_GUIDE_PATH)) { + return LEGACY_GUIDE_PATH; + } + return scopedPath; +} const handler = async (event) => { if (event.type !== "agent" || event.action !== "bootstrap") return; @@ -30,7 +39,7 @@ const handler = async (event) => { // Inject behavioral guide try { - const guide = readFileSync(GUIDE_PATH, "utf-8"); + const guide = readFileSync(guidePath(), "utf-8"); if (guide) parts.push(guide); } catch { // guide.md not found — skill-only mode, no guide injection diff --git a/internal/setup/claude.go b/internal/setup/claude.go index 94fc27a..d98c293 100644 --- a/internal/setup/claude.go +++ b/internal/setup/claude.go @@ -17,8 +17,8 @@ type HookSelection struct { } // promptDir returns the directory where mnemon prompt files (guide.md, -// skill.md) are written and read. Resolution follows the same convention as -// the --data-dir flag: MNEMON_DATA_DIR env var if set, else ~/.mnemon. +// skill.md) are written and read. Resolution follows MNEMON_DATA_DIR if set, +// else ~/.mnemon. func promptDir() (string, error) { if env := os.Getenv("MNEMON_DATA_DIR"); env != "" { return filepath.Join(env, "prompt"), nil diff --git a/internal/setup/openclaw_test.go b/internal/setup/openclaw_test.go index 6dca64d..3ac9429 100644 --- a/internal/setup/openclaw_test.go +++ b/internal/setup/openclaw_test.go @@ -4,7 +4,10 @@ import ( "encoding/json" "os" "path/filepath" + "strings" "testing" + + "github.com/mnemon-dev/mnemon/internal/setup/assets" ) func TestOpenClawRegisterPluginWritesSelection(t *testing.T) { @@ -89,3 +92,17 @@ func TestRemoveOpenClawPluginEntryRemovesEmptyConfig(t *testing.T) { t.Fatalf("expected empty config file removal, got err=%v", err) } } + +func TestOpenClawPrimeHookResolvesMnemonDataDir(t *testing.T) { + handler := string(assets.OpenClawHookHandler) + for _, want := range []string{ + "process.env.MNEMON_DATA_DIR", + "LEGACY_GUIDE_PATH", + "existsSync(scopedPath)", + "readFileSync(guidePath()", + } { + if !strings.Contains(handler, want) { + t.Fatalf("OpenClaw prime hook missing %q", want) + } + } +}