From 427e8e8b074f1bb7a57339c711c157c64bc41656 Mon Sep 17 00:00:00 2001 From: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com> Date: Sun, 3 May 2026 00:15:18 +0000 Subject: [PATCH] [AI-assisted] fix(feishu): probe status with account credentials Co-authored-by: brokemac79 <255583030+brokemac79@users.noreply.github.com> --- extensions/feishu/src/setup-surface.test.ts | 55 ++++++++++++++++++++- extensions/feishu/src/setup-surface.ts | 11 ++--- 2 files changed, 58 insertions(+), 8 deletions(-) diff --git a/extensions/feishu/src/setup-surface.test.ts b/extensions/feishu/src/setup-surface.test.ts index c8f1a15fdd0..db60f8fada8 100644 --- a/extensions/feishu/src/setup-surface.test.ts +++ b/extensions/feishu/src/setup-surface.test.ts @@ -5,10 +5,18 @@ import { createTestWizardPrompter, runSetupWizardConfigure, } from "openclaw/plugin-sdk/plugin-test-runtime"; -import { describe, expect, it, vi } from "vitest"; +import { beforeEach, describe, expect, it, vi } from "vitest"; +import type { FeishuProbeResult } from "./types.js"; + +const { probeFeishuMock } = vi.hoisted(() => ({ + probeFeishuMock: vi.fn<() => Promise>(async () => ({ + ok: false, + error: "mocked", + })), +})); vi.mock("./probe.js", () => ({ - probeFeishu: vi.fn(async () => ({ ok: false, error: "mocked" })), + probeFeishu: probeFeishuMock, })); vi.mock("./app-registration.js", () => ({ @@ -69,6 +77,11 @@ const feishuConfigure = createPluginSetupWizardConfigure(feishuPlugin); const feishuGetStatus = createPluginSetupWizardStatus(feishuPlugin); describe("feishu setup wizard", () => { + beforeEach(() => { + probeFeishuMock.mockReset(); + probeFeishuMock.mockResolvedValue({ ok: false, error: "mocked" }); + }); + it("does not throw when config appId/appSecret are SecretRef objects", async () => { const text = vi .fn() @@ -101,6 +114,11 @@ describe("feishu setup wizard", () => { }); describe("feishu setup wizard status", () => { + beforeEach(() => { + probeFeishuMock.mockReset(); + probeFeishuMock.mockResolvedValue({ ok: false, error: "mocked" }); + }); + it("treats SecretRef appSecret as configured when appId is present", async () => { const status = await feishuGetStatus({ cfg: { @@ -121,6 +139,39 @@ describe("feishu setup wizard status", () => { expect(status.configured).toBe(true); }); + it("probes the resolved default account in multi-account config", async () => { + probeFeishuMock.mockResolvedValueOnce({ ok: true, botName: "Feishu Main" }); + + const status = await feishuGetStatus({ + cfg: { + channels: { + feishu: { + enabled: true, + defaultAccount: "main-bot", + accounts: { + "main-bot": { + appId: "cli_main", + appSecret: "main-app-secret", // pragma: allowlist secret + connectionMode: "websocket", + }, + }, + }, + }, + } as never, + ...baseStatusContext, + }); + + expect(status.configured).toBe(true); + expect(status.statusLines).toEqual(["Feishu: connected as Feishu Main"]); + expect(probeFeishuMock).toHaveBeenCalledWith( + expect.objectContaining({ + accountId: "main-bot", + appId: "cli_main", + appSecret: "main-app-secret", // pragma: allowlist secret + }), + ); + }); + it("does not fallback to top-level appId when account explicitly sets empty appId", async () => { const status = await feishuGetStatus({ cfg: { diff --git a/extensions/feishu/src/setup-surface.ts b/extensions/feishu/src/setup-surface.ts index ec207dca658..5f4fc8008c3 100644 --- a/extensions/feishu/src/setup-surface.ts +++ b/extensions/feishu/src/setup-surface.ts @@ -12,7 +12,7 @@ import { type OpenClawConfig, type SecretInput, } from "openclaw/plugin-sdk/setup"; -import { inspectFeishuCredentials, resolveDefaultFeishuAccountId } from "./accounts.js"; +import { resolveDefaultFeishuAccountId, resolveFeishuAccount } from "./accounts.js"; import type { AppRegistrationResult } from "./app-registration.js"; import type { FeishuConfig, FeishuDomain } from "./types.js"; @@ -515,14 +515,13 @@ export const feishuSetupWizard: ChannelSetupWizard = { configuredScore: 2, unconfiguredScore: 0, resolveConfigured: ({ cfg }) => isFeishuConfigured(cfg), - resolveStatusLines: async ({ cfg, configured }) => { - const feishuCfg = cfg.channels?.feishu as FeishuConfig | undefined; - const resolvedCredentials = inspectFeishuCredentials(feishuCfg); + resolveStatusLines: async ({ cfg, accountId, configured }) => { + const account = resolveFeishuAccount({ cfg, accountId }); let probeResult = null; - if (configured && resolvedCredentials) { + if (configured && account.configured) { try { const { probeFeishu } = await import("./probe.js"); - probeResult = await probeFeishu(resolvedCredentials); + probeResult = await probeFeishu(account); } catch {} } if (!configured) {