{
- let user_prompt = build_local_project_prompt_polish_prompt(prompt, context)?;
- let app_config = load_game_creator_app_config()?;
- if app_config.agent_mode == GAME_CREATOR_AGENT_MODE_CODEX_APP_SERVER {
- let reply = crate::agent::direct_game_creator_home_codex_chat(
- LOCAL_PROJECT_PROMPT_POLISH_SYSTEM_PROMPT.trim().to_string(),
- user_prompt,
- )
- .await?;
- return normalize_polished_prompt(&reply)
- .ok_or_else(|| "AI 润色没有返回可用文本".to_string());
- }
- let mut llm = app_config.llm.clone();
- llm.max_retries = 0;
- let client = build_game_creator_llm_client_from_llm_config(&llm, "llm")?;
- let request = LlmRunRequest::single_turn(
- LOCAL_PROJECT_PROMPT_POLISH_SYSTEM_PROMPT.trim(),
- user_prompt,
- )
- .with_api_kind(parse_game_creator_llm_api_kind(&llm.api_kind)?)
- .with_model(llm.model.clone())
- .with_request_timeout_ms(llm.request_timeout_ms)
- .with_max_output_tokens(LOCAL_PROJECT_PROMPT_POLISH_MAX_OUTPUT_TOKENS)
- .with_web_search(false);
- let response = client
- .run(request)
- .await
- .map_err(|error| format!("AI 润色失败:{error}"))?;
- normalize_polished_prompt(&response.text).ok_or_else(|| "AI 润色没有返回可用文本".to_string())
-}
-
#[cfg(test)]
mod local_project_prompt_polish_tests {
use super::*;
@@ -469,21 +378,6 @@ pub(crate) fn closest_existing_project_picker_directory(path: &Path) -> Option Result {
- app.path()
- .app_data_dir()
- .map(|app_data_root| {
- // Automatic workspaces are AGC-managed data. Keeping them below
- // the hardened per-user app-data root avoids applying the strict
- // private-DACL gate to a user Documents directory whose inherited
- // ACL AGC is not allowed to rewrite.
- app_data_root.join(AUTOMATIC_PROJECTS_DIRECTORY_NAME)
- })
- .map_err(|error| format!("无法读取 AGC 应用数据目录:{error}"))
-}
-
/// 校验用户选择的项目创建目录。
///
/// 目录必须已经存在(原生目录选择器返回的结果),并且先过 AGC 私有路径门禁:门禁失败时
@@ -510,22 +404,6 @@ pub(crate) fn validate_requested_game_project_creation_root(
Ok(root.to_path_buf())
}
-/// 解析本次建项要使用的根目录:显式参数优先,其次读取 Rust 工作区偏好,最后回落 AGC 默认目录。
-pub(crate) fn resolve_game_project_creation_root(
- app: &tauri::AppHandle,
- requested: Option<&str>,
-) -> Result {
- let stored = requested
- .map(str::trim)
- .filter(|value| !value.is_empty())
- .map(str::to_string)
- .or_else(|| crate::workspace_preferences::stored_project_creation_directory(app));
- match stored.as_deref() {
- Some(requested) => validate_requested_game_project_creation_root(requested),
- None => automatic_local_game_projects_root(app),
- }
-}
-
pub(crate) fn create_automatic_local_game_project_at(
projects_root: &Path,
requested_name: Option<&str>,
@@ -590,61 +468,6 @@ pub(crate) fn create_automatic_local_game_project_at(
Err("自动工作区命名冲突,请重试".to_string())
}
-#[tauri::command]
-pub(crate) fn create_automatic_local_game_project(
- app: tauri::AppHandle,
- name: Option,
- planning: Option,
- projects_root: Option,
-) -> Result {
- let analytics_context = crate::analytics::gui::capture_analytics_context();
- let result = create_automatic_local_game_project_at(
- &resolve_game_project_creation_root(&app, projects_root.as_deref())?,
- name.as_deref(),
- planning.unwrap_or(false),
- );
- if let Ok(project) = &result {
- crate::analytics::gui::created(
- analytics_context,
- Path::new(&project.project_path),
- project.manifest.project_id.clone(),
- if planning.unwrap_or(false) {
- crate::analytics::contract::CreationSource::HomeDesign
- } else {
- crate::analytics::contract::CreationSource::HomeGame
- },
- None,
- );
- }
- result
-}
-
-#[tauri::command]
-pub(crate) fn init_local_game_project(
- project_path: String,
- project_id: String,
- name: String,
-) -> Result {
- let analytics_context = crate::analytics::gui::capture_analytics_context();
- let root = Path::new(project_path.trim());
- enforce_project_permission_policy(root, "project.create")?;
- let _lock = acquire_project_write_lock(root, "project.create")?;
- let new_project = matches!(fs::symlink_metadata(root.join(".agent/manifest.json")), Err(error) if error.kind() == std::io::ErrorKind::NotFound);
- let result = init_local_game_project_at(root, project_id.trim(), name.trim());
- if new_project {
- if let Ok(project) = &result {
- crate::analytics::gui::created(
- analytics_context,
- Path::new(&project.project_path),
- project.manifest.project_id.clone(),
- crate::analytics::contract::CreationSource::SelectedDirectory,
- None,
- );
- }
- }
- result
-}
-
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct RenameLocalProjectResult {
@@ -708,67 +531,6 @@ pub(crate) fn import_local_godot_project(
result
}
-#[tauri::command]
-pub(crate) fn import_local_cocos_project(
- project_path: String,
- project_id: String,
- name: String,
-) -> Result {
- let analytics_context = crate::analytics::gui::capture_analytics_context();
- let root = Path::new(project_path.trim());
- enforce_project_permission_policy(root, "project.create")?;
- if discover_local_cocos_project_root(root)?.is_none() {
- return Err(
- "所选目录不是有效的 Cocos Creator 项目(需要 package.json.creator.version 和 assets/)"
- .to_string(),
- );
- }
- let _lock = acquire_project_write_lock(root, "project.create")?;
- let new_project = matches!(fs::symlink_metadata(root.join(".agent/manifest.json")), Err(error) if error.kind() == std::io::ErrorKind::NotFound);
- let result = import_local_cocos_project_at(root, project_id.trim(), name.trim());
- if new_project {
- if let Ok(project) = &result {
- crate::analytics::gui::created(
- analytics_context,
- Path::new(&project.project_path),
- project.manifest.project_id.clone(),
- crate::analytics::contract::CreationSource::SelectedDirectory,
- None,
- );
- }
- }
- result
-}
-
-#[tauri::command]
-pub(crate) fn import_local_unity_project(
- project_path: String,
- project_id: String,
- name: String,
-) -> Result {
- let analytics_context = crate::analytics::gui::capture_analytics_context();
- let root = Path::new(project_path.trim());
- enforce_project_permission_policy(root, "project.create")?;
- if discover_local_unity_project_root(root)?.is_none() {
- return Err("所选目录不是有效的 Unity 项目".to_string());
- }
- let _lock = acquire_project_write_lock(root, "project.create")?;
- let new_project = matches!(fs::symlink_metadata(root.join(".agent/manifest.json")), Err(error) if error.kind() == std::io::ErrorKind::NotFound);
- let result = import_local_unity_project_at(root, project_id.trim(), name.trim());
- if new_project {
- if let Ok(project) = &result {
- crate::analytics::gui::created(
- analytics_context,
- Path::new(&project.project_path),
- project.manifest.project_id.clone(),
- crate::analytics::contract::CreationSource::SelectedDirectory,
- None,
- );
- }
- }
- result
-}
-
#[tauri::command]
pub(crate) fn is_local_project_directory_non_empty(project_path: String) -> Result {
let root = Path::new(project_path.trim());
@@ -796,15 +558,6 @@ pub(crate) fn is_local_project_directory_non_empty(project_path: String) -> Resu
.map(|entry| entry.is_some())
}
-#[tauri::command]
-pub(crate) async fn inspect_local_project_directory(
- project_path: String,
-) -> Result {
- tauri::async_runtime::spawn_blocking(move || inspect_local_project_directory_sync(project_path))
- .await
- .map_err(|error| format!("检查项目目录后台任务失败:{error}"))?
-}
-
pub(crate) fn inspect_local_project_directory_sync(
project_path: String,
) -> Result {
@@ -898,84 +651,6 @@ pub(crate) fn recent_game_creator_run_trace(root: &Path) -> Option(&content).ok()
}
-/// 目录选择器标题:调用方只能给短标题,其余(超长、含控制字符、空白)一律回退默认文案。
-fn pick_project_directory_title(title: Option<&str>) -> &str {
- const MAX_TITLE_CHARS: usize = 24;
- title
- .map(str::trim)
- .filter(|value| {
- !value.is_empty()
- && value.chars().count() <= MAX_TITLE_CHARS
- && !value.chars().any(char::is_control)
- })
- .unwrap_or("选择游戏项目目录")
-}
-
-#[tauri::command]
-pub(crate) async fn pick_local_project_directory(
- app: tauri::AppHandle,
- initial_path: Option,
- title: Option,
-) -> Result