Files
Genarrative/apps/ai-game-creator-shell/src/services/pluginHost.ts
T
kdletters 5822b64d7c 合并 Godot 编辑器插件与常用操作指导到主分支
接入 Godot 原生桥、受控执行、Runner 回执与编辑器操作指南
保留主分支 Cocos 和 Unity 跨工程能力及外置提示词结构
解决插件生命周期、工具目录、前端启动和文档合并冲突
2026-09-20 17:38:48 +08:00

125 lines
3.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { resolveTauriInvoke } from '../app/tauri';
import type {
AgcExtensionSummary,
AgcPluginPanel,
AgcPluginSummary,
} from '../app/types';
export type PluginRpcParams = Record<string, unknown> | unknown[] | null;
function invokeOrThrow() {
const invoke = resolveTauriInvoke();
if (!invoke) throw new Error('需要在 Tauri App 内运行');
return invoke;
}
export async function listAgcPlugins() {
return invokeOrThrow()('list_agc_plugins') as Promise<AgcPluginSummary[]>;
}
export async function listAgcExtensions() {
return invokeOrThrow()('list_agc_extensions') as Promise<
AgcExtensionSummary[]
>;
}
export async function refreshAgcPlugins() {
return invokeOrThrow()('refresh_agc_plugins') as Promise<AgcPluginSummary[]>;
}
export async function startAgcPlugin(id: string) {
return invokeOrThrow()('start_agc_plugin', {
id,
}) as Promise<AgcPluginSummary>;
}
/** 只消费宿主的能力投影;项目类型与平台支持均不在前端再次判断。 */
export async function startAvailableAgcEditorPlugins(
isActive: () => boolean = () => true,
) {
const plugins = await listAgcPlugins();
const available = plugins.filter(
(plugin) =>
plugin.builtin &&
(plugin.id === 'agc-cocos-editor' ||
plugin.id === 'agc-unity-editor' ||
plugin.id === 'agc-godot-editor') &&
plugin.enabled &&
plugin.hasRuntime &&
(plugin.status === 'stopped' || plugin.status === 'discovered'),
);
const results = await Promise.allSettled(
available.map((plugin) =>
isActive() ? startAgcPlugin(plugin.id) : Promise.resolve(),
),
);
const errors = results.flatMap((result, index) =>
result.status === 'rejected'
? [
`${available[index]!.name}:${
result.reason instanceof Error
? result.reason.message
: String(result.reason)
}`,
]
: [],
);
if (errors.length) {
throw new Error(errors.join(';'));
}
}
export async function stopAgcPlugin(id: string) {
return invokeOrThrow()('stop_agc_plugin', {
id,
}) as Promise<AgcPluginSummary>;
}
export async function reloadAgcPlugin(id: string) {
return invokeOrThrow()('reload_agc_plugin', {
id,
}) as Promise<AgcPluginSummary>;
}
/** 内置插件的可用开关;禁用后不能启动,对应 Agent 工具也不再出现。 */
export async function setAgcPluginEnabled(id: string, enabled: boolean) {
return invokeOrThrow()('set_agc_plugin_enabled', {
id,
enabled,
}) as Promise<AgcPluginSummary[]>;
}
export async function callAgcPlugin<T = unknown>(
id: string,
method: string,
params: PluginRpcParams = null,
) {
return invokeOrThrow()('call_agc_plugin', {
id,
method,
params,
}) as Promise<T>;
}
export async function readAgcPluginPanel(id: string, panelId: string) {
return invokeOrThrow()('read_agc_plugin_panel', { id, panelId }) as Promise<{
panel: AgcPluginPanel;
html: string;
}>;
}
export async function setAgcPluginProjectPath(projectPath: string | null) {
const invoke = invokeOrThrow();
// 项目 effect 的 cleanup(null) 与下个项目的设置必须按提交顺序抵达宿主。
const next = pluginProjectUpdate
.catch(() => undefined)
.then(
() =>
invoke('set_agc_plugin_project_path', { projectPath }) as Promise<void>,
);
pluginProjectUpdate = next;
return next;
}
let pluginProjectUpdate: Promise<void> = Promise.resolve();