mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 18:40:44 +00:00
CLI: address channel setup review comments
This commit is contained in:
@@ -24,7 +24,7 @@ import { removeChannelConfigWizard } from "./configure.channels.js";
|
||||
|
||||
describe("removeChannelConfigWizard", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.resetAllMocks();
|
||||
confirm.mockResolvedValue(true);
|
||||
});
|
||||
|
||||
@@ -34,6 +34,8 @@ describe("removeChannelConfigWizard", () => {
|
||||
await removeChannelConfigWizard(
|
||||
{
|
||||
channels: {
|
||||
defaults: { groupPolicy: "open" },
|
||||
modelByChannel: { openai: { telegram: "gpt-5.4" } },
|
||||
twitch: {},
|
||||
unknown: {},
|
||||
telegram: {},
|
||||
@@ -80,6 +82,26 @@ describe("removeChannelConfigWizard", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("preserves channel-wide defaults when deleting the last channel block", async () => {
|
||||
select.mockResolvedValueOnce("telegram").mockResolvedValueOnce("done");
|
||||
|
||||
const next = await removeChannelConfigWizard(
|
||||
{
|
||||
channels: {
|
||||
defaults: { groupPolicy: "open" },
|
||||
modelByChannel: { openai: { telegram: "gpt-5.4" } },
|
||||
telegram: { token: "secret" },
|
||||
},
|
||||
} as never,
|
||||
{} as never,
|
||||
);
|
||||
|
||||
expect(next.channels).toEqual({
|
||||
defaults: { groupPolicy: "open" },
|
||||
modelByChannel: { openai: { telegram: "gpt-5.4" } },
|
||||
});
|
||||
});
|
||||
|
||||
it("sanitizes unknown channel keys before rendering prompts", async () => {
|
||||
const unsafeChannel = "bad\u001B[31m\nkey\u0007";
|
||||
select.mockResolvedValueOnce(unsafeChannel).mockResolvedValueOnce("done");
|
||||
|
||||
@@ -14,6 +14,8 @@ type ConfiguredChannelRemovalChoice = {
|
||||
label: string;
|
||||
};
|
||||
|
||||
const RESERVED_CHANNEL_CONFIG_KEYS = new Set(["defaults", "modelByChannel"]);
|
||||
|
||||
function listConfiguredChannelRemovalChoices(
|
||||
cfg: OpenClawConfig,
|
||||
): ConfiguredChannelRemovalChoice[] {
|
||||
@@ -23,6 +25,7 @@ function listConfiguredChannelRemovalChoices(
|
||||
}
|
||||
const labelsById = new Map(listChatChannels().map((meta) => [meta.id, meta.label]));
|
||||
return Object.keys(channels)
|
||||
.filter((id) => !RESERVED_CHANNEL_CONFIG_KEYS.has(id))
|
||||
.map((id) => ({
|
||||
id,
|
||||
label: labelsById.get(id) ?? formatUnknownChannelRemovalLabel(id),
|
||||
|
||||
@@ -72,7 +72,8 @@ vi.mock("../commands/channel-setup/plugin-install.js", () => ({
|
||||
}));
|
||||
|
||||
vi.mock("../commands/channel-setup/registry.js", () => ({
|
||||
resolveChannelSetupWizardAdapterForPlugin: () => undefined,
|
||||
resolveChannelSetupWizardAdapterForPlugin: (plugin?: { setupWizard?: unknown }) =>
|
||||
plugin?.setupWizard,
|
||||
}));
|
||||
|
||||
vi.mock("../commands/channel-setup/trusted-catalog.js", () => ({
|
||||
@@ -226,4 +227,91 @@ describe("setupChannels workspace shadow exclusion", () => {
|
||||
expect(getChannelSetupPlugin).not.toHaveBeenCalled();
|
||||
expect(loadChannelSetupPluginRegistrySnapshotForChannel).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("loads the selected bundled catalog plugin without writing explicit plugin enablement", async () => {
|
||||
const setupWizard = {
|
||||
channel: "telegram",
|
||||
getStatus: vi.fn(async () => ({
|
||||
channel: "telegram",
|
||||
configured: false,
|
||||
statusLines: [],
|
||||
})),
|
||||
configure: vi.fn(async ({ cfg }: { cfg: Record<string, unknown> }) => ({
|
||||
cfg: {
|
||||
...cfg,
|
||||
channels: {
|
||||
telegram: { token: "secret" },
|
||||
},
|
||||
},
|
||||
})),
|
||||
};
|
||||
const telegramPlugin = {
|
||||
id: "telegram",
|
||||
meta: { id: "telegram", label: "Telegram", blurb: "" },
|
||||
capabilities: {},
|
||||
config: {
|
||||
resolveAccount: vi.fn(() => ({})),
|
||||
},
|
||||
setupWizard,
|
||||
};
|
||||
const installedCatalogEntry = {
|
||||
id: "telegram",
|
||||
pluginId: "telegram",
|
||||
origin: "bundled",
|
||||
meta: { id: "telegram", label: "Telegram", blurb: "" },
|
||||
};
|
||||
resolveChannelSetupEntries.mockReturnValue({
|
||||
entries: [
|
||||
{
|
||||
id: "telegram",
|
||||
meta: { id: "telegram", label: "Telegram", blurb: "" },
|
||||
},
|
||||
],
|
||||
installedCatalogEntries: [installedCatalogEntry],
|
||||
installableCatalogEntries: [],
|
||||
installedCatalogById: new Map([["telegram", installedCatalogEntry]]),
|
||||
installableCatalogById: new Map(),
|
||||
});
|
||||
loadChannelSetupPluginRegistrySnapshotForChannel.mockReturnValue({
|
||||
channels: [{ plugin: telegramPlugin }],
|
||||
channelSetups: [],
|
||||
});
|
||||
const select = vi.fn().mockResolvedValueOnce("telegram").mockResolvedValueOnce("__done__");
|
||||
|
||||
const next = await setupChannels(
|
||||
{} as never,
|
||||
{} as never,
|
||||
{
|
||||
confirm: vi.fn(async () => true),
|
||||
note: vi.fn(async () => undefined),
|
||||
select,
|
||||
} as never,
|
||||
{
|
||||
deferStatusUntilSelection: true,
|
||||
skipConfirm: true,
|
||||
skipDmPolicyPrompt: true,
|
||||
},
|
||||
);
|
||||
|
||||
expect(loadChannelSetupPluginRegistrySnapshotForChannel).toHaveBeenCalledTimes(1);
|
||||
expect(loadChannelSetupPluginRegistrySnapshotForChannel).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
channel: "telegram",
|
||||
pluginId: "telegram",
|
||||
workspaceDir: "/tmp/openclaw-workspace",
|
||||
}),
|
||||
);
|
||||
expect(getChannelSetupPlugin).not.toHaveBeenCalled();
|
||||
expect(collectChannelStatus).not.toHaveBeenCalled();
|
||||
expect(setupWizard.configure).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
cfg: {},
|
||||
}),
|
||||
);
|
||||
expect(next).toEqual({
|
||||
channels: {
|
||||
telegram: { token: "secret" },
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -512,7 +512,7 @@ export async function setupChannels(
|
||||
}
|
||||
await loadScopedChannelPlugin(channel, result.pluginId ?? catalogEntry.pluginId);
|
||||
await refreshStatus(channel);
|
||||
} else if (installedCatalogEntry && installedCatalogEntry.origin !== "bundled") {
|
||||
} else if (installedCatalogEntry) {
|
||||
const plugin = await loadScopedChannelPlugin(channel, installedCatalogEntry.pluginId);
|
||||
if (!plugin) {
|
||||
await prompter.note(`${channel} plugin not available.`, "Channel setup");
|
||||
|
||||
Reference in New Issue
Block a user