修复AI游戏创作壳跨平台启动
修复 macOS 下 Unix 文件身份比较和临时目录测试兼容 隔离 AI 游戏创作本地数据库与发布身份并阻止旧 schema 降级启动 完善 Tauri 开发栈错误传播和 POSIX 子进程树清理 跳过 macOS 不支持的进程指标回调以消除周期告警 补充开发调度测试、技术方案和团队排障记忆
This commit is contained in:
@@ -13,6 +13,7 @@ const viteUrl = `http://${viteHost}:${vitePort}/`;
|
||||
const viteMarkerUrl = `${viteUrl}__agc_dev_server.json`;
|
||||
const defaultApiTarget = process.env.RUST_SERVER_TARGET || 'http://127.0.0.1:8082';
|
||||
const backendDatabase = 'genarrative-game-creator-dev';
|
||||
const backendSpacetimeDataDir = 'server-rs/.spacetimedb/ai-game-creator/data';
|
||||
const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm';
|
||||
|
||||
function readJson(path) {
|
||||
@@ -146,9 +147,13 @@ async function isExistingVitePairedWithBackend(apiTarget) {
|
||||
}
|
||||
|
||||
function spawnChild(command, args, options) {
|
||||
const useShell = process.platform === 'win32';
|
||||
return spawn(command, args, {
|
||||
...options,
|
||||
shell: true,
|
||||
shell: useShell,
|
||||
// POSIX 下让每个长驻服务拥有独立进程组,退出时可以连同 npm、
|
||||
// Node、Cargo 及其子进程一起清理,避免残留订阅任务持续刷日志。
|
||||
detached: !useShell,
|
||||
stdio: 'inherit',
|
||||
});
|
||||
}
|
||||
@@ -158,9 +163,17 @@ function stopChild(child, signal = 'SIGTERM') {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
child.kill(signal);
|
||||
if (process.platform !== 'win32' && Number.isInteger(child.pid)) {
|
||||
process.kill(-child.pid, signal);
|
||||
} else {
|
||||
child.kill(signal);
|
||||
}
|
||||
} catch {
|
||||
// ignore cleanup races
|
||||
try {
|
||||
child.kill(signal);
|
||||
} catch {
|
||||
// ignore cleanup races
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,6 +213,8 @@ async function ensureBackend() {
|
||||
'--',
|
||||
'--database',
|
||||
backendDatabase,
|
||||
'--spacetime-data-dir',
|
||||
backendSpacetimeDataDir,
|
||||
'--no-interactive',
|
||||
],
|
||||
{ cwd: appRoot },
|
||||
|
||||
@@ -336,8 +336,8 @@ fn verify_unix_agent_db_root(root: &Path, opened: &File) -> Result<(), String> {
|
||||
let metadata = opened
|
||||
.metadata()
|
||||
.map_err(|error| format!("复核 Agent DB 项目目录句柄失败:{error}"))?;
|
||||
if stat.st_dev != metadata.dev()
|
||||
|| stat.st_ino != metadata.ino()
|
||||
if stat.st_dev as u64 != metadata.dev()
|
||||
|| stat.st_ino as u64 != metadata.ino()
|
||||
|| stat.st_mode & libc::S_IFMT != libc::S_IFDIR
|
||||
{
|
||||
return Err("Agent DB 项目目录在安全打开期间发生替换或不是普通目录".to_string());
|
||||
@@ -380,8 +380,8 @@ fn verify_unix_agent_db_entry(
|
||||
} else {
|
||||
libc::S_IFREG
|
||||
};
|
||||
if stat.st_dev != metadata.dev()
|
||||
|| stat.st_ino != metadata.ino()
|
||||
if stat.st_dev as u64 != metadata.dev()
|
||||
|| stat.st_ino as u64 != metadata.ino()
|
||||
|| stat.st_mode & libc::S_IFMT != expected_type
|
||||
{
|
||||
return Err(format!("{label}在安全打开期间发生替换"));
|
||||
|
||||
@@ -1200,8 +1200,8 @@ fn verify_unix_project_owner_entry(
|
||||
} else {
|
||||
libc::S_IFREG
|
||||
};
|
||||
if stat.st_dev != opened_metadata.dev()
|
||||
|| stat.st_ino != opened_metadata.ino()
|
||||
if stat.st_dev as u64 != opened_metadata.dev()
|
||||
|| stat.st_ino as u64 != opened_metadata.ino()
|
||||
|| stat.st_mode & libc::S_IFMT != expected_type
|
||||
{
|
||||
return Err(format!("{label} 在安全打开期间发生替换"));
|
||||
|
||||
@@ -1286,7 +1286,10 @@ fn unique_project_path() -> PathBuf {
|
||||
.expect("system clock should be after epoch")
|
||||
.as_millis();
|
||||
let counter = TEST_PROJECT_COUNTER.fetch_add(1, Ordering::Relaxed);
|
||||
std::env::temp_dir().join(format!(
|
||||
let temp_root = std::env::temp_dir()
|
||||
.canonicalize()
|
||||
.unwrap_or_else(|_| std::env::temp_dir());
|
||||
temp_root.join(format!(
|
||||
"genarrative-ai-game-creator-test-{}-{millis}-{counter}",
|
||||
std::process::id()
|
||||
))
|
||||
|
||||
@@ -1673,8 +1673,8 @@ fn verify_unix_tool_plan_entry(
|
||||
} else {
|
||||
libc::S_IFREG
|
||||
};
|
||||
if stat.st_dev != opened_metadata.dev()
|
||||
|| stat.st_ino != opened_metadata.ino()
|
||||
if stat.st_dev as u64 != opened_metadata.dev()
|
||||
|| stat.st_ino as u64 != opened_metadata.ino()
|
||||
|| stat.st_mode & libc::S_IFMT != expected_type
|
||||
{
|
||||
return Err(format!("{label} 在安全扫描期间发生替换"));
|
||||
|
||||
Reference in New Issue
Block a user