feat: globalize Magic Notes and improve runtime tools

This commit is contained in:
lofyer
2026-08-10 10:27:14 +08:00
parent 1a8e110866
commit 5ea022ad5c
47 changed files with 2442 additions and 1177 deletions
+12 -1
View File
@@ -1,9 +1,20 @@
import { z } from 'zod'
export const magicNoteCommentModeSchema = z.enum([
'immediate',
'after-save-auto',
'after-save-manual'
])
export type MagicNoteCommentMode = z.infer<
typeof magicNoteCommentModeSchema
>
export const applicationSettingsSchema = z
.object({
checkUpdatesOnStartup: z.boolean(),
magicNotesEnabled: z.boolean()
magicNotesEnabled: z.boolean(),
magicNoteCommentMode: magicNoteCommentModeSchema
})
.strict()
+28 -2
View File
@@ -4,7 +4,11 @@ export type BuiltinMcpServerSummary = {
id: string
name: string
description: string
tools: readonly string[]
tools: readonly {
name: string
description: string
access: 'read'
}[]
assignments: readonly RuntimeTarget[]
access: 'read'
authorization: 'conversation-scoped'
@@ -16,7 +20,29 @@ export const builtinMcpServers = [
name: '知识库 MCP',
description:
'搜索当前对话明确选择的知识库,并返回可核验的来源与证据引用。',
tools: ['knowledge_search'],
tools: [
{
name: 'knowledge_search',
description: '搜索当前对话已授权的知识库并返回来源引用。',
access: 'read'
}
],
assignments: ['model', 'opencode', 'continue'],
access: 'read',
authorization: 'conversation-scoped'
},
{
id: 'magic-notes',
name: '笔记 MCP',
description:
'搜索全局魔法笔记,返回匹配的笔记、记录正文与更新时间。',
tools: [
{
name: 'note_search',
description: '搜索全局魔法笔记中的标题和记录正文。',
access: 'read'
}
],
assignments: ['model', 'opencode', 'continue'],
access: 'read',
authorization: 'conversation-scoped'
+38 -10
View File
@@ -3,6 +3,7 @@ export type BuiltinModelToolSummary = {
displayName: string
description: string
access: 'read' | 'write'
group: 'filesystem' | 'browser'
}
export const builtinModelTools = [
@@ -10,61 +11,88 @@ export const builtinModelTools = [
name: 'workspace_read_text',
displayName: '读取工作区文本',
description: '读取当前工作区内不超过 256KB 的 UTF-8 文本文件。',
access: 'read'
access: 'read',
group: 'filesystem'
},
{
name: 'workspace_list_directory',
displayName: '列出工作区目录',
description: '列出当前工作区内目录的直属内容,最多返回 200 项。',
access: 'read'
access: 'read',
group: 'filesystem'
},
{
name: 'workspace_write_text',
displayName: '写入工作区文本',
description:
'在当前工作区内新建或覆盖不超过 512KB 的 UTF-8 文本文件,父目录必须已存在。',
access: 'write'
access: 'write',
group: 'filesystem'
},
{
name: 'browser_navigate',
displayName: '浏览器导航',
description: '在隔离浏览器中打开当前设备可连接的 HTTP 或 HTTPS 页面。',
access: 'write'
access: 'write',
group: 'browser'
},
{
name: 'browser_snapshot',
displayName: '读取浏览器快照',
description: '读取当前页面的有界可访问性快照;可编辑值会被隐藏。',
access: 'read'
access: 'read',
group: 'browser'
},
{
name: 'browser_click',
displayName: '点击浏览器元素',
description: '点击最近一次浏览器快照中的可见元素。',
access: 'write'
access: 'write',
group: 'browser'
},
{
name: 'browser_type',
displayName: '输入浏览器文本',
description: '向可编辑页面元素(包括密码框)输入文本;不支持上传文件。',
access: 'write'
access: 'write',
group: 'browser'
},
{
name: 'browser_select',
displayName: '选择浏览器选项',
description: '在最近一次快照标识的原生选择控件中选择值。',
access: 'write'
access: 'write',
group: 'browser'
},
{
name: 'browser_back',
displayName: '浏览器返回',
description: '在隔离浏览器的历史记录中返回上一页。',
access: 'write'
access: 'write',
group: 'browser'
},
{
name: 'browser_screenshot',
displayName: '截取浏览器页面',
description: '截取当前可见页面区域、约 200KB 的有界 JPEG 图片。',
access: 'read'
access: 'read',
group: 'browser'
}
] as const satisfies readonly BuiltinModelToolSummary[]
export const builtinModelToolGroups = [
{
id: 'filesystem',
name: '文件系统操作',
description:
'在 Execute 模式下读取、列出或写入当前工作区范围内的文件。',
tools: builtinModelTools.filter((tool) => tool.group === 'filesystem')
},
{
id: 'browser',
name: '浏览器操作',
description:
'启用“浏览器控制”后,在 Execute 模式下操作 GoodBuddy 隔离浏览器。',
tools: builtinModelTools.filter((tool) => tool.group === 'browser')
}
] as const
+8 -8
View File
@@ -37,16 +37,16 @@ import {
type ExpertUpdateInput
} from './assistant-contracts'
import type {
MagicNoteDraftAnalysis,
MagicNoteDetail,
MagicNoteCreateInput,
MagicNoteEntryCreateInput,
MagicNoteEntryUpdateInput,
MagicNoteRichContent,
MagicNotesSnapshot,
MagicNoteUpdateInput,
MagicTodoCreateInput,
MagicTodoItem,
MagicTodosSnapshot,
MagicTodoUpdateInput
MagicTodosSnapshot
} from './magic-notes-contracts'
import type {
ChannelConnectionTestResult,
@@ -1158,7 +1158,7 @@ export type DesktopApi = {
remove: (contextId: string) => Promise<void>
}
magicNotes: {
list: (projectId?: string) => Promise<MagicNotesSnapshot>
list: () => Promise<MagicNotesSnapshot>
get: (noteId: string) => Promise<MagicNoteDetail>
create: (input: MagicNoteCreateInput) => Promise<MagicNoteDetail>
update: (input: MagicNoteUpdateInput) => Promise<MagicNoteDetail>
@@ -1171,10 +1171,10 @@ export type DesktopApi = {
) => Promise<MagicNoteDetail>
removeEntry: (entryId: string) => Promise<MagicNoteDetail>
analyze: (entryId: string) => Promise<MagicNoteDetail>
listTodos: (projectId?: string) => Promise<MagicTodosSnapshot>
createTodo: (input: MagicTodoCreateInput) => Promise<MagicTodoItem>
updateTodo: (input: MagicTodoUpdateInput) => Promise<MagicTodoItem>
removeTodo: (todoId: string) => Promise<void>
analyzeDraft: (
content: MagicNoteRichContent
) => Promise<MagicNoteDraftAnalysis>
listTodos: () => Promise<MagicTodosSnapshot>
analyzeTodo: (todoId: string) => Promise<MagicTodoItem>
}
knowledge: {
+1 -3
View File
@@ -126,10 +126,8 @@ export const ipcChannels = {
magicNotesUpdateEntry: 'magic-notes:update-entry',
magicNotesDeleteEntry: 'magic-notes:delete-entry',
magicNotesAnalyze: 'magic-notes:analyze',
magicNotesAnalyzeDraft: 'magic-notes:analyze-draft',
magicTodosList: 'magic-todos:list',
magicTodosCreate: 'magic-todos:create',
magicTodosUpdate: 'magic-todos:update',
magicTodosDelete: 'magic-todos:delete',
magicTodosAnalyze: 'magic-todos:analyze',
knowledgeSnapshot: 'knowledge:snapshot',
knowledgeCreateLibrary: 'knowledge:library:create',
+21 -37
View File
@@ -100,15 +100,8 @@ export type MagicNoteRichContent = z.infer<
typeof magicNoteRichContentSchema
>
export const magicNoteScopeSchema = z
.object({
projectId: magicNoteIdSchema.optional()
})
.strict()
export const magicNoteCreateSchema = z
.object({
projectId: magicNoteIdSchema.optional(),
title: z.string().trim().min(1).max(100)
})
.strict()
@@ -166,32 +159,11 @@ export const magicNoteAnalyzeSchema = z
})
.strict()
export const magicTodoCreateSchema = z
export const magicNoteDraftAnalyzeSchema = z
.object({
projectId: magicNoteIdSchema.optional(),
title: z.string().trim().min(1).max(120),
instructions: z.string().trim().max(20_000)
content: magicNoteRichContentSchema
})
.strict()
export type MagicTodoCreateInput = z.infer<typeof magicTodoCreateSchema>
export const magicTodoUpdateSchema = z
.object({
todoId: magicNoteIdSchema,
title: z.string().trim().min(1).max(120).optional(),
instructions: z.string().trim().max(20_000).optional(),
completed: z.boolean().optional(),
expectedRevision: z.number().int().nonnegative()
})
.strict()
.refine(
(input) =>
input.title !== undefined ||
input.instructions !== undefined ||
input.completed !== undefined,
{ message: '没有可更新的待办字段' }
)
export type MagicTodoUpdateInput = z.infer<typeof magicTodoUpdateSchema>
export const magicTodoIdSchema = z
.object({
@@ -221,7 +193,6 @@ export type MagicNoteEntry = {
export type MagicNoteSummary = {
id: string
projectId?: string
title: string
preview: string
entryCount: number
@@ -241,12 +212,11 @@ export type MagicNotesSnapshot = {
export type MagicTodoItem = {
id: string
projectId?: string
noteId?: string
entryId?: string
noteTitle?: string
sourceIndex?: number
source: 'note' | 'manual'
noteId: string
entryId: string
noteTitle: string
sourceIndex: number
source: 'note'
title: string
instructions: string
completed: boolean
@@ -260,3 +230,17 @@ export type MagicTodoItem = {
export type MagicTodosSnapshot = {
todos: MagicTodoItem[]
}
export type MagicNoteDraftAnalysis = {
id: string
comments: MagicNoteComment[]
analyzedAt: string
}
export type MagicNoteSearchResult = {
noteId: string
noteTitle: string
entryId: string
content: string
updatedAt: string
}