From 0a6d550d731e3470a8d31e63fe2dc498925c1a46 Mon Sep 17 00:00:00 2001 From: kdletters Date: Sat, 8 Aug 2026 22:21:57 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=8F=8C=20PR=20?= =?UTF-8?q?=E5=90=88=E5=B9=B6=E5=90=8E=E7=9A=84=E6=8C=81=E7=BB=AD=E9=9B=86?= =?UTF-8?q?=E6=88=90=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补齐生成引用槽位参数并恢复 source 稳定标识\n恢复画布导出元数据格式化函数导入\n同步图标规范 GenerationInputs V2 测试契约\n修正音效提交并发测试的画布落层断言\n统一 Rust 格式以通过仓库门禁 --- .../crates/api-server/src/editor_project.rs | 15 +++++++---- ...CanvasEditorGenerationIntegration.test.tsx | 26 ++++++++++++++++--- .../image-editor/ImageCanvasExportModel.ts | 1 + ...anvasGenerationSubmissionWorkflow.test.tsx | 2 +- 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/server-rs/crates/api-server/src/editor_project.rs b/server-rs/crates/api-server/src/editor_project.rs index 3690fa81b..285d0885e 100644 --- a/server-rs/crates/api-server/src/editor_project.rs +++ b/server-rs/crates/api-server/src/editor_project.rs @@ -2481,8 +2481,7 @@ fn build_editor_scene_generation_inputs( .map(str::trim) .filter(|value| !value.is_empty()) { - fields - .push(json!({ "id": "customStyle", "title": "自定义画风", "value": custom_style })); + fields.push(json!({ "id": "customStyle", "title": "自定义画风", "value": custom_style })); } json!({ "version": 2, @@ -6292,6 +6291,7 @@ async fn resolve_editor_pixel_art_source_for_owner( )?; let generation_input_reference = if let Some(source_resource) = source_resource { Some(json!({ + "id": "source", "title": "原图", "label": source_resource .label @@ -6305,6 +6305,7 @@ async fn resolve_editor_pixel_art_source_for_owner( editor_generation_reference_from_records( projects.as_slice(), library.assets.as_slice(), + Some("source"), "原图".to_string(), source, ) @@ -6312,6 +6313,7 @@ async fn resolve_editor_pixel_art_source_for_owner( editor_generation_reference_from_records( projects.as_slice(), library.assets.as_slice(), + Some("source"), "原图".to_string(), object_key.as_str(), ) @@ -8544,9 +8546,7 @@ pub(crate) async fn rebuild_editor_generation_input_references( editor_generation_reference_from_records( projects.as_slice(), library.assets.as_slice(), - reference_slot_ids - .get(index) - .and_then(|id| id.as_deref()), + reference_slot_ids.get(index).and_then(|id| id.as_deref()), title, source.as_str(), ) @@ -13566,27 +13566,32 @@ mod tests { let resource_reference = editor_generation_reference_from_records( projects.as_slice(), std::slice::from_ref(&asset), + Some("specReference"), "参考图 1".to_string(), "generated-character-drafts/editor/shared.png", ) .expect("owned resource object key should produce provenance"); assert_eq!(resource_reference["refType"], "project-resource"); assert_eq!(resource_reference["refId"], "resource-1"); + assert_eq!(resource_reference["id"], "specReference"); let asset_reference = editor_generation_reference_from_records( projects.as_slice(), std::slice::from_ref(&asset), + Some("reference"), "参考图 2".to_string(), "asset-1", ) .expect("owned asset id should produce provenance"); assert_eq!(asset_reference["refType"], "asset"); assert_eq!(asset_reference["refId"], "asset-1"); + assert_eq!(asset_reference["id"], "reference"); assert!( editor_generation_reference_from_records( projects.as_slice(), std::slice::from_ref(&asset), + Some("reference"), "参考图 3".to_string(), "asset-forged", ) diff --git a/src/components/image-editor/ImageCanvasEditorGenerationIntegration.test.tsx b/src/components/image-editor/ImageCanvasEditorGenerationIntegration.test.tsx index 04e6af030..7f2ef9a4c 100644 --- a/src/components/image-editor/ImageCanvasEditorGenerationIntegration.test.tsx +++ b/src/components/image-editor/ImageCanvasEditorGenerationIntegration.test.tsx @@ -2241,9 +2241,20 @@ describe('ImageCanvasEditorView generation integration', () => { projectId: 'editor-project-default', assetFolderId: 'project', generationInputs: { + version: 2, + action: 'spec.generate', fields: [ - { title: '玩法设定', value: '消除类派对玩法' }, - { title: '美术风格', value: '糖果玻璃拟物' }, + { id: 'specType', title: '规范类型', value: 'icon' }, + { + id: 'playSetting', + title: '玩法设定', + value: '消除类派对玩法', + }, + { + id: 'artStyle', + title: '美术风格', + value: '糖果玻璃拟物', + }, ], references: [], }, @@ -3165,9 +3176,16 @@ describe('ImageCanvasEditorView generation integration', () => { projectId: 'editor-project-default', assetFolderId: 'project', generationInputs: { + version: 2, + action: 'spec.generate', fields: [ - { title: '玩法设定', value: '背包整理玩法' }, - { title: '美术风格', value: '清爽卡通' }, + { id: 'specType', title: '规范类型', value: 'icon' }, + { + id: 'playSetting', + title: '玩法设定', + value: '背包整理玩法', + }, + { id: 'artStyle', title: '美术风格', value: '清爽卡通' }, ], references: [], }, diff --git a/src/components/image-editor/ImageCanvasExportModel.ts b/src/components/image-editor/ImageCanvasExportModel.ts index 6865ebb55..020bb627f 100644 --- a/src/components/image-editor/ImageCanvasExportModel.ts +++ b/src/components/image-editor/ImageCanvasExportModel.ts @@ -8,6 +8,7 @@ import type { import { DEFAULT_ICON_DESCRIPTIONS, formatEditorGenerationInputFieldValue, + formatGenerationInputValue, formatLayerImageType, getEditorLayerModelDisplayName, isEditorUserVisibleGenerationInputField, diff --git a/src/components/image-editor/useImageCanvasGenerationSubmissionWorkflow.test.tsx b/src/components/image-editor/useImageCanvasGenerationSubmissionWorkflow.test.tsx index 875a0f463..fb1e8ec49 100644 --- a/src/components/image-editor/useImageCanvasGenerationSubmissionWorkflow.test.tsx +++ b/src/components/image-editor/useImageCanvasGenerationSubmissionWorkflow.test.tsx @@ -2395,7 +2395,7 @@ describe('useImageCanvasGenerationSubmissionWorkflow', () => { expect(screen.getByTestId('sound-effect-assist').textContent).toBe( 'idle', ); - expect(screen.getByTestId('layers').textContent).not.toContain( + expect(screen.getByTestId('layers').textContent).toContain( 'sound-effect', ); }); From 8d4d7ecc950529af16e678a147b877f7e8d52f9a Mon Sep 17 00:00:00 2001 From: kdletters Date: Sat, 8 Aug 2026 22:25:28 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E5=85=BC=E5=AE=B9=E5=8E=86=E5=8F=B2=20UI?= =?UTF-8?q?=20=E8=A7=84=E8=8C=83=E7=9A=84=E7=BB=9F=E4=B8=80=E5=9B=BE?= =?UTF-8?q?=E6=A0=87=E5=85=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将历史 spec.generate 的 ui 类型映射到 icon\n补充 GenerationInputs V2 恢复回归测试 --- .../ImageCanvasGenerationDialogModel.test.ts | 32 +++++++++++++++++++ .../ImageCanvasGenerationDialogModel.ts | 10 +++--- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/components/image-editor/ImageCanvasGenerationDialogModel.test.ts b/src/components/image-editor/ImageCanvasGenerationDialogModel.test.ts index 7cd0757be..235b3f282 100644 --- a/src/components/image-editor/ImageCanvasGenerationDialogModel.test.ts +++ b/src/components/image-editor/ImageCanvasGenerationDialogModel.test.ts @@ -1206,6 +1206,38 @@ describe('ImageCanvasGenerationDialogModel', () => { }); }); + it('maps legacy ui spec.generate inputs to the unified icon spec composer', () => { + expect( + createSameSourceGenerationDialogDraft({ + sourceLayer: createLayer({ + sourceType: 'generated', + assetKind: 'icon-spec', + generationInputs: { + version: 2, + action: 'spec.generate', + fields: [ + { id: 'specType', title: '规范类型', value: 'ui' }, + { id: 'playSetting', title: '玩法设定', value: '消除玩法' }, + { id: 'artStyle', title: '美术风格', value: '糖果玻璃' }, + ], + references: [], + }, + }), + availableLayers: [], + canvasSize: { width: 960, height: 720 }, + viewport: { x: 0, y: 0, scale: 1 }, + mode: 'redraw', + }), + ).toMatchObject({ + mode: 'spec', + specType: 'icon', + specValues: { + playSetting: '消除玩法', + artStyle: '糖果玻璃', + }, + }); + }); + it('restores the narrowly scoped legacy scene recipe into the scene composer', () => { expect( createSameSourceGenerationDialogDraft({ diff --git a/src/components/image-editor/ImageCanvasGenerationDialogModel.ts b/src/components/image-editor/ImageCanvasGenerationDialogModel.ts index e9707888d..b13778570 100644 --- a/src/components/image-editor/ImageCanvasGenerationDialogModel.ts +++ b/src/components/image-editor/ImageCanvasGenerationDialogModel.ts @@ -1001,11 +1001,11 @@ function createNormalizedGenerationDialogDraft({ 'custom', ); const specType: SpecGenerationType = - specTypeValue === 'character' || - specTypeValue === 'ui' || - specTypeValue === 'icon' - ? specTypeValue - : 'custom'; + specTypeValue === 'ui' + ? 'icon' + : specTypeValue === 'character' || specTypeValue === 'icon' + ? specTypeValue + : 'custom'; return placeDraftBesideSourceLayer( { ...createSpecDialogDraft({ canvasSize, viewport, specType }), From dfcd67bd05a592223f5769c32c780c1819afa051 Mon Sep 17 00:00:00 2001 From: kdletters Date: Sat, 8 Aug 2026 22:33:55 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=BF=9B=E7=A8=8B?= =?UTF-8?q?=E4=BC=9A=E8=AF=9D=E7=BB=88=E6=AD=A2=E6=B8=85=E7=90=86=E7=AB=9E?= =?UTF-8?q?=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在发布终态通知前先移除 live registry 会话\n避免取消清理瞬时误判仍有未收束进程 --- .../src-tauri/src/process_session/lifecycle.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/ai-game-creator-shell/src-tauri/src/process_session/lifecycle.rs b/apps/ai-game-creator-shell/src-tauri/src/process_session/lifecycle.rs index 8f259dad5..d5e5f166d 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/process_session/lifecycle.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/process_session/lifecycle.rs @@ -1435,11 +1435,13 @@ fn finalize_live_process_session( output.needs_reconciliation = true; } let needs_reconciliation = output.needs_reconciliation; - live.output_changed.notify_all(); - drop(output); + // 只有 live registry 已收束后才能发布可信终态。等待 `output_changed` 的调用方 + // 可能立即执行 run 级取消清理,而 registry 中的任何 live 条目都会被视为未完成会话。 if record_persisted && !needs_reconciliation { if let Ok(mut registry) = process_session_registry().lock() { registry.sessions.remove(&live.process_id); } } + live.output_changed.notify_all(); + drop(output); }