合并编辑器素材库分支

合并 codex/editor-asset-library 到 master
保留原生壳桥接统一分支已合入内容
合并图片编辑器素材库、模型定价和项目记忆更新
解决项目记忆踩坑记录冲突
This commit is contained in:
2026-06-22 22:37:14 +08:00
102 changed files with 8494 additions and 1648 deletions
+107 -12
View File
@@ -37,6 +37,92 @@ const manifestPath = resolve(serverRsDir, 'Cargo.toml');
const modulePath = resolve(serverRsDir, 'crates/spacetime-module');
const viteCliPath = resolve(repoRoot, 'scripts/vite-cli.mjs');
const adminWebDir = resolve(repoRoot, 'apps/admin-web');
function resolveLocalGenarrativeFfmpeg(env = process.env, platform = process.platform) {
if (platform !== 'win32') {
return null;
}
const localAppData =
String(env.LOCALAPPDATA ?? '').trim() ||
(String(env.USERPROFILE ?? '').trim()
? join(String(env.USERPROFILE).trim(), 'AppData', 'Local')
: '');
if (!localAppData) {
return null;
}
const binDir = join(localAppData, 'Genarrative', 'ffmpeg', 'bin');
const ffmpegPath = join(binDir, 'ffmpeg.exe');
const ffprobePath = join(binDir, 'ffprobe.exe');
if (!existsSync(ffmpegPath) || !existsSync(ffprobePath)) {
return null;
}
return {binDir, ffmpegPath, ffprobePath};
}
function resolvePathEnvKey(env, platform = process.platform) {
return (
Object.keys(env).find((key) => key.toLowerCase() === 'path') ||
(platform === 'win32' ? 'Path' : 'PATH')
);
}
function prependEnvPathEntry(env, entry, platform = process.platform) {
const pathKey = resolvePathEnvKey(env, platform);
const separator = platform === 'win32' ? ';' : ':';
const currentEntries = String(env[pathKey] ?? '')
.split(separator)
.map((value) => value.trim())
.filter(Boolean);
const normalize = (value) =>
platform === 'win32' ? value.toLowerCase() : value;
if (currentEntries.some((value) => normalize(value) === normalize(entry))) {
return;
}
env[pathKey] = [entry, ...currentEntries].join(separator);
}
function setDefaultEnvValue(env, key, value) {
if (!String(env[key] ?? '').trim()) {
env[key] = value;
}
}
function applyLocalFfmpegEnv(env, platform = process.platform) {
const localFfmpeg = resolveLocalGenarrativeFfmpeg(env, platform);
if (!localFfmpeg) {
return env;
}
// 本地 dev 进程常在安装 FFmpeg 前已经启动;这里用绝对路径兜底,避免只依赖旧 PATH。
prependEnvPathEntry(env, localFfmpeg.binDir, platform);
const ffmpegPath =
String(env.CHARACTER_ANIMATION_FFMPEG_PATH ?? '').trim() ||
String(env.GENARRATIVE_CHARACTER_ANIMATION_FFMPEG_PATH ?? '').trim() ||
localFfmpeg.ffmpegPath;
const ffprobePath =
String(env.CHARACTER_ANIMATION_FFPROBE_PATH ?? '').trim() ||
String(env.GENARRATIVE_CHARACTER_ANIMATION_FFPROBE_PATH ?? '').trim() ||
localFfmpeg.ffprobePath;
setDefaultEnvValue(env, 'CHARACTER_ANIMATION_FFMPEG_PATH', ffmpegPath);
setDefaultEnvValue(
env,
'GENARRATIVE_CHARACTER_ANIMATION_FFMPEG_PATH',
ffmpegPath,
);
setDefaultEnvValue(env, 'CHARACTER_ANIMATION_FFPROBE_PATH', ffprobePath);
setDefaultEnvValue(
env,
'GENARRATIVE_CHARACTER_ANIMATION_FFPROBE_PATH',
ffprobePath,
);
return env;
}
function resolveLocalDevRustcWrapperBypass() {
// Windows 下不能把 rustc 自身当成 Cargo wrapper;空值会覆盖仓库 .cargo/config.toml 中的 sccache。
return process.platform === 'win32' ? '' : '/usr/bin/env';
@@ -2156,23 +2242,32 @@ function isSpacetimePublishPermissionError(error) {
);
}
function buildApiServerProcessEnv({baseEnv, options, state}) {
return {
...baseEnv,
// 本地 dev 允许密码入口直接创建账号,生产默认仍由 api-server 配置保持关闭。
GENARRATIVE_DEV_PASSWORD_ENTRY_AUTO_REGISTER_ENABLED: 'true',
GENARRATIVE_API_HOST: options.apiHost,
GENARRATIVE_API_PORT: String(options.apiPort),
GENARRATIVE_API_LOG: options.apiLog,
GENARRATIVE_SPACETIME_SERVER_URL: state.spacetimeServer,
GENARRATIVE_SPACETIME_DATABASE: options.database,
GENARRATIVE_SPACETIME_TOKEN: baseEnv.GENARRATIVE_SPACETIME_TOKEN || '',
};
function buildApiServerProcessEnv({
baseEnv,
options,
state,
platform = process.platform,
}) {
return applyLocalFfmpegEnv(
{
...baseEnv,
// 本地 dev 允许密码入口直接创建账号,生产默认仍由 api-server 配置保持关闭。
GENARRATIVE_DEV_PASSWORD_ENTRY_AUTO_REGISTER_ENABLED: 'true',
GENARRATIVE_API_HOST: options.apiHost,
GENARRATIVE_API_PORT: String(options.apiPort),
GENARRATIVE_API_LOG: options.apiLog,
GENARRATIVE_SPACETIME_SERVER_URL: state.spacetimeServer,
GENARRATIVE_SPACETIME_DATABASE: options.database,
GENARRATIVE_SPACETIME_TOKEN: baseEnv.GENARRATIVE_SPACETIME_TOKEN || '',
},
platform,
);
}
export {
assertReusableSpacetimeProcessVersionMatchesWorkspace,
assertSpacetimeToolVersionMatchesWorkspace,
applyLocalFfmpegEnv,
buildApiServerProcessEnv,
buildDevStackSnapshot,
buildLocalRustProcessEnv,