From 018697203f1020ba25148cb358e7cbd587c3385d Mon Sep 17 00:00:00 2001 From: Linghong Date: Wed, 23 Sep 2026 10:58:19 +0000 Subject: [PATCH] =?UTF-8?q?=E6=B8=85=E7=90=86=E4=BD=8E=E9=A3=8E=E9=99=A9?= =?UTF-8?q?=E7=BC=96=E8=AF=91=E8=AD=A6=E5=91=8A=E5=B9=B6=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E6=9E=84=E5=BB=BA=E6=A3=80=E6=9F=A5=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 清理冗余导入、可变绑定和赋值,将 AGC 默认编译警告从 231 条降至 195 条 按测试和平台边界限定导入,保留兼容出口与待核查的业务参数 修复预览部署器嵌套 npm 警告和移动端检查脚本的 Windows 启动错误 更新警告清单、开发运维文档与共享开发流程,记录验证结果和剩余项 --- .../src/agent/codex_app_server/mod.rs | 8 ++-- .../src/agent/codex_provider_proxy.rs | 2 +- .../src/agent/direct_project_context.rs | 4 +- .../src-tauri/src/agent/direct_runtime/mod.rs | 5 ++- .../src-tauri/src/agent/direct_tool_bridge.rs | 10 +++-- .../runtime_actions/context_compaction.rs | 3 +- .../provider_request_builders.rs | 2 +- .../runtime_protocol/autonomous_completion.rs | 2 +- .../agent/runtime_protocol/json_sidecar.rs | 2 + .../src-tauri/src/assets.rs | 2 +- .../src-tauri/src/commands.rs | 6 +-- .../src-tauri/src/config.rs | 1 - .../src-tauri/src/main.rs | 3 +- .../src-tauri/src/platform_session.rs | 2 +- .../src-tauri/src/resource_inspect.rs | 2 +- .../src-tauri/src/runner/endpoint.rs | 9 ++-- .../src-tauri/src/runner/server.rs | 2 + .../src/tool_plan_handoff/discovery.rs | 5 ++- .../src/ui_editor/commands/recognition.rs | 2 +- .../commands/separation/image_preprocess.rs | 4 +- .../commands/separation/persistence.rs | 1 - .../src/ui_editor/html_renderer/mod.rs | 2 +- .../src-tauri/src/ui_editor/persistence.rs | 4 +- .../src-tauri/src/ui_editor/workflow.rs | 2 +- .../scripts/check-eas-build-config.mjs | 11 +++-- .../scripts/check-expo-config.mjs | 8 ++-- .../scripts/check-expo-export.mjs | 20 ++++----- apps/preview-deployer-web/package.json | 2 +- .../shared-memory/development-workflow.md | 2 + ...解决】主要构建入口编译警告清单-2026-09-23.md | 45 +++++++++++++++++-- ...发运维】本地开发验证与生产运维-2026-05-15.md | 2 + 31 files changed, 115 insertions(+), 60 deletions(-) diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/codex_app_server/mod.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/codex_app_server/mod.rs index bc5d088a0..b30f5ef2b 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/codex_app_server/mod.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/codex_app_server/mod.rs @@ -8,7 +8,6 @@ use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; use std::sync::{Arc, OnceLock, Weak}; use tokio::io::{AsyncBufRead, AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader}; use tokio::sync::{mpsc, oneshot, Mutex, Notify}; -use uuid::Uuid; mod direct_project_history_wire; use direct_project_history_wire::build_direct_project_history_injection_params; @@ -3236,9 +3235,9 @@ impl CodexAppServerConnection { snapshot: &AgentRuntimeProviderRequestSnapshot, llm: &GameCreatorLlmConfig, request: LlmRunRequest, - mut on_agent_message_delta: Option<&mut (dyn FnMut(&platform_llm::LlmStreamDelta) + Send)>, - mut direct_observer: Option<&mut (dyn FnMut(DirectCodexTurnObservation) + Send)>, - mut audit: Option<&mut DirectCodexTurnAudit>, + on_agent_message_delta: Option<&mut (dyn FnMut(&platform_llm::LlmStreamDelta) + Send)>, + direct_observer: Option<&mut (dyn FnMut(DirectCodexTurnObservation) + Send)>, + audit: Option<&mut DirectCodexTurnAudit>, ) -> Result { self.run_turn_with_direct_observer_and_history( snapshot, @@ -3288,7 +3287,6 @@ impl CodexAppServerConnection { } } }); - let mut request = request; let history_root = direct_history_root.unwrap_or(&self.inner.workspace_path); // 工具调用卡片的 turnId 用 AGC 客户端回合 id(与实时事件、落盘条目同一口径), // 不用 Codex app-server 自己的 turnId——前端要按它把卡片挂回对应的那一轮。 diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/codex_provider_proxy.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/codex_provider_proxy.rs index 98f5356f1..63773936a 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/codex_provider_proxy.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/codex_provider_proxy.rs @@ -4,7 +4,7 @@ use axum::extract::State; use axum::http::{HeaderMap, HeaderName, Request, Response, StatusCode}; use axum::routing::any; use axum::Router; -use futures::{Stream, StreamExt}; +use futures::Stream; use std::pin::Pin; use std::sync::{Arc, Mutex}; use std::task::{Context, Poll}; diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_project_context.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_project_context.rs index 08fbbd568..57ed7cbbe 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_project_context.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_project_context.rs @@ -6,7 +6,9 @@ use serde_json::{json, Value}; use sha2::{Digest, Sha256}; use std::collections::HashSet; use std::io::Read; -use std::path::{Path, PathBuf}; +use std::path::Path; +#[cfg(test)] +use std::path::PathBuf; use std::sync::Arc; const MAX_FILES: usize = 8; diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_runtime/mod.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_runtime/mod.rs index 4db66f9f7..a466faa8c 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_runtime/mod.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_runtime/mod.rs @@ -2,14 +2,15 @@ use super::*; use base64::Engine as _; use std::collections::BTreeMap; use std::collections::HashMap; -use std::future::Future; use std::io::Write; use std::path::{Path, PathBuf}; use std::sync::{Mutex, OnceLock}; use std::time::{SystemTime, UNIX_EPOCH}; mod user_input; -pub(crate) use user_input::{chat_with_game_creator_direct_codex, normalize_direct_client_turn_id}; +pub(crate) use user_input::chat_with_game_creator_direct_codex; +#[cfg(test)] +pub(crate) use user_input::normalize_direct_client_turn_id; const MAX_DIRECT_SYSTEM_PROMPT_CHARS: usize = 16 * 1024; const MIN_DIRECT_CLIENT_TURN_ID_CHARS: usize = 6; diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_tool_bridge.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_tool_bridge.rs index 25224ba5d..6f287a6ae 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_tool_bridge.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_tool_bridge.rs @@ -1,6 +1,10 @@ use super::*; -use axum::extract::{DefaultBodyLimit, Query, State}; -use axum::routing::{get, post}; +#[cfg(test)] +use axum::extract::Query; +use axum::extract::{DefaultBodyLimit, State}; +#[cfg(test)] +use axum::routing::get; +use axum::routing::post; use axum::{Json, Router}; use base64::{engine::general_purpose::STANDARD as BASE64_STANDARD, Engine as _}; use serde::Deserialize; @@ -777,7 +781,7 @@ pub(crate) fn compact_mcp_image_data(data: &str) -> Option<(String, &'static str preview = image.thumbnail(dimension, dimension); } let mut encoded = Vec::new(); - let mut encoder = image::codecs::jpeg::JpegEncoder::new_with_quality(&mut encoded, quality); + let encoder = image::codecs::jpeg::JpegEncoder::new_with_quality(&mut encoded, quality); preview.write_with_encoder(encoder).ok()?; if encoded.len() <= DIRECT_TOOL_BRIDGE_IMAGE_PREVIEW_MAX_BYTES { return Some((BASE64_STANDARD.encode(encoded), "image/jpeg")); diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/context_compaction.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/context_compaction.rs index cb239c2d2..33788355e 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/context_compaction.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/context_compaction.rs @@ -60,8 +60,7 @@ pub(in crate::agent) async fn compact_game_creator_agent_runtime_context_at( let app_config = load_game_creator_app_config()?; let llm = resolve_game_creator_llm_config_for_agent(&app_config, &template_agent_id); let config_path = format!("agentLlm.{template_agent_id}"); - let mut request = - build_game_creator_agent_runtime_context_compaction_request(&source, &llm)?; + let request = build_game_creator_agent_runtime_context_compaction_request(&source, &llm)?; let estimated_request_tokens = estimate_game_creator_llm_request_tokens(&request)?; validate_game_creator_llm_request_context_budget( &llm, diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/provider_request_builders.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/provider_request_builders.rs index cc3f270f1..1c74612fa 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/provider_request_builders.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_actions/provider_request_builders.rs @@ -603,7 +603,7 @@ fn build_game_creator_agent_background_tool_plan_request_at( .messages .push(LlmMessage::user(goal_contract_instruction)); } - let mut request = apply_game_creator_llm_reasoning_effort(request, &llm)?; + let request = apply_game_creator_llm_reasoning_effort(request, &llm)?; let request = apply_game_creator_llm_web_search(request, &llm, true)?; Ok(( llm, diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/autonomous_completion.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/autonomous_completion.rs index 1623a07d6..6468106d3 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/autonomous_completion.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/autonomous_completion.rs @@ -6322,7 +6322,7 @@ fn autonomous_manifest_parent_completion_gaps_at( { missing_paths.push(gap); } - let mut owner_artifact_gaps = autonomous_manifest_owner_artifact_gaps_at( + let owner_artifact_gaps = autonomous_manifest_owner_artifact_gaps_at( root, &seed_task.id, contract.baseline_index_sha256.as_deref(), diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/json_sidecar.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/json_sidecar.rs index fa526579e..20cd88b1d 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/json_sidecar.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/json_sidecar.rs @@ -31,6 +31,8 @@ pub(in crate::agent) fn sync_agent_runtime_sidecar_parent( path: &Path, label: &str, ) -> Result<(), String> { + #[cfg(not(unix))] + let _ = (path, label); #[cfg(unix)] { let parent = path.parent().ok_or_else(|| format!("{label} 缺少父目录"))?; diff --git a/apps/ai-game-creator-shell/src-tauri/src/assets.rs b/apps/ai-game-creator-shell/src-tauri/src/assets.rs index 0710c3351..8bdca4c5f 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/assets.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/assets.rs @@ -1,5 +1,5 @@ use super::*; -use sha2::{Digest as _, Sha256}; +use sha2::Sha256; use shared_contracts::game_creation_app::GameCreationAppAssetCategory; use std::future::Future; diff --git a/apps/ai-game-creator-shell/src-tauri/src/commands.rs b/apps/ai-game-creator-shell/src-tauri/src/commands.rs index a18bdb369..88765880d 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/commands.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/commands.rs @@ -2089,7 +2089,7 @@ pub(crate) fn create_ui_design_resource( use std::os::windows::fs::OpenOptionsExt; options.custom_flags(crate::PROJECT_FILE_FLAG_OPEN_REPARSE_POINT); } - let mut file = options + let file = options .open(&absolute_path) .map_err(|error| format!("创建 UI 资源失败:{}: {error}", absolute_path.display()))?; if let Err(error) = harden_new_game_creator_private_path(&absolute_path, false, "UI 资源") { @@ -4640,13 +4640,13 @@ pub(crate) async fn import_ui_editor_remote_assets( ); let local_path = remote_asset_local_path(&asset_id, extension); reserve_remote_asset_destination(&mut destinations, &local_path)?; - downloads.push((asset, asset_id, media_type.to_string(), local_path, bytes)); + downloads.push((asset, media_type.to_string(), local_path, bytes)); } let _lock = acquire_project_write_lock(root, "canvas.asset_import")?; // 远程素材导入保持与本地图片/字体相同的增量语义,不对已成功项目文件做整批回滚。 let mut imported = Vec::with_capacity(downloads.len()); - for (asset, asset_id, media_type, local_path, bytes) in downloads { + for (asset, media_type, local_path, bytes) in downloads { let target = resolve_local_project_path(root, &local_path)?; if let Some(parent) = target.parent() { ensure_game_creator_private_directory_tree(parent, "平台素材导入目录")?; diff --git a/apps/ai-game-creator-shell/src-tauri/src/config.rs b/apps/ai-game-creator-shell/src-tauri/src/config.rs index 839311a3f..676eb6c71 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/config.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/config.rs @@ -3639,7 +3639,6 @@ pub(crate) fn migrate_legacy_game_creator_agent_mode(path: &Path) -> Result<(), if let Some(llm) = config.llm.as_mut() { if llm.web_search_enabled.is_none() { llm.web_search_enabled = Some(true); - changed = true; } } } 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 256c38c3d..597935ded 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/main.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/main.rs @@ -10,7 +10,6 @@ use std::fs::{File, OpenOptions}; use std::io::{BufRead, BufReader, Read, Seek, SeekFrom, Write}; use std::net::{TcpListener, TcpStream}; use std::path::{Path, PathBuf}; -use std::process::Command; use std::sync::atomic::AtomicBool; use std::sync::{mpsc, Arc, Mutex, OnceLock}; use std::thread; @@ -2453,7 +2452,7 @@ fn main() { set_game_creator_runtime_config_dir(config_dir); } - let mut tauri_context = tauri::generate_context!(); + let tauri_context = tauri::generate_context!(); // 配置目录确定之前先推导启动日志路径:优先用已经生效的配置目录(例如 // `--config-dir`),否则退到平台配置根,保证 // `configure_game_creator_runtime_config_dir` 自身失败也有落点。 diff --git a/apps/ai-game-creator-shell/src-tauri/src/platform_session.rs b/apps/ai-game-creator-shell/src-tauri/src/platform_session.rs index a58d9eebf..e1df0f8d9 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/platform_session.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/platform_session.rs @@ -186,7 +186,7 @@ fn read_fixture_file(path: &Path) -> Result, String> { use std::os::unix::fs::OpenOptionsExt; options.custom_flags(libc::O_NOFOLLOW); } - let mut file = options + let file = options .open(path) .map_err(|_| "平台登录态 fixture 文件不可读取".to_string())?; let opened = file diff --git a/apps/ai-game-creator-shell/src-tauri/src/resource_inspect.rs b/apps/ai-game-creator-shell/src-tauri/src/resource_inspect.rs index 3a666b253..f592a98df 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/resource_inspect.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/resource_inspect.rs @@ -351,7 +351,7 @@ pub(crate) fn load_local_project_media_preview_with_cancellation( } cancellation.check()?; let source_byte_len = bytes.len() as u64; - /** + /* * 图像容器(TGA / TIFF / HDR / EXR)在浏览器里没有解码器:先在原生侧转成 PNG, * 再走与 GIF / BMP / AVIF 完全相同的「数据 URL + 图片卡」链路。转码是**只读**的, * 不改工程文件;像素尺寸仍受既有的尺寸与像素总量上限约束,不会因为多一层解码 diff --git a/apps/ai-game-creator-shell/src-tauri/src/runner/endpoint.rs b/apps/ai-game-creator-shell/src-tauri/src/runner/endpoint.rs index a1cc76b58..267943ae2 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/runner/endpoint.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/runner/endpoint.rs @@ -1040,9 +1040,8 @@ pub(crate) fn acquire_external_agent_runner_gui_participant_lock( None }; let deadline = Instant::now() + EXTERNAL_AGENT_RUNNER_GUI_PARTICIPANT_LOCK_ACQUIRE_TIMEOUT; - let mut last_error = "AGC 界面参与锁未知失败".to_string(); loop { - match open_external_agent_runner_lock_file( + let last_error = match open_external_agent_runner_lock_file( &path, "AGC 界面参与锁", ExternalAgentRunnerLockMode::Shared, @@ -1052,10 +1051,10 @@ pub(crate) fn acquire_external_agent_runner_gui_participant_lock( return Ok(ExternalAgentRunnerGuiParticipantLock { _file: file }); } Ok(None) => { - last_error = format!("AGC 界面参与锁无法以共享方式取得:{}", path.display()); + format!("AGC 界面参与锁无法以共享方式取得:{}", path.display()) } - Err(error) => last_error = error, - } + Err(error) => error, + }; if Instant::now() >= deadline { return Err(format!("取得 AGC 界面参与锁失败:{last_error}")); } diff --git a/apps/ai-game-creator-shell/src-tauri/src/runner/server.rs b/apps/ai-game-creator-shell/src-tauri/src/runner/server.rs index 67c01849a..7df02de91 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/runner/server.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/runner/server.rs @@ -1,5 +1,7 @@ use super::{dispatch::*, endpoint::*, protocol::*, state::*}; +#[cfg(target_os = "linux")] use sha2::{Digest as _, Sha256}; +#[cfg(target_os = "linux")] use std::fs; use std::io; use std::net::{Ipv4Addr, SocketAddrV4, TcpListener}; diff --git a/apps/ai-game-creator-shell/src-tauri/src/tool_plan_handoff/discovery.rs b/apps/ai-game-creator-shell/src-tauri/src/tool_plan_handoff/discovery.rs index 77945eeef..ff1046731 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/tool_plan_handoff/discovery.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/tool_plan_handoff/discovery.rs @@ -1,9 +1,10 @@ use std::collections::BTreeMap; use std::path::Path; +use super::model::{AgentRuntimeToolPlanHandoffLedger, TOOL_PLAN_HANDOFF_MAX_DISCOVERED_LEDGERS}; +#[cfg(unix)] use super::model::{ - AgentRuntimeToolPlanHandoffLedger, TOOL_PLAN_HANDOFF_MAX_DISCOVERED_AGENTS, - TOOL_PLAN_HANDOFF_MAX_DISCOVERED_FILES, TOOL_PLAN_HANDOFF_MAX_DISCOVERED_LEDGERS, + TOOL_PLAN_HANDOFF_MAX_DISCOVERED_AGENTS, TOOL_PLAN_HANDOFF_MAX_DISCOVERED_FILES, }; use super::storage_common::is_handoff_path_key; #[cfg(unix)] diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/recognition.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/recognition.rs index 97e7ba78c..963b056cd 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/recognition.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/recognition.rs @@ -12,7 +12,7 @@ use crate::ui_editor::layout::node::{Node as LayoutNode, NodeMetadata, NodeSourc use crate::ui_editor::layout::transform::Transform; use crate::ui_editor::resource::ui_design_image::UIDesignImage; use crate::ui_editor::state::{State, UITree}; -use crate::ui_editor::utils::{random_node_id, NodeId, UIDesignImageId}; +use crate::ui_editor::utils::{random_node_id, UIDesignImageId}; use nalgebra::{Point2, Vector2}; use platform_llm::{ LlmFunctionTool, LlmMessage, LlmMessageContentPart, LlmRunRequest, LlmToolChoice, diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/image_preprocess.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/image_preprocess.rs index 147a6dce1..44095e80a 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/image_preprocess.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/image_preprocess.rs @@ -1,6 +1,8 @@ use super::area::MIN_VISIBLE_ALPHA; use base64::Engine as _; -use image::{ImageFormat, ImageReader, Rgba, RgbaImage}; +#[cfg(test)] +use image::RgbaImage; +use image::{ImageFormat, ImageReader, Rgba}; use std::fs; use std::io::Cursor; use std::path::{Path, PathBuf}; diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/persistence.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/persistence.rs index ee383d9c1..2f8a4dce7 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/persistence.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation/persistence.rs @@ -1,5 +1,4 @@ use super::model::*; -use crate::ui_editor::commands::separation::*; use std::fs::{self, OpenOptions}; use std::io::Write; use std::path::{Path, PathBuf}; diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/html_renderer/mod.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/html_renderer/mod.rs index e908a3117..4ac3ec1b8 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/html_renderer/mod.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/html_renderer/mod.rs @@ -137,7 +137,7 @@ pub(crate) fn render_ui_design_state_js( } fn render_tree(state: &State, tree: &UITree) -> Result { - let image = state + state .ui_design_images .get(&tree.src_ui_design) .ok_or_else(|| format!("UITree 缺少 src_ui_design:{}", tree.src_ui_design.as_str()))?; diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/persistence.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/persistence.rs index 43c045d4b..e089532df 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/persistence.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/persistence.rs @@ -12,7 +12,9 @@ use nalgebra::Vector2; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; use std::collections::HashSet; -use std::fs::{self, File}; +use std::fs; +#[cfg(unix)] +use std::fs::File; use std::io::{Read, Write}; use std::path::Path; use std::time::{SystemTime, UNIX_EPOCH}; diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/workflow.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/workflow.rs index e827ea75d..520ae77bb 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/workflow.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/workflow.rs @@ -19,7 +19,7 @@ use crate::*; use image::GenericImageView as _; use nalgebra::Vector2; use serde::{Deserialize, Serialize}; -use sha2::{Digest as _, Sha256}; +use sha2::Sha256; use shared_contracts::game_creation_app::GameCreationAppAssetKind; use std::collections::{HashMap, HashSet}; use std::fs; diff --git a/apps/mobile-shell/scripts/check-eas-build-config.mjs b/apps/mobile-shell/scripts/check-eas-build-config.mjs index f629b10ae..daaf3fcb7 100644 --- a/apps/mobile-shell/scripts/check-eas-build-config.mjs +++ b/apps/mobile-shell/scripts/check-eas-build-config.mjs @@ -1,5 +1,7 @@ import { spawnSync } from 'node:child_process'; import fs from 'node:fs'; +import { createRequire } from 'node:module'; +import { dirname, resolve } from 'node:path'; const shellRoot = new URL('../', import.meta.url); const easConfigPath = new URL('eas.json', shellRoot); @@ -7,7 +9,10 @@ const packagePath = new URL('package.json', shellRoot); const easConfig = JSON.parse(fs.readFileSync(easConfigPath, 'utf8')); const packageConfig = JSON.parse(fs.readFileSync(packagePath, 'utf8')); -const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm'; +const shellRequire = createRequire(packagePath); +const easPackagePath = shellRequire.resolve('eas-cli/package.json'); +const easPackage = JSON.parse(fs.readFileSync(easPackagePath, 'utf8')); +const easCliPath = resolve(dirname(easPackagePath), easPackage.bin.eas); const androidBuildOutputPath = '../../build/native/mobile/genarrative-mobile-android.apk'; const iosSimulatorBuildOutputPath = @@ -43,8 +48,8 @@ if (packageConfig.devDependencies?.['eas-cli'] !== '^20.3.0') { } const easVersionResult = spawnSync( - npmCommand, - ['exec', 'eas', '--', '--version'], + process.execPath, + [easCliPath, '--version'], { cwd: shellRoot, encoding: 'utf8', diff --git a/apps/mobile-shell/scripts/check-expo-config.mjs b/apps/mobile-shell/scripts/check-expo-config.mjs index e3ee16064..8cd7da0e9 100644 --- a/apps/mobile-shell/scripts/check-expo-config.mjs +++ b/apps/mobile-shell/scripts/check-expo-config.mjs @@ -29,11 +29,13 @@ const expoPrivacyInfoPluginSource = fs.readFileSync( 'utf8', ); const sharedContractSource = fs.readFileSync(sharedContractPath, 'utf8'); -const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm'; +const expoPackagePath = shellRequire.resolve('expo/package.json'); +const expoPackage = JSON.parse(fs.readFileSync(expoPackagePath, 'utf8')); +const expoCliPath = resolve(dirname(expoPackagePath), expoPackage.bin.expo); const result = spawnSync( - npmCommand, - ['exec', 'expo', 'config', '--', '--type', 'public', '--json'], + process.execPath, + [expoCliPath, 'config', '--type', 'public', '--json'], { cwd: shellRoot, encoding: 'utf8', diff --git a/apps/mobile-shell/scripts/check-expo-export.mjs b/apps/mobile-shell/scripts/check-expo-export.mjs index cb58b2d8d..cc2248dfd 100644 --- a/apps/mobile-shell/scripts/check-expo-export.mjs +++ b/apps/mobile-shell/scripts/check-expo-export.mjs @@ -1,5 +1,7 @@ import { spawnSync } from 'node:child_process'; import fs from 'node:fs'; +import { createRequire } from 'node:module'; +import { dirname, resolve } from 'node:path'; const shellRoot = new URL('../', import.meta.url); const outputRoot = new URL('../.expo-export-smoke/', import.meta.url); @@ -7,7 +9,10 @@ const hostBridgeContractUrl = new URL( '../../../packages/shared/src/contracts/hostBridge.ts', import.meta.url, ); -const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm'; +const shellRequire = createRequire(new URL('package.json', shellRoot)); +const expoPackagePath = shellRequire.resolve('expo/package.json'); +const expoPackage = JSON.parse(fs.readFileSync(expoPackagePath, 'utf8')); +const expoCliPath = resolve(dirname(expoPackagePath), expoPackage.bin.expo); const platforms = ['android', 'ios']; const blockedDevelopmentWebUrlPatterns = [ /http:\\?\/\\?\/localhost(?::\d+)?/u, @@ -51,17 +56,8 @@ const requiredNativeHostContextTokens = [ function runExpoExport(platform) { const outputDir = `.expo-export-smoke/${platform}`; const result = spawnSync( - npmCommand, - [ - 'exec', - 'expo', - 'export', - '--', - '--platform', - platform, - '--output-dir', - outputDir, - ], + process.execPath, + [expoCliPath, 'export', '--platform', platform, '--output-dir', outputDir], { cwd: shellRoot, encoding: 'utf8', diff --git a/apps/preview-deployer-web/package.json b/apps/preview-deployer-web/package.json index 18438be15..33a82540a 100644 --- a/apps/preview-deployer-web/package.json +++ b/apps/preview-deployer-web/package.json @@ -7,7 +7,7 @@ "dev": "vite --host 127.0.0.1", "typecheck": "tsc --noEmit -p tsconfig.json", "test": "vitest run -c vitest.config.ts", - "build": "npm run typecheck && vite build", + "build": "tsc --noEmit -p tsconfig.json && vite build", "preview": "vite preview --host 127.0.0.1" }, "dependencies": { diff --git a/docs/project-memory/shared-memory/development-workflow.md b/docs/project-memory/shared-memory/development-workflow.md index 71fbddf88..6b9ba3efb 100644 --- a/docs/project-memory/shared-memory/development-workflow.md +++ b/docs/project-memory/shared-memory/development-workflow.md @@ -53,6 +53,8 @@ ## 验证路由 +Windows 下的移动壳 smoke 通过 Node 启动从当前 workspace 包解析出的 Expo/EAS CLI,不直接 `spawnSync('npm.cmd')`;保留原配置与导出断言。具体入口和警告清理边界见本地开发运维文档。 + 提示词外置变更运行 `runtime_prompt_bundle_build` 与 `prompt_source_boundaries` 两个 Rust 集成测试,验证编译期文本、目录登记和源码边界;现有 `agc-rust-shard-1` 本地/CI 入口先执行这组检查,再运行分片单测。 提示词测试验证实际请求中的片段来源、动态参数和工具结构;措辞不作为逐字契约。已有行为测试覆盖的限制不再另设整段文案检查。Direct 回合测试复用生产的消息转换和文件投影函数,不维护仅供测试调用的回合编排副本。 diff --git a/docs/project-memory/todos/【待解决】主要构建入口编译警告清单-2026-09-23.md b/docs/project-memory/todos/【待解决】主要构建入口编译警告清单-2026-09-23.md index b2b77eebf..31ca1e629 100644 --- a/docs/project-memory/todos/【待解决】主要构建入口编译警告清单-2026-09-23.md +++ b/docs/project-memory/todos/【待解决】主要构建入口编译警告清单-2026-09-23.md @@ -7,7 +7,7 @@ ## 1. 基线与范围 -本次仅检查和讨论,尚未实施警告清理。基线提交为 `016356e509f11a1a638ce45ed51b9e40ef3e36a2`,诊断时工作树干净。环境为 Windows x64、Rust `1.98.1`、Node `v24.15.0`、npm `12.0.2`。 +首次诊断的基线提交为 `016356e509f11a1a638ce45ed51b9e40ef3e36a2`,诊断时工作树干净。环境为 Windows x64、Rust `1.98.1`、Node `v24.15.0`、npm `12.0.2`。第 2~6 节和附录保留首次诊断快照;后续处理状态以第 7 节为准,不能将附录的全部条目视为仍未解决。 AGC Rust 使用默认 features、dev profile;237 是本轮编译器诊断数,不代表 237 个独立根因,也不是所有平台、features 和 test targets 的总数。另有 5 条不带常规源码 span 的 ts-rs 宏提示,不计入 237。 @@ -104,8 +104,47 @@ three、FBX/GLTF loader、OrbitControls 已动态 import。不能把“改为动 ## 7. 待办与关闭条件 -- [ ] 第一批:核对并清理低风险导入、mut、注释、变量和赋值;修复预览部署器嵌套 npm 及移动 smoke 的 Windows 调用。 -- [ ] 第二批:对 165 条 dead_code 核对测试、正式 features、平台及退役合同,逐项确定保留、条件编译或删除;涉及退役范围扩大时先补方案。 +### 2026-09-23 首批低风险清理 + +清理前分支已合入上游,实际代码基线为 `07feed751`。重新运行默认 Windows dev 配置的 AGC `cargo check`,修复前为 **231 条**,修复后为 **195 条**,本次减少 **36 条**;首次记录的 237 与本轮修复前的 231 之间的差异来自上游合并,不计作本次修复。 + +| 诊断类型 | 本轮修复前 | 本轮修复后 | +| --- | ---: | ---: | +| `dead_code` | 158 | 158 | +| `unused_imports` | 45 | 27 | +| `unused_variables` | 13 | 9 | +| `unused_mut` | 11 | 0 | +| `unused_assignments` | 3 | 1 | +| `unused_doc_comments` | 1 | 0 | +| **合计** | **231** | **195** | + +已完成的局部修改: + +- 清理普通未用导入,将测试和 Linux/Unix 分支专用导入限定在对应编译条件;未删除兼容重导出、业务实现或新增 allow。 +- 清理 11 处 mut、局部语句前的文档注释、两个必然被覆盖的赋值;去除远程导入中间元组的冗余 asset ID,保留原始稳定身份校验及路径计算。 +- HTML 导出仍校验设计图存在,只去除未读取的绑定;目录同步保留 Unix 行为,非 Unix 分支显式忽略参数。 +- 预览部署器 build 直接调用 TSC/Vite,原 npm 配置 warning 已消除。 +- 移动壳三个 smoke 通过包解析得到已安装 Expo/EAS 的 CLI 入口,再由当前 Node 启动;原 Windows EINVAL 已消除,配置、EAS 配置和 Android/iOS 导出 smoke 均通过,原断言与清理范围不变。 + +对应首次清单已处理的编号为 W166、W167、W170~W174、W197、W198、W200、W202~W209、W217、W218、W220、W222~W233、W235~W237。合并后的新增导入 warning 是 `runtime_driver.rs` 中的 `start_game_creator_agent_background_task_for_session_at` 重导出,本轮按兼容边界保留。 + +保留项包括:兼容 facade、涉及身份/锁/完成门禁的未使用参数、Direct 重试回合的 response 初始化、全部 dead_code,以及 5 条 ts-rs 提示和 AGC chunk 体积告警。这些项需要语义或合同核查,不能仅改名或屏蔽。 + +验证通过: + +- AGC 默认 `cargo check --locked --offline` 及同一 package 的 `cargo check --locked --offline --tests`;均使用第 2 节的 manifest/package 参数。后者证明测试目标可编译,不代表已执行 Rust 单元测试,195 条仅统计普通 dev 构建。 +- `npm run preview-deployer:web:build`,无原 npm 配置 warning。 +- `npm run config:smoke -w @genarrative/mobile-shell`、`npm run build-config:smoke -w @genarrative/mobile-shell`、`npm run export:smoke -w @genarrative/mobile-shell`(Android/iOS)。 +- 修改 Rust 文件的 `rustfmt --check --edition 2021 --config skip_children=true`、三个移动脚本的 ESLint、脚本及预览 package 的 Prettier。 +- `npm run check:encoding`、`npm run check:doc-index`、`git diff --check`。 + +未执行 Rust 单元/运行时测试、正式 editor features、Linux/macOS 原生编译或安装包。独立只读审查未发现这批局部修改的行为回归;仍需其他平台实际编译才能补齐平台验证。 + +### 剩余工作 + +- [x] 第一批:清理确认不改变行为的低风险项,修复预览部署器嵌套 npm 及移动 smoke 的 Windows 调用。 +- [ ] 单独核查保留的兼容重导出、身份/锁/门禁参数及 Direct 重试回合初始化,确认合同后再修改。 +- [ ] 第二批:对当前 158 条 dead_code(首次快照为 165 条)核对测试、正式 features、平台及退役合同,逐项确定保留、条件编译或删除;涉及退役范围扩大时先补方案。 - [ ] 第三批:核实 5 条 ts-rs 提示的源类型及 TS 输出,保留现有反序列化约束。 - [ ] 第四批:评估 AGC 主包拆分;为无法合理拆分且已有按需加载的依赖明确体积取舍。 - [ ] 补充相关正式 features / 平台 / test targets 验证后更新剩余项,不用当前默认配置代表全部构建。 diff --git a/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md b/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md index 8fcaf11f0..4c9529a08 100644 --- a/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md +++ b/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md @@ -285,6 +285,8 @@ npm run check `npm run build` 由 `scripts/build-gate.mjs` 串行构建主站和后台;该门禁会把 Vite warning 当成失败处理。若看到 `Build gate failed because warnings were emitted`,先看 warning 原文,例如 chunk 体积超过 `vite.config.ts` / `apps/admin-web/vite.config.ts` 的 `chunkSizeWarningLimit`,不要先按 Rust 编译失败排查。 +编译警告的局部清理保持运行行为与验证断言不变:先在当前提交复现,再移除冗余导入、可变绑定及被无条件覆盖的赋值;仅测试或平台分支需要的导入按实际使用边界编译,兼容重导出和涉及锁、权限、持久化的参数单独核查。独立前端 build 可以直接执行本包已有的 TSC/Vite,避免嵌套 npm 传递配置警告;移动壳 smoke 使用 Node 直接启动本包解析出的已安装 Expo/EAS CLI,兼容 Windows,并保留原配置与导出断言。验收使用原构建入口及受影响的测试目标编译,不以全局屏蔽 warning、删除业务校验或提高包体积阈值代替修复。 + ### Gitea Actions PR 门禁 Linux process-session 的 owner SIGKILL 用例必须在启动 owner 后立即建立测试清理 guard:正常退出或断言 panic 时终止、回收 owner,并在有界时间内清理其独立临时项目目录中的残留进程。原有「owner 退出后子进程自行消失」断言在兜底清理之前执行,不能由 guard 代替生产生命周期验证。清理覆盖 panic 路径及临时项目间隔离,且不得因清理失败再次 panic。