diff --git a/.claude/scripts/generate.py b/.claude/scripts/generate.py index 69ea70c..4a346fc 100644 --- a/.claude/scripts/generate.py +++ b/.claude/scripts/generate.py @@ -256,11 +256,14 @@ def generate(args): from datetime import date today = date.today().isoformat() + report_url = (args.report_url or "").strip() or update_url.rstrip('/').rstrip('/check').rstrip('/Verification').rstrip('/') + "/Report" + bowl_lower = "yes" if with_bowl else "no" variables = { "PROJECT_NAME": project_name, "APP_SECRET_KEY": app_secret, "UPDATE_URL": update_url, + "REPORT_URL": report_url, "CLIENT_VERSION": version, "PRODUCT_ID": product_id, "STRATEGY": strategy, @@ -329,6 +332,7 @@ def generate(args): help="Project name (default: MyApp)") parser.add_argument("--app-secret-key", help="AppSecretKey (min 32 chars)") parser.add_argument("--update-url", help="Update API URL") + parser.add_argument("--report-url", help="Report API URL (default: derived from update-url)") parser.add_argument("--version", "-v", default="1.0.0.0", help="Client version (default: 1.0.0.0)") parser.add_argument("--product-id", help="Product ID (default: -001)") diff --git a/.claude/scripts/generate/templates/Bootstrap.cs.template b/.claude/scripts/generate/templates/Bootstrap.cs.template index 20a5331..6c4985f 100644 --- a/.claude/scripts/generate/templates/Bootstrap.cs.template +++ b/.claude/scripts/generate/templates/Bootstrap.cs.template @@ -1,24 +1,21 @@ using GeneralUpdate.Core; using GeneralUpdate.Core.Configuration; +using GeneralUpdate.Core.Event; using GeneralUpdate.Core.Download; -var config = new UpdateRequest +// Only 3 secrets needed in code. Identity fields (MainAppName, ClientVersion, +// ProductId, etc.) are auto-discovered from generalupdate.manifest.json. +var request = new UpdateRequest { - // === 必需 === - UpdateUrl = "{{UPDATE_URL}}", + UpdateUrl = "{{UPDATE_URL}}", + ReportUrl = "{{REPORT_URL}}", AppSecretKey = "{{APP_SECRET_KEY}}", - MainAppName = "{{PROJECT_NAME}}.exe", - ClientVersion = "{{CLIENT_VERSION}}", - ProductId = "{{PRODUCT_ID}}", - InstallPath = {{INSTALL_PATH}}, -{{#BOWL}} - // Bowl 配置(仅包含 GeneralUpdate.Bowl 包,不重复添加 Core) -{{/BOWL}} }; {{STRATEGY_WARNING}} {{BOWL_NOTICE}} await new GeneralUpdateBootstrap() - .SetConfig(config) + .SetConfig(request) + .SetOption(Option.AppType, AppType.Client) {{LISTENERS}} .LaunchAsync(); diff --git a/.claude/scripts/generate/templates/UpgradeProgram.cs.template b/.claude/scripts/generate/templates/UpgradeProgram.cs.template index aa9382c..c1e707e 100644 --- a/.claude/scripts/generate/templates/UpgradeProgram.cs.template +++ b/.claude/scripts/generate/templates/UpgradeProgram.cs.template @@ -1,11 +1,25 @@ using GeneralUpdate.Core; +using GeneralUpdate.Core.Configuration; +using GeneralUpdate.Core.Event; -// Upgrade 进程入口 — 从 IPC 文件读取配置,无需 SetConfig -// 注意: Upgrade 项目的 AppType 设为 2 (UpgradeApp) +// ================================================================ +// Upgrade — standalone upgrade process +// No SetConfig() needed — parameters come via encrypted IPC from Client +// ================================================================ await new GeneralUpdateBootstrap() + .SetOption(Option.AppType, AppType.Upgrade) + .AddListenerMultiDownloadStatistics((_, e) => + { + System.Console.WriteLine($"\rApplying: {e.ProgressPercentage:F0}%"); + }) + .AddListenerMultiDownloadCompleted((_, e) => + { + System.Console.WriteLine(); + System.Console.WriteLine($"Patch {(e.IsCompleted ? "✓ done" : "✗ failed")}"); + }) .AddListenerException((_, e) => { - System.Console.Error.WriteLine($"升级错误: {e.Message}"); + System.Console.Error.WriteLine($"Error: {e.Exception.Message}"); }) .LaunchAsync(); diff --git a/.claude/scripts/generate/templates/manifest.json.template b/.claude/scripts/generate/templates/manifest.json.template index 7319d50..161320f 100644 --- a/.claude/scripts/generate/templates/manifest.json.template +++ b/.claude/scripts/generate/templates/manifest.json.template @@ -2,7 +2,7 @@ "mainAppName": "{{PROJECT_NAME}}.exe", "updateAppName": "Upgrade{{PROJECT_NAME}}.exe", "updatePath": "./update/", - "appType": 1, - "version": "{{CLIENT_VERSION}}", + "appType": "Client", + "clientVersion": "{{CLIENT_VERSION}}", "productId": "{{PRODUCT_ID}}" } diff --git a/.claude/skills/generalupdate-init/SKILL.md b/.claude/skills/generalupdate-init/SKILL.md index f57ffd7..e106aa5 100644 --- a/.claude/skills/generalupdate-init/SKILL.md +++ b/.claude/skills/generalupdate-init/SKILL.md @@ -3,7 +3,7 @@ name: generalupdate-init description: | Integrate GeneralUpdate auto-update into any .NET application. Generates Bootstrap configuration code, manifest files, and dual-project (Client+Upgrade) scaffolding. - Covers 4 update scenes, Configinfo configuration, appsettings.json, HTTP auth (HMAC/Basic/Bearer), + Covers 4 update scenes, UpdateRequest configuration, appsettings.json, HTTP auth (HMAC/Basic/Bearer), and complete deployment checklist. Triggers on: "add auto update", "integrate GeneralUpdate", "configure bootstrap", "我需要自动更新", "配置更新", "初始化GeneralUpdate", "添加更新功能", "接入更新", "升级框架". Also triggers when user mentions their project type + update. @@ -13,7 +13,7 @@ when_to_use: | - First-time integration of GeneralUpdate into a .NET project - User wants Bootstrap configuration code (Minimal or Full) - User needs the Client + Upgrade dual-project structure explained - - User asks about manifest.json, Configinfo, or generalupdate.manifest.json + - User asks about manifest.json, UpdateRequest, or generalupdate.manifest.json - User mentions their specific .NET framework (WPF/WinForms/Avalonia/MAUI/console) - User asks about deployment considerations or CI/CD integration - Best used as the entry point; guide to other skills as needed @@ -47,7 +47,7 @@ allowed-tools: "Bash, Read, Write, Edit, Glob, Grep, WebSearch" ### 已有配置(如果存在) - 是否已安装 NuGet: ______(是/否,版本号) -- 是否已有 Configinfo 配置: ______(是/否) +- 是否已有 UpdateRequest 配置: ______(是/否) - 是否已有 manifest.json: ______(是/否) ``` @@ -60,7 +60,7 @@ allowed-tools: "Bash, Read, Write, Edit, Glob, Grep, WebSearch" ``` ├── 检查 .csproj → 目标框架、UI 类型、是否有 NuGet 引用 ├── 检查是否存在 generalupdate.manifest.json -├── 检查是否存在 Configinfo/Bootstrap 配置代码 +├── 检查是否存在 UpdateRequest/Bootstrap 配置代码 └── 检查项目结构 → 是否已有独立的 Upgrade 项目 ``` @@ -71,7 +71,7 @@ allowed-tools: "Bash, Read, Write, Edit, Glob, Grep, WebSearch" | 模式 | 适用场景 | 产出 | |------|---------|------| | **[Minimal]** | 新用户快速上手,控制台/服务应用 | 3 行 Bootstrap 代码 | -| **[Standard]** | 需要精确控制更新过程 | Configinfo + 完整事件监听 | +| **[Standard]** | 需要精确控制更新过程 | UpdateRequest + 完整事件监听 | | **[Scaffold]** | 团队项目,从零开始 | 完整 Client + Upgrade 双项目结构 | ### Step 3:生成输出 @@ -345,7 +345,7 @@ v10.5.0-beta.4 新增以下功能: ## ✅ 集成验证清单(交付前逐项检查) ### Bootstrap 配置 -- [ ] `Configinfo` 的 6 个必填字段都已设置(UpdateUrl, AppSecretKey, AppName, MainAppName, ClientVersion, ProductId, InstallPath) +- [ ] `UpdateRequest` 的 6 个必填字段都已设置(UpdateUrl, AppSecretKey, MainAppName, ClientVersion, ProductId, InstallPath) - [ ] `UpdateUrl` 指向的服务端 API 可正常返回版本信息 - [ ] `AppSecretKey` 长度 ≥ 16 字符,与服务端一致 - [ ] `AppType` 设置正确(Client = 1, Upgrade = 2) @@ -358,7 +358,7 @@ v10.5.0-beta.4 新增以下功能: - [ ] 无需额外引用 `GeneralUpdate.Differential`(已嵌入 Core) ### 部署结构 -- [ ] UpgradeApp.exe 存在于发布目录(首个版本就必须有) +- [ ] UpgradeApp.exe 存在于发布目录 update/ 子目录中(首个版本就必须有) - [ ] `generalupdate.manifest.json` 的 `UpdateAppName` 包含 `.exe` - [ ] IPC 文件(`UpdateInfo.msg`)路径在 Client/Upgrade 间一致 - [ ] `Encoding` 设置为 `Encoding.UTF8`(防止 Linux/macOS 中文乱码) diff --git a/.claude/skills/generalupdate-troubleshoot/SKILL.md b/.claude/skills/generalupdate-troubleshoot/SKILL.md index d7daa15..aaf5528 100644 --- a/.claude/skills/generalupdate-troubleshoot/SKILL.md +++ b/.claude/skills/generalupdate-troubleshoot/SKILL.md @@ -128,7 +128,7 @@ reference.md 中的问题按严重度分级: - [ ] `AppType` 设置正确(Client = 1, Upgrade = 2) ### 配置检查 -- [ ] `Configinfo` 的 6 个必填字段都已设置 +- [ ] `UpdateRequest` 的 6 个必填字段都已设置 - [ ] `UpdateUrl` 可通过 HTTP GET 访问并返回合法 JSON - [ ] `AppSecretKey` 与服务端配置一致(长度 ≥ 16 字符) - [ ] UpgradeApp.exe 存在于发布目录的 `update/` 子目录中 diff --git a/.claude/skills/generalupdate-ui/SKILL.md b/.claude/skills/generalupdate-ui/SKILL.md index c856d01..d6b8ac5 100644 --- a/.claude/skills/generalupdate-ui/SKILL.md +++ b/.claude/skills/generalupdate-ui/SKILL.md @@ -192,8 +192,8 @@ GeneralUpdateBootstrap.AddListenerException ### 事件桥接 - [ ] 所有 6 个事件都已绑定(UpdateInfo, MultiDownloadStatistics, MultiDownloadCompleted, MultiDownloadError, MultiAllDownloadCompleted, Exception) -- [ ] 桥接代码使用正确的 EventArgs 类型(检查命名空间 `GeneralUpdate.Common.Download`) -- [ ] `IsComplated` 注意拼写(v10.4.6 API 中的实际拼写,不是 `IsCompleted`) +- [ ] 桥接代码使用正确的 EventArgs 类型(检查命名空间 `GeneralUpdate.Core.Download` / `GeneralUpdate.Core.Event`) +- [ ] `IsCompleted` 属性名正确(v10.5.0-beta.4 使用 `IsCompleted`) ### 线程安全 - [ ] UI 更新操作在正确的线程上执行(WPF/Avalonia 用 `Dispatcher`,WinForms 用 `Invoke`,MAUI 用 `MainThread`) diff --git a/cli/assets/scripts/generate.py b/cli/assets/scripts/generate.py index 69ea70c..4a346fc 100644 --- a/cli/assets/scripts/generate.py +++ b/cli/assets/scripts/generate.py @@ -256,11 +256,14 @@ def generate(args): from datetime import date today = date.today().isoformat() + report_url = (args.report_url or "").strip() or update_url.rstrip('/').rstrip('/check').rstrip('/Verification').rstrip('/') + "/Report" + bowl_lower = "yes" if with_bowl else "no" variables = { "PROJECT_NAME": project_name, "APP_SECRET_KEY": app_secret, "UPDATE_URL": update_url, + "REPORT_URL": report_url, "CLIENT_VERSION": version, "PRODUCT_ID": product_id, "STRATEGY": strategy, @@ -329,6 +332,7 @@ def generate(args): help="Project name (default: MyApp)") parser.add_argument("--app-secret-key", help="AppSecretKey (min 32 chars)") parser.add_argument("--update-url", help="Update API URL") + parser.add_argument("--report-url", help="Report API URL (default: derived from update-url)") parser.add_argument("--version", "-v", default="1.0.0.0", help="Client version (default: 1.0.0.0)") parser.add_argument("--product-id", help="Product ID (default: -001)") diff --git a/cli/assets/scripts/generate/templates/Bootstrap.cs.template b/cli/assets/scripts/generate/templates/Bootstrap.cs.template index 20a5331..6c4985f 100644 --- a/cli/assets/scripts/generate/templates/Bootstrap.cs.template +++ b/cli/assets/scripts/generate/templates/Bootstrap.cs.template @@ -1,24 +1,21 @@ using GeneralUpdate.Core; using GeneralUpdate.Core.Configuration; +using GeneralUpdate.Core.Event; using GeneralUpdate.Core.Download; -var config = new UpdateRequest +// Only 3 secrets needed in code. Identity fields (MainAppName, ClientVersion, +// ProductId, etc.) are auto-discovered from generalupdate.manifest.json. +var request = new UpdateRequest { - // === 必需 === - UpdateUrl = "{{UPDATE_URL}}", + UpdateUrl = "{{UPDATE_URL}}", + ReportUrl = "{{REPORT_URL}}", AppSecretKey = "{{APP_SECRET_KEY}}", - MainAppName = "{{PROJECT_NAME}}.exe", - ClientVersion = "{{CLIENT_VERSION}}", - ProductId = "{{PRODUCT_ID}}", - InstallPath = {{INSTALL_PATH}}, -{{#BOWL}} - // Bowl 配置(仅包含 GeneralUpdate.Bowl 包,不重复添加 Core) -{{/BOWL}} }; {{STRATEGY_WARNING}} {{BOWL_NOTICE}} await new GeneralUpdateBootstrap() - .SetConfig(config) + .SetConfig(request) + .SetOption(Option.AppType, AppType.Client) {{LISTENERS}} .LaunchAsync(); diff --git a/cli/assets/scripts/generate/templates/UpgradeProgram.cs.template b/cli/assets/scripts/generate/templates/UpgradeProgram.cs.template index aa9382c..c1e707e 100644 --- a/cli/assets/scripts/generate/templates/UpgradeProgram.cs.template +++ b/cli/assets/scripts/generate/templates/UpgradeProgram.cs.template @@ -1,11 +1,25 @@ using GeneralUpdate.Core; +using GeneralUpdate.Core.Configuration; +using GeneralUpdate.Core.Event; -// Upgrade 进程入口 — 从 IPC 文件读取配置,无需 SetConfig -// 注意: Upgrade 项目的 AppType 设为 2 (UpgradeApp) +// ================================================================ +// Upgrade — standalone upgrade process +// No SetConfig() needed — parameters come via encrypted IPC from Client +// ================================================================ await new GeneralUpdateBootstrap() + .SetOption(Option.AppType, AppType.Upgrade) + .AddListenerMultiDownloadStatistics((_, e) => + { + System.Console.WriteLine($"\rApplying: {e.ProgressPercentage:F0}%"); + }) + .AddListenerMultiDownloadCompleted((_, e) => + { + System.Console.WriteLine(); + System.Console.WriteLine($"Patch {(e.IsCompleted ? "✓ done" : "✗ failed")}"); + }) .AddListenerException((_, e) => { - System.Console.Error.WriteLine($"升级错误: {e.Message}"); + System.Console.Error.WriteLine($"Error: {e.Exception.Message}"); }) .LaunchAsync(); diff --git a/cli/assets/scripts/generate/templates/manifest.json.template b/cli/assets/scripts/generate/templates/manifest.json.template index 7319d50..161320f 100644 --- a/cli/assets/scripts/generate/templates/manifest.json.template +++ b/cli/assets/scripts/generate/templates/manifest.json.template @@ -2,7 +2,7 @@ "mainAppName": "{{PROJECT_NAME}}.exe", "updateAppName": "Upgrade{{PROJECT_NAME}}.exe", "updatePath": "./update/", - "appType": 1, - "version": "{{CLIENT_VERSION}}", + "appType": "Client", + "clientVersion": "{{CLIENT_VERSION}}", "productId": "{{PRODUCT_ID}}" } diff --git a/cli/assets/skills/generalupdate-init/SKILL.md b/cli/assets/skills/generalupdate-init/SKILL.md index f57ffd7..e106aa5 100644 --- a/cli/assets/skills/generalupdate-init/SKILL.md +++ b/cli/assets/skills/generalupdate-init/SKILL.md @@ -3,7 +3,7 @@ name: generalupdate-init description: | Integrate GeneralUpdate auto-update into any .NET application. Generates Bootstrap configuration code, manifest files, and dual-project (Client+Upgrade) scaffolding. - Covers 4 update scenes, Configinfo configuration, appsettings.json, HTTP auth (HMAC/Basic/Bearer), + Covers 4 update scenes, UpdateRequest configuration, appsettings.json, HTTP auth (HMAC/Basic/Bearer), and complete deployment checklist. Triggers on: "add auto update", "integrate GeneralUpdate", "configure bootstrap", "我需要自动更新", "配置更新", "初始化GeneralUpdate", "添加更新功能", "接入更新", "升级框架". Also triggers when user mentions their project type + update. @@ -13,7 +13,7 @@ when_to_use: | - First-time integration of GeneralUpdate into a .NET project - User wants Bootstrap configuration code (Minimal or Full) - User needs the Client + Upgrade dual-project structure explained - - User asks about manifest.json, Configinfo, or generalupdate.manifest.json + - User asks about manifest.json, UpdateRequest, or generalupdate.manifest.json - User mentions their specific .NET framework (WPF/WinForms/Avalonia/MAUI/console) - User asks about deployment considerations or CI/CD integration - Best used as the entry point; guide to other skills as needed @@ -47,7 +47,7 @@ allowed-tools: "Bash, Read, Write, Edit, Glob, Grep, WebSearch" ### 已有配置(如果存在) - 是否已安装 NuGet: ______(是/否,版本号) -- 是否已有 Configinfo 配置: ______(是/否) +- 是否已有 UpdateRequest 配置: ______(是/否) - 是否已有 manifest.json: ______(是/否) ``` @@ -60,7 +60,7 @@ allowed-tools: "Bash, Read, Write, Edit, Glob, Grep, WebSearch" ``` ├── 检查 .csproj → 目标框架、UI 类型、是否有 NuGet 引用 ├── 检查是否存在 generalupdate.manifest.json -├── 检查是否存在 Configinfo/Bootstrap 配置代码 +├── 检查是否存在 UpdateRequest/Bootstrap 配置代码 └── 检查项目结构 → 是否已有独立的 Upgrade 项目 ``` @@ -71,7 +71,7 @@ allowed-tools: "Bash, Read, Write, Edit, Glob, Grep, WebSearch" | 模式 | 适用场景 | 产出 | |------|---------|------| | **[Minimal]** | 新用户快速上手,控制台/服务应用 | 3 行 Bootstrap 代码 | -| **[Standard]** | 需要精确控制更新过程 | Configinfo + 完整事件监听 | +| **[Standard]** | 需要精确控制更新过程 | UpdateRequest + 完整事件监听 | | **[Scaffold]** | 团队项目,从零开始 | 完整 Client + Upgrade 双项目结构 | ### Step 3:生成输出 @@ -345,7 +345,7 @@ v10.5.0-beta.4 新增以下功能: ## ✅ 集成验证清单(交付前逐项检查) ### Bootstrap 配置 -- [ ] `Configinfo` 的 6 个必填字段都已设置(UpdateUrl, AppSecretKey, AppName, MainAppName, ClientVersion, ProductId, InstallPath) +- [ ] `UpdateRequest` 的 6 个必填字段都已设置(UpdateUrl, AppSecretKey, MainAppName, ClientVersion, ProductId, InstallPath) - [ ] `UpdateUrl` 指向的服务端 API 可正常返回版本信息 - [ ] `AppSecretKey` 长度 ≥ 16 字符,与服务端一致 - [ ] `AppType` 设置正确(Client = 1, Upgrade = 2) @@ -358,7 +358,7 @@ v10.5.0-beta.4 新增以下功能: - [ ] 无需额外引用 `GeneralUpdate.Differential`(已嵌入 Core) ### 部署结构 -- [ ] UpgradeApp.exe 存在于发布目录(首个版本就必须有) +- [ ] UpgradeApp.exe 存在于发布目录 update/ 子目录中(首个版本就必须有) - [ ] `generalupdate.manifest.json` 的 `UpdateAppName` 包含 `.exe` - [ ] IPC 文件(`UpdateInfo.msg`)路径在 Client/Upgrade 间一致 - [ ] `Encoding` 设置为 `Encoding.UTF8`(防止 Linux/macOS 中文乱码) diff --git a/cli/assets/skills/generalupdate-troubleshoot/SKILL.md b/cli/assets/skills/generalupdate-troubleshoot/SKILL.md index d7daa15..aaf5528 100644 --- a/cli/assets/skills/generalupdate-troubleshoot/SKILL.md +++ b/cli/assets/skills/generalupdate-troubleshoot/SKILL.md @@ -128,7 +128,7 @@ reference.md 中的问题按严重度分级: - [ ] `AppType` 设置正确(Client = 1, Upgrade = 2) ### 配置检查 -- [ ] `Configinfo` 的 6 个必填字段都已设置 +- [ ] `UpdateRequest` 的 6 个必填字段都已设置 - [ ] `UpdateUrl` 可通过 HTTP GET 访问并返回合法 JSON - [ ] `AppSecretKey` 与服务端配置一致(长度 ≥ 16 字符) - [ ] UpgradeApp.exe 存在于发布目录的 `update/` 子目录中 diff --git a/cli/assets/skills/generalupdate-ui/SKILL.md b/cli/assets/skills/generalupdate-ui/SKILL.md index c856d01..d6b8ac5 100644 --- a/cli/assets/skills/generalupdate-ui/SKILL.md +++ b/cli/assets/skills/generalupdate-ui/SKILL.md @@ -192,8 +192,8 @@ GeneralUpdateBootstrap.AddListenerException ### 事件桥接 - [ ] 所有 6 个事件都已绑定(UpdateInfo, MultiDownloadStatistics, MultiDownloadCompleted, MultiDownloadError, MultiAllDownloadCompleted, Exception) -- [ ] 桥接代码使用正确的 EventArgs 类型(检查命名空间 `GeneralUpdate.Common.Download`) -- [ ] `IsComplated` 注意拼写(v10.4.6 API 中的实际拼写,不是 `IsCompleted`) +- [ ] 桥接代码使用正确的 EventArgs 类型(检查命名空间 `GeneralUpdate.Core.Download` / `GeneralUpdate.Core.Event`) +- [ ] `IsCompleted` 属性名正确(v10.5.0-beta.4 使用 `IsCompleted`) ### 线程安全 - [ ] UI 更新操作在正确的线程上执行(WPF/Avalonia 用 `Dispatcher`,WinForms 用 `Invoke`,MAUI 用 `MainThread`)