Skip to content

Commit d841d8c

Browse files
committed
merge main into doctor plugin drift fix
2 parents aad643f + da40134 commit d841d8c

17 files changed

Lines changed: 710 additions & 135 deletions

docs/.i18n/glossary.zh-CN.json

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,10 +263,66 @@
263263
"source": "Feishu",
264264
"target": "Feishu"
265265
},
266+
{
267+
"source": "ClickClack",
268+
"target": "ClickClack"
269+
},
270+
{
271+
"source": "IRC",
272+
"target": "IRC"
273+
},
274+
{
275+
"source": "LINE",
276+
"target": "LINE"
277+
},
278+
{
279+
"source": "Nextcloud Talk",
280+
"target": "Nextcloud Talk"
281+
},
282+
{
283+
"source": "Nostr",
284+
"target": "Nostr"
285+
},
286+
{
287+
"source": "QQ bot",
288+
"target": "QQ Bot"
289+
},
290+
{
291+
"source": "SMS",
292+
"target": "SMS"
293+
},
294+
{
295+
"source": "Synology Chat",
296+
"target": "Synology Chat"
297+
},
298+
{
299+
"source": "Tlon",
300+
"target": "Tlon"
301+
},
302+
{
303+
"source": "Twitch",
304+
"target": "Twitch"
305+
},
306+
{
307+
"source": "Twilio",
308+
"target": "Twilio"
309+
},
266310
{
267311
"source": "Yuanbao",
268312
"target": "腾讯元宝"
269313
},
314+
{
315+
"source": "Zalo",
316+
"target": "Zalo"
317+
},
318+
{
319+
"source": "Zalo Personal",
320+
"target": "Zalo Personal"
321+
},
322+
{
323+
"source": "Zalo personal",
324+
"target": "Zalo Personal"
325+
},
270326
{
271327
"source": "WeChat",
272328
"target": "微信"
@@ -563,6 +619,10 @@
563619
"source": "QQ Bot",
564620
"target": "QQ Bot"
565621
},
622+
{
623+
"source": "QQBot",
624+
"target": "QQ Bot"
625+
},
566626
{
567627
"source": "Release Policy",
568628
"target": "发布策略"

docs/.i18n/glossary.zh-TW.json

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
"source": "ClawHub",
1212
"target": "ClawHub"
1313
},
14+
{
15+
"source": "ClickClack",
16+
"target": "ClickClack"
17+
},
1418
{
1519
"source": "CLI",
1620
"target": "命令列介面"
@@ -35,14 +39,38 @@
3539
"source": "Heartbeat",
3640
"target": "心跳偵測"
3741
},
42+
{
43+
"source": "Feishu",
44+
"target": "Feishu"
45+
},
46+
{
47+
"source": "IRC",
48+
"target": "IRC"
49+
},
50+
{
51+
"source": "LINE",
52+
"target": "LINE"
53+
},
54+
{
55+
"source": "Mattermost",
56+
"target": "Mattermost"
57+
},
3858
{
3959
"source": "Mintlify",
4060
"target": "Mintlify"
4161
},
62+
{
63+
"source": "Nextcloud Talk",
64+
"target": "Nextcloud Talk"
65+
},
4266
{
4367
"source": "Node",
4468
"target": "節點"
4569
},
70+
{
71+
"source": "Nostr",
72+
"target": "Nostr"
73+
},
4674
{
4775
"source": "OpenClaw",
4876
"target": "OpenClaw"
@@ -55,10 +83,30 @@
5583
"source": "Plugin",
5684
"target": "外掛"
5785
},
86+
{
87+
"source": "QQ Bot",
88+
"target": "QQ Bot"
89+
},
90+
{
91+
"source": "QQBot",
92+
"target": "QQ Bot"
93+
},
94+
{
95+
"source": "QQ bot",
96+
"target": "QQ Bot"
97+
},
98+
{
99+
"source": "SMS",
100+
"target": "SMS"
101+
},
58102
{
59103
"source": "Skills",
60104
"target": "Skills"
61105
},
106+
{
107+
"source": "Synology Chat",
108+
"target": "Synology Chat"
109+
},
62110
{
63111
"source": "Tailscale",
64112
"target": "Tailscale"
@@ -67,12 +115,48 @@
67115
"source": "TaskFlow",
68116
"target": "TaskFlow"
69117
},
118+
{
119+
"source": "Tlon",
120+
"target": "Tlon"
121+
},
122+
{
123+
"source": "Twitch",
124+
"target": "Twitch"
125+
},
126+
{
127+
"source": "Twilio",
128+
"target": "Twilio"
129+
},
70130
{
71131
"source": "TUI",
72132
"target": "終端介面"
73133
},
134+
{
135+
"source": "WeChat",
136+
"target": "微信"
137+
},
138+
{
139+
"source": "Weixin",
140+
"target": "微信"
141+
},
74142
{
75143
"source": "Webhook",
76144
"target": "網路鉤子"
145+
},
146+
{
147+
"source": "Yuanbao",
148+
"target": "騰訊元寶"
149+
},
150+
{
151+
"source": "Zalo",
152+
"target": "Zalo"
153+
},
154+
{
155+
"source": "Zalo Personal",
156+
"target": "Zalo Personal"
157+
},
158+
{
159+
"source": "Zalo personal",
160+
"target": "Zalo Personal"
77161
}
78162
]

src/agents/cli-runner.reliability.test.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
createUserTurnTranscriptRecorder,
1717
type UserTurnTranscriptRecorder,
1818
} from "../sessions/user-turn-transcript.js";
19+
import { captureEnv, setTestEnvValue } from "../test-utils/env.js";
1920
import { runPreparedCliAgent } from "./cli-runner.js";
2021
import {
2122
createManagedRun,
@@ -40,6 +41,7 @@ vi.mock("../tts/tts.js", () => ({
4041

4142
const mockGetGlobalHookRunner = vi.mocked(getGlobalHookRunner);
4243
const hookRunnerGlobalStateKey = Symbol.for("openclaw.plugins.hook-runner-global-state");
44+
let sessionFileEnvSnapshot: ReturnType<typeof captureEnv> | undefined;
4345

4446
type HookRunnerGlobalStateForTest = {
4547
hookRunner: unknown;
@@ -65,7 +67,8 @@ function createSessionFile(params?: { history?: Array<{ role: "user"; content: s
6567
// Session files use the real JSONL shape so transcript/history readers stay
6668
// covered without spinning up a full CLI process.
6769
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-cli-hooks-"));
68-
vi.stubEnv("OPENCLAW_STATE_DIR", dir);
70+
sessionFileEnvSnapshot ??= captureEnv(["OPENCLAW_STATE_DIR"]);
71+
setTestEnvValue("OPENCLAW_STATE_DIR", dir);
6972
const sessionFile = path.join(dir, "agents", "main", "sessions", "s1.jsonl");
7073
const storePath = path.join(path.dirname(sessionFile), "sessions.json");
7174
fs.mkdirSync(path.dirname(sessionFile), { recursive: true });
@@ -274,6 +277,8 @@ describe("runCliAgent reliability", () => {
274277
mockGetGlobalHookRunner.mockReset();
275278
setHookRunnerForTest(null);
276279
vi.unstubAllEnvs();
280+
sessionFileEnvSnapshot?.restore();
281+
sessionFileEnvSnapshot = undefined;
277282
});
278283

279284
it("fails with timeout when no-output watchdog trips", async () => {

src/agents/cli-runner/bundle-mcp.test-support.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
createBundleMcpTempHarness,
66
createBundleProbePlugin,
77
} from "../../plugins/bundle-mcp.test-support.js";
8-
import { captureEnv } from "../../test-utils/env.js";
8+
import { captureEnv, setTestEnvValue, withEnvAsync } from "../../test-utils/env.js";
99
import { prepareCliBundleMcpConfig } from "./bundle-mcp.js";
1010

1111
const tempHarness = createBundleMcpTempHarness();
@@ -47,7 +47,7 @@ export function setupCliBundleMcpTestHarness(): void {
4747
bundleProbeHomeDir = await tempHarness.createTempDir("openclaw-cli-bundle-mcp-home-");
4848
bundleProbeWorkspaceDir = await tempHarness.createTempDir("openclaw-cli-bundle-mcp-workspace-");
4949
const emptyBundledDir = await tempHarness.createTempDir("openclaw-cli-bundle-mcp-bundled-");
50-
process.env.OPENCLAW_BUNDLED_PLUGINS_DIR = emptyBundledDir;
50+
setTestEnvValue("OPENCLAW_BUNDLED_PLUGINS_DIR", emptyBundledDir);
5151
({ serverPath: bundleProbeServerPath } = await createBundleProbePlugin(bundleProbeHomeDir));
5252
});
5353

@@ -70,10 +70,8 @@ function createEnabledBundleProbeConfig(): OpenClawConfig {
7070
export async function prepareBundleProbeCliConfig(params?: {
7171
additionalConfig?: Parameters<typeof prepareCliBundleMcpConfig>[0]["additionalConfig"];
7272
}) {
73-
const env = captureEnv(["HOME"]);
74-
try {
75-
// Bundle discovery reads HOME for per-user plugin roots.
76-
process.env.HOME = bundleProbeHomeDir;
73+
// Bundle discovery reads HOME for per-user plugin roots.
74+
return await withEnvAsync({ HOME: bundleProbeHomeDir }, async () => {
7775
return await prepareCliBundleMcpConfig({
7876
enabled: true,
7977
mode: "claude-config-file",
@@ -85,7 +83,5 @@ export async function prepareBundleProbeCliConfig(params?: {
8583
config: createEnabledBundleProbeConfig(),
8684
additionalConfig: params?.additionalConfig,
8785
});
88-
} finally {
89-
env.restore();
90-
}
86+
});
9187
}

src/agents/cli-runner/bundle-mcp.user-config.test.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import fs from "node:fs/promises";
33
import path from "node:path";
44
import { describe, expect, it } from "vitest";
55
import { writeClaudeBundleManifest } from "../../plugins/bundle-mcp.test-support.js";
6-
import { captureEnv } from "../../test-utils/env.js";
6+
import { withEnvAsync } from "../../test-utils/env.js";
77
import { prepareCliBundleMcpConfig } from "./bundle-mcp.js";
88
import {
99
cliBundleMcpHarness,
@@ -214,9 +214,7 @@ describe("prepareCliBundleMcpConfig user mcp.servers", () => {
214214
"utf-8",
215215
);
216216

217-
const env = captureEnv(["HOME"]);
218-
try {
219-
process.env.HOME = cliBundleMcpHarness.bundleProbeHomeDir;
217+
await withEnvAsync({ HOME: cliBundleMcpHarness.bundleProbeHomeDir }, async () => {
220218
const prepared = await prepareCliBundleMcpConfig({
221219
enabled: true,
222220
mode: "claude-config-file",
@@ -263,8 +261,6 @@ describe("prepareCliBundleMcpConfig user mcp.servers", () => {
263261
expect(raw.mcpServers?.omi?.env).toBeUndefined();
264262

265263
await prepared.cleanup?.();
266-
} finally {
267-
env.restore();
268-
}
264+
});
269265
});
270266
});

src/agents/cli-runner/prepare.test.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
import type { ContextEngine } from "../../context-engine/types.js";
1515
import { getGlobalHookRunner } from "../../plugins/hook-runner-global.js";
1616
import { clearMemoryPluginState, registerMemoryPromptSection } from "../../plugins/memory-state.js";
17+
import { captureEnv, setTestEnvValue } from "../../test-utils/env.js";
1718
import { testing as cliBackendsTesting } from "../cli-backends.js";
1819
import { hashCliSessionText } from "../cli-session.js";
1920
import { resetContextWindowCacheForTest } from "../context.js";
@@ -28,6 +29,7 @@ import {
2829
} from "./prepare.js";
2930

3031
const getRuntimeConfigMock = vi.hoisted(() => vi.fn(() => ({})));
32+
let sessionFileEnvSnapshot: ReturnType<typeof captureEnv> | undefined;
3133

3234
vi.mock("../../config/config.js", () => ({
3335
getRuntimeConfig: getRuntimeConfigMock,
@@ -180,7 +182,8 @@ function createSessionFile() {
180182
// Prepare tests use canonical OpenClaw session paths because several cases
181183
// assert that external or stale transcript paths are ignored.
182184
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-cli-prepare-"));
183-
vi.stubEnv("OPENCLAW_STATE_DIR", dir);
185+
sessionFileEnvSnapshot ??= captureEnv(["OPENCLAW_STATE_DIR"]);
186+
setTestEnvValue("OPENCLAW_STATE_DIR", dir);
184187
const sessionFile = path.join(dir, "agents", "main", "sessions", "session-test.jsonl");
185188
fs.mkdirSync(path.dirname(sessionFile), { recursive: true });
186189
fs.writeFileSync(
@@ -263,6 +266,8 @@ describe("shouldSkipLocalCliCredentialEpoch", () => {
263266
resetContextWindowCacheForTest();
264267
clearMemoryPluginState();
265268
vi.unstubAllEnvs();
269+
sessionFileEnvSnapshot?.restore();
270+
sessionFileEnvSnapshot = undefined;
266271
});
267272

268273
it("skips local cli auth only when a profile-owned execution was prepared", () => {

0 commit comments

Comments
 (0)