feat: 构建系统重构 + VCHSM 架构迁移 + 右键菜单修复 + 尺寸参数统一

## 构建、打包与分发系统重构 (build/)

- 构建系统收敛至 build/ 目录:build.mjs + electron-builder.js + 6 个脚本

- electron-builder 配置从 package.json 提取为 build/electron-builder.js

- 新增 --edition (personal/enterprise) 和 --channel (stable/beta/alpha) 参数

- OSS 路径按渠道隔离

- 新增 pre-build-check.mjs:Git/CHANGELOG/版本/环境变量校验

- 新增 bump-version.mjs:版本号管理 + CHANGELOG 自动生成

- updater.ts 发送 channel/edition/deviceFingerprint

- 新增 src/shared/utils/rollout.ts 灰度测试工具

- 新增 10 条 NPM 脚本

## VCHSM 五层架构迁移

- 7 个业务模块 + ~500 处导入路径同步

## 修复

- MediaCardContextMenu 改用共享 ContextMenu 组件

- ComboBox 尺寸参数显示统一 (size-format.ts)

## 文档

- UpdateA.md / build/README.md / README.md / .env.example 更新

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-06-29 18:41:07 +08:00
parent e0d91335c7
commit 337d6c1205
187 changed files with 5252 additions and 1702 deletions

View File

@@ -0,0 +1,153 @@
// ============================================================
// bump-version.mjs — 版本号管理与 CHANGELOG 模板生成
//
// 用法:
// node build/scripts/bump-version.mjs <major|minor|patch> [--no-changelog]
// node build/scripts/bump-version.mjs set <x.y.z>
// node build/scripts/bump-version.mjs pre <beta|alpha>
//
// 示例:
// node build/scripts/bump-version.mjs patch # 0.0.28 → 0.0.29
// node build/scripts/bump-version.mjs minor # 0.0.28 → 0.1.0
// node build/scripts/bump-version.mjs set 1.0.0 # 直接设置版本
// node build/scripts/bump-version.mjs pre beta # 0.0.29 → 0.0.29-beta.1
// ============================================================
import { readFileSync, writeFileSync } from 'node:fs';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = join(__dirname, '..', '..');
const args = process.argv.slice(2);
const command = args[0];
const arg1 = args[1];
const noChangelog = args.includes('--no-changelog');
if (!command) {
console.error('用法: node build/scripts/bump-version.mjs <major|minor|patch|set|pre> [value]');
console.error('示例: node build/scripts/bump-version.mjs patch');
console.error(' node build/scripts/bump-version.mjs set 1.0.0');
console.error(' node build/scripts/bump-version.mjs pre beta');
process.exit(1);
}
const pkgPath = join(ROOT, 'package.json');
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
const oldVersion = pkg.version;
// ---------- 版本计算 ----------
function parseSemver(v) {
const match = v.match(/^(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/);
if (!match) throw new Error(`无效的版本号格式: ${v}`);
return {
major: parseInt(match[1]),
minor: parseInt(match[2]),
patch: parseInt(match[3]),
pre: match[4] || null,
};
}
let newVersion;
switch (command) {
case 'major':
case 'minor':
case 'patch': {
const sv = parseSemver(oldVersion);
if (command === 'major') {
sv.major++;
sv.minor = 0;
sv.patch = 0;
} else if (command === 'minor') {
sv.minor++;
sv.patch = 0;
} else {
sv.patch++;
}
sv.pre = null;
newVersion = `${sv.major}.${sv.minor}.${sv.patch}`;
break;
}
case 'set': {
if (!arg1) {
console.error('用法: node build/scripts/bump-version.mjs set <x.y.z>');
process.exit(1);
}
// 基本格式校验
if (!/^\d+\.\d+\.\d+(-.+)?$/.test(arg1)) {
console.error(`无效的版本号: ${arg1}`);
process.exit(1);
}
newVersion = arg1;
break;
}
case 'pre': {
if (!arg1 || !['beta', 'alpha'].includes(arg1)) {
console.error('用法: node build/scripts/bump-version.mjs pre <beta|alpha>');
process.exit(1);
}
const sv = parseSemver(oldVersion);
// 如果当前版本已有预发布后缀,递增进位号
if (sv.pre) {
const match = sv.pre.match(new RegExp(`^${arg1}\\.(\\d+)$`));
if (match) {
const num = parseInt(match[1]) + 1;
newVersion = `${sv.major}.${sv.minor}.${sv.patch}-${arg1}.${num}`;
} else {
// 不同预发布类型,重新开始
newVersion = `${sv.major}.${sv.minor}.${sv.patch}-${arg1}.1`;
}
} else {
// 纯 semver → 首次预发布:自动升 patch 再加后缀
sv.patch++;
newVersion = `${sv.major}.${sv.minor}.${sv.patch}-${arg1}.1`;
}
break;
}
default:
console.error(`未知命令: ${command}。支持: major | minor | patch | set <ver> | pre <beta|alpha>`);
process.exit(1);
}
// ---------- 更新 package.json ----------
pkg.version = newVersion;
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
console.log(`✅ package.json: ${oldVersion}${newVersion}`);
// ---------- 更新 shared/constants/version.ts由 import pkg 动态读取,无需修改) ----------
console.log(' shared/constants/version.ts 自动读取 package.json无需手动同步');
// ---------- 更新 CHANGELOG.md ----------
if (!noChangelog) {
const changelogPath = join(ROOT, 'CHANGELOG.md');
try {
let changelog = readFileSync(changelogPath, 'utf-8');
const today = new Date().toISOString().slice(0, 10);
const entry = `## ${newVersion}${today}\n\n**更新内容待补充**\n\n---\n\n`;
// 在第一个 ## 之前插入新版本条目
const firstHeaderMatch = changelog.match(/^##\s/m);
if (firstHeaderMatch) {
const insertAt = firstHeaderMatch.index;
changelog = changelog.slice(0, insertAt) + entry + changelog.slice(insertAt);
writeFileSync(changelogPath, changelog, 'utf-8');
console.log(`✅ CHANGELOG.md: 已添加 v${newVersion} 模板条目`);
} else {
console.warn('⚠️ CHANGELOG.md 格式异常,未找到 ## 版本标题');
}
} catch {
console.warn('⚠️ CHANGELOG.md 不存在,跳过更新');
}
}
console.log(`\n版本已更新: ${oldVersion}${newVersion}`);