


























@@ -6414,6 +6414,85 @@ describe("runCodexAppServerAttempt", () => {
64146414expect(binding?.pluginAppPolicyContext).toEqual(pluginAppPolicyContext);
64156415});
641664166417+it("keeps native hook relay config as the final thread config patch", async () => {
6418+const sessionFile = path.join(tempDir, "session.jsonl");
6419+const workspaceDir = path.join(tempDir, "workspace");
6420+const params = createParams(sessionFile, workspaceDir);
6421+const appServer = createThreadLifecycleAppServerOptions();
6422+const request = vi.fn(async (method: string) => {
6423+if (method === "thread/start" || method === "thread/resume") {
6424+return threadStartResult("thread-hooks");
6425+}
6426+throw new Error(`unexpected method: ${method}`);
6427+});
6428+const pluginAppPolicyContext = createPluginAppPolicyContext();
6429+const finalConfigPatch = {
6430+"features.hooks": true,
6431+"hooks.PreToolUse": [
6432+{
6433+hooks: [{ type: "command", command: "openclaw-native-hook-relay", timeout: 5 }],
6434+},
6435+],
6436+};
6437+const buildPluginThreadConfig = vi.fn(async () => ({
6438+enabled: true,
6439+configPatch: {
6440+"features.hooks": false,
6441+"hooks.PreToolUse": [],
6442+ ...createPluginAppConfigPatch(),
6443+},
6444+fingerprint: "plugin-apps-config-1",
6445+inputFingerprint: "plugin-apps-input-1",
6446+policyContext: pluginAppPolicyContext,
6447+diagnostics: [],
6448+}));
6449+const pluginThreadConfig = {
6450+enabled: true,
6451+inputFingerprint: "plugin-apps-input-1",
6452+build: buildPluginThreadConfig,
6453+};
6454+6455+await startOrResumeThread({
6456+client: { request } as never,
6457+ params,
6458+cwd: workspaceDir,
6459+dynamicTools: [],
6460+ appServer,
6461+config: { "features.hooks": false },
6462+ finalConfigPatch,
6463+ pluginThreadConfig,
6464+});
6465+await startOrResumeThread({
6466+client: { request } as never,
6467+ params,
6468+cwd: workspaceDir,
6469+dynamicTools: [],
6470+ appServer,
6471+config: { "features.hooks": false },
6472+ finalConfigPatch,
6473+pluginThreadConfig: {
6474+ ...pluginThreadConfig,
6475+enabledPluginConfigKeys: ["google-calendar"],
6476+},
6477+});
6478+6479+const requestCalls = request.mock.calls as unknown as Array<[string, { config?: unknown }]>;
6480+expect(requestCalls.map(([method]) => method)).toEqual(["thread/start", "thread/resume"]);
6481+expect(requestCalls[0]?.[1].config).toMatchObject({
6482+"features.hooks": true,
6483+"features.code_mode": true,
6484+"features.code_mode_only": true,
6485+"hooks.PreToolUse": finalConfigPatch["hooks.PreToolUse"],
6486+ ...createPluginAppConfigPatch(),
6487+});
6488+expect(requestCalls[1]?.[1].config).toMatchObject({
6489+"features.hooks": true,
6490+"features.code_mode": true,
6491+"features.code_mode_only": true,
6492+"hooks.PreToolUse": finalConfigPatch["hooks.PreToolUse"],
6493+});
6494+});
6495+64176496it("revalidates compatible plugin app bindings without resending app config", async () => {
64186497const sessionFile = path.join(tempDir, "session.jsonl");
64196498const workspaceDir = path.join(tempDir, "workspace");
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。