diff --git a/apps/ai-game-creator-shell/src-tauri/src/desktop.rs b/apps/ai-game-creator-shell/src-tauri/src/desktop.rs index 5cdf5df04..fadc5fb15 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/desktop.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/desktop.rs @@ -8,7 +8,8 @@ use client_extensions::*; use environment_check::preflight_web_game_creation; use error_report::*; use export::draft::xhs_minitool::commands::{ - read_xhs_minitool_export, run_xhs_minitool_export_build, save_xhs_minitool_export_form, + read_xhs_minitool_export, read_xhs_minitool_export_hash, run_xhs_minitool_export_build, + save_xhs_minitool_export_form, }; use game_distribution_publish::*; use plugin_host::{ @@ -689,6 +690,7 @@ pub(super) fn run() { create_local_project_checkpoint, export_local_project_package, read_xhs_minitool_export, + read_xhs_minitool_export_hash, save_xhs_minitool_export_form, run_xhs_minitool_export_build, prepare_local_project_game_package, diff --git a/apps/ai-game-creator-shell/src-tauri/src/export/draft/xhs_minitool/commands.rs b/apps/ai-game-creator-shell/src-tauri/src/export/draft/xhs_minitool/commands.rs index e8c9ccc64..02f427bd3 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/export/draft/xhs_minitool/commands.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/export/draft/xhs_minitool/commands.rs @@ -1,8 +1,12 @@ -//! 导出面板用到的三个 `#[tauri::command]`。 +//! 导出面板用到的四个 `#[tauri::command]`。 //! //! 每个命令只做一件事,全部走 typed 失败([`XHSMiniToolExportError`])。没有项目写锁、不推进 //! revision:宿主在这里读写的,就是 `.export/` 下那一个注册表文件。 //! +//! 「内容」与「注册表指纹」是两条命令:[`read_xhs_minitool_export`] 是面板自动刷新反复调的 +//! 那条,拿不到指纹;指纹(写回时的 `baseHash`)只在进编辑会话、或内容真的被采纳时单独取一次。 +//! 分开是为了让刷新动作在类型上就动不了写回基线——否则外部改动会被静默吞掉。 +//! //! 入参在 JS 侧是 camelCase(Tauri 的既有口径):`projectPath`、`baseHash`。 use std::path::{Path, PathBuf}; @@ -13,16 +17,27 @@ use super::registry::{self, RegistrySnapshot}; use super::validation::validate_form; use super::{build, script}; -/// 读现场:注册表(缺则补一份空表单)+ 脚本是否存在。 +/// 读内容:注册表(缺则补一份空表单)+ 脚本是否存在。自动刷新反复调的就是这一条。 #[tauri::command] pub(crate) async fn read_xhs_minitool_export( project_path: String, ) -> Result { let root = project_root(&project_path)?; - Ok(state(&root, registry::load(&root)?)) + Ok(content(&root, registry::load(&root)?)) } -/// 保存表单:先硬校验(首个错误即返回),再按 `base_hash` 判冲突。 +/// 读注册表指纹:写回时原样带回做冲突判据。 +/// +/// 单独一条命令,且**只在内容被采纳时**取:让「刷新」这条高频路径在类型上碰不到写回基线。 +#[tauri::command] +pub(crate) async fn read_xhs_minitool_export_hash( + project_path: String, +) -> Result { + let root = project_root(&project_path)?; + Ok(registry::load(&root)?.content_hash) +} + +/// 保存表单:先硬校验(首个错误即返回),再按 `base_hash` 判冲突;成功后回新的指纹。 /// /// 校验挡在保存之前是刻意的——平台字数与 icon 限制是硬约束,让它在用户输入时就被看见,比等到 /// 人工上传被平台打回便宜。 @@ -31,10 +46,10 @@ pub(crate) async fn save_xhs_minitool_export_form( project_path: String, form: XHSMiniToolExportForm, base_hash: String, -) -> Result { +) -> Result { let root = project_root(&project_path)?; validate_form(&root, &form)?; - Ok(state(&root, registry::save(&root, &form, &base_hash)?)) + Ok(registry::save(&root, &form, &base_hash)?.content_hash) } /// 跑一次导出:每次都重新执行项目脚本、重新产出 zip。 @@ -47,11 +62,10 @@ pub(crate) async fn run_xhs_minitool_export_build( } /// `hasScript` 永远现算:注册表里不存、也不缓存这个事实。 -fn state(root: &Path, snapshot: RegistrySnapshot) -> XHSMiniToolExportState { +fn content(root: &Path, snapshot: RegistrySnapshot) -> XHSMiniToolExportState { XHSMiniToolExportState { form: snapshot.form, has_script: script::find(root).is_some(), - content_hash: snapshot.content_hash, } } diff --git a/apps/ai-game-creator-shell/src-tauri/src/export/draft/xhs_minitool/dto.rs b/apps/ai-game-creator-shell/src-tauri/src/export/draft/xhs_minitool/dto.rs index 578531675..107bf0bd3 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/export/draft/xhs_minitool/dto.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/export/draft/xhs_minitool/dto.rs @@ -52,10 +52,11 @@ pub(crate) enum XHSMiniToolExportField { IconPath, } -/// 面板读到的现场状态。 +/// 面板读到的现场内容。 /// /// 没有「产物是否已存在」:每次导出都重新构建。也没有 status / 已适配标记——「有没有脚本」 -/// 永远从 npm 包的 `package.json` 现算,不落盘。 +/// 永远从 npm 包的 `package.json` 现算,不落盘。也没有注册表指纹:那是写回时的同步细节, +/// 由 `read_xhs_minitool_export_hash` 单独给,自动刷新读的这条命令碰不到它。 #[derive(Clone, Debug, PartialEq, Eq, Serialize, TS)] #[serde(rename_all = "camelCase")] #[ts(export, export_to = concat!(env!("CARGO_MANIFEST_DIR"), "/../src/view/project-development/export/generated/"))] @@ -63,8 +64,6 @@ pub(crate) struct XHSMiniToolExportState { pub(crate) form: XHSMiniToolExportForm, /// `scripts["build:xhs-minitool"]` 是否存在。 pub(crate) has_script: bool, - /// 注册表文件的当前内容指纹。保存时原样带回做冲突判据;它不写进文件。 - pub(crate) content_hash: String, } /// 一次成功导出的结果。产物路径是常量(`.export/xhs-minitool.zip`),不进 DTO。 diff --git a/apps/ai-game-creator-shell/src/view/project-development/export/generated/XHSMiniToolExportState.ts b/apps/ai-game-creator-shell/src/view/project-development/export/generated/XHSMiniToolExportState.ts index e70d76cf1..e8729b0e2 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/export/generated/XHSMiniToolExportState.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/export/generated/XHSMiniToolExportState.ts @@ -2,17 +2,14 @@ import type { XHSMiniToolExportForm } from "./XHSMiniToolExportForm"; /** - * 面板读到的现场状态。 + * 面板读到的现场内容。 * * 没有「产物是否已存在」:每次导出都重新构建。也没有 status / 已适配标记——「有没有脚本」 - * 永远从 npm 包的 `package.json` 现算,不落盘。 + * 永远从 npm 包的 `package.json` 现算,不落盘。也没有注册表指纹:那是写回时的同步细节, + * 由 `read_xhs_minitool_export_hash` 单独给,自动刷新读的这条命令碰不到它。 */ export type XHSMiniToolExportState = { form: XHSMiniToolExportForm, /** * `scripts["build:xhs-minitool"]` 是否存在。 */ -hasScript: boolean, -/** - * 注册表文件的当前内容指纹。保存时原样带回做冲突判据;它不写进文件。 - */ -contentHash: string, }; +hasScript: boolean, };