Files
Genarrative/apps/ai-game-creator-shell/scripts/start-tauri-dev.mjs
T
menghao 53e37ea361
Project CI / Repository checks (pull_request) Failing after 10s
Project CI / Backend tests (pull_request) Failing after 10s
Project CI / Frontend tests (pull_request) Successful in 3m28s
Project CI / Native shell tests (pull_request) Failing after 9m27s
支持App Run并行开发并修复资源画布
新增App Run独立开发profile并隔离端口、数据库、Tauri身份与AppData
常驻资源排列切换并避免布局状态挤压操作入口
显式扩展资源画布横向滚动范围并收敛依赖图可见连线
补充启动器、资源布局、界面回归测试与项目文档
2026-08-07 10:13:25 +08:00

151 lines
3.8 KiB
JavaScript

import { resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import {
preflightExistingVite,
resolveDevStackProfile,
spawnChild,
stopChild,
terminateChildTree,
waitForChildTermination,
} from './start-dev-stack.mjs';
const appRoot = fileURLToPath(new URL('..', import.meta.url));
const repoRoot = resolve(appRoot, '../..');
const tauriCliPath = resolve(repoRoot, 'node_modules/@tauri-apps/cli/tauri.js');
function parseLauncherArguments(argv) {
const args = [...argv];
const appRun = args[0] === '--app-run';
if (appRun) {
args.shift();
}
const gameChat = args[0] === '--game-chat';
if (gameChat) {
args.shift();
}
if (appRun && gameChat) {
throw new Error('app-run profile 不能与 game-chat 入口同时使用');
}
return { appRun, gameChat, args };
}
function buildTauriArguments(argv) {
const { appRun, gameChat, args } = parseLauncherArguments(argv);
if (appRun) {
return [
'dev',
'--config',
'src-tauri/tauri.app-run-dev.conf.json',
...args,
];
}
if (gameChat) {
return ['dev', '--', '--', '--game-chat', ...args];
}
return ['dev', ...args];
}
function spawnTauriCli(argv, { profileName = 'default' } = {}) {
return spawnChild(process.execPath, [tauriCliPath, ...argv], {
cwd: appRoot,
env: {
...process.env,
GENARRATIVE_AGC_DEV_PROFILE: profileName,
},
shell: false,
});
}
async function runTauriDev(
argv = process.argv.slice(2),
{
preflight = preflightExistingVite,
spawnCli = spawnTauriCli,
waitForCli = waitForChildTermination,
terminateTree = terminateChildTree,
} = {},
) {
const { appRun } = parseLauncherArguments(argv);
const profile = resolveDevStackProfile(appRun ? 'app-run' : 'default');
await preflight({ profile });
const tauriArguments = buildTauriArguments(argv);
const child = spawnCli(tauriArguments, { profileName: profile.name });
let resolveShutdown;
let shutdownSignal = '';
let repeatedSignal = false;
const shutdownRequested = new Promise((resolveRequest) => {
resolveShutdown = resolveRequest;
});
const signalHandlers = new Map();
for (const signal of ['SIGINT', 'SIGTERM']) {
const handler = () => {
if (!shutdownSignal) {
shutdownSignal = signal;
stopChild(child, 'SIGTERM');
resolveShutdown(signal);
return;
}
repeatedSignal = true;
stopChild(child, 'SIGKILL');
};
signalHandlers.set(signal, handler);
process.on(signal, handler);
}
try {
const childResult = waitForCli(child);
const outcome = await Promise.race([
childResult.then((failure) => ({ type: 'exit', failure })),
shutdownRequested.then((signal) => ({ type: 'signal', signal })),
]);
const cleanup = await terminateTree(child, {
gracefulTimeoutMs: repeatedSignal ? 0 : 2500,
});
if (!cleanup.stopped) {
console.error(
'[ai-game-creator-shell] Tauri dev exited, but its process tree could not be fully stopped.',
);
return 1;
}
if (outcome.type === 'signal') {
return 1;
}
const { failure } = outcome;
return failure.type === 'error' || failure.signal ? 1 : (failure.code ?? 0);
} finally {
for (const [signal, handler] of signalHandlers) {
process.off(signal, handler);
}
}
}
function isDirectModuleExecution() {
return Boolean(
process.argv[1] &&
resolve(process.argv[1]) === fileURLToPath(import.meta.url),
);
}
export {
buildTauriArguments,
isDirectModuleExecution,
parseLauncherArguments,
runTauriDev,
spawnTauriCli,
};
if (isDirectModuleExecution()) {
try {
process.exitCode = await runTauriDev();
} catch (error) {
console.error(
`[ai-game-creator-shell] ${error instanceof Error ? error.message : String(error)}`,
);
process.exitCode = 1;
}
}