From 3a3503226bfb614e36e3fd3461f826a82f2bdcc3 Mon Sep 17 00:00:00 2001 From: Vincent Menard Date: Fri, 9 Oct 2026 21:57:42 +0200 Subject: [PATCH 1/2] fix(aidd-context): keep memory README links relative on Windows memoryRelative stripped a prefix joined with the platform separator from a path normalised to "/", so on win32 it matched nothing and every README link kept its aidd_docs/memory/ prefix and pointed nowhere. Closes #986 Co-Authored-By: Claude Opus 5.5 --- plugins/aidd-context/hooks/update_memory.js | 2 +- scripts/__tests__/update-memory.test.js | 26 +++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/plugins/aidd-context/hooks/update_memory.js b/plugins/aidd-context/hooks/update_memory.js index 4cb856ec1..2cfb4ba01 100644 --- a/plugins/aidd-context/hooks/update_memory.js +++ b/plugins/aidd-context/hooks/update_memory.js @@ -184,7 +184,7 @@ function updateBlock(content, innerContent) { // memory/-relative path, e.g. aidd_docs/memory/internal/x.md -> internal/x.md. function memoryRelative(path, filePath) { - return filePath.replace(/\\/g, "/").replace(`${memoryPath(path)}/`, ""); + return filePath.replace(/\\/g, "/").replace(`${memoryPath(path).replace(/\\/g, "/")}/`, ""); } function buildToc(rootFiles, onDemandFiles, path) { diff --git a/scripts/__tests__/update-memory.test.js b/scripts/__tests__/update-memory.test.js index 2041424ea..f8e8d3514 100644 --- a/scripts/__tests__/update-memory.test.js +++ b/scripts/__tests__/update-memory.test.js @@ -231,3 +231,29 @@ test("a nested context file prefixes its links with the climb back out", () => { /^\[aidd_docs\/memory\/architecture\.md\]\(\.\.\/aidd_docs\/memory\/architecture\.md\)$/mu, ); }); + +// The README sits inside the memory directory, so its links are relative to it. The path +// is joined with the platform separator but the file paths are normalised to "/", so a +// replace on the joined form silently matches nothing on Windows. +test("the memory README lists its files relative to itself, on every platform's separator", () => { + const root = fs.mkdtempSync(path.join(os.tmpdir(), "update-memory-")); + try { + const memory = path.join(root, "aidd_docs/memory"); + fs.mkdirSync(path.join(memory, "internal/decisions"), { recursive: true }); + fs.writeFileSync(path.join(memory, "architecture.md"), "# x\n"); + fs.writeFileSync(path.join(memory, "internal/decisions/x.md"), "# x\n"); + fs.writeFileSync(path.join(memory, "README.md"), "\n\n"); + fs.writeFileSync(path.join(root, "CLAUDE.md"), `${OPEN}\n${CLOSE}\n`); + + const result = spawnSync(process.execPath, [HOOK, "claude"], { cwd: root }); + assert.equal(result.status, 0, result.stderr.toString()); + + const readme = fs.readFileSync(path.join(memory, "README.md"), "utf8"); + const toc = readme.slice(readme.indexOf(""), readme.indexOf("")); + assert.match(toc, /^- \[architecture\.md\]\(architecture\.md\)$/mu); + assert.match(toc, /^- \[internal\/decisions\/x\.md\]\(internal\/decisions\/x\.md\)$/mu); + assert.doesNotMatch(toc, /aidd_docs\/memory\//u); + } finally { + fs.rmSync(root, { recursive: true, force: true }); + } +}); From 76dd5892997a4d7bea86c8ff4e2a030c081fab9a Mon Sep 17 00:00:00 2001 From: Vincent Menard Date: Fri, 9 Oct 2026 22:01:23 +0200 Subject: [PATCH 2/2] test(aidd-context): keep the memory hook suite out of the real project Run from inside a Claude Code session, the suite inherited CLAUDE_PROJECT_DIR and the hook would have rewritten that project's CLAUDE.md and memory README. Refs #986 Co-Authored-By: Claude Opus 5.5 --- scripts/__tests__/update-memory.test.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/__tests__/update-memory.test.js b/scripts/__tests__/update-memory.test.js index f8e8d3514..fc9440cf4 100644 --- a/scripts/__tests__/update-memory.test.js +++ b/scripts/__tests__/update-memory.test.js @@ -9,6 +9,9 @@ const test = require("node:test"); // where a "type": "module" package.json decides how it is parsed. Driving it as a // subprocess is the only way to test what actually ships. const HOOK = path.resolve(__dirname, "../../plugins/aidd-context/hooks/update_memory.js"); +// Run from inside a Claude Code session, an inherited CLAUDE_PROJECT_DIR would send the hook +// into that real project and rewrite its CLAUDE.md and memory README. +const HOOK_ENV = { ...process.env, CLAUDE_PROJECT_DIR: "" }; const OPEN = ""; const CLOSE = ""; @@ -49,7 +52,7 @@ function run({ fs.copyFileSync(HOOK, hook); } - const invoke = () => spawnSync(process.execPath, [hook, ...(args ?? ["claude"])], { cwd: root }); + const invoke = () => spawnSync(process.execPath, [hook, ...(args ?? ["claude"])], { cwd: root, env: HOOK_ENV }); const read = () => fs.readFileSync(path.join(root, contextAt), "utf8"); const first = invoke(); @@ -245,7 +248,7 @@ test("the memory README lists its files relative to itself, on every platform's fs.writeFileSync(path.join(memory, "README.md"), "\n\n"); fs.writeFileSync(path.join(root, "CLAUDE.md"), `${OPEN}\n${CLOSE}\n`); - const result = spawnSync(process.execPath, [HOOK, "claude"], { cwd: root }); + const result = spawnSync(process.execPath, [HOOK, "claude"], { cwd: root, env: HOOK_ENV }); assert.equal(result.status, 0, result.stderr.toString()); const readme = fs.readFileSync(path.join(memory, "README.md"), "utf8");