From 2cb712e4bad95ca475a387da246b945fd4a69c15 Mon Sep 17 00:00:00 2001 From: lofyer Date: Mon, 10 Aug 2026 11:47:03 +0800 Subject: [PATCH] fix: align WeChat channel modes --- package-lock.json | 4 ++-- package.json | 2 +- src/main/channels/channel-env.ts | 2 +- src/main/channels/channel-service.test.ts | 8 +++++++- .../channels/remote-channel-routing.test.ts | 4 ++-- src/main/channels/remote-channel-routing.ts | 6 +++--- src/main/ipc.test.ts | 18 +++++++++--------- src/main/ipc.ts | 8 ++------ .../src/ChannelSettingsSection.test.tsx | 5 +++++ src/renderer/src/ChannelSettingsSection.tsx | 4 +++- src/shared/channel-contracts.ts | 2 +- 11 files changed, 36 insertions(+), 27 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6d55493..c37a8f2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "goodbuddy", - "version": "0.8.10", + "version": "0.8.11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "goodbuddy", - "version": "0.8.10", + "version": "0.8.11", "license": "UNLICENSED", "dependencies": { "@modelcontextprotocol/sdk": "^1.30.0", diff --git a/package.json b/package.json index c4eb8ce..df04ff3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "goodbuddy", - "version": "0.8.10", + "version": "0.8.11", "private": true, "description": "Secure desktop AI workspace with controlled Agent Runtimes", "desktopName": "GoodBuddy", diff --git a/src/main/channels/channel-env.ts b/src/main/channels/channel-env.ts index 333e762..05604e6 100644 --- a/src/main/channels/channel-env.ts +++ b/src/main/channels/channel-env.ts @@ -226,5 +226,5 @@ export function startEnvironmentChannels( export function isReadOnlyChannelMessage( message: ChannelInboundText ): boolean { - return message.workMode === 'ask' || message.workMode === 'plan' + return message.workMode === 'ask' } diff --git a/src/main/channels/channel-service.test.ts b/src/main/channels/channel-service.test.ts index b82c6d4..718eccd 100644 --- a/src/main/channels/channel-service.test.ts +++ b/src/main/channels/channel-service.test.ts @@ -71,7 +71,7 @@ async function waitForSent( } describe('channel contracts', () => { - it('normalizes text, defaults to ask, and strictly refuses execute mode', () => { + it('normalizes text, defaults to ask, and refuses non-ask modes', () => { expect( channelInboundTextSchema.parse({ channel: ' fake ', @@ -98,6 +98,12 @@ describe('channel contracts', () => { workMode: 'execute' }).success ).toBe(false) + expect( + channelInboundTextSchema.safeParse({ + ...inbound(), + workMode: 'plan' + }).success + ).toBe(false) expect( channelInboundTextSchema.parse({ channel: 'fake', diff --git a/src/main/channels/remote-channel-routing.test.ts b/src/main/channels/remote-channel-routing.test.ts index e6d6220..ab6347a 100644 --- a/src/main/channels/remote-channel-routing.test.ts +++ b/src/main/channels/remote-channel-routing.test.ts @@ -13,8 +13,8 @@ describe('parseRemoteChannelPrompt', () => { workMode: 'execute', prompt: '请整理下载目录' }) - expect(parseRemoteChannelPrompt('总结进展', 'plan')).toEqual({ - workMode: 'plan', + expect(parseRemoteChannelPrompt('总结进展', 'ask')).toEqual({ + workMode: 'ask', prompt: '总结进展' }) }) diff --git a/src/main/channels/remote-channel-routing.ts b/src/main/channels/remote-channel-routing.ts index 0007741..536d8f5 100644 --- a/src/main/channels/remote-channel-routing.ts +++ b/src/main/channels/remote-channel-routing.ts @@ -1,4 +1,4 @@ -import type { WorkMode } from '../../shared/assistant-contracts' +import type { InteractiveWorkMode } from '../../shared/assistant-contracts' const COMMAND_PATTERN = /^\/(?ask|execute|exec)(?=$|[\s::])[\s::]*/iu @@ -7,9 +7,9 @@ const CHINESE_PATTERN = export function parseRemoteChannelPrompt( text: string, - defaultWorkMode: WorkMode + defaultWorkMode: InteractiveWorkMode ): { - workMode: WorkMode + workMode: InteractiveWorkMode prompt: string } { const value = text.trim() diff --git a/src/main/ipc.test.ts b/src/main/ipc.test.ts index 97b88bd..69a3395 100644 --- a/src/main/ipc.test.ts +++ b/src/main/ipc.test.ts @@ -41,7 +41,7 @@ const channelMocks = vi.hoisted(() => ({ conversationType: 'direct' | 'group' text: string mentioned: boolean - workMode: 'ask' | 'plan' + workMode: 'ask' attachments?: Array<{ name: string mimeType: string @@ -276,7 +276,7 @@ vi.mock('./agent/create-runtime', () => runtimeFactoryMocks) vi.mock('./channels/channel-env', () => ({ isReadOnlyChannelMessage: (message: { workMode: string }) => - message.workMode === 'ask' || message.workMode === 'plan', + message.workMode === 'ask', startEnvironmentChannels: vi.fn( (options: { executor: typeof channelMocks.executor }) => { channelMocks.executor = options.executor @@ -1873,7 +1873,7 @@ describe('registerIpcHandlers agent terminal state', () => { await harness.dispose() }) - it('bridges channel requests to read-only delegation tasks without approval', async () => { + it('bridges channel ask requests to read-only tasks without approval', async () => { let received: | { request: { @@ -1928,9 +1928,9 @@ describe('registerIpcHandlers agent terminal state', () => { senderId: 'user-1', conversationId: 'conversation-1', conversationType: 'direct', - text: '请制定只读计划', + text: '请只读分析', mentioned: false, - workMode: 'plan' + workMode: 'ask' }, new AbortController().signal ) @@ -1939,8 +1939,8 @@ describe('registerIpcHandlers agent terminal state', () => { output: '只读结果' }) expect(received?.request).toMatchObject({ - workMode: 'plan', - prompt: expect.stringContaining('请制定只读计划') + workMode: 'ask', + prompt: expect.stringContaining('请只读分析') }) await expect( received?.authorize?.({ @@ -1953,8 +1953,8 @@ describe('registerIpcHandlers agent terminal state', () => { expect(harness.assistantDatabase.createTask).toHaveBeenCalledWith( expect.objectContaining({ title: '企业微信远程请求', - instructions: '请制定只读计划', - workMode: 'plan', + instructions: '请只读分析', + workMode: 'ask', origin: 'delegation' }) ) diff --git a/src/main/ipc.ts b/src/main/ipc.ts index a2f2002..df88d4b 100644 --- a/src/main/ipc.ts +++ b/src/main/ipc.ts @@ -1352,9 +1352,7 @@ export function registerIpcHandlers( try { parsed = parseRemoteChannelPrompt( remoteInput, - message.workMode === 'plan' - ? 'plan' - : project.defaultWorkMode + normalizeInteractiveWorkMode(project.defaultWorkMode) ) } catch (error) { return { @@ -1432,9 +1430,7 @@ export function registerIpcHandlers( status: `${channelLabel} · ${ parsed.workMode === 'execute' ? '执行' - : parsed.workMode === 'plan' - ? '规划' - : '对话' + : '对话' }` }) publishRemoteConversationChange() diff --git a/src/renderer/src/ChannelSettingsSection.test.tsx b/src/renderer/src/ChannelSettingsSection.test.tsx index 031ae81..4b33679 100644 --- a/src/renderer/src/ChannelSettingsSection.test.tsx +++ b/src/renderer/src/ChannelSettingsSection.test.tsx @@ -330,6 +330,11 @@ describe('ChannelSettingsSection', () => { const close = await screen.findByRole('button', { name: '关闭微信绑定' }) + expect( + screen.getByText( + '请在微信中依次打开“设置 → ClawBot → 开始扫一扫”,扫描下方二维码。二维码不会发送到第三方页面。' + ) + ).toBeInTheDocument() await waitFor(() => expect(close).toHaveFocus()) fireEvent.keyDown(document, { key: 'Escape' }) diff --git a/src/renderer/src/ChannelSettingsSection.tsx b/src/renderer/src/ChannelSettingsSection.tsx index 9213070..f0e80d9 100644 --- a/src/renderer/src/ChannelSettingsSection.tsx +++ b/src/renderer/src/ChannelSettingsSection.tsx @@ -681,7 +681,9 @@ function WeixinQrDialog({
绑定微信 ClawBot - 请使用个人微信扫码。二维码不会发送到第三方页面。 + + 请在微信中依次打开“设置 → ClawBot → 开始扫一扫”,扫描下方二维码。二维码不会发送到第三方页面。 +