chore: Fix types in tests 1/N.

This commit is contained in:
cpojer
2026-02-17 10:26:25 +09:00
parent 25126d75c3
commit 0cf443afe8
5 changed files with 135 additions and 90 deletions

View File

@@ -1,5 +1,6 @@
import type { OpenClawConfig } from "../../config/config.js"; import type { OpenClawConfig } from "../../config/config.js";
import type { MsgContext } from "../templating.js"; import type { MsgContext } from "../templating.js";
import type { HandleCommandsParams } from "./commands-types.js";
import { buildCommandContext } from "./commands.js"; import { buildCommandContext } from "./commands.js";
import { parseInlineDirectives } from "./directive-handling.js"; import { parseInlineDirectives } from "./directive-handling.js";
@@ -10,7 +11,7 @@ export function buildCommandTestParams(
options?: { options?: {
workspaceDir?: string; workspaceDir?: string;
}, },
) { ): HandleCommandsParams {
const ctx = { const ctx = {
Body: commandBody, Body: commandBody,
CommandBody: commandBody, CommandBody: commandBody,
@@ -29,7 +30,7 @@ export function buildCommandTestParams(
commandAuthorized: true, commandAuthorized: true,
}); });
return { const params: HandleCommandsParams = {
ctx, ctx,
cfg, cfg,
command, command,
@@ -38,12 +39,13 @@ export function buildCommandTestParams(
sessionKey: "agent:main:main", sessionKey: "agent:main:main",
workspaceDir: options?.workspaceDir ?? "/tmp", workspaceDir: options?.workspaceDir ?? "/tmp",
defaultGroupActivation: () => "mention", defaultGroupActivation: () => "mention",
resolvedVerboseLevel: "off" as const, resolvedVerboseLevel: "off",
resolvedReasoningLevel: "off" as const, resolvedReasoningLevel: "off",
resolveDefaultThinkingLevel: async () => undefined, resolveDefaultThinkingLevel: async () => undefined,
provider: "whatsapp", provider: "whatsapp",
model: "test-model", model: "test-model",
contextTokens: 0, contextTokens: 0,
isGroup: false, isGroup: false,
}; };
return params;
} }

View File

@@ -102,6 +102,7 @@ vi.mock("../../gateway/call.js", () => ({
callGateway: (opts: unknown) => callGatewayMock(opts), callGateway: (opts: unknown) => callGatewayMock(opts),
})); }));
import type { HandleCommandsParams } from "./commands-types.js";
import { buildCommandContext, handleCommands } from "./commands.js"; import { buildCommandContext, handleCommands } from "./commands.js";
// Avoid expensive workspace scans during /context tests. // Avoid expensive workspace scans during /context tests.
@@ -504,6 +505,7 @@ describe("/compact command", () => {
...params, ...params,
sessionEntry: { sessionEntry: {
sessionId: "session-1", sessionId: "session-1",
updatedAt: Date.now(),
groupId: "group-1", groupId: "group-1",
groupChannel: "#general", groupChannel: "#general",
space: "workspace-1", space: "workspace-1",
@@ -651,7 +653,7 @@ function buildPolicyParams(
commandBody: string, commandBody: string,
cfg: OpenClawConfig, cfg: OpenClawConfig,
ctxOverrides?: Partial<MsgContext>, ctxOverrides?: Partial<MsgContext>,
) { ): HandleCommandsParams {
const ctx = { const ctx = {
Body: commandBody, Body: commandBody,
CommandBody: commandBody, CommandBody: commandBody,
@@ -670,7 +672,7 @@ function buildPolicyParams(
commandAuthorized: true, commandAuthorized: true,
}); });
return { const params: HandleCommandsParams = {
ctx, ctx,
cfg, cfg,
command, command,
@@ -679,14 +681,15 @@ function buildPolicyParams(
sessionKey: "agent:main:main", sessionKey: "agent:main:main",
workspaceDir: "/tmp", workspaceDir: "/tmp",
defaultGroupActivation: () => "mention", defaultGroupActivation: () => "mention",
resolvedVerboseLevel: "off" as const, resolvedVerboseLevel: "off",
resolvedReasoningLevel: "off" as const, resolvedReasoningLevel: "off",
resolveDefaultThinkingLevel: async () => undefined, resolveDefaultThinkingLevel: async () => undefined,
provider: "telegram", provider: "telegram",
model: "test-model", model: "test-model",
contextTokens: 0, contextTokens: 0,
isGroup: false, isGroup: false,
}; };
return params;
} }
describe("handleCommands /allowlist", () => { describe("handleCommands /allowlist", () => {

View File

@@ -1,27 +1,27 @@
import { beforeEach, describe, expect, it, vi } from "vitest"; import { beforeEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../../../config/config.js"; import type { OpenClawConfig } from "../../../config/config.js";
const handleDiscordAction = vi.fn(async () => ({ details: { ok: true } })); const handleDiscordAction = vi.fn(async (..._args: unknown[]) => ({ details: { ok: true } }));
const handleTelegramAction = vi.fn(async () => ({ ok: true })); const handleTelegramAction = vi.fn(async (..._args: unknown[]) => ({ ok: true }));
const sendReactionSignal = vi.fn(async () => ({ ok: true })); const sendReactionSignal = vi.fn(async (..._args: unknown[]) => ({ ok: true }));
const removeReactionSignal = vi.fn(async () => ({ ok: true })); const removeReactionSignal = vi.fn(async (..._args: unknown[]) => ({ ok: true }));
const handleSlackAction = vi.fn(async () => ({ details: { ok: true } })); const handleSlackAction = vi.fn(async (..._args: unknown[]) => ({ details: { ok: true } }));
vi.mock("../../../agents/tools/discord-actions.js", () => ({ vi.mock("../../../agents/tools/discord-actions.js", () => ({
handleDiscordAction: (...args: unknown[]) => handleDiscordAction(...args), handleDiscordAction,
})); }));
vi.mock("../../../agents/tools/telegram-actions.js", () => ({ vi.mock("../../../agents/tools/telegram-actions.js", () => ({
handleTelegramAction: (...args: unknown[]) => handleTelegramAction(...args), handleTelegramAction,
})); }));
vi.mock("../../../signal/send-reactions.js", () => ({ vi.mock("../../../signal/send-reactions.js", () => ({
sendReactionSignal: (...args: unknown[]) => sendReactionSignal(...args), sendReactionSignal,
removeReactionSignal: (...args: unknown[]) => removeReactionSignal(...args), removeReactionSignal,
})); }));
vi.mock("../../../agents/tools/slack-actions.js", () => ({ vi.mock("../../../agents/tools/slack-actions.js", () => ({
handleSlackAction: (...args: unknown[]) => handleSlackAction(...args), handleSlackAction,
})); }));
const { discordMessageActions } = await import("./discord.js"); const { discordMessageActions } = await import("./discord.js");
@@ -136,7 +136,8 @@ describe("telegram message actions", () => {
}); });
it("routes poll with normalized params", async () => { it("routes poll with normalized params", async () => {
await telegramMessageActions.handleAction({ await telegramMessageActions.handleAction?.({
channel: "telegram",
action: "poll", action: "poll",
params: { params: {
to: "123", to: "123",
@@ -332,7 +333,7 @@ describe("handleDiscordMessageAction", () => {
describe("telegramMessageActions", () => { describe("telegramMessageActions", () => {
it("excludes sticker actions when not enabled", () => { it("excludes sticker actions when not enabled", () => {
const cfg = { channels: { telegram: { botToken: "tok" } } } as OpenClawConfig; const cfg = { channels: { telegram: { botToken: "tok" } } } as OpenClawConfig;
const actions = telegramMessageActions.listActions({ cfg }); const actions = telegramMessageActions.listActions?.({ cfg }) ?? [];
expect(actions).not.toContain("sticker"); expect(actions).not.toContain("sticker");
expect(actions).not.toContain("sticker-search"); expect(actions).not.toContain("sticker-search");
}); });
@@ -340,7 +341,8 @@ describe("telegramMessageActions", () => {
it("allows media-only sends and passes asVoice", async () => { it("allows media-only sends and passes asVoice", async () => {
const cfg = { channels: { telegram: { botToken: "tok" } } } as OpenClawConfig; const cfg = { channels: { telegram: { botToken: "tok" } } } as OpenClawConfig;
await telegramMessageActions.handleAction({ await telegramMessageActions.handleAction?.({
channel: "telegram",
action: "send", action: "send",
params: { params: {
to: "123", to: "123",
@@ -366,7 +368,8 @@ describe("telegramMessageActions", () => {
it("passes silent flag for silent sends", async () => { it("passes silent flag for silent sends", async () => {
const cfg = { channels: { telegram: { botToken: "tok" } } } as OpenClawConfig; const cfg = { channels: { telegram: { botToken: "tok" } } } as OpenClawConfig;
await telegramMessageActions.handleAction({ await telegramMessageActions.handleAction?.({
channel: "telegram",
action: "send", action: "send",
params: { params: {
to: "456", to: "456",
@@ -391,7 +394,8 @@ describe("telegramMessageActions", () => {
it("maps edit action params into editMessage", async () => { it("maps edit action params into editMessage", async () => {
const cfg = { channels: { telegram: { botToken: "tok" } } } as OpenClawConfig; const cfg = { channels: { telegram: { botToken: "tok" } } } as OpenClawConfig;
await telegramMessageActions.handleAction({ await telegramMessageActions.handleAction?.({
channel: "telegram",
action: "edit", action: "edit",
params: { params: {
chatId: "123", chatId: "123",
@@ -421,6 +425,7 @@ describe("telegramMessageActions", () => {
await expect( await expect(
telegramMessageActions.handleAction({ telegramMessageActions.handleAction({
channel: "telegram",
action: "edit", action: "edit",
params: { params: {
chatId: "123", chatId: "123",
@@ -445,7 +450,7 @@ describe("telegramMessageActions", () => {
}, },
}, },
} as OpenClawConfig; } as OpenClawConfig;
const actions = telegramMessageActions.listActions({ cfg }); const actions = telegramMessageActions.listActions?.({ cfg }) ?? [];
expect(actions).toContain("sticker"); expect(actions).toContain("sticker");
expect(actions).toContain("sticker-search"); expect(actions).toContain("sticker-search");
@@ -462,7 +467,7 @@ describe("telegramMessageActions", () => {
}, },
}, },
} as OpenClawConfig; } as OpenClawConfig;
const actions = telegramMessageActions.listActions({ cfg }); const actions = telegramMessageActions.listActions?.({ cfg }) ?? [];
expect(actions).not.toContain("sticker"); expect(actions).not.toContain("sticker");
expect(actions).not.toContain("sticker-search"); expect(actions).not.toContain("sticker-search");
@@ -471,7 +476,8 @@ describe("telegramMessageActions", () => {
it("accepts numeric messageId and channelId for reactions", async () => { it("accepts numeric messageId and channelId for reactions", async () => {
const cfg = { channels: { telegram: { botToken: "tok" } } } as OpenClawConfig; const cfg = { channels: { telegram: { botToken: "tok" } } } as OpenClawConfig;
await telegramMessageActions.handleAction({ await telegramMessageActions.handleAction?.({
channel: "telegram",
action: "react", action: "react",
params: { params: {
channelId: 123, channelId: 123,
@@ -483,17 +489,22 @@ describe("telegramMessageActions", () => {
}); });
expect(handleTelegramAction).toHaveBeenCalledTimes(1); expect(handleTelegramAction).toHaveBeenCalledTimes(1);
const call = handleTelegramAction.mock.calls[0]?.[0] as Record<string, unknown>; const call = handleTelegramAction.mock.calls[0]?.[0];
expect(call.action).toBe("react"); if (!call) {
expect(String(call.chatId)).toBe("123"); throw new Error("missing telegram action call");
expect(String(call.messageId)).toBe("456"); }
expect(call.emoji).toBe("ok"); const callPayload = call as Record<string, unknown>;
expect(callPayload.action).toBe("react");
expect(String(callPayload.chatId)).toBe("123");
expect(String(callPayload.messageId)).toBe("456");
expect(callPayload.emoji).toBe("ok");
}); });
it("routes poll action to sendPoll with question and options", async () => { it("routes poll action to sendPoll with question and options", async () => {
const cfg = { channels: { telegram: { botToken: "tok" } } } as OpenClawConfig; const cfg = { channels: { telegram: { botToken: "tok" } } } as OpenClawConfig;
await telegramMessageActions.handleAction({ await telegramMessageActions.handleAction?.({
channel: "telegram",
action: "poll", action: "poll",
params: { params: {
to: "-100123", to: "-100123",
@@ -519,14 +530,14 @@ describe("telegramMessageActions", () => {
describe("signalMessageActions", () => { describe("signalMessageActions", () => {
it("returns no actions when no configured accounts exist", () => { it("returns no actions when no configured accounts exist", () => {
const cfg = {} as OpenClawConfig; const cfg = {} as OpenClawConfig;
expect(signalMessageActions.listActions({ cfg })).toEqual([]); expect(signalMessageActions.listActions?.({ cfg }) ?? []).toEqual([]);
}); });
it("hides react when reactions are disabled", () => { it("hides react when reactions are disabled", () => {
const cfg = { const cfg = {
channels: { signal: { account: "+15550001111", actions: { reactions: false } } }, channels: { signal: { account: "+15550001111", actions: { reactions: false } } },
} as OpenClawConfig; } as OpenClawConfig;
expect(signalMessageActions.listActions({ cfg })).toEqual(["send"]); expect(signalMessageActions.listActions?.({ cfg }) ?? []).toEqual(["send"]);
}); });
it("enables react when at least one account allows reactions", () => { it("enables react when at least one account allows reactions", () => {
@@ -540,7 +551,7 @@ describe("signalMessageActions", () => {
}, },
}, },
} as OpenClawConfig; } as OpenClawConfig;
expect(signalMessageActions.listActions({ cfg })).toEqual(["send", "react"]); expect(signalMessageActions.listActions?.({ cfg }) ?? []).toEqual(["send", "react"]);
}); });
it("skips send for plugin dispatch", () => { it("skips send for plugin dispatch", () => {
@@ -555,6 +566,7 @@ describe("signalMessageActions", () => {
await expect( await expect(
signalMessageActions.handleAction({ signalMessageActions.handleAction({
channel: "signal",
action: "react", action: "react",
params: { to: "+15550001111", messageId: "123", emoji: "✅" }, params: { to: "+15550001111", messageId: "123", emoji: "✅" },
cfg, cfg,
@@ -575,7 +587,8 @@ describe("signalMessageActions", () => {
}, },
} as OpenClawConfig; } as OpenClawConfig;
await signalMessageActions.handleAction({ await signalMessageActions.handleAction?.({
channel: "signal",
action: "react", action: "react",
params: { to: "+15550001111", messageId: "123", emoji: "👍" }, params: { to: "+15550001111", messageId: "123", emoji: "👍" },
cfg, cfg,
@@ -592,7 +605,8 @@ describe("signalMessageActions", () => {
channels: { signal: { account: "+15550001111" } }, channels: { signal: { account: "+15550001111" } },
} as OpenClawConfig; } as OpenClawConfig;
await signalMessageActions.handleAction({ await signalMessageActions.handleAction?.({
channel: "signal",
action: "react", action: "react",
params: { params: {
recipient: "uuid:123e4567-e89b-12d3-a456-426614174000", recipient: "uuid:123e4567-e89b-12d3-a456-426614174000",
@@ -618,6 +632,7 @@ describe("signalMessageActions", () => {
await expect( await expect(
signalMessageActions.handleAction({ signalMessageActions.handleAction({
channel: "signal",
action: "react", action: "react",
params: { to: "signal:group:group-id", messageId: "123", emoji: "✅" }, params: { to: "signal:group:group-id", messageId: "123", emoji: "✅" },
cfg, cfg,
@@ -631,7 +646,8 @@ describe("signalMessageActions", () => {
channels: { signal: { account: "+15550001111" } }, channels: { signal: { account: "+15550001111" } },
} as OpenClawConfig; } as OpenClawConfig;
await signalMessageActions.handleAction({ await signalMessageActions.handleAction?.({
channel: "signal",
action: "react", action: "react",
params: { params: {
to: "signal:group:group-id", to: "signal:group:group-id",

View File

@@ -8,8 +8,8 @@ import type { ConfigFileSnapshot, OpenClawConfig } from "../config/types.js";
* but before runtime defaults), so runtime defaults don't leak into the written config. * but before runtime defaults), so runtime defaults don't leak into the written config.
*/ */
const mockReadConfigFileSnapshot = vi.fn<[], Promise<ConfigFileSnapshot>>(); const mockReadConfigFileSnapshot = vi.fn<() => Promise<ConfigFileSnapshot>>();
const mockWriteConfigFile = vi.fn<[OpenClawConfig], Promise<void>>(async () => {}); const mockWriteConfigFile = vi.fn<(cfg: OpenClawConfig) => Promise<void>>(async () => {});
vi.mock("../config/config.js", () => ({ vi.mock("../config/config.js", () => ({
readConfigFileSnapshot: () => mockReadConfigFileSnapshot(), readConfigFileSnapshot: () => mockReadConfigFileSnapshot(),
@@ -107,7 +107,7 @@ describe("config cli", () => {
const resolved: OpenClawConfig = { const resolved: OpenClawConfig = {
gateway: { port: 18789 }, gateway: { port: 18789 },
}; };
const runtimeMerged: OpenClawConfig = { const runtimeMerged = {
...resolved, ...resolved,
agents: { agents: {
defaults: { defaults: {
@@ -118,7 +118,7 @@ describe("config cli", () => {
} as never, } as never,
messages: { ackReaction: "✅" } as never, messages: { ackReaction: "✅" } as never,
sessions: { persistence: { enabled: true } } as never, sessions: { persistence: { enabled: true } } as never,
}; } as unknown as OpenClawConfig;
setSnapshot(resolved, runtimeMerged); setSnapshot(resolved, runtimeMerged);
await runConfigCommand(["config", "set", "gateway.auth.mode", "token"]); await runConfigCommand(["config", "set", "gateway.auth.mode", "token"]);

View File

@@ -11,7 +11,16 @@ import { OpenClawSchema } from "./zod-schema.js";
const { mapSensitivePaths } = __test__; const { mapSensitivePaths } = __test__;
function makeSnapshot(config: Record<string, unknown>, raw?: string): ConfigFileSnapshot { type TestSnapshot<TConfig extends Record<string, unknown>> = ConfigFileSnapshot & {
parsed: TConfig;
resolved: TConfig;
config: TConfig;
};
function makeSnapshot<TConfig extends Record<string, unknown>>(
config: TConfig,
raw?: string,
): TestSnapshot<TConfig> {
return { return {
path: "/home/user/.openclaw/config.json5", path: "/home/user/.openclaw/config.json5",
exists: true, exists: true,
@@ -24,17 +33,17 @@ function makeSnapshot(config: Record<string, unknown>, raw?: string): ConfigFile
issues: [], issues: [],
warnings: [], warnings: [],
legacyIssues: [], legacyIssues: [],
}; } as TestSnapshot<TConfig>;
} }
function restoreRedactedValues( function restoreRedactedValues<TOriginal>(
incoming: unknown, incoming: unknown,
original: unknown, original: TOriginal,
hints?: ConfigUiHints, hints?: ConfigUiHints,
): unknown { ): TOriginal {
var result = restoreRedactedValues_orig(incoming, original, hints); var result = restoreRedactedValues_orig(incoming, original, hints);
expect(result.ok).toBe(true); expect(result.ok).toBe(true);
return result.result; return result.result as TOriginal;
} }
describe("redactConfigSnapshot", () => { describe("redactConfigSnapshot", () => {
@@ -335,7 +344,8 @@ describe("redactConfigSnapshot", () => {
compaction: { softThresholdTokens: 50000 }, compaction: { softThresholdTokens: 50000 },
}); });
const result = redactConfigSnapshot(snapshot); const result = redactConfigSnapshot(snapshot);
const compaction = result.config.compaction as Record<string, number>; const config = result.config as typeof snapshot.config;
const compaction = config.compaction as Record<string, number>;
expect(compaction.softThresholdTokens).toBe(50000); expect(compaction.softThresholdTokens).toBe(50000);
}); });
@@ -365,7 +375,8 @@ describe("redactConfigSnapshot", () => {
custom: { mySecret: "this-is-a-custom-secret-value" }, custom: { mySecret: "this-is-a-custom-secret-value" },
}); });
const result = redactConfigSnapshot(snapshot, hints); const result = redactConfigSnapshot(snapshot, hints);
const custom = result.config.custom as Record<string, string>; const config = result.config as typeof snapshot.config;
const custom = config.custom as Record<string, string>;
const resolved = result.resolved as Record<string, Record<string, string>>; const resolved = result.resolved as Record<string, Record<string, string>>;
expect(custom.mySecret).toBe(REDACTED_SENTINEL); expect(custom.mySecret).toBe(REDACTED_SENTINEL);
expect(resolved.custom.mySecret).toBe(REDACTED_SENTINEL); expect(resolved.custom.mySecret).toBe(REDACTED_SENTINEL);
@@ -396,12 +407,11 @@ describe("redactConfigSnapshot", () => {
}); });
const redacted = redactConfigSnapshot(snapshot, hints); const redacted = redactConfigSnapshot(snapshot, hints);
expect(redacted.config.plugins.entries["voice-call"].config.apiToken).toBe(REDACTED_SENTINEL); const config = redacted.config as typeof snapshot.config;
expect(redacted.config.plugins.entries["voice-call"].config.displayName).toBe( expect(config.plugins.entries["voice-call"].config.apiToken).toBe(REDACTED_SENTINEL);
"Voice call extension", expect(config.plugins.entries["voice-call"].config.displayName).toBe("Voice call extension");
); expect(config.channels["my-channel"].accessToken).toBe(REDACTED_SENTINEL);
expect(redacted.config.channels["my-channel"].accessToken).toBe(REDACTED_SENTINEL); expect(config.channels["my-channel"].room).toBe("general");
expect(redacted.config.channels["my-channel"].room).toBe("general");
const restored = restoreRedactedValues(redacted.config, snapshot.config, hints); const restored = restoreRedactedValues(redacted.config, snapshot.config, hints);
expect(restored).toEqual(snapshot.config); expect(restored).toEqual(snapshot.config);
@@ -425,9 +435,8 @@ describe("redactConfigSnapshot", () => {
}); });
const redacted = redactConfigSnapshot(snapshot, hints); const redacted = redactConfigSnapshot(snapshot, hints);
expect(redacted.config.plugins.entries["voice-call"].config.apiToken).toBe( const config = redacted.config as typeof snapshot.config;
"not-secret-on-purpose", expect(config.plugins.entries["voice-call"].config.apiToken).toBe("not-secret-on-purpose");
);
}); });
it("handles nested values properly (roundtrip)", () => { it("handles nested values properly (roundtrip)", () => {
@@ -436,8 +445,9 @@ describe("redactConfigSnapshot", () => {
custom2: [{ mySecret: "this-is-a-custom-secret-value" }], custom2: [{ mySecret: "this-is-a-custom-secret-value" }],
}); });
const result = redactConfigSnapshot(snapshot); const result = redactConfigSnapshot(snapshot);
expect(result.config.custom1.anykey.mySecret).toBe(REDACTED_SENTINEL); const config = result.config as typeof snapshot.config;
expect(result.config.custom2[0].mySecret).toBe(REDACTED_SENTINEL); expect(config.custom1.anykey.mySecret).toBe(REDACTED_SENTINEL);
expect(config.custom2[0].mySecret).toBe(REDACTED_SENTINEL);
const restored = restoreRedactedValues(result.config, snapshot.config); const restored = restoreRedactedValues(result.config, snapshot.config);
expect(restored.custom1.anykey.mySecret).toBe("this-is-a-custom-secret-value"); expect(restored.custom1.anykey.mySecret).toBe("this-is-a-custom-secret-value");
expect(restored.custom2[0].mySecret).toBe("this-is-a-custom-secret-value"); expect(restored.custom2[0].mySecret).toBe("this-is-a-custom-secret-value");
@@ -453,8 +463,9 @@ describe("redactConfigSnapshot", () => {
custom2: [{ mySecret: "this-is-a-custom-secret-value" }], custom2: [{ mySecret: "this-is-a-custom-secret-value" }],
}); });
const result = redactConfigSnapshot(snapshot, hints); const result = redactConfigSnapshot(snapshot, hints);
expect(result.config.custom1.anykey.mySecret).toBe(REDACTED_SENTINEL); const config = result.config as typeof snapshot.config;
expect(result.config.custom2[0].mySecret).toBe(REDACTED_SENTINEL); expect(config.custom1.anykey.mySecret).toBe(REDACTED_SENTINEL);
expect(config.custom2[0].mySecret).toBe(REDACTED_SENTINEL);
const restored = restoreRedactedValues(result.config, snapshot.config, hints); const restored = restoreRedactedValues(result.config, snapshot.config, hints);
expect(restored.custom1.anykey.mySecret).toBe("this-is-a-custom-secret-value"); expect(restored.custom1.anykey.mySecret).toBe("this-is-a-custom-secret-value");
expect(restored.custom2[0].mySecret).toBe("this-is-a-custom-secret-value"); expect(restored.custom2[0].mySecret).toBe("this-is-a-custom-secret-value");
@@ -465,8 +476,9 @@ describe("redactConfigSnapshot", () => {
custom: { token: "this-is-a-custom-secret-value", mySecret: "this-is-a-custom-secret-value" }, custom: { token: "this-is-a-custom-secret-value", mySecret: "this-is-a-custom-secret-value" },
}); });
const result = redactConfigSnapshot(snapshot); const result = redactConfigSnapshot(snapshot);
expect(result.config.custom.token).toBe(REDACTED_SENTINEL); const config = result.config as typeof snapshot.config;
expect(result.config.custom.mySecret).toBe(REDACTED_SENTINEL); expect(config.custom.token).toBe(REDACTED_SENTINEL);
expect(config.custom.mySecret).toBe(REDACTED_SENTINEL);
const restored = restoreRedactedValues(result.config, snapshot.config); const restored = restoreRedactedValues(result.config, snapshot.config);
expect(restored.custom.token).toBe("this-is-a-custom-secret-value"); expect(restored.custom.token).toBe("this-is-a-custom-secret-value");
expect(restored.custom.mySecret).toBe("this-is-a-custom-secret-value"); expect(restored.custom.mySecret).toBe("this-is-a-custom-secret-value");
@@ -483,8 +495,9 @@ describe("redactConfigSnapshot", () => {
}, },
}); });
const result = redactConfigSnapshot(snapshot, hints); const result = redactConfigSnapshot(snapshot, hints);
expect(result.config.custom.anykey).toBe(REDACTED_SENTINEL); const config = result.config as typeof snapshot.config;
expect(result.config.custom.mySecret).toBe(REDACTED_SENTINEL); expect(config.custom.anykey).toBe(REDACTED_SENTINEL);
expect(config.custom.mySecret).toBe(REDACTED_SENTINEL);
const restored = restoreRedactedValues(result.config, snapshot.config, hints); const restored = restoreRedactedValues(result.config, snapshot.config, hints);
expect(restored.custom.anykey).toBe("this-is-a-custom-secret-value"); expect(restored.custom.anykey).toBe("this-is-a-custom-secret-value");
expect(restored.custom.mySecret).toBe("this-is-a-custom-secret-value"); expect(restored.custom.mySecret).toBe("this-is-a-custom-secret-value");
@@ -495,8 +508,9 @@ describe("redactConfigSnapshot", () => {
token: ["this-is-a-custom-secret-value", "this-is-a-custom-secret-value"], token: ["this-is-a-custom-secret-value", "this-is-a-custom-secret-value"],
}); });
const result = redactConfigSnapshot(snapshot); const result = redactConfigSnapshot(snapshot);
expect(result.config.token[0]).toBe(REDACTED_SENTINEL); const config = result.config as typeof snapshot.config;
expect(result.config.token[1]).toBe(REDACTED_SENTINEL); expect(config.token[0]).toBe(REDACTED_SENTINEL);
expect(config.token[1]).toBe(REDACTED_SENTINEL);
const restored = restoreRedactedValues(result.config, snapshot.config); const restored = restoreRedactedValues(result.config, snapshot.config);
expect(restored.token[0]).toBe("this-is-a-custom-secret-value"); expect(restored.token[0]).toBe("this-is-a-custom-secret-value");
expect(restored.token[1]).toBe("this-is-a-custom-secret-value"); expect(restored.token[1]).toBe("this-is-a-custom-secret-value");
@@ -510,8 +524,9 @@ describe("redactConfigSnapshot", () => {
custom: ["this-is-a-custom-secret-value", "this-is-a-custom-secret-value"], custom: ["this-is-a-custom-secret-value", "this-is-a-custom-secret-value"],
}); });
const result = redactConfigSnapshot(snapshot, hints); const result = redactConfigSnapshot(snapshot, hints);
expect(result.config.custom[0]).toBe(REDACTED_SENTINEL); const config = result.config as typeof snapshot.config;
expect(result.config.custom[1]).toBe(REDACTED_SENTINEL); expect(config.custom[0]).toBe(REDACTED_SENTINEL);
expect(config.custom[1]).toBe(REDACTED_SENTINEL);
const restored = restoreRedactedValues(result.config, snapshot.config, hints); const restored = restoreRedactedValues(result.config, snapshot.config, hints);
expect(restored.custom[0]).toBe("this-is-a-custom-secret-value"); expect(restored.custom[0]).toBe("this-is-a-custom-secret-value");
expect(restored.custom[1]).toBe("this-is-a-custom-secret-value"); expect(restored.custom[1]).toBe("this-is-a-custom-secret-value");
@@ -522,8 +537,9 @@ describe("redactConfigSnapshot", () => {
harmless: ["this-is-a-custom-harmless-value", "this-is-a-custom-secret-looking-value"], harmless: ["this-is-a-custom-harmless-value", "this-is-a-custom-secret-looking-value"],
}); });
const result = redactConfigSnapshot(snapshot); const result = redactConfigSnapshot(snapshot);
expect(result.config.harmless[0]).toBe("this-is-a-custom-harmless-value"); const config = result.config as typeof snapshot.config;
expect(result.config.harmless[1]).toBe("this-is-a-custom-secret-looking-value"); expect(config.harmless[0]).toBe("this-is-a-custom-harmless-value");
expect(config.harmless[1]).toBe("this-is-a-custom-secret-looking-value");
const restored = restoreRedactedValues(result.config, snapshot.config); const restored = restoreRedactedValues(result.config, snapshot.config);
expect(restored.harmless[0]).toBe("this-is-a-custom-harmless-value"); expect(restored.harmless[0]).toBe("this-is-a-custom-harmless-value");
expect(restored.harmless[1]).toBe("this-is-a-custom-secret-looking-value"); expect(restored.harmless[1]).toBe("this-is-a-custom-secret-looking-value");
@@ -537,8 +553,9 @@ describe("redactConfigSnapshot", () => {
custom: ["this-is-a-custom-harmless-value", "this-is-a-custom-secret-value"], custom: ["this-is-a-custom-harmless-value", "this-is-a-custom-secret-value"],
}); });
const result = redactConfigSnapshot(snapshot, hints); const result = redactConfigSnapshot(snapshot, hints);
expect(result.config.custom[0]).toBe("this-is-a-custom-harmless-value"); const config = result.config as typeof snapshot.config;
expect(result.config.custom[1]).toBe("this-is-a-custom-secret-value"); expect(config.custom[0]).toBe("this-is-a-custom-harmless-value");
expect(config.custom[1]).toBe("this-is-a-custom-secret-value");
const restored = restoreRedactedValues(result.config, snapshot.config, hints); const restored = restoreRedactedValues(result.config, snapshot.config, hints);
expect(restored.custom[0]).toBe("this-is-a-custom-harmless-value"); expect(restored.custom[0]).toBe("this-is-a-custom-harmless-value");
expect(restored.custom[1]).toBe("this-is-a-custom-secret-value"); expect(restored.custom[1]).toBe("this-is-a-custom-secret-value");
@@ -553,8 +570,9 @@ describe("redactConfigSnapshot", () => {
}, },
}); });
const result = redactConfigSnapshot(snapshot); const result = redactConfigSnapshot(snapshot);
expect(result.config.nested.level.token[0]).toBe(REDACTED_SENTINEL); const config = result.config as typeof snapshot.config;
expect(result.config.nested.level.token[1]).toBe(REDACTED_SENTINEL); expect(config.nested.level.token[0]).toBe(REDACTED_SENTINEL);
expect(config.nested.level.token[1]).toBe(REDACTED_SENTINEL);
const restored = restoreRedactedValues(result.config, snapshot.config); const restored = restoreRedactedValues(result.config, snapshot.config);
expect(restored.nested.level.token[0]).toBe("this-is-a-custom-secret-value"); expect(restored.nested.level.token[0]).toBe("this-is-a-custom-secret-value");
expect(restored.nested.level.token[1]).toBe("this-is-a-custom-secret-value"); expect(restored.nested.level.token[1]).toBe("this-is-a-custom-secret-value");
@@ -572,8 +590,9 @@ describe("redactConfigSnapshot", () => {
}, },
}); });
const result = redactConfigSnapshot(snapshot, hints); const result = redactConfigSnapshot(snapshot, hints);
expect(result.config.nested.level.custom[0]).toBe(REDACTED_SENTINEL); const config = result.config as typeof snapshot.config;
expect(result.config.nested.level.custom[1]).toBe(REDACTED_SENTINEL); expect(config.nested.level.custom[0]).toBe(REDACTED_SENTINEL);
expect(config.nested.level.custom[1]).toBe(REDACTED_SENTINEL);
const restored = restoreRedactedValues(result.config, snapshot.config, hints); const restored = restoreRedactedValues(result.config, snapshot.config, hints);
expect(restored.nested.level.custom[0]).toBe("this-is-a-custom-secret-value"); expect(restored.nested.level.custom[0]).toBe("this-is-a-custom-secret-value");
expect(restored.nested.level.custom[1]).toBe("this-is-a-custom-secret-value"); expect(restored.nested.level.custom[1]).toBe("this-is-a-custom-secret-value");
@@ -588,8 +607,9 @@ describe("redactConfigSnapshot", () => {
}, },
}); });
const result = redactConfigSnapshot(snapshot); const result = redactConfigSnapshot(snapshot);
expect(result.config.nested.level.token[0]).toBe(42); const config = result.config as typeof snapshot.config;
expect(result.config.nested.level.token[1]).toBe(815); expect(config.nested.level.token[0]).toBe(42);
expect(config.nested.level.token[1]).toBe(815);
const restored = restoreRedactedValues(result.config, snapshot.config); const restored = restoreRedactedValues(result.config, snapshot.config);
expect(restored.nested.level.token[0]).toBe(42); expect(restored.nested.level.token[0]).toBe(42);
expect(restored.nested.level.token[1]).toBe(815); expect(restored.nested.level.token[1]).toBe(815);
@@ -607,8 +627,9 @@ describe("redactConfigSnapshot", () => {
}, },
}); });
const result = redactConfigSnapshot(snapshot, hints); const result = redactConfigSnapshot(snapshot, hints);
expect(result.config.nested.level.custom[0]).toBe(42); const config = result.config as typeof snapshot.config;
expect(result.config.nested.level.custom[1]).toBe(815); expect(config.nested.level.custom[0]).toBe(42);
expect(config.nested.level.custom[1]).toBe(815);
const restored = restoreRedactedValues(result.config, snapshot.config, hints); const restored = restoreRedactedValues(result.config, snapshot.config, hints);
expect(restored.nested.level.custom[0]).toBe(42); expect(restored.nested.level.custom[0]).toBe(42);
expect(restored.nested.level.custom[1]).toBe(815); expect(restored.nested.level.custom[1]).toBe(815);
@@ -623,8 +644,9 @@ describe("redactConfigSnapshot", () => {
}, },
}); });
const result = redactConfigSnapshot(snapshot); const result = redactConfigSnapshot(snapshot);
expect(result.config.nested.password.harmless[0]).toBe(REDACTED_SENTINEL); const config = result.config as typeof snapshot.config;
expect(result.config.nested.password.harmless[1]).toBe(REDACTED_SENTINEL); expect(config.nested.password.harmless[0]).toBe(REDACTED_SENTINEL);
expect(config.nested.password.harmless[1]).toBe(REDACTED_SENTINEL);
const restored = restoreRedactedValues(result.config, snapshot.config); const restored = restoreRedactedValues(result.config, snapshot.config);
expect(restored.nested.password.harmless[0]).toBe("value"); expect(restored.nested.password.harmless[0]).toBe("value");
expect(restored.nested.password.harmless[1]).toBe("value"); expect(restored.nested.password.harmless[1]).toBe("value");
@@ -639,8 +661,9 @@ describe("redactConfigSnapshot", () => {
}, },
}); });
const result = redactConfigSnapshot(snapshot); const result = redactConfigSnapshot(snapshot);
expect(result.config.nested.level.harmless[0]).toBe("value"); const config = result.config as typeof snapshot.config;
expect(result.config.nested.level.harmless[1]).toBe("value"); expect(config.nested.level.harmless[0]).toBe("value");
expect(config.nested.level.harmless[1]).toBe("value");
const restored = restoreRedactedValues(result.config, snapshot.config); const restored = restoreRedactedValues(result.config, snapshot.config);
expect(restored.nested.level.harmless[0]).toBe("value"); expect(restored.nested.level.harmless[0]).toBe("value");
expect(restored.nested.level.harmless[1]).toBe("value"); expect(restored.nested.level.harmless[1]).toBe("value");
@@ -816,7 +839,7 @@ describe("restoreRedactedValues", () => {
}; };
const snapshot = makeSnapshot(originalConfig); const snapshot = makeSnapshot(originalConfig);
const redacted = redactConfigSnapshot(snapshot, hints); const redacted = redactConfigSnapshot(snapshot, hints);
const custom = redacted.config.custom as Record<string, string>; const custom = (redacted.config as typeof originalConfig).custom as Record<string, string>;
expect(custom.myApiKey).toBe(REDACTED_SENTINEL); expect(custom.myApiKey).toBe(REDACTED_SENTINEL);
expect(custom.displayName).toBe("My Bot"); expect(custom.displayName).toBe("My Bot");
@@ -905,8 +928,9 @@ describe("realredactConfigSnapshot_real", () => {
}); });
const result = redactConfigSnapshot(snapshot, hints); const result = redactConfigSnapshot(snapshot, hints);
expect(result.config.agents.defaults.memorySearch.remote.apiKey).toBe(REDACTED_SENTINEL); const config = result.config as typeof snapshot.config;
expect(result.config.agents.list[0].memorySearch.remote.apiKey).toBe(REDACTED_SENTINEL); expect(config.agents.defaults.memorySearch.remote.apiKey).toBe(REDACTED_SENTINEL);
expect(config.agents.list[0].memorySearch.remote.apiKey).toBe(REDACTED_SENTINEL);
const restored = restoreRedactedValues(result.config, snapshot.config, hints); const restored = restoreRedactedValues(result.config, snapshot.config, hints);
expect(restored.agents.defaults.memorySearch.remote.apiKey).toBe("1234"); expect(restored.agents.defaults.memorySearch.remote.apiKey).toBe("1234");
expect(restored.agents.list[0].memorySearch.remote.apiKey).toBe("6789"); expect(restored.agents.list[0].memorySearch.remote.apiKey).toBe("6789");