Skip to content

Commit cb6be91

Browse files
committed
fix(qqbot): support QQBOT_DATA_DIR environment variable
Allow users to customize QQBot data directory by setting QQBOT_DATA_DIR environment variable. Falls back to ~/.openclaw/qqbot when not set. Closes [Bug]:#39461
1 parent 31a710c commit cb6be91

3 files changed

Lines changed: 84 additions & 4 deletions

File tree

docs/channels/qqbot.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ Default-account env vars:
6767

6868
- `QQBOT_APP_ID`
6969
- `QQBOT_CLIENT_SECRET`
70+
- `QQBOT_DATA_DIR` (optional): custom data directory path for QQBot storage. Defaults to `~/.openclaw/qqbot`.
7071

7172
File-backed AppSecret:
7273

extensions/qqbot/src/engine/utils/platform.test.ts

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,83 @@
11
import fs from "node:fs";
22
import os from "node:os";
33
import path from "node:path";
4-
import { afterEach, describe, expect, it, vi } from "vitest";
4+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
55
import {
66
getHomeDir,
7+
getQQBotDataDir,
8+
getQQBotDataPath,
79
resolveQQBotLocalMediaPath,
810
resolveQQBotPayloadLocalFilePath,
911
} from "./platform.js";
1012

13+
describe("QQBot data directory with QQBOT_DATA_DIR", () => {
14+
const createdPaths: string[] = [];
15+
let originalDataDir: string | undefined;
16+
17+
beforeEach(() => {
18+
originalDataDir = process.env.QQBOT_DATA_DIR;
19+
});
20+
21+
afterEach(() => {
22+
vi.restoreAllMocks();
23+
if (originalDataDir === undefined) {
24+
delete process.env.QQBOT_DATA_DIR;
25+
} else {
26+
process.env.QQBOT_DATA_DIR = originalDataDir;
27+
}
28+
for (const target of createdPaths.splice(0)) {
29+
fs.rmSync(target, { recursive: true, force: true });
30+
}
31+
});
32+
33+
it("uses QQBOT_DATA_DIR when set", () => {
34+
const customDir = fs.mkdtempSync(path.join(os.tmpdir(), "qqbot-custom-data-"));
35+
createdPaths.push(customDir);
36+
process.env.QQBOT_DATA_DIR = customDir;
37+
38+
const dataDir = getQQBotDataDir();
39+
expect(dataDir).toBe(customDir);
40+
expect(fs.existsSync(dataDir)).toBe(true);
41+
});
42+
43+
it("uses QQBOT_DATA_DIR with subpaths", () => {
44+
const customDir = fs.mkdtempSync(path.join(os.tmpdir(), "qqbot-custom-data-"));
45+
createdPaths.push(customDir);
46+
process.env.QQBOT_DATA_DIR = customDir;
47+
48+
const sessionsDir = getQQBotDataDir("sessions", "test");
49+
expect(sessionsDir).toBe(path.join(customDir, "sessions", "test"));
50+
expect(fs.existsSync(sessionsDir)).toBe(true);
51+
});
52+
53+
it("falls back to ~/.openclaw/qqbot when QQBOT_DATA_DIR is not set", () => {
54+
delete process.env.QQBOT_DATA_DIR;
55+
const homeDir = getHomeDir();
56+
const expectedDir = path.join(homeDir, ".openclaw", "qqbot");
57+
58+
const dataDir = getQQBotDataDir();
59+
expect(dataDir).toBe(expectedDir);
60+
});
61+
62+
it("expands tilde in QQBOT_DATA_DIR", () => {
63+
const homeDir = getHomeDir();
64+
const customDir = path.join(homeDir, "custom-qqbot-data");
65+
process.env.QQBOT_DATA_DIR = "~/custom-qqbot-data";
66+
67+
const dataDir = getQQBotDataPath();
68+
expect(dataDir).toBe(customDir);
69+
});
70+
71+
it("returns path without creating when using getQQBotDataPath", () => {
72+
const customDir = path.join(os.tmpdir(), "qqbot-not-created-yet");
73+
process.env.QQBOT_DATA_DIR = customDir;
74+
75+
const dataPath = getQQBotDataPath("not-created", "subdir");
76+
expect(dataPath).toBe(path.join(customDir, "not-created", "subdir"));
77+
expect(fs.existsSync(dataPath)).toBe(false);
78+
});
79+
});
80+
1181
describe("qqbot local media path remapping", () => {
1282
const createdPaths: string[] = [];
1383

extensions/qqbot/src/engine/utils/platform.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,21 @@ export function getHomeDir(): string {
3939
return getPlatformAdapter().getTempDir();
4040
}
4141

42-
/** Return a path under `~/.openclaw/qqbot` without creating it. */
42+
/** Return the base QQBot data directory, respecting QQBOT_DATA_DIR env var. */
43+
function getQQBotDataBaseDir(): string {
44+
const envDataDir = process.env.QQBOT_DATA_DIR;
45+
if (envDataDir) {
46+
return normalizePath(envDataDir);
47+
}
48+
return path.join(getHomeDir(), ".openclaw", "qqbot");
49+
}
50+
51+
/** Return a path under `~/.openclaw/qqbot` (or QQBOT_DATA_DIR) without creating it. */
4352
export function getQQBotDataPath(...subPaths: string[]): string {
44-
return path.join(getHomeDir(), ".openclaw", "qqbot", ...subPaths);
53+
return path.join(getQQBotDataBaseDir(), ...subPaths);
4554
}
4655

47-
/** Return a path under `~/.openclaw/qqbot`, creating it on demand. */
56+
/** Return a path under `~/.openclaw/qqbot` (or QQBOT_DATA_DIR), creating it on demand. */
4857
export function getQQBotDataDir(...subPaths: string[]): string {
4958
const dir = getQQBotDataPath(...subPaths);
5059
if (!fs.existsSync(dir)) {

0 commit comments

Comments
 (0)