13a15fed5c
Project CI / AI game creator shell Rust crates (push) Successful in 3m5s
Project CI / AI game creator shell Rust lane 2/2 (push) Successful in 4m24s
Project CI / AI game creator shell Rust lane 1/2 (push) Successful in 5m20s
Project CI / Backend tests (push) Successful in 6m42s
Project CI / Frontend tests (push) Successful in 3m2s
Project CI / Native shell tests (push) Successful in 7m16s
Project CI / AI game creator shell web tests (push) Successful in 3m17s
Project CI / Repository checks (push) Successful in 6m25s
为 release 与自定义渠道注入独立主程序名,隔离 Windows 更新进程。 新增 release 旧安装目录与快捷方式迁移钩子,保护 dev 历史目录清理。 同步渠道规范、共享决策与排障记录,补充发布脚本回归测试。
92 lines
3.3 KiB
JavaScript
92 lines
3.3 KiB
JavaScript
/**
|
||
* AGC 渠道 → 安装身份。
|
||
*
|
||
* 渠道同时决定两件事:
|
||
* - 更新端点:OSS 分区 `<channel>-win` / `<channel>-mac` 的清单地址;
|
||
* - 安装身份:`productName` 与 `identifier`。
|
||
*
|
||
* 安装身份决定 Windows 安装目录与卸载项、macOS `.app` 名字与 bundle id、
|
||
* Windows WebView2 数据目录以及 `%APPDATA%\<identifier>` 客户端数据目录。
|
||
* 因此不同渠道的包体在同一台设备上并存时互不顶掉,也不会共享登录态、
|
||
* 本地项目与运行锁。
|
||
*
|
||
* 默认渠道 `dev` 保持已发布客户端标识不变:升级链路与既有安装不能断;展示名显式标记为开发版。
|
||
*/
|
||
|
||
export const AGC_DEFAULT_CHANNEL = 'dev';
|
||
export const AGC_PRODUCT_NAME = '陶泥儿';
|
||
export const AGC_APP_IDENTIFIER = 'world.genarrative.ai-game-creator';
|
||
/**
|
||
* Tauri/NSIS 默认按主可执行文件名查找并结束进程。
|
||
* dev 保留历史文件名以维持既有更新链;其它渠道使用独立文件名,
|
||
* 这样更新一个渠道时不会把另一个渠道的进程一起结束。
|
||
*/
|
||
export const AGC_MAIN_BINARY_NAME = 'genarrative-ai-game-creator-shell';
|
||
|
||
const reservedChannelNames = new Set([
|
||
'win',
|
||
'mac',
|
||
'windows',
|
||
'macos',
|
||
'darwin',
|
||
'linux',
|
||
]);
|
||
|
||
/** 校验渠道名:小写字母开头,允许数字与连字符,系统名不属于渠道。 */
|
||
export function validateReleaseChannel(channel) {
|
||
if (
|
||
typeof channel !== 'string' ||
|
||
!/^[a-z][a-z0-9-]{0,31}$/u.test(channel) ||
|
||
channel.endsWith('-') ||
|
||
reservedChannelNames.has(channel) ||
|
||
/-(win|mac)$/u.test(channel)
|
||
) {
|
||
throw new Error(
|
||
'发布渠道无效:请使用 dev、release 或最多 32 位的小写字母、数字和连字符名称,系统名称不属于渠道',
|
||
);
|
||
}
|
||
return channel;
|
||
}
|
||
|
||
export function resolveReleaseChannel(env = process.env) {
|
||
return validateReleaseChannel(env.AGC_UPDATE_CHANNEL?.trim() ?? 'dev');
|
||
}
|
||
|
||
/** 安装身份里的展示后缀:`dev` → `开发版`,`beta-2` → `Beta-2`;release 复用正式产品名。 */
|
||
export function channelDisplaySuffix(channel) {
|
||
if (channel === AGC_DEFAULT_CHANNEL) return '开发版';
|
||
return validateReleaseChannel(channel)
|
||
.split('-')
|
||
.map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
|
||
.join('-');
|
||
}
|
||
|
||
/**
|
||
* 渠道对应的安装身份。默认渠道保持既有 identifier 以兼容已安装客户端,
|
||
* 但展示名明确标记为开发版;release 复用正式产品名,其它渠道带展示后缀;
|
||
* 所有非默认渠道都派生独立 identifier,保证同一台设备上并存。
|
||
*/
|
||
export function resolveChannelInstallIdentity(channel = AGC_DEFAULT_CHANNEL) {
|
||
validateReleaseChannel(channel);
|
||
return Object.freeze({
|
||
productName:
|
||
channel === AGC_DEFAULT_CHANNEL
|
||
? `${AGC_PRODUCT_NAME}开发版`
|
||
: channel === 'release'
|
||
? AGC_PRODUCT_NAME
|
||
: `${AGC_PRODUCT_NAME} ${channelDisplaySuffix(channel)}`,
|
||
identifier:
|
||
channel === AGC_DEFAULT_CHANNEL
|
||
? AGC_APP_IDENTIFIER
|
||
: `${AGC_APP_IDENTIFIER}.${channel}`,
|
||
});
|
||
}
|
||
|
||
/** 渠道对应的主可执行文件名(不含平台扩展名)。 */
|
||
export function resolveChannelMainBinaryName(channel = AGC_DEFAULT_CHANNEL) {
|
||
validateReleaseChannel(channel);
|
||
return channel === AGC_DEFAULT_CHANNEL
|
||
? AGC_MAIN_BINARY_NAME
|
||
: `${AGC_MAIN_BINARY_NAME}-${channel}`;
|
||
}
|