diff --git a/apps/ai-game-creator-shell/scripts/check-config.mjs b/apps/ai-game-creator-shell/scripts/check-config.mjs
index b5a1bf7b5..7af269b5b 100644
--- a/apps/ai-game-creator-shell/scripts/check-config.mjs
+++ b/apps/ai-game-creator-shell/scripts/check-config.mjs
@@ -646,6 +646,10 @@ for (const snippet of [
'open_developer_window(app.handle())?',
'tauri::WebviewWindowBuilder::new(app, "developer", developer_window_url())',
'index.html?agent-chat',
+ 'supervisorChatMode',
+ 'supervisorChatOnly',
+ 'open_project_supervisor_chat_window',
+ 'index.html?supervisor-chat&projectPath=',
]) {
if (!`${appEntrypointSource}\n${tauriRustSource}`.includes(snippet)) {
throw new Error(
diff --git a/apps/ai-game-creator-shell/src-tauri/src/main.rs b/apps/ai-game-creator-shell/src-tauri/src/main.rs
index 2011937f7..6ecd10abe 100644
--- a/apps/ai-game-creator-shell/src-tauri/src/main.rs
+++ b/apps/ai-game-creator-shell/src-tauri/src/main.rs
@@ -1749,6 +1749,7 @@ fn main() {
write_project_permission_policy,
open_game_creator_workspace_window,
open_game_creator_launcher_window,
+ open_project_supervisor_chat_window,
start_local_game_preview,
open_local_game_preview,
stop_local_game_preview,
diff --git a/apps/ai-game-creator-shell/src-tauri/src/tests.rs b/apps/ai-game-creator-shell/src-tauri/src/tests.rs
index c9e2c971b..141d66e26 100644
--- a/apps/ai-game-creator-shell/src-tauri/src/tests.rs
+++ b/apps/ai-game-creator-shell/src-tauri/src/tests.rs
@@ -48860,6 +48860,14 @@ fn developer_window_uses_agent_chat_route() {
assert_eq!(developer_window_url().to_string(), "index.html?agent-chat");
}
+#[test]
+fn supervisor_chat_window_carries_encoded_project_path() {
+ assert_eq!(
+ supervisor_chat_window_url("/tmp/AI Game 项目").to_string(),
+ "index.html?supervisor-chat&projectPath=%2Ftmp%2FAI%20Game%20%E9%A1%B9%E7%9B%AE"
+ );
+}
+
#[test]
fn workspace_window_url_carries_encoded_project_path() {
assert_eq!(
diff --git a/apps/ai-game-creator-shell/src-tauri/src/windows.rs b/apps/ai-game-creator-shell/src-tauri/src/windows.rs
index c141602dc..784a4a014 100644
--- a/apps/ai-game-creator-shell/src-tauri/src/windows.rs
+++ b/apps/ai-game-creator-shell/src-tauri/src/windows.rs
@@ -15,6 +15,13 @@ pub(crate) fn developer_window_url() -> tauri::WebviewUrl {
tauri::WebviewUrl::App(PathBuf::from("index.html?agent-chat"))
}
+pub(crate) fn supervisor_chat_window_url(project_path: &str) -> tauri::WebviewUrl {
+ tauri::WebviewUrl::App(PathBuf::from(format!(
+ "index.html?supervisor-chat&projectPath={}",
+ percent_encode_query_value(project_path)
+ )))
+}
+
pub(crate) fn validate_workspace_window_project_path(project_path: &str) -> Result<&str, String> {
let project_path = project_path.trim();
if project_path.is_empty() {
@@ -81,6 +88,37 @@ pub(crate) fn open_game_creator_launcher_window(
Ok(())
}
+#[tauri::command]
+pub(crate) fn open_project_supervisor_chat_window(
+ app: tauri::AppHandle,
+ project_path: String,
+) -> Result<(), String> {
+ let project_path = validate_workspace_window_project_path(&project_path)?;
+ #[cfg(not(debug_assertions))]
+ {
+ let _ = app;
+ let _ = project_path;
+ return Err("项目总控对话窗口仅在开发构建中可用".to_string());
+ }
+ #[cfg(debug_assertions)]
+ {
+ if let Some(existing) = app.get_webview_window("supervisor-chat") {
+ existing.close().map_err(|error| error.to_string())?;
+ }
+ tauri::WebviewWindowBuilder::new(
+ &app,
+ "supervisor-chat",
+ supervisor_chat_window_url(project_path),
+ )
+ .title("项目总控 Agent 对话")
+ .inner_size(820.0, 720.0)
+ .min_inner_size(560.0, 480.0)
+ .build()
+ .map_err(|error| error.to_string())?;
+ Ok(())
+ }
+}
+
#[cfg(all(debug_assertions, not(test)))]
pub(crate) fn open_developer_window(app: &tauri::AppHandle) -> Result<(), String> {
if let Some(existing) = app.get_webview_window("developer") {
diff --git a/apps/ai-game-creator-shell/src/App.tsx b/apps/ai-game-creator-shell/src/App.tsx
index 960f3f863..92cc89bd6 100644
--- a/apps/ai-game-creator-shell/src/App.tsx
+++ b/apps/ai-game-creator-shell/src/App.tsx
@@ -1642,6 +1642,22 @@ function agentRuntimeConversationStatus(runtime: AgentRuntimeState) {
return waitingOn ? `Agent 正在运行,等待${waitingOn}` : 'Agent 正在运行';
}
+function projectSupervisorChatRuntimeStatus(runtime: AgentRuntimeState) {
+ if (runtime.status === 'idle' || runtime.phase === 'idle') {
+ return '等待输入';
+ }
+ if (isAgentRuntimeTerminalState(runtime)) {
+ if (runtime.status === 'failed' || runtime.phase === 'failed') {
+ return runtime.error || 'Agent 运行失败';
+ }
+ if (runtime.status === 'cancelled' || runtime.phase === 'cancelled') {
+ return '本轮已取消';
+ }
+ return '本轮已完成';
+ }
+ return agentRuntimeConversationStatus(runtime);
+}
+
function formatAgentRuntimeEvent(event: AgentRuntimeEventRecord) {
const summary = event.summary || event.detail || event.runId;
const detail =
@@ -6561,6 +6577,32 @@ export function WorkspaceLauncher({
agentChatGoalDialog !== null && !agentChatBackgroundBusy,
);
+ async function handleOpenProjectSupervisorChatWindow() {
+ if (agentChatBusy || agentChatBackgroundBusy) {
+ return;
+ }
+ const projectPathForChat = validateAgentChatProjectPath();
+ if (!projectPathForChat) {
+ return;
+ }
+ const invoke = resolveTauriInvoke();
+ if (!invoke) {
+ setAgentChatStatus('需要在 Tauri App 内运行');
+ return;
+ }
+ setAgentChatStatus('正在打开项目总控对话');
+ try {
+ await invoke('open_project_supervisor_chat_window', {
+ projectPath: projectPathForChat,
+ });
+ setAgentChatStatus('已打开项目总控对话');
+ } catch (error) {
+ setAgentChatStatus(
+ error instanceof Error ? error.message : String(error),
+ );
+ }
+ }
+
async function handleAgentChatPickProjectDirectory() {
if (agentChatBusy || agentChatBackgroundBusy) {
return;
@@ -8896,6 +8938,13 @@ export function WorkspaceLauncher({
{agentChatStatus}
+