fix: align WeChat channel modes
This commit is contained in:
Generated
+2
-2
@@ -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",
|
||||
|
||||
+1
-1
@@ -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",
|
||||
|
||||
@@ -226,5 +226,5 @@ export function startEnvironmentChannels(
|
||||
export function isReadOnlyChannelMessage(
|
||||
message: ChannelInboundText
|
||||
): boolean {
|
||||
return message.workMode === 'ask' || message.workMode === 'plan'
|
||||
return message.workMode === 'ask'
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -13,8 +13,8 @@ describe('parseRemoteChannelPrompt', () => {
|
||||
workMode: 'execute',
|
||||
prompt: '请整理下载目录'
|
||||
})
|
||||
expect(parseRemoteChannelPrompt('总结进展', 'plan')).toEqual({
|
||||
workMode: 'plan',
|
||||
expect(parseRemoteChannelPrompt('总结进展', 'ask')).toEqual({
|
||||
workMode: 'ask',
|
||||
prompt: '总结进展'
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { WorkMode } from '../../shared/assistant-contracts'
|
||||
import type { InteractiveWorkMode } from '../../shared/assistant-contracts'
|
||||
|
||||
const COMMAND_PATTERN =
|
||||
/^\/(?<command>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()
|
||||
|
||||
@@ -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'
|
||||
})
|
||||
)
|
||||
|
||||
+2
-6
@@ -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()
|
||||
|
||||
@@ -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' })
|
||||
|
||||
@@ -681,7 +681,9 @@ function WeixinQrDialog({
|
||||
<header>
|
||||
<div>
|
||||
<strong id="channel-qr-title">绑定微信 ClawBot</strong>
|
||||
<small>请使用个人微信扫码。二维码不会发送到第三方页面。</small>
|
||||
<small>
|
||||
请在微信中依次打开“设置 → ClawBot → 开始扫一扫”,扫描下方二维码。二维码不会发送到第三方页面。
|
||||
</small>
|
||||
</div>
|
||||
<button
|
||||
aria-label="关闭微信绑定"
|
||||
|
||||
@@ -20,7 +20,7 @@ const channelIdentifierSchema = z
|
||||
.min(1)
|
||||
.max(CHANNEL_LIMITS.maximumIdentityLength)
|
||||
|
||||
export const channelWorkModeSchema = z.enum(['ask', 'plan'])
|
||||
export const channelWorkModeSchema = z.literal('ask')
|
||||
export type ChannelWorkMode = z.infer<typeof channelWorkModeSchema>
|
||||
|
||||
const attachmentBase64Schema = z
|
||||
|
||||
Reference in New Issue
Block a user