mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-13 17:56:07 +00:00
fix: isolate Claude history HOME setup
This commit is contained in:
@@ -4,6 +4,7 @@ import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
||||
import { withEnvAsync } from "../test-utils/env.js";
|
||||
import {
|
||||
augmentChatHistoryWithCliSessionImports,
|
||||
mergeImportedChatHistoryMessages,
|
||||
@@ -13,8 +14,6 @@ import {
|
||||
} from "./cli-session-history.js";
|
||||
import { expectRecordFields, requireRecord } from "./test-helpers.assertions.js";
|
||||
|
||||
const ORIGINAL_HOME = process.env.HOME;
|
||||
|
||||
type ClaudeCliFallbackSeed = NonNullable<ReturnType<typeof readClaudeCliFallbackSeed>>;
|
||||
type AugmentCliHistoryParams = Parameters<typeof augmentChatHistoryWithCliSessionImports>[0];
|
||||
|
||||
@@ -150,28 +149,14 @@ async function withClaudeProjectsDir<T>(
|
||||
const filePath = path.join(projectsDir, `${sessionId}.jsonl`);
|
||||
await fs.mkdir(projectsDir, { recursive: true });
|
||||
await fs.writeFile(filePath, createClaudeHistoryLines(sessionId), "utf-8");
|
||||
process.env.HOME = homeDir;
|
||||
try {
|
||||
return await run({ homeDir, sessionId, filePath });
|
||||
return await withEnvAsync({ HOME: homeDir }, () => run({ homeDir, sessionId, filePath }));
|
||||
} finally {
|
||||
if (ORIGINAL_HOME === undefined) {
|
||||
delete process.env.HOME;
|
||||
} else {
|
||||
process.env.HOME = ORIGINAL_HOME;
|
||||
}
|
||||
await fs.rm(root, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
describe("cli session history", () => {
|
||||
afterEach(() => {
|
||||
if (ORIGINAL_HOME === undefined) {
|
||||
delete process.env.HOME;
|
||||
} else {
|
||||
process.env.HOME = ORIGINAL_HOME;
|
||||
}
|
||||
});
|
||||
|
||||
it("reads claude-cli session messages from the Claude projects store", async () => {
|
||||
await withClaudeProjectsDir(async ({ homeDir, sessionId, filePath }) => {
|
||||
expect(resolveClaudeCliSessionFilePath({ cliSessionId: sessionId, homeDir })).toBe(filePath);
|
||||
@@ -460,25 +445,25 @@ describe("readClaudeCliFallbackSeed", () => {
|
||||
homeDir = path.join(tmpRoot, "home");
|
||||
projectsDir = path.join(homeDir, ".claude", "projects", "demo-workspace");
|
||||
await fs.mkdir(projectsDir, { recursive: true });
|
||||
process.env.HOME = homeDir;
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
if (ORIGINAL_HOME === undefined) {
|
||||
delete process.env.HOME;
|
||||
} else {
|
||||
process.env.HOME = ORIGINAL_HOME;
|
||||
}
|
||||
await fs.rm(tmpRoot, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
function readFallbackSeed(
|
||||
cliSessionId = SESSION_ID,
|
||||
): ReturnType<typeof readClaudeCliFallbackSeed> {
|
||||
return readClaudeCliFallbackSeed({ cliSessionId, homeDir });
|
||||
}
|
||||
|
||||
async function writeJsonl(lines: ReadonlyArray<Record<string, unknown>>): Promise<void> {
|
||||
const file = path.join(projectsDir, `${SESSION_ID}.jsonl`);
|
||||
await fs.writeFile(file, `${lines.map((line) => JSON.stringify(line)).join("\n")}\n`, "utf-8");
|
||||
}
|
||||
|
||||
it("returns undefined when the Claude session file does not exist", () => {
|
||||
const seed = readClaudeCliFallbackSeed({ cliSessionId: SESSION_ID });
|
||||
const seed = readFallbackSeed();
|
||||
expect(seed).toBeUndefined();
|
||||
});
|
||||
|
||||
@@ -505,7 +490,7 @@ describe("readClaudeCliFallbackSeed", () => {
|
||||
},
|
||||
]);
|
||||
|
||||
const seed = readClaudeCliFallbackSeed({ cliSessionId: SESSION_ID });
|
||||
const seed = readFallbackSeed();
|
||||
const fallbackSeed = requireFallbackSeed(seed, "uncompacted session");
|
||||
expect(fallbackSeed.summaryText).toBeUndefined();
|
||||
expect(fallbackSeed.recentTurns).toHaveLength(3);
|
||||
@@ -555,7 +540,7 @@ describe("readClaudeCliFallbackSeed", () => {
|
||||
},
|
||||
]);
|
||||
|
||||
const seed = readClaudeCliFallbackSeed({ cliSessionId: SESSION_ID });
|
||||
const seed = readFallbackSeed();
|
||||
const fallbackSeed = requireFallbackSeed(seed, "compacted session");
|
||||
expect(fallbackSeed.summaryText).toBe(
|
||||
"User asked about deployment; agent recommended a blue-green strategy.",
|
||||
@@ -587,7 +572,7 @@ describe("readClaudeCliFallbackSeed", () => {
|
||||
},
|
||||
]);
|
||||
|
||||
const seed = readClaudeCliFallbackSeed({ cliSessionId: SESSION_ID });
|
||||
const seed = readFallbackSeed();
|
||||
const fallbackSeed = requireFallbackSeed(seed, "compact boundary session");
|
||||
// Falls back to the boundary's content so the seed at least labels
|
||||
// that compaction happened, instead of replaying nothing.
|
||||
@@ -632,7 +617,7 @@ describe("readClaudeCliFallbackSeed", () => {
|
||||
},
|
||||
]);
|
||||
|
||||
const seed = readClaudeCliFallbackSeed({ cliSessionId: SESSION_ID });
|
||||
const seed = readFallbackSeed();
|
||||
expect(seed?.summaryText).toBe("LATER summary that must win.");
|
||||
expect(seed?.recentTurns).toHaveLength(1);
|
||||
expect(JSON.stringify(seed?.recentTurns)).toContain("tail turn");
|
||||
@@ -649,12 +634,12 @@ describe("readClaudeCliFallbackSeed", () => {
|
||||
message: { role: "user", content: "sidechain user turn" },
|
||||
},
|
||||
]);
|
||||
const seed = readClaudeCliFallbackSeed({ cliSessionId: SESSION_ID });
|
||||
const seed = readFallbackSeed();
|
||||
expect(seed).toBeUndefined();
|
||||
});
|
||||
|
||||
it("rejects path-like session ids instead of escaping the Claude projects tree", () => {
|
||||
const seed = readClaudeCliFallbackSeed({ cliSessionId: "../escape" });
|
||||
const seed = readFallbackSeed("../escape");
|
||||
expect(seed).toBeUndefined();
|
||||
});
|
||||
|
||||
@@ -685,7 +670,7 @@ describe("readClaudeCliFallbackSeed", () => {
|
||||
},
|
||||
]);
|
||||
|
||||
const seed = readClaudeCliFallbackSeed({ cliSessionId: SESSION_ID });
|
||||
const seed = readFallbackSeed();
|
||||
const fallbackSeed = requireFallbackSeed(seed, "latest boundary session");
|
||||
expect(fallbackSeed.summaryText).toBe("Conversation compacted (2)");
|
||||
expect(fallbackSeed.summaryText).not.toBe("FIRST compact summary");
|
||||
@@ -708,7 +693,7 @@ describe("readClaudeCliFallbackSeed", () => {
|
||||
},
|
||||
]);
|
||||
|
||||
const seed = readClaudeCliFallbackSeed({ cliSessionId: SESSION_ID });
|
||||
const seed = readFallbackSeed();
|
||||
expect(seed?.summaryText).toBe("trailing summary without boundary");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user