fix(telegram): clean up update offset on channels remove --delete (#18233)

This commit is contained in:
yinghaosang
2026-02-17 01:51:48 +08:00
committed by Peter Steinberger
parent b91e43714b
commit 6757a9fedc
4 changed files with 156 additions and 0 deletions

View File

@@ -11,6 +11,10 @@ const authMocks = vi.hoisted(() => ({
loadAuthProfileStore: vi.fn(),
}));
const offsetMocks = vi.hoisted(() => ({
deleteTelegramUpdateOffset: vi.fn().mockResolvedValue(undefined),
}));
vi.mock("../config/config.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../config/config.js")>();
return {
@@ -28,6 +32,14 @@ vi.mock("../agents/auth-profiles.js", async (importOriginal) => {
};
});
vi.mock("../telegram/update-offset-store.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../telegram/update-offset-store.js")>();
return {
...actual,
deleteTelegramUpdateOffset: offsetMocks.deleteTelegramUpdateOffset,
};
});
import {
channelsAddCommand,
channelsListCommand,
@@ -42,6 +54,7 @@ describe("channels command", () => {
configMocks.readConfigFileSnapshot.mockReset();
configMocks.writeConfigFile.mockClear();
authMocks.loadAuthProfileStore.mockReset();
offsetMocks.deleteTelegramUpdateOffset.mockClear();
runtime.log.mockClear();
runtime.error.mockClear();
runtime.exit.mockClear();
@@ -456,4 +469,70 @@ describe("channels command", () => {
});
expect(disconnected.join("\n")).toMatch(/disconnected/i);
});
it("cleans up telegram update offset when deleting a telegram account", async () => {
configMocks.readConfigFileSnapshot.mockResolvedValue({
...baseConfigSnapshot,
config: {
channels: {
telegram: { botToken: "123:abc", enabled: true },
},
},
});
await channelsRemoveCommand(
{ channel: "telegram", account: "default", delete: true },
runtime,
{
hasFlags: true,
},
);
expect(offsetMocks.deleteTelegramUpdateOffset).toHaveBeenCalledWith({ accountId: "default" });
});
it("does not clean up offset when deleting a non-telegram channel", async () => {
configMocks.readConfigFileSnapshot.mockResolvedValue({
...baseConfigSnapshot,
config: {
channels: {
discord: {
accounts: {
default: { token: "d0" },
},
},
},
},
});
await channelsRemoveCommand({ channel: "discord", account: "default", delete: true }, runtime, {
hasFlags: true,
});
expect(offsetMocks.deleteTelegramUpdateOffset).not.toHaveBeenCalled();
});
it("does not clean up offset when disabling (not deleting) a telegram account", async () => {
configMocks.readConfigFileSnapshot.mockResolvedValue({
...baseConfigSnapshot,
config: {
channels: {
telegram: { botToken: "123:abc", enabled: true },
},
},
});
const prompt = { confirm: vi.fn().mockResolvedValue(true) };
const prompterModule = await import("../wizard/clack-prompter.js");
const promptSpy = vi
.spyOn(prompterModule, "createClackPrompter")
.mockReturnValue(prompt as never);
await channelsRemoveCommand({ channel: "telegram", account: "default" }, runtime, {
hasFlags: true,
});
expect(offsetMocks.deleteTelegramUpdateOffset).not.toHaveBeenCalled();
promptSpy.mockRestore();
});
});

View File

@@ -7,6 +7,7 @@ import {
import { type OpenClawConfig, writeConfigFile } from "../../config/config.js";
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../../routing/session-key.js";
import { defaultRuntime, type RuntimeEnv } from "../../runtime.js";
import { deleteTelegramUpdateOffset } from "../../telegram/update-offset-store.js";
import { createClackPrompter } from "../../wizard/clack-prompter.js";
import { type ChatChannel, channelLabel, requireValidConfig, shouldUseWizard } from "./shared.js";
@@ -112,6 +113,11 @@ export async function channelsRemoveCommand(
cfg: next,
accountId: resolvedAccountId,
});
// Clean up Telegram polling offset to prevent stale offset on bot token change (#18233)
if (channel === "telegram") {
await deleteTelegramUpdateOffset({ accountId: resolvedAccountId });
}
} else {
if (!plugin.config.setAccountEnabled) {
runtime.error(`Channel ${channel} does not support disable.`);