chore: establish YCode replication baseline and TODO

This commit is contained in:
xiaohan.yuan committed 2026-10-17 02:43:49 +08:00
commit 6dc59f89ba
1118 files changed
+196002

No files matched your search

+164
View File
@@ -0,0 +1,164 @@
/**
* Preload:contextBridge 暴露受控 API。
* 渲染进程只能看到这里列出的方法,拿不到 ipcRenderer 本体。
*/
import { contextBridge, ipcRenderer } from 'electron'
import type { ChatEvent, WindowState } from '@shared/types'
import type { ConfigPatchLike, EditAction, SendPayload, WorkspaceAttachResult, YCodeApi } from '@shared/ipc'
import type { DownloadPayload, ResourceRange } from '@shared/resources'
import type { InteractionResponse } from '@shared/conversation'
const api: YCodeApi = {
experts: {
list: () => ipcRenderer.invoke('experts:list'),
read: id => ipcRenderer.invoke('experts:read', id),
activate: id => ipcRenderer.invoke('experts:activate', id),
remove: id => ipcRenderer.invoke('experts:remove', id),
openPath: id => ipcRenderer.invoke('experts:open-path', id)
},
skills: {
list: (cwd) => ipcRenderer.invoke('skills:list', cwd),
importPath: (path, overwrite, kind) => ipcRenderer.invoke('skills:import', path, overwrite, kind),
read: (id, cwd) => ipcRenderer.invoke('skills:read', id, cwd),
setEnabled: (id, enabled, cwd) => ipcRenderer.invoke('skills:enable', id, enabled, cwd),
remove: (id) => ipcRenderer.invoke('skills:remove', id),
export: (id, destination) => ipcRenderer.invoke('skills:export', id, destination)
},
mcp: {
list: () => ipcRenderer.invoke('mcp:list'),
save: (input) => ipcRenderer.invoke('mcp:save', input),
trust: (id, hash) => ipcRenderer.invoke('mcp:trust', id, hash),
connect: (id) => ipcRenderer.invoke('mcp:connect', id),
disconnect: (id) => ipcRenderer.invoke('mcp:disconnect', id),
setEnabled: (id, enabled) => ipcRenderer.invoke('mcp:enable', id, enabled),
setToolEnabled: (id, tool, enabled) => ipcRenderer.invoke('mcp:tool-enable', id, tool, enabled),
remove: (id) => ipcRenderer.invoke('mcp:remove', id)
},
terminal: {
rebind: (id, previousSessionId, nextSessionId) => ipcRenderer.invoke('terminal:rebind', id, previousSessionId, nextSessionId),
create: (sessionId, cols, rows) => ipcRenderer.invoke('terminal:create', sessionId, cols, rows),
get: (id, sessionId) => ipcRenderer.invoke('terminal:get', id, sessionId),
write: (id, data, sessionId) => ipcRenderer.invoke('terminal:write', id, data, sessionId),
resize: (id, cols, rows, sessionId) => ipcRenderer.invoke('terminal:resize', id, cols, rows, sessionId),
clear: (id, sessionId) => ipcRenderer.invoke('terminal:clear', id, sessionId),
close: (id, sessionId) => ipcRenderer.invoke('terminal:close', id, sessionId),
onEvent: (listener) => {
const handler = (_event: unknown, payload: Parameters<typeof listener>[0]): void => listener(payload)
ipcRenderer.on('terminal:event', handler)
return () => ipcRenderer.removeListener('terminal:event', handler)
}
},
browser: {
rebind: (id, previousSessionId, nextSessionId) => ipcRenderer.invoke('browser:rebind', id, previousSessionId, nextSessionId),
create: (sessionId, url) => ipcRenderer.invoke('browser:create', sessionId, url),
get: (id, sessionId) => ipcRenderer.invoke('browser:get', id, sessionId),
navigate: (id, url, sessionId) => ipcRenderer.invoke('browser:navigate', id, url, sessionId),
back: (id, sessionId) => ipcRenderer.invoke('browser:back', id, sessionId),
forward: (id, sessionId) => ipcRenderer.invoke('browser:forward', id, sessionId),
reload: (id, sessionId) => ipcRenderer.invoke('browser:reload', id, sessionId),
bounds: (id, bounds, sessionId) => ipcRenderer.invoke('browser:bounds', id, bounds, sessionId),
close: (id, sessionId) => ipcRenderer.invoke('browser:close', id, sessionId)
},
window: {
minimize: () => ipcRenderer.invoke('window:minimize'),
toggleMaximize: () => ipcRenderer.invoke('window:toggleMaximize'),
close: () => ipcRenderer.invoke('window:close'),
getState: () => ipcRenderer.invoke('window:state'),
onState: (listener: (state: WindowState) => void) => {
const handler = (_event: unknown, payload: WindowState): void => listener(payload)
ipcRenderer.on('window:state', handler)
return () => {
ipcRenderer.removeListener('window:state', handler)
}
},
onFocus: (listener: (focused: boolean) => void) => {
const handler = (_event: unknown, payload: { focused: boolean }): void =>
listener(payload.focused)
ipcRenderer.on('window:focus', handler)
return () => {
ipcRenderer.removeListener('window:focus', handler)
}
}
},
edit: {
action: (action: EditAction) => ipcRenderer.invoke('edit:action', action)
},
app: {
info: () => ipcRenderer.invoke('app:info'),
openConfigDir: () => ipcRenderer.invoke('app:openConfigDir'),
openSettings: (section, action) => ipcRenderer.invoke('app:openSettings', section, action),
onSettingsNavigate: (listener) => {
const handler = (_event: Electron.IpcRendererEvent, section: string, action?: 'new'): void => listener(section, action)
ipcRenderer.on('settings:navigate', handler)
return () => { ipcRenderer.removeListener('settings:navigate', handler) }
},
onSettingsChanged: (listener) => {
const handler = (): void => listener()
ipcRenderer.on('settings:changed', handler)
return () => ipcRenderer.removeListener('settings:changed', handler)
}
},
config: {
get: () => ipcRenderer.invoke('config:get'),
update: (patch: ConfigPatchLike) => ipcRenderer.invoke('config:update', patch)
},
workspace: {
get: () => ipcRenderer.invoke('workspace:get'),
choose: () => ipcRenderer.invoke('workspace:choose'),
list: () => ipcRenderer.invoke('workspace:list'),
generate: (name) => ipcRenderer.invoke('workspace:generate', name),
attach: (path): Promise<WorkspaceAttachResult> => ipcRenderer.invoke('workspace:attach', path),
select: (id) => ipcRenderer.invoke('workspace:select', id),
rename: (id, name) => ipcRenderer.invoke('workspace:rename', id, name),
remove: (id) => ipcRenderer.invoke('workspace:remove', id),
open: (id) => ipcRenderer.invoke('workspace:open', id)
},
models: {
list: () => ipcRenderer.invoke('models:list'),
save: (input, overwrite) => ipcRenderer.invoke('models:save', input, overwrite),
remove: (id) => ipcRenderer.invoke('models:remove', id),
select: (id) => ipcRenderer.invoke('models:select', id),
test: (input) => ipcRenderer.invoke('models:test', input)
},
resources: {
list: (sessionId?: string, workspaceId?: string) => ipcRenderer.invoke('resources:list', sessionId, workspaceId),
openExternal: (url) => ipcRenderer.invoke('resources:openExternal', url),
read: (path: string, range?: ResourceRange, sessionId?: string) => ipcRenderer.invoke('resources:read', path, range, sessionId),
readText: (path: string, sessionId?: string) => ipcRenderer.invoke('resources:read-text', path, sessionId),
classify: (path: string, sessionId?: string) => ipcRenderer.invoke('resources:classify', path, sessionId),
resolveImage: (source: string, sessionId?: string) => ipcRenderer.invoke('resources:resolveImage', source, sessionId),
download: (payload: DownloadPayload) => ipcRenderer.invoke('resources:download', payload),
downloadImage: (source: string, filename?: string, sessionId?: string) => ipcRenderer.invoke('resources:downloadImage', source, filename, sessionId)
},
attachments: {
pick: () => ipcRenderer.invoke('attachments:pick'),
stage: (payload) => ipcRenderer.invoke('attachments:stage', payload),
remove: (id) => ipcRenderer.invoke('attachments:remove', id)
},
speech: { transcribe: (payload) => ipcRenderer.invoke('speech:transcribe', payload) },
session: {
list: () => ipcRenderer.invoke('session:list'),
create: (title, context) => ipcRenderer.invoke('session:create', title, context),
updateContext: (id, context) => ipcRenderer.invoke('session:update-context', id, context),
messages: (sessionId: string) => ipcRenderer.invoke('session:messages', sessionId),
rename: (sessionId: string, title: string) => ipcRenderer.invoke('session:rename', sessionId, title),
remove: (sessionId: string) => ipcRenderer.invoke('session:delete', sessionId)
},
chat: {
revert: (sessionId, userMessageId) => ipcRenderer.invoke('chat:revert', sessionId, userMessageId),
feedback: (sessionId, messageId, value) => ipcRenderer.invoke('chat:feedback', sessionId, messageId, value),
send: (payload: SendPayload) => ipcRenderer.invoke('chat:send', payload),
cancel: (runId: string) => ipcRenderer.invoke('chat:cancel', runId),
respond: (runId: string, interactionId: string, response: InteractionResponse) => ipcRenderer.invoke('chat:respond', runId, interactionId, response),
onEvent: (listener: (event: ChatEvent) => void) => {
const handler = (_event: unknown, payload: ChatEvent): void => listener(payload)
ipcRenderer.on('chat:event', handler)
return () => {
ipcRenderer.removeListener('chat:event', handler)
}
}
}
}
contextBridge.exposeInMainWorld('ycode', api)