格式化 AGC 壳 Rust 源码(rustfmt)
- cargo fmt --all --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml - 覆盖退役与合并期间改动的 27 个文件,恢复 check:rustfmt 门禁
This commit is contained in:
@@ -4,8 +4,8 @@ use std::collections::BTreeSet;
|
||||
use std::io::{Seek, SeekFrom};
|
||||
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
|
||||
|
||||
mod claude_code_cli;
|
||||
mod art_manifest;
|
||||
mod claude_code_cli;
|
||||
mod codex_app_server;
|
||||
mod codex_cli;
|
||||
mod codex_provider_proxy;
|
||||
@@ -22,6 +22,7 @@ mod direct_patch;
|
||||
pub(crate) use direct_paid_submission::ensure_direct_paid_submission_dispatch;
|
||||
#[cfg(test)]
|
||||
pub(crate) use direct_paid_submission::with_test_direct_paid_submission_scope;
|
||||
pub(crate) mod design_session;
|
||||
mod direct_project_context;
|
||||
mod direct_project_history;
|
||||
mod direct_project_turn_history;
|
||||
@@ -31,17 +32,17 @@ mod direct_tools_mcp;
|
||||
mod direct_turn_error;
|
||||
mod direct_turn_failure;
|
||||
mod direct_validation;
|
||||
mod runtime_error;
|
||||
mod runtime_models;
|
||||
mod generation;
|
||||
pub(crate) mod design_session;
|
||||
pub(crate) mod json_sidecar;
|
||||
pub(crate) mod redaction;
|
||||
mod task_lock;
|
||||
mod runtime_error;
|
||||
mod runtime_models;
|
||||
mod skill_pack;
|
||||
mod task_lock;
|
||||
mod thread_manager;
|
||||
pub mod tool;
|
||||
|
||||
pub(crate) use art_manifest::*;
|
||||
use claude_code_cli::*;
|
||||
pub(crate) use claude_code_cli::{
|
||||
cancel_direct_claude_code_turn_at, direct_game_creator_claude_code_chat_at,
|
||||
@@ -62,6 +63,7 @@ pub(crate) use codex_cli::{
|
||||
pub(crate) use codex_provider_proxy::*;
|
||||
#[cfg(not(test))]
|
||||
pub(crate) use design_runtime::*;
|
||||
pub(crate) use design_session::*;
|
||||
pub(crate) use direct_codex_attachments::*;
|
||||
pub(crate) use direct_codex_user_item::*;
|
||||
pub(crate) use direct_events::*;
|
||||
@@ -73,15 +75,13 @@ pub(crate) use direct_tools_mcp::*;
|
||||
pub(crate) use direct_turn_error::*;
|
||||
pub(crate) use direct_turn_failure::*;
|
||||
pub(crate) use direct_validation::DirectValidationConfig;
|
||||
pub(crate) use art_manifest::*;
|
||||
pub(crate) use runtime_error::*;
|
||||
pub(in crate::agent) use runtime_models::*;
|
||||
pub(crate) use generation::*;
|
||||
pub(crate) use design_session::*;
|
||||
pub(crate) use json_sidecar::*;
|
||||
pub(crate) use redaction::*;
|
||||
pub(crate) use task_lock::*;
|
||||
pub(crate) use runtime_error::*;
|
||||
pub(in crate::agent) use runtime_models::*;
|
||||
pub(crate) use skill_pack::*;
|
||||
pub(crate) use task_lock::*;
|
||||
pub(crate) use thread_manager::dispatch::*;
|
||||
pub(crate) use thread_manager::queue::*;
|
||||
pub(crate) use thread_manager::wire::*;
|
||||
|
||||
@@ -44,10 +44,11 @@ impl OwnedProcessTree {
|
||||
pub(super) fn attach(child: &Child) -> Result<Self, String> {
|
||||
let pid = child.id().ok_or("app-server-process-owner-missing")?;
|
||||
#[cfg(unix)]
|
||||
let start_identity = crate::process_identity::external_agent_runner_process_start_identity(pid)
|
||||
.map_err(|_| "app-server-process-identity-unknown")?
|
||||
.filter(|value| !value.is_empty())
|
||||
.ok_or("app-server-process-identity-unknown")?;
|
||||
let start_identity =
|
||||
crate::process_identity::external_agent_runner_process_start_identity(pid)
|
||||
.map_err(|_| "app-server-process-identity-unknown")?
|
||||
.filter(|value| !value.is_empty())
|
||||
.ok_or("app-server-process-identity-unknown")?;
|
||||
#[cfg(windows)]
|
||||
let job = crate::process_session::WindowsProcessJob::assign_tokio_named(
|
||||
child,
|
||||
@@ -162,8 +163,9 @@ impl OwnedProcessTree {
|
||||
return Ok(());
|
||||
}
|
||||
// leader 已消失或 PID 被复用时不盲杀 PGID;保留不确定状态。
|
||||
let current = crate::process_identity::external_agent_runner_process_start_identity(self.pid)
|
||||
.map_err(|_| "app-server-process-identity-unknown")?;
|
||||
let current =
|
||||
crate::process_identity::external_agent_runner_process_start_identity(self.pid)
|
||||
.map_err(|_| "app-server-process-identity-unknown")?;
|
||||
if current.as_deref() != Some(self.start_identity.as_str()) {
|
||||
return Err("app-server-process-owner-mismatch".into());
|
||||
}
|
||||
|
||||
@@ -17,9 +17,7 @@ const DESIGN_ACTIVE_LOCK: &str = ".agent/design-agent/active.lock";
|
||||
const DESIGN_PROVIDER_TRANSIENT_BACKOFF_MAX_MS: u64 = 30_000;
|
||||
|
||||
/// 判定一个 Provider 错误是否属于可重试的瞬时故障;预算/余额类错误不算。
|
||||
fn design_provider_error_transient_kind(
|
||||
error: &platform_llm::LlmError,
|
||||
) -> Option<&'static str> {
|
||||
fn design_provider_error_transient_kind(error: &platform_llm::LlmError) -> Option<&'static str> {
|
||||
if game_creator_agent_llm_error_is_mud_points_insufficient(error) {
|
||||
return None;
|
||||
}
|
||||
@@ -526,8 +524,7 @@ fn resolve_design_turn_llm_config(
|
||||
}
|
||||
|
||||
fn checkpoint_design(root: &Path, session: &DesignSession) -> Result<(), String> {
|
||||
let _write =
|
||||
acquire_project_write_lock_with_wait(root, "design.session")?;
|
||||
let _write = acquire_project_write_lock_with_wait(root, "design.session")?;
|
||||
write_design_session(root, session)
|
||||
}
|
||||
|
||||
@@ -952,9 +949,7 @@ async fn request_design_provider(
|
||||
"error",
|
||||
json!({"turnId":turn_id,"attempt":attempt,"error":detail}),
|
||||
);
|
||||
if attempt == max_retries
|
||||
|| design_provider_error_transient_kind(&error)
|
||||
.is_none()
|
||||
if attempt == max_retries || design_provider_error_transient_kind(&error).is_none()
|
||||
{
|
||||
emit(design_reasoning_event(
|
||||
root,
|
||||
@@ -965,10 +960,7 @@ async fn request_design_provider(
|
||||
return Err(design_provider_failure(&error, detail));
|
||||
}
|
||||
tokio::time::sleep(Duration::from_millis(
|
||||
design_provider_transient_retry_backoff_ms(
|
||||
llm.retry_backoff_ms,
|
||||
attempt + 1,
|
||||
),
|
||||
design_provider_transient_retry_backoff_ms(llm.retry_backoff_ms, attempt + 1),
|
||||
))
|
||||
.await;
|
||||
}
|
||||
@@ -1034,9 +1026,7 @@ async fn request_scripted_design_provider(
|
||||
&game_creator_agent_llm_error_public_summary(&error),
|
||||
1800,
|
||||
);
|
||||
if attempt == max_retries
|
||||
|| design_provider_error_transient_kind(&error)
|
||||
.is_none()
|
||||
if attempt == max_retries || design_provider_error_transient_kind(&error).is_none()
|
||||
{
|
||||
emit(design_reasoning_event(
|
||||
root,
|
||||
@@ -1514,10 +1504,7 @@ fn design_session_error_is_recoverable(error: &str) -> bool {
|
||||
}
|
||||
|
||||
fn quarantine_corrupted_design_session(root: &Path) -> Result<(), String> {
|
||||
let _lock = acquire_project_write_lock_with_wait(
|
||||
root,
|
||||
"design.session-quarantine",
|
||||
)?;
|
||||
let _lock = acquire_project_write_lock_with_wait(root, "design.session-quarantine")?;
|
||||
let path = crate::agent::design_session::design_session_path(root);
|
||||
if !path.exists() {
|
||||
return Ok(());
|
||||
@@ -1589,10 +1576,7 @@ pub(crate) fn set_design_agent_runtime_mode(
|
||||
let root = Path::new(project_path.trim());
|
||||
enforce_project_permission_policy(root, "conversation.write")?;
|
||||
design_project_id(root)?;
|
||||
let _lock = acquire_project_write_lock_with_wait(
|
||||
root,
|
||||
"design.runtime-mode",
|
||||
)?;
|
||||
let _lock = acquire_project_write_lock_with_wait(root, "design.runtime-mode")?;
|
||||
if active_runtime.trim() == "game" {
|
||||
if crate::assets::register_design_artifacts_at(root)? {
|
||||
advance_agent_runtime_project_revision_locked(root)?;
|
||||
@@ -1624,10 +1608,7 @@ fn debug_fast_forward_design_session_at(
|
||||
}
|
||||
let project_id = design_project_id(root)?;
|
||||
let target_index = design_phase_index(target_phase.trim())?;
|
||||
let _lock = acquire_project_write_lock_with_wait(
|
||||
root,
|
||||
"design.debug-fast-forward",
|
||||
)?;
|
||||
let _lock = acquire_project_write_lock_with_wait(root, "design.debug-fast-forward")?;
|
||||
let artifact_paths = [
|
||||
"project/00_concept/design.md",
|
||||
"project/速览卡.md",
|
||||
|
||||
@@ -572,10 +572,7 @@ fn import_design_workspace_file_at(
|
||||
) -> Result<String, String> {
|
||||
enforce_project_permission_policy(root, "conversation.write")?;
|
||||
read_existing_manifest_for_project(root)?;
|
||||
let _lock = acquire_project_write_lock_with_wait(
|
||||
root,
|
||||
"conversation.write",
|
||||
)?;
|
||||
let _lock = acquire_project_write_lock_with_wait(root, "conversation.write")?;
|
||||
|
||||
if file_name.contains(['/', '\\']) {
|
||||
return Err("附件文件名必须是单个文件名,不能包含目录".to_string());
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
//! 从已退役的 runtime_driver 中抽出,仅保留直连路径与外部编辑器桥仍在使用的事件接线。
|
||||
|
||||
use crate::agent::thread_manager::update_active_turn;
|
||||
use crate::{GameCreatorAgentProgressEvent, GameCreatorManifestInvalidatedEvent,
|
||||
GameCreatorManifestInvalidationEventSink, GameCreatorManifestInvalidationRelayEnvelope};
|
||||
use tauri::Emitter;
|
||||
use crate::{
|
||||
GameCreatorAgentProgressEvent, GameCreatorManifestInvalidatedEvent,
|
||||
GameCreatorManifestInvalidationEventSink, GameCreatorManifestInvalidationRelayEnvelope,
|
||||
};
|
||||
use std::io::{Read, Write};
|
||||
use std::net::{TcpListener, TcpStream};
|
||||
use std::path::Path;
|
||||
@@ -12,9 +13,9 @@ use std::sync::atomic::{AtomicU64, Ordering};
|
||||
use std::sync::{Arc, Mutex, OnceLock};
|
||||
use std::thread;
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
use tauri::Emitter;
|
||||
|
||||
static GAME_CREATOR_AGENT_RUNTIME_UPDATE_APP_HANDLE: OnceLock<tauri::AppHandle> =
|
||||
OnceLock::new();
|
||||
static GAME_CREATOR_AGENT_RUNTIME_UPDATE_APP_HANDLE: OnceLock<tauri::AppHandle> = OnceLock::new();
|
||||
/// 同一 AppData 允许多个界面窗口同时挂载事件接收端,因此这里是按 token 去重的注册表。
|
||||
static GAME_CREATOR_MANIFEST_INVALIDATION_EVENT_SINKS: OnceLock<
|
||||
std::sync::Mutex<Vec<GameCreatorManifestInvalidationEventSink>>,
|
||||
|
||||
@@ -274,8 +274,7 @@ fn run_transaction(
|
||||
return Err("direct-execution-closed: 本轮执行许可已关闭,未派发补丁".into());
|
||||
}
|
||||
enforce_project_permission_policy(root, "file.write")?;
|
||||
let _lock =
|
||||
acquire_project_write_lock_with_wait(root, "direct.patch")?;
|
||||
let _lock = acquire_project_write_lock_with_wait(root, "direct.patch")?;
|
||||
let targets = collect_targets(root, &parsed.hunks)?;
|
||||
let executable = session.codex_executor()?;
|
||||
validate_argv(&executable, &parsed.patch)?;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::acquire_project_write_lock_with_wait;
|
||||
use super::thread_item_identity;
|
||||
use crate::acquire_project_write_lock_with_wait;
|
||||
use crate::config::prepare_game_creator_private_path_for_read;
|
||||
use crate::project::{
|
||||
append_jsonl_line_unlocked, enforce_project_permission_policy, project_append_lock_for,
|
||||
@@ -465,10 +465,7 @@ fn append_direct_project_history_item_once(root: &Path, item: &Value) -> Result<
|
||||
// 流式历史落盘在写文件期间直接失败,并把整轮判成“项目正在被其他写操作占用”
|
||||
// (持锁方 commandId=direct-codex.file.write、ownerIsSelf=true)。这里与其它写入口
|
||||
// 保持同一档有界等待;主路径已在阻塞线程池中执行。
|
||||
let _project_lock = acquire_project_write_lock_with_wait(
|
||||
root,
|
||||
"conversation.write",
|
||||
)?;
|
||||
let _project_lock = acquire_project_write_lock_with_wait(root, "conversation.write")?;
|
||||
let lock = project_append_lock_for(&path)?;
|
||||
let _append_guard = lock.lock("DirectProject 历史追加写")?;
|
||||
// 回扫到取锁之间可能有别的进程(或本项目另一条链)追加过:只有文件状态仍与回扫时一致
|
||||
|
||||
@@ -987,10 +987,8 @@ fn finish_direct_taonier_regeneration_reset_at(
|
||||
root: &Path,
|
||||
expected: &DirectTaonierRegenerationWorkflow,
|
||||
) -> Result<DirectTaonierRegenerationWorkflow, String> {
|
||||
let _lock = acquire_project_write_lock_with_wait(
|
||||
root,
|
||||
"direct-codex.taonier-package-reset-finish",
|
||||
)?;
|
||||
let _lock =
|
||||
acquire_project_write_lock_with_wait(root, "direct-codex.taonier-package-reset-finish")?;
|
||||
let current = read_direct_taonier_regeneration_workflow_at(root)?;
|
||||
if current.as_ref() != Some(expected)
|
||||
|| expected.state != DirectTaonierRegenerationWorkflowState::Resetting
|
||||
@@ -2863,10 +2861,8 @@ async fn recover_direct_taonier_spritesheet_read_only_at(
|
||||
if !validated.has_visible_pixels {
|
||||
return Err("恢复的陶泥儿 art-spritesheet 没有可见像素".to_string());
|
||||
}
|
||||
let _lock = acquire_project_write_lock_with_wait(
|
||||
root,
|
||||
"direct-codex.art-spritesheet-recovery",
|
||||
)?;
|
||||
let _lock =
|
||||
acquire_project_write_lock_with_wait(root, "direct-codex.art-spritesheet-recovery")?;
|
||||
let _platform_session_lease = access
|
||||
.frozen_platform_session()
|
||||
.map(|session| acquire_platform_session_identity_lease(&session.identity()))
|
||||
@@ -4100,10 +4096,7 @@ fn sync_direct_codex_project_file_projection_at(
|
||||
}
|
||||
update_manifest_task_status_at(root, "code-prototype", GameCreationAppTaskStatus::Completed)?;
|
||||
if outputs_changed || manifest_requires_sync {
|
||||
let _lock = acquire_project_write_lock_with_wait(
|
||||
root,
|
||||
"direct-codex.version",
|
||||
)?;
|
||||
let _lock = acquire_project_write_lock_with_wait(root, "direct-codex.version")?;
|
||||
let version_revision = advance_agent_runtime_project_revision_locked(root)?;
|
||||
append_agent_game_iteration_version_at(root, version_revision)?;
|
||||
}
|
||||
|
||||
@@ -1829,11 +1829,8 @@ fn bridge_write_file_with_permit(
|
||||
// 这是用户直接触发、失败即整轮无法落盘的项目写入通道:
|
||||
// 短暂重叠排队等成功,只有预算耗尽才报出带持锁方身份的错误。
|
||||
let acquire_started = std::time::Instant::now();
|
||||
let _lock = acquire_project_write_lock_with_wait(
|
||||
root,
|
||||
"direct-codex.file.write",
|
||||
)
|
||||
.map_err(|cause| WriteFileError::WriteLockUnavailable { cause })?;
|
||||
let _lock = acquire_project_write_lock_with_wait(root, "direct-codex.file.write")
|
||||
.map_err(|cause| WriteFileError::WriteLockUnavailable { cause })?;
|
||||
let lock_wait_ms = acquire_started.elapsed().as_millis();
|
||||
let analytics_change_kind = write_permit.and_then(|_| {
|
||||
let kind = crate::analytics::project::file_change_kind(&path)?;
|
||||
|
||||
@@ -1282,10 +1282,7 @@ fn external_mcp_record_response(root: &Path, arguments: &Value) -> Value {
|
||||
}
|
||||
// 与 DirectProject 历史落盘同一档有界等待:`agc_write_file` 持锁期间可能持续数秒,
|
||||
// 零等待取锁会让 Codex 返回记录直接丢失。调用方已把本函数放进阻塞线程池。
|
||||
let _project_lock = match acquire_project_write_lock_with_wait(
|
||||
root,
|
||||
"conversation.write",
|
||||
) {
|
||||
let _project_lock = match acquire_project_write_lock_with_wait(root, "conversation.write") {
|
||||
Ok(lock) => lock,
|
||||
Err(error) => {
|
||||
return mcp_tool_result(format!("项目对话锁不可用:{error}"), Vec::new(), true)
|
||||
|
||||
@@ -3026,10 +3026,8 @@ async fn generate_platform_art_asset_with_runtime_options_and_retention_at(
|
||||
// platform-art request. Both operations are short-lived project writes;
|
||||
// wait for the active writer instead of failing the whole generation on
|
||||
// the expected startup race.
|
||||
let recovery_lock = acquire_project_write_lock_with_wait(
|
||||
root,
|
||||
"canvas.asset_generate.runtime.recover",
|
||||
)?;
|
||||
let recovery_lock =
|
||||
acquire_project_write_lock_with_wait(root, "canvas.asset_generate.runtime.recover")?;
|
||||
recover_interrupted_strict_platform_art_transaction_locked_at(root, &recovery_lock)?;
|
||||
}
|
||||
let mut prepared = request_platform_art_asset_with_runtime_options_at(
|
||||
@@ -3056,10 +3054,7 @@ async fn generate_platform_art_asset_with_runtime_options_and_retention_at(
|
||||
}
|
||||
}
|
||||
prepared.validate_frozen_session()?;
|
||||
let lock = acquire_project_write_lock_with_wait(
|
||||
root,
|
||||
"canvas.asset_generate.runtime",
|
||||
)?;
|
||||
let lock = acquire_project_write_lock_with_wait(root, "canvas.asset_generate.runtime")?;
|
||||
recover_interrupted_strict_platform_art_transaction_locked_at(root, &lock)?;
|
||||
advance_agent_runtime_project_revision_locked(root)?;
|
||||
let generated = if require_slices {
|
||||
|
||||
@@ -9,7 +9,6 @@ use oxc_parser::Parser as JavascriptParser;
|
||||
use oxc_semantic::SemanticBuilder as JavascriptSemanticBuilder;
|
||||
use oxc_span::{GetSpan as JavascriptGetSpan, SourceType as JavascriptSourceType};
|
||||
|
||||
|
||||
pub(crate) fn evaluate_game_draft(prompt: &str, draft: &LlmGameDraft) -> Vec<String> {
|
||||
let mut issues = Vec::new();
|
||||
if let Err(error) = validate_llm_game_draft(prompt, draft) {
|
||||
@@ -497,9 +496,7 @@ fn javascript_is_syntactically_valid(content: &str, is_module: bool) -> bool {
|
||||
semantic.diagnostics.is_empty()
|
||||
}
|
||||
|
||||
fn validate_executable_inline_javascript_syntax(
|
||||
html: &str,
|
||||
) -> Result<(), String> {
|
||||
fn validate_executable_inline_javascript_syntax(html: &str) -> Result<(), String> {
|
||||
let lower = html.to_ascii_lowercase();
|
||||
let mut cursor = 0usize;
|
||||
let mut executable_index = 0usize;
|
||||
|
||||
+4
-8
@@ -641,10 +641,8 @@ pub(super) fn prepare_platform_art_generation_runtime_state(
|
||||
// Idempotency-Key. Hold the cross-process project lock across the complete
|
||||
// read/create/readback claim so two callers can never both observe Missing
|
||||
// and publish different keys for the same fixed stage identity.
|
||||
let _claim_lock = acquire_project_write_lock_with_wait(
|
||||
root,
|
||||
"canvas.asset_generate.runtime.claim",
|
||||
)?;
|
||||
let _claim_lock =
|
||||
acquire_project_write_lock_with_wait(root, "canvas.asset_generate.runtime.claim")?;
|
||||
if let Some(existing) = read_platform_art_generation_runtime_state(root, context)? {
|
||||
let existing =
|
||||
migrate_platform_art_generation_external_configuration(root, existing, access)?;
|
||||
@@ -1130,10 +1128,8 @@ pub(super) fn adopt_legacy_standalone_platform_art_generation_runtime_state_at(
|
||||
}
|
||||
// 与账本创建互斥:迁移必须在同一把项目写锁内完成,否则两个调用可能同时把同一份
|
||||
// 旧账本迁移到新路径,或与新建账本互相覆盖。
|
||||
let _claim_lock = acquire_project_write_lock_with_wait(
|
||||
root,
|
||||
"canvas.asset_generate.runtime.claim",
|
||||
)?;
|
||||
let _claim_lock =
|
||||
acquire_project_write_lock_with_wait(root, "canvas.asset_generate.runtime.claim")?;
|
||||
if game_creator_agent_runtime_external_generation_exists(
|
||||
root,
|
||||
&context.agent_id,
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
//! 这套锁只服务外部编辑器绑定、设计会话和埋点侧车这些仍在服役的写路径,
|
||||
//! 与已退役的 Agent Runtime 状态机解耦;自锁方式是在 `.agent/runtime/locks/`
|
||||
//! 下打开一个普通文件并对它加系统文件锁(unix flock / windows share-deny)。
|
||||
use crate::project::{normalize_relative_path, unix_timestamp, validate_project_root};
|
||||
use super::redaction::unix_timestamp_nanos;
|
||||
#[cfg(windows)]
|
||||
use crate::process_identity::validate_windows_regular_file_handle;
|
||||
use crate::project::{normalize_relative_path, unix_timestamp, validate_project_root};
|
||||
use std::fs::{self, File};
|
||||
use std::io::{Seek, SeekFrom, Write};
|
||||
use std::path::Path;
|
||||
|
||||
@@ -35,7 +35,8 @@ pub(super) struct BrowserProcessOwner {
|
||||
/// 运行期 launch 的身份锚点;任何一步拿不到身份证明都不写,
|
||||
/// 该目录之后按旧残留只删不杀。
|
||||
pub(super) fn write_browser_process_owner(temp_root: &Path, browser_pid: u32, executable: &Path) {
|
||||
let identity = crate::process_identity::external_agent_runner_process_start_identity(browser_pid);
|
||||
let identity =
|
||||
crate::process_identity::external_agent_runner_process_start_identity(browser_pid);
|
||||
let owner_identity =
|
||||
crate::process_identity::external_agent_runner_process_start_identity(std::process::id());
|
||||
let (Ok(Some(identity)), Ok(Some(owner_identity))) = (identity, owner_identity) else {
|
||||
@@ -252,7 +253,9 @@ fn track_process(tracked: &mut Vec<(u32, String)>, pid: u32) {
|
||||
if tracked.iter().any(|(known, _)| *known == pid) {
|
||||
return;
|
||||
}
|
||||
if let Ok(Some(identity)) = crate::process_identity::external_agent_runner_process_start_identity(pid) {
|
||||
if let Ok(Some(identity)) =
|
||||
crate::process_identity::external_agent_runner_process_start_identity(pid)
|
||||
{
|
||||
tracked.push((pid, identity));
|
||||
}
|
||||
}
|
||||
@@ -486,10 +489,11 @@ mod tests {
|
||||
let root = tempfile::tempdir().unwrap();
|
||||
let dir = root.path().join(format!("{BROWSER_TEMP_PREFIX}owned"));
|
||||
fs::create_dir(&dir).unwrap();
|
||||
let owner_identity =
|
||||
crate::process_identity::external_agent_runner_process_start_identity(std::process::id())
|
||||
.expect("self identity")
|
||||
.expect("self identity present");
|
||||
let owner_identity = crate::process_identity::external_agent_runner_process_start_identity(
|
||||
std::process::id(),
|
||||
)
|
||||
.expect("self identity")
|
||||
.expect("self identity present");
|
||||
let mut owner = owner_fixture(exited_child_pid(), std::process::id());
|
||||
owner.owner_start_identity = owner_identity;
|
||||
write_owner(&dir, &owner);
|
||||
|
||||
@@ -525,5 +525,4 @@ mod tests {
|
||||
assert!(initialize(directory.path()).is_err());
|
||||
assert!(!is_enabled(AGC_COCOS_EDITOR_PLUGIN_ID));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -153,10 +153,11 @@ impl ProjectCommandTree {
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
let pid = child.id().ok_or("受控命令缺少进程身份")?;
|
||||
let start_identity = crate::process_identity::external_agent_runner_process_start_identity(pid)
|
||||
.ok()
|
||||
.flatten()
|
||||
.filter(|identity| !identity.is_empty());
|
||||
let start_identity =
|
||||
crate::process_identity::external_agent_runner_process_start_identity(pid)
|
||||
.ok()
|
||||
.flatten()
|
||||
.filter(|identity| !identity.is_empty());
|
||||
Ok(Self::Group {
|
||||
pid,
|
||||
start_identity,
|
||||
@@ -183,8 +184,9 @@ impl ProjectCommandTree {
|
||||
Err("受控进程组状态未确认,拒绝发送终止信号".into())
|
||||
};
|
||||
}
|
||||
let observed = crate::process_identity::external_agent_runner_process_start_identity(*pid)
|
||||
.map_err(|_| "受控进程组 leader 身份未确认,拒绝发送终止信号")?;
|
||||
let observed =
|
||||
crate::process_identity::external_agent_runner_process_start_identity(*pid)
|
||||
.map_err(|_| "受控进程组 leader 身份未确认,拒绝发送终止信号")?;
|
||||
if !owned_project_command_group_identity_matches(
|
||||
start_identity.as_deref(),
|
||||
observed.as_deref(),
|
||||
|
||||
@@ -457,7 +457,10 @@ fn validate_command_output_file_handle(file: &File, path: &Path) -> Result<(), S
|
||||
}
|
||||
}
|
||||
#[cfg(windows)]
|
||||
crate::process_identity::validate_windows_regular_file_handle(file, "command.exec 输出 sidecar")?;
|
||||
crate::process_identity::validate_windows_regular_file_handle(
|
||||
file,
|
||||
"command.exec 输出 sidecar",
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -3178,10 +3178,7 @@ pub(crate) fn import_local_project_assets_for_agent_with_write_permit(
|
||||
));
|
||||
}
|
||||
|
||||
let _lock = acquire_project_write_lock_with_wait(
|
||||
root,
|
||||
"canvas.asset_import",
|
||||
)?;
|
||||
let _lock = acquire_project_write_lock_with_wait(root, "canvas.asset_import")?;
|
||||
enforce_project_permission_policy(root, "canvas.asset_import")?;
|
||||
let commit = || {
|
||||
let manifest = read_existing_manifest_for_project(root)?;
|
||||
@@ -3413,10 +3410,7 @@ fn commit_account_editor_asset_downloads(
|
||||
write_permit: Option<&crate::agent::WritePermit>,
|
||||
frozen_session: Option<&PlatformSessionSnapshot>,
|
||||
) -> Result<RemoteImportResult, String> {
|
||||
let _lock = acquire_project_write_lock_with_wait(
|
||||
root,
|
||||
"canvas.asset_import",
|
||||
)?;
|
||||
let _lock = acquire_project_write_lock_with_wait(root, "canvas.asset_import")?;
|
||||
enforce_project_permission_policy(root, "canvas.asset_import")?;
|
||||
// 等待后才取得身份租约;等待期间允许换号,提交时拒绝旧账号结果。
|
||||
let _platform_session_lease = frozen_session
|
||||
|
||||
@@ -944,10 +944,7 @@ pub(crate) fn create_game_creator_agent_session(
|
||||
enforce_project_permission_policy(root, "conversation.write")?;
|
||||
// 首轮策划消息可能紧跟项目初始化写入到达;对话保存应等待这段短暂的
|
||||
// 项目锁竞争,避免把可恢复的初始化竞态直接显示成保存失败。
|
||||
let _lock = acquire_project_write_lock_with_wait(
|
||||
root,
|
||||
"conversation.write",
|
||||
)?;
|
||||
let _lock = acquire_project_write_lock_with_wait(root, "conversation.write")?;
|
||||
create_game_creator_agent_session_at(root, agent_id.trim(), title.trim())
|
||||
}
|
||||
|
||||
|
||||
+5
-4
@@ -15,10 +15,11 @@ impl ProcessIdentity {
|
||||
if pid == 0 {
|
||||
return Err("web-scaffold-process-identity-unknown".into());
|
||||
}
|
||||
let start_identity = crate::process_identity::external_agent_runner_process_start_identity(pid)
|
||||
.map_err(|_| "web-scaffold-process-identity-unknown")?
|
||||
.filter(|value| !value.is_empty())
|
||||
.ok_or("web-scaffold-process-identity-unknown")?;
|
||||
let start_identity =
|
||||
crate::process_identity::external_agent_runner_process_start_identity(pid)
|
||||
.map_err(|_| "web-scaffold-process-identity-unknown")?
|
||||
.filter(|value| !value.is_empty())
|
||||
.ok_or("web-scaffold-process-identity-unknown")?;
|
||||
Ok(Self {
|
||||
pid,
|
||||
start_identity,
|
||||
|
||||
@@ -114,11 +114,11 @@ mod platform_maintenance;
|
||||
mod platform_session;
|
||||
mod plugin_host;
|
||||
mod preview;
|
||||
mod process_identity;
|
||||
mod process_session;
|
||||
mod process_session_bridge;
|
||||
mod project;
|
||||
mod project_snapshot;
|
||||
mod process_identity;
|
||||
mod repository_context;
|
||||
mod resource_inspect;
|
||||
mod resource_preview_scheduler;
|
||||
|
||||
@@ -519,8 +519,7 @@ where
|
||||
.find(|session| session.session_id == source_session_id)
|
||||
.cloned()
|
||||
.ok_or_else(|| format!("Agent Session 不存在:{source_session_id}"))?;
|
||||
if source.session_id != catalog.active_session_id {
|
||||
}
|
||||
if source.session_id != catalog.active_session_id {}
|
||||
|
||||
let records = read_persisted_local_conversation_records_unlocked(&source_path)?;
|
||||
let session_id = new_agent_conversation_session_id(&catalog, &agent_id)?;
|
||||
|
||||
@@ -4302,8 +4302,7 @@ fn commit_resource_edit_asset_internal(
|
||||
reference_resource_ids: vec![source.canonical_resource_id.clone()],
|
||||
},
|
||||
};
|
||||
let _project_lock =
|
||||
acquire_project_write_lock_with_wait(root, "resource.edit")?;
|
||||
let _project_lock = acquire_project_write_lock_with_wait(root, "resource.edit")?;
|
||||
let mut manifest = read_existing_manifest_for_project(root)?;
|
||||
if manifest.project_id != input.expected_project_id {
|
||||
return Err("project-identity-conflict".to_string());
|
||||
@@ -4618,8 +4617,7 @@ fn commit_resource_edit_asset_with_frozen_platform_session(
|
||||
) -> Result<DeriveLocalProjectResourceResult, String> {
|
||||
// 项目锁先于平台身份租约,避免等待时挡住换号或与其它提交形成锁顺序反转。
|
||||
// 内层提交在同一线程复用项目锁,整个事务不能跨 await 或线程迁移。
|
||||
let _project_lock =
|
||||
acquire_project_write_lock_with_wait(root, "resource.edit")?;
|
||||
let _project_lock = acquire_project_write_lock_with_wait(root, "resource.edit")?;
|
||||
with_frozen_resource_edit_platform_session(platform_session, || {
|
||||
commit_resource_edit_asset(root, input, source, prompt, asset_name, ledger)
|
||||
})
|
||||
@@ -4701,10 +4699,7 @@ fn commit_resource_edit_version(
|
||||
ledger: &mut ResourceEditLedger,
|
||||
) -> Result<DeriveLocalProjectResourceResult, String> {
|
||||
let version_id = format!("edit-{}", input.operation_id);
|
||||
let _project_lock = acquire_project_write_lock_with_wait(
|
||||
root,
|
||||
"resource.edit.version",
|
||||
)?;
|
||||
let _project_lock = acquire_project_write_lock_with_wait(root, "resource.edit.version")?;
|
||||
let mut manifest = read_existing_manifest_for_project(root)?;
|
||||
if manifest.project_id != input.expected_project_id {
|
||||
return Err("project-identity-conflict".to_string());
|
||||
@@ -5672,10 +5667,7 @@ pub(crate) async fn derive_local_project_resource_at(
|
||||
let _project_guard = project_guard;
|
||||
if ledger.phase == ResourceEditLedgerPhase::Committed {
|
||||
let _project_write_lock =
|
||||
acquire_project_write_lock_with_wait(
|
||||
&root,
|
||||
"resource.edit.cleanup",
|
||||
)?;
|
||||
acquire_project_write_lock_with_wait(&root, "resource.edit.cleanup")?;
|
||||
cleanup_committed_resource_edit_staging(&root, &mut ledger)?;
|
||||
committed_resource_edit_result(
|
||||
&root,
|
||||
|
||||
@@ -991,7 +991,9 @@ fn project_revision_project_id(root: &Path) -> Result<String, String> {
|
||||
return Err("项目 revision 缺少项目 ID".to_string());
|
||||
}
|
||||
Ok(crate::agent::redaction::redact_agent_runtime_project_paths(
|
||||
root, &project_id, 240,
|
||||
root,
|
||||
&project_id,
|
||||
240,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -1023,15 +1025,14 @@ fn validate_project_revision(
|
||||
pub(crate) fn read_game_creator_agent_runtime_project_revision(
|
||||
root: &Path,
|
||||
) -> Result<AgentRuntimeProjectRevision, String> {
|
||||
let revision = crate::agent::json_sidecar::read_agent_runtime_json_sidecar::<
|
||||
AgentRuntimeProjectRevision,
|
||||
>(
|
||||
root,
|
||||
AGENT_RUNTIME_PROJECT_REVISION_RELATIVE_PATH,
|
||||
"项目 revision",
|
||||
)?
|
||||
.map(Ok)
|
||||
.unwrap_or_else(|| default_project_revision(root))?;
|
||||
let revision =
|
||||
crate::agent::json_sidecar::read_agent_runtime_json_sidecar::<AgentRuntimeProjectRevision>(
|
||||
root,
|
||||
AGENT_RUNTIME_PROJECT_REVISION_RELATIVE_PATH,
|
||||
"项目 revision",
|
||||
)?
|
||||
.map(Ok)
|
||||
.unwrap_or_else(|| default_project_revision(root))?;
|
||||
validate_project_revision(root, &revision)?;
|
||||
Ok(revision)
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user