























@@ -18,6 +18,123 @@ import {
18181919let tempRoot: string | null = null;
202021+vi.mock("../channels/plugins/bundled.js", () => {
22+function fileExists(filePath: string): boolean {
23+try {
24+return fs.existsSync(filePath) && fs.statSync(filePath).isFile();
25+} catch {
26+return false;
27+}
28+}
29+30+function resolveTelegramAccountId(cfg: OpenClawConfig): string {
31+const defaultAgentId = cfg.agents?.list?.find((agent) => agent.default)?.id ?? "main";
32+const boundAccountId = cfg.bindings?.find(
33+(binding) =>
34+binding.agentId === defaultAgentId &&
35+binding.match?.channel === "telegram" &&
36+typeof binding.match.accountId === "string",
37+)?.match.accountId;
38+return boundAccountId ?? cfg.channels?.telegram?.defaultAccount ?? "default";
39+}
40+41+function detectTelegramAllowFromMigration(params: {
42+cfg: OpenClawConfig;
43+env: NodeJS.ProcessEnv;
44+}) {
45+const root = params.env.OPENCLAW_STATE_DIR;
46+if (!root) {
47+return [];
48+}
49+const legacyPath = path.join(root, "credentials", "telegram-allowFrom.json");
50+if (!fileExists(legacyPath)) {
51+return [];
52+}
53+const targetPath = path.join(
54+root,
55+"credentials",
56+`telegram-${resolveTelegramAccountId(params.cfg)}-allowFrom.json`,
57+);
58+return fileExists(targetPath)
59+ ? []
60+ : [
61+{
62+kind: "copy" as const,
63+label: "Telegram pairing allowFrom",
64+sourcePath: legacyPath,
65+ targetPath,
66+},
67+];
68+}
69+70+function detectWhatsAppLegacyStateMigrations(params: { oauthDir: string }) {
71+let entries: fs.Dirent[] = [];
72+try {
73+entries = fs.readdirSync(params.oauthDir, { withFileTypes: true });
74+} catch {
75+return [];
76+}
77+return entries.flatMap((entry) => {
78+const isLegacyAuthFile =
79+entry.name === "creds.json" ||
80+entry.name === "creds.json.bak" ||
81+(/^(app-state-sync|session|sender-key|pre-key)-/.test(entry.name) &&
82+entry.name.endsWith(".json"));
83+if (!entry.isFile() || entry.name === "oauth.json" || !isLegacyAuthFile) {
84+return [];
85+}
86+const sourcePath = path.join(params.oauthDir, entry.name);
87+const targetPath = path.join(params.oauthDir, "whatsapp", "default", entry.name);
88+return fileExists(targetPath)
89+ ? []
90+ : [{ kind: "move" as const, label: `WhatsApp auth ${entry.name}`, sourcePath, targetPath }];
91+});
92+}
93+94+return {
95+listBundledChannelSetupPluginsByFeature: vi.fn((feature: string) => {
96+if (feature === "legacySessionSurfaces") {
97+return [
98+{
99+id: "whatsapp",
100+messaging: {
101+isLegacyGroupSessionKey: (key: string) => /^group:.+@g\.us$/i.test(key.trim()),
102+canonicalizeLegacySessionKey: ({ key, agentId }: { key: string; agentId: string }) =>
103+/^group:.+@g\.us$/i.test(key.trim())
104+ ? `agent:${agentId}:whatsapp:${key.trim().toLowerCase()}`
105+ : null,
106+},
107+},
108+];
109+}
110+if (feature === "legacyStateMigrations") {
111+return [
112+{
113+id: "whatsapp",
114+lifecycle: {
115+detectLegacyStateMigrations: ({ oauthDir }: { oauthDir: string }) =>
116+detectWhatsAppLegacyStateMigrations({ oauthDir }),
117+},
118+},
119+{
120+id: "telegram",
121+lifecycle: {
122+detectLegacyStateMigrations: ({
123+ cfg,
124+ env,
125+}: {
126+cfg: OpenClawConfig;
127+env: NodeJS.ProcessEnv;
128+}) => detectTelegramAllowFromMigration({ cfg, env }),
129+},
130+},
131+];
132+}
133+return [];
134+}),
135+};
136+});
137+21138vi.mock("../infra/json-files.js", async () => {
22139const actual =
23140await vi.importActual<typeof import("../infra/json-files.js")>("../infra/json-files.js");
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。