diff --git a/.gitignore b/.gitignore index c0c014b..76a20d6 100644 --- a/.gitignore +++ b/.gitignore @@ -99,6 +99,10 @@ temp/ extension-temp/ crx/ +# Release packages (generated by npm run package) +releases/ +*.zip + # Test files test-results/ playwright-report/ diff --git a/CHANGELOG-PERMISSIONS.md b/CHANGELOG-PERMISSIONS.md new file mode 100644 index 0000000..e076c9f --- /dev/null +++ b/CHANGELOG-PERMISSIONS.md @@ -0,0 +1,236 @@ +# 🔒 权限配置优化记录 + +## 📅 优化时间 +2025-11-07 + +## 🎯 优化目标 +提高 Chrome Web Store 审核通过率,符合最小权限原则。 + +--- + +## ⚠️ 优化前配置(高风险) + +### 问题:使用了广泛的主机权限 + +```json +"host_permissions": [ + "" +] +``` + +### 风险分析 + +| 风险级别 | 说明 | +|---------|------| +| 🔴 **审核风险** | `` 是高敏感权限,会触发严格审核 | +| 🔴 **信任问题** | 用户看到"可访问所有网站"会担心隐私 | +| 🔴 **政策违规** | 不符合 Chrome Web Store 最小权限原则 | + +--- + +## ✅ 优化后配置(低风险) + +### 解决方案:明确列出需要的域名 + +```json +"host_permissions": [ + "https://www.baidu.com/*", + "https://www.google.com/*", + "https://www.bing.com/*", + "https://www.sogou.com/*", + "https://www.so.com/*" +] +``` + +### 优势分析 + +| 优势 | 说明 | +|------|------| +| ✅ **审核友好** | 明确的权限范围,降低审核难度 | +| ✅ **用户信任** | 用户清楚知道扩展只在 5 个搜索引擎工作 | +| ✅ **政策合规** | 符合最小权限原则,透明化权限申请 | +| ✅ **功能无损** | 完全满足现有功能需求 | + +--- + +## 🔍 技术验证 + +### 配置一致性检查 + +✅ **host_permissions 与 content_scripts.matches 完全一致** + +```json +// host_permissions(主机权限) +"host_permissions": [ + "https://www.baidu.com/*", + "https://www.google.com/*", + "https://www.bing.com/*", + "https://www.sogou.com/*", + "https://www.so.com/*" +] + +// content_scripts.matches(内容脚本匹配) +"matches": [ + "https://www.baidu.com/*", + "https://www.google.com/*", + "https://www.bing.com/*", + "https://www.sogou.com/*", + "https://www.so.com/*" +] +``` + +### 权限统计 + +| 配置项 | 数量 | 说明 | +|--------|------|------| +| 基础权限 (permissions) | 4 | storage, activeTab, scripting, contextMenus | +| 主机权限 (host_permissions) | 5 | 5 个搜索引擎域名 | +| Content Scripts 域名 | 5 | 与主机权限一致 ✅ | + +--- + +## 📦 打包验证 + +### 新版本包信息 + +``` +文件名: releases/ssp-v1.0.0.zip +版本号: v1.0.0 +文件大小: 101.59 KB +``` + +### ZIP 包内容验证 + +✅ `manifest.json` 已包含优化后的权限配置 +✅ 所有域名列表一致 +✅ JSON 格式正确 +✅ 符合 Manifest V3 规范 + +--- + +## 🎯 Chrome Web Store 审核材料 + +### 更新后的主机权限理由 + +``` +本扩展请求主机权限的理由: + +1. 多搜索引擎支持 + - 在百度、谷歌、必应、搜狗、360搜索 5 个主流搜索引擎上提供功能 + - 为每个搜索引擎提供适配的高级语法生成 + +2. 功能实现 + - 在搜索结果页面注入内容脚本 + - 读取搜索框内容以实现"优化当前搜索"功能 + - 将生成的搜索语法自动填入搜索框 + +3. 权限范围 + - 仅限于明确列出的 5 个搜索引擎域名 + - 不访问其他网站,不收集用户浏览数据 + - 符合最小权限原则 + +此权限是扩展核心功能的必要条件。 +``` + +--- + +## 📊 影响分析 + +### ✅ 正面影响 + +1. **审核通过率提升** + - 从高风险配置改为低风险配置 + - 减少审核人员的疑虑和问询 + +2. **用户信任度提升** + - 权限申请更透明 + - 用户清楚扩展的工作范围 + +3. **政策合规性** + - 符合 Chrome Web Store 最佳实践 + - 遵循最小权限原则 + +### ⚠️ 注意事项 + +1. **未来扩展搜索引擎支持** + - 如需支持新搜索引擎,需更新 `host_permissions` + - 同时更新 `content_scripts.matches` + - 重新发布版本并说明权限变更原因 + +2. **版本更新流程** + - 添加新域名前评估必要性 + - 在更新说明中解释权限变更 + - 提前准备审核材料 + +--- + +## 🚀 后续维护 + +### 添加新搜索引擎的流程 + +1. **评估必要性** + - 确认用户需求 + - 评估搜索引擎市场份额 + +2. **更新配置** + ```json + // 在两个地方同时添加 + "host_permissions": [ + // 现有域名... + "https://www.new-search-engine.com/*" // 新增 + ], + "content_scripts": [{ + "matches": [ + // 现有域名... + "https://www.new-search-engine.com/*" // 新增 + ] + }] + ``` + +3. **更新审核材料** + - 在权限理由中说明新增搜索引擎 + - 更新"支持的搜索引擎数量" + - 准备详细的功能说明 + +4. **版本发布** + - 更新 `package.json` 版本号 + - 在 CHANGELOG.md 记录变更 + - 重新打包发布 + +--- + +## ✅ 最佳实践总结 + +### Chrome Web Store 审核最佳实践 + +1. **最小权限原则** + - ✅ 只申请必要的权限 + - ✅ 使用具体域名代替通配符 + - ✅ 避免 `` 等广泛权限 + +2. **透明度原则** + - ✅ 清晰说明每个权限的用途 + - ✅ 提供具体的使用场景 + - ✅ 强调隐私保护措施 + +3. **一致性原则** + - ✅ 确保 `host_permissions` 与实际使用一致 + - ✅ 与 `content_scripts.matches` 保持同步 + - ✅ 权限理由与实际功能匹配 + +4. **用户信任原则** + - ✅ 让用户了解扩展的工作范围 + - ✅ 说明数据处理方式(本地存储) + - ✅ 提供隐私政策链接 + +--- + +## 📝 相关文档 + +- [Chrome 扩展权限文档](https://developer.chrome.com/docs/extensions/mv3/declare_permissions/) +- [Chrome Web Store 政策](https://developer.chrome.com/docs/webstore/program_policies/) +- [最小权限原则](https://developer.chrome.com/docs/extensions/mv3/security/#permissions) + +--- + +**SearchSyntax Pro** - 遵循最佳实践,保护用户隐私 diff --git a/PACKAGING.md b/PACKAGING.md new file mode 100644 index 0000000..89e2a3e --- /dev/null +++ b/PACKAGING.md @@ -0,0 +1,258 @@ +# 📦 Chrome扩展打包指南 + +本文档说明如何将 SearchSyntax Pro 打包为可发布到 Chrome Web Store 的 ZIP 文件。 + +## 🚀 快速开始 + +### 方式一:完整打包流程(推荐) + +```bash +npm run package +``` + +这个命令会: +1. 执行 TypeScript 编译 +2. 运行 Vite 构建 +3. 复制静态资源(manifest.json、icons、国际化文件) +4. 将 dist 目录打包为 ZIP 文件 + +### 方式二:仅打包(快速迭代) + +如果你已经运行过 `npm run build`,可以直接打包: + +```bash +npm run package:only +``` + +## 📁 输出文件 + +打包后会在项目根目录生成: + +``` +releases/ +└── ssp-v{version}.zip +``` + +例如:`releases/ssp-v1.0.0.zip` + +版本号自动从 `package.json` 读取。 + +## 🔍 打包内容 + +ZIP 包会包含 `dist/` 目录的所有必要文件: + +- ✅ `manifest.json` - Chrome 扩展配置 +- ✅ `background.js` - Service Worker(后台脚本) +- ✅ `popup.js` - 弹窗界面脚本 +- ✅ `options.js` - 设置页面脚本 +- ✅ `content.js` - 内容脚本 +- ✅ `icons/` - 所有尺寸的图标(16x16, 32x32, 48x48, 128x128) +- ✅ `_locales/` - 国际化资源文件 +- ✅ 其他构建产物(CSS、资源文件等) + +### 自动排除的文件 + +打包脚本会自动排除以下文件: +- ❌ `.DS_Store` - macOS 系统文件 +- ❌ `*.backup`, `*.bak` - 备份文件 +- ❌ `*.tmp` - 临时文件 +- ❌ `__MACOSX/` - macOS 压缩产物 +- ❌ `.git/` - Git 版本控制文件 +- ❌ `node_modules/` - 依赖文件 + +## 📊 打包信息 + +打包完成后,脚本会显示: + +- ✅ 文件名称和路径 +- ✅ 版本号 +- ✅ 文件大小(压缩后) +- ✅ 文件质量评估(<5MB优秀) + +## 🌐 上传到 Chrome Web Store + +### 前提条件 + +1. **开发者账户**:注册 Chrome Web Store 开发者账户($5 一次性费用) +2. **准备材料**: + - 扩展 ZIP 包(通过 `npm run package` 生成) + - 至少 1 张截图(1280x800 或 640x400) + - 详细描述和简短描述 + - 隐私政策 URL(如果使用权限) + +### 上传步骤 + +1. **访问开发者控制台** + ``` + https://chrome.google.com/webstore/devconsole + ``` + +2. **创建新项** + - 点击"新增项" + - 上传生成的 ZIP 文件(`releases/ssp-v1.0.0.zip`) + +3. **填写商店列表信息** + - 详细描述(推荐 800-1000 字) + - 简短描述(<132 字符) + - 上传截图(至少 1 张,推荐 3-5 张) + - 选择分类:生产力工具 + +4. **配置隐私设置** + - 说明权限用途 + - 提供隐私政策链接 + - 说明数据处理方式 + +5. **提交审核** + - 检查所有必填项 + - 点击"提交审核" + - 等待审核结果(通常 24-48 小时) + +## 🔄 版本更新流程 + +### 1. 更新版本号 + +在 `package.json` 中更新版本号: + +```json +{ + "version": "1.1.0" +} +``` + +建议同步更新 `public/manifest.json` 的版本号(虽然打包脚本会使用 package.json 的版本)。 + +### 2. 构建和打包 + +```bash +npm run package +``` + +### 3. 上传新版本 + +- 在 Chrome Web Store 开发者控制台 +- 选择现有扩展 +- 上传新的 ZIP 包 +- 填写更新说明 +- 提交审核 + +## 🛠️ 故障排查 + +### 问题:找不到 zip 命令 + +**错误信息**: +``` +❌ 未找到系统zip命令 +``` + +**解决方案**: + +- **macOS**:已预装 zip,无需操作 +- **Linux**: + ```bash + sudo apt-get install zip + ``` +- **Windows**: + - 安装 [Git for Windows](https://git-scm.com/download/win)(包含 Git Bash) + - 或使用 [WSL (Windows Subsystem for Linux)](https://docs.microsoft.com/en-us/windows/wsl/install) + +### 问题:dist 目录不存在 + +**错误信息**: +``` +❌ dist目录不存在 +请先运行构建命令:npm run build +``` + +**解决方案**: +```bash +npm run build +``` + +### 问题:文件大小过大 + +**警告信息**: +``` +⚠️ ZIP文件超过10MB,可能影响审核速度 +``` + +**优化建议**: +1. 检查是否包含不必要的资源文件 +2. 压缩图片资源 +3. 移除未使用的依赖 +4. 使用 Vite 构建优化 + +### 问题:版本号格式无效 + +**错误信息**: +``` +❌ 无效的版本号格式 +``` + +**解决方案**: +确保 `package.json` 中的版本号遵循语义化版本规范(SemVer): +- ✅ 正确:`1.0.0`, `1.2.3`, `2.0.0-beta.1` +- ❌ 错误:`v1.0`, `1.0`, `latest` + +## 📝 最佳实践 + +### 1. 版本管理 + +- 遵循[语义化版本](https://semver.org/lang/zh-CN/)规范 +- 主版本号(Major):不兼容的 API 修改 +- 次版本号(Minor):向下兼容的功能新增 +- 修订号(Patch):向下兼容的问题修正 + +### 2. 发布前检查清单 + +- [ ] 运行所有测试:`npm test` +- [ ] 代码质量检查:`npm run lint` +- [ ] 类型检查:`npm run type-check` +- [ ] 本地功能测试(加载 dist 到浏览器) +- [ ] 更新版本号 +- [ ] 更新 CHANGELOG.md +- [ ] 创建 Git 标签 + +### 3. Git 工作流 + +```bash +# 1. 更新版本号 +npm version patch # 或 minor, major + +# 2. 提交更改 +git add . +git commit -m "chore: release v1.0.1" + +# 3. 创建标签 +git tag v1.0.1 + +# 4. 推送到远程 +git push origin main --tags + +# 5. 打包发布 +npm run package +``` + +### 4. 保留历史版本 + +`releases/` 目录已在 `.gitignore` 中排除,但建议: +- 在本地保留最近 3-5 个版本的 ZIP 包 +- 使用 GitHub Releases 存档重要版本 +- 记录每个版本的发布日期和审核通过日期 + +## 🔗 相关资源 + +- [Chrome 扩展开发者文档](https://developer.chrome.com/docs/extensions/) +- [Chrome Web Store 政策](https://developer.chrome.com/docs/webstore/program_policies/) +- [发布检查清单](https://developer.chrome.com/docs/webstore/publish/) +- [语义化版本规范](https://semver.org/lang/zh-CN/) + +## 💡 提示 + +- 首次发布审核可能需要更长时间(1-7 天) +- 后续更新通常更快(24-48 小时) +- 保持良好的代码质量和文档可以加速审核 +- 及时响应审核人员的问题和反馈 + +--- + +**SearchSyntax Pro** - 让高级搜索变得简单易用 diff --git a/package.json b/package.json index 73e0a89..28cd870 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,8 @@ "scripts": { "dev": "vite", "build": "tsc && vite build && node scripts/post-build.js", + "package": "npm run build && node scripts/package.js", + "package:only": "node scripts/package.js", "preview": "vite preview", "test": "jest", "test:e2e": "playwright test", diff --git a/public/manifest.json b/public/manifest.json index 3aa8d7e..2b9d045 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -13,7 +13,11 @@ ], "host_permissions": [ - "" + "https://www.baidu.com/*", + "https://www.google.com/*", + "https://www.bing.com/*", + "https://www.sogou.com/*", + "https://www.so.com/*" ], "background": { diff --git a/scripts/package.js b/scripts/package.js new file mode 100644 index 0000000..11dfd5f --- /dev/null +++ b/scripts/package.js @@ -0,0 +1,380 @@ +/** + * Chrome扩展自动打包脚本 + * + * 功能: + * - 自动从package.json读取版本号 + * - 将dist目录打包为ZIP格式 + * - 生成带版本号的发布包:releases/ssp-v{version}.zip + * - 提供详细的错误提示和成功信息 + * + * 架构设计: + * - 单一职责原则:每个函数只做一件事 + * - 错误优先:完善的错误处理和用户提示 + * - 零依赖:仅使用Node.js内置模块 + * + * @author SearchSyntax Pro Team + */ + +import { execSync } from 'child_process'; +import { existsSync, mkdirSync, readFileSync, statSync } from 'fs'; +import { join, dirname } from 'path'; +import { fileURLToPath } from 'url'; + +// ============================================================================ +// 配置常量 +// ============================================================================ + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +const rootDir = join(__dirname, '..'); + +const CONFIG = { + distDir: join(rootDir, 'dist'), + releasesDir: join(rootDir, 'releases'), + packageName: 'ssp', + packageJsonPath: join(rootDir, 'package.json'), +}; + +// 颜色输出(在终端中更友好) +const colors = { + reset: '\x1b[0m', + bright: '\x1b[1m', + red: '\x1b[31m', + green: '\x1b[32m', + yellow: '\x1b[33m', + blue: '\x1b[34m', + cyan: '\x1b[36m', +}; + +// ============================================================================ +// 工具函数 +// ============================================================================ + +/** + * 格式化文件大小为人类可读格式 + * @param {number} bytes - 字节数 + * @returns {string} 格式化后的大小(如 "1.23 MB") + */ +function formatFileSize(bytes) { + const units = ['B', 'KB', 'MB', 'GB']; + let size = bytes; + let unitIndex = 0; + + while (size >= 1024 && unitIndex < units.length - 1) { + size /= 1024; + unitIndex++; + } + + return `${size.toFixed(2)} ${units[unitIndex]}`; +} + +/** + * 打印带颜色的消息 + * @param {string} message - 消息内容 + * @param {string} color - 颜色代码 + */ +function log(message, color = colors.reset) { + console.log(`${color}${message}${colors.reset}`); +} + +/** + * 打印成功消息 + */ +function logSuccess(message) { + log(`✅ ${message}`, colors.green); +} + +/** + * 打印错误消息 + */ +function logError(message) { + log(`❌ ${message}`, colors.red); +} + +/** + * 打印警告消息 + */ +function logWarning(message) { + log(`⚠️ ${message}`, colors.yellow); +} + +/** + * 打印信息消息 + */ +function logInfo(message) { + log(`ℹ️ ${message}`, colors.cyan); +} + +/** + * 打印标题 + */ +function logHeader(message) { + log(`\n${'='.repeat(60)}`, colors.blue); + log(` ${message}`, colors.bright + colors.blue); + log(`${'='.repeat(60)}\n`, colors.blue); +} + +// ============================================================================ +// 环境验证层 +// ============================================================================ + +/** + * 检查系统是否安装了zip命令 + * @throws {Error} 如果zip命令不存在 + */ +function checkZipCommand() { + try { + execSync('which zip', { stdio: 'ignore' }); + logSuccess('检测到系统zip命令'); + } catch (error) { + logError('未找到系统zip命令'); + console.log('\n请安装zip工具:'); + console.log(' macOS: 已预装'); + console.log(' Linux: sudo apt-get install zip'); + console.log(' Windows: 安装 Git Bash 或使用 WSL\n'); + throw new Error('缺少zip命令'); + } +} + +/** + * 检查dist目录是否存在 + * @throws {Error} 如果dist目录不存在 + */ +function checkDistDirectory() { + if (!existsSync(CONFIG.distDir)) { + logError('dist目录不存在'); + console.log('\n请先运行构建命令:'); + console.log(' npm run build\n'); + throw new Error('缺少dist目录'); + } + logSuccess(`找到构建目录: ${CONFIG.distDir}`); +} + +// ============================================================================ +// 版本管理层 +// ============================================================================ + +/** + * 从package.json读取版本号 + * @returns {string} 版本号(如 "1.0.0") + * @throws {Error} 如果读取失败或版本号无效 + */ +function getVersion() { + try { + const packageJson = JSON.parse( + readFileSync(CONFIG.packageJsonPath, 'utf-8') + ); + + const version = packageJson.version; + if (!version) { + throw new Error('package.json中未找到version字段'); + } + + // 验证版本号格式(语义化版本) + if (!/^\d+\.\d+\.\d+(-[\w.]+)?$/.test(version)) { + throw new Error(`无效的版本号格式: ${version}`); + } + + logSuccess(`读取版本号: v${version}`); + return version; + } catch (error) { + logError(`读取版本号失败: ${error.message}`); + throw error; + } +} + +// ============================================================================ +// 文件系统层 +// ============================================================================ + +/** + * 创建releases目录(如果不存在) + */ +function prepareReleasesDir() { + if (!existsSync(CONFIG.releasesDir)) { + mkdirSync(CONFIG.releasesDir, { recursive: true }); + logSuccess(`创建输出目录: ${CONFIG.releasesDir}`); + } else { + logInfo(`使用现有输出目录: ${CONFIG.releasesDir}`); + } +} + +/** + * 检查同名包文件是否已存在 + * @param {string} zipFileName - ZIP文件名 + * @returns {boolean} 是否存在 + */ +function checkExistingPackage(zipFileName) { + const zipPath = join(CONFIG.releasesDir, zipFileName); + if (existsSync(zipPath)) { + const stats = statSync(zipPath); + const size = formatFileSize(stats.size); + logWarning(`发现同名文件: ${zipFileName} (${size})`); + logInfo('将覆盖现有文件'); + return true; + } + return false; +} + +// ============================================================================ +// 打包执行层 +// ============================================================================ + +/** + * 执行ZIP打包命令 + * @param {string} version - 版本号 + * @returns {string} 生成的ZIP文件路径 + * @throws {Error} 如果打包失败 + */ +function createZipPackage(version) { + const zipFileName = `${CONFIG.packageName}-v${version}.zip`; + const zipPath = join(CONFIG.releasesDir, zipFileName); + + logInfo('开始打包...'); + + try { + // 切换到dist目录并打包所有内容 + // -r: 递归打包目录 + // -q: 安静模式(不显示进度) + // -9: 最高压缩率 + // -x: 排除不必要的文件 + const excludePatterns = [ + '*.DS_Store', // macOS系统文件 + '__MACOSX/*', // macOS压缩产物 + '*.backup', // 备份文件 + '*.bak', // 备份文件 + '*.tmp', // 临时文件 + '.git/*', // Git文件 + 'node_modules/*', // 依赖文件(不应该在dist中) + ].map(p => `"${p}"`).join(' '); + + const command = `cd "${CONFIG.distDir}" && zip -r -q -9 "${zipPath}" . -x ${excludePatterns}`; + + execSync(command, { stdio: 'inherit' }); + + // 验证ZIP文件是否成功创建 + if (!existsSync(zipPath)) { + throw new Error('ZIP文件创建失败'); + } + + return zipPath; + } catch (error) { + logError(`打包失败: ${error.message}`); + throw error; + } +} + +/** + * 计算并返回文件大小信息 + * @param {string} filePath - 文件路径 + * @returns {Object} 包含size和formattedSize的对象 + */ +function getFileInfo(filePath) { + const stats = statSync(filePath); + return { + size: stats.size, + formattedSize: formatFileSize(stats.size), + }; +} + +// ============================================================================ +// 报告层 +// ============================================================================ + +/** + * 显示打包成功信息 + * @param {string} zipPath - ZIP文件路径 + * @param {string} version - 版本号 + */ +function displaySuccess(zipPath, version) { + const fileInfo = getFileInfo(zipPath); + const fileName = join('releases', `${CONFIG.packageName}-v${version}.zip`); + + logHeader('打包成功!'); + + console.log(`${colors.bright}📦 扩展包信息${colors.reset}`); + console.log(` 文件名称: ${colors.cyan}${fileName}${colors.reset}`); + console.log(` 版本号: ${colors.green}v${version}${colors.reset}`); + console.log(` 文件大小: ${colors.yellow}${fileInfo.formattedSize}${colors.reset}`); + console.log(` 完整路径: ${colors.blue}${zipPath}${colors.reset}`); + + console.log(`\n${colors.bright}🚀 下一步操作${colors.reset}`); + console.log(' 1. 访问 Chrome Web Store Developer Console'); + console.log(' https://chrome.google.com/webstore/devconsole'); + console.log(' 2. 上传生成的ZIP文件'); + console.log(' 3. 填写商店列表信息'); + console.log(' 4. 提交审核\n'); + + // 文件大小警告 + if (fileInfo.size > 10 * 1024 * 1024) { + logWarning('ZIP文件超过10MB,可能影响审核速度'); + logInfo('建议优化资源文件大小'); + } else if (fileInfo.size > 5 * 1024 * 1024) { + logInfo('ZIP文件大小适中(5-10MB)'); + } else { + logSuccess('ZIP文件大小优秀(<5MB)'); + } +} + +/** + * 显示错误信息并退出 + * @param {Error} error - 错误对象 + */ +function displayError(error) { + logHeader('打包失败'); + logError(error.message); + + if (error.stack) { + console.log(`\n${colors.yellow}详细错误信息:${colors.reset}`); + console.log(error.stack); + } + + console.log(`\n${colors.cyan}需要帮助?${colors.reset}`); + console.log(' - 查看项目文档: README.md'); + console.log(' - 提交Issue: https://github.com/lhly/search-syntax-pro/issues\n'); + + process.exit(1); +} + +// ============================================================================ +// 主流程 +// ============================================================================ + +/** + * 主函数:执行完整的打包流程 + */ +async function main() { + try { + logHeader('🎁 Chrome扩展自动打包工具'); + + // 第1步:环境验证 + console.log(`${colors.bright}第1步: 环境验证${colors.reset}`); + checkZipCommand(); + checkDistDirectory(); + + // 第2步:读取版本号 + console.log(`\n${colors.bright}第2步: 版本管理${colors.reset}`); + const version = getVersion(); + + // 第3步:准备输出目录 + console.log(`\n${colors.bright}第3步: 文件系统准备${colors.reset}`); + prepareReleasesDir(); + + const zipFileName = `${CONFIG.packageName}-v${version}.zip`; + checkExistingPackage(zipFileName); + + // 第4步:执行打包 + console.log(`\n${colors.bright}第4步: 执行打包${colors.reset}`); + const zipPath = createZipPackage(version); + + // 第5步:显示结果 + logSuccess('打包完成'); + displaySuccess(zipPath, version); + + } catch (error) { + displayError(error); + } +} + +// 执行主流程 +main();