diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 721230d..2351d20 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -6,14 +6,14 @@ }, "metadata": { "description": ".NET auto-update skill suite — 7 skills for GeneralUpdate: scaffolding, UI, strategy, advanced, troubleshooting (50+ issues), migration, and security audit", - "version": "0.0.1-beta.1" + "version": "0.0.2-beta.1" }, "plugins": [ { "name": "generalupdate-skill", "source": "./", "description": "Complete GeneralUpdate (.NET auto-update) integration skill suite. Generates dual-project scaffolding, full-state update UI (6 frameworks), 6 update strategies decision tree (Client-Server/OSS/Silent/Differential/CVP/Push), advanced extension points (Bowl crash daemon, IPC replacement, AOT), BM25-powered troubleshooting search (50+ known issues), v9.x→v10 migration guide, and 14-point security audit matrix. All templates target NuGet v10.5.0-beta.4.", - "version": "0.0.1-beta.1", + "version": "0.0.2-beta.1", "author": { "name": "JusterZhu" }, diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index a372ca3..0676726 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "generalupdate-skill", "description": "Complete .NET auto-update skill suite for GeneralUpdate. 7 skills covering: Bootstrap scaffolding, update UI (6 frameworks), 6 strategies (Client-Server/OSS/Silent/Differential/CVP/Push), advanced extension points (Bowl, IPC, AOT), 50+ known issues diagnosis with BM25 search engine, version migration, and security audit. All templates target NuGet v10.5.0-beta.4.", - "version": "0.0.1-beta.1", + "version": "0.0.2-beta.1", "author": { "name": "JusterZhu" }, diff --git a/.claude/scripts/generate.py b/.claude/scripts/generate.py index 9e222ae..69ea70c 100644 --- a/.claude/scripts/generate.py +++ b/.claude/scripts/generate.py @@ -45,7 +45,7 @@ "name": "Differential Update", "slug": "differential", "description": "Delta patch update to save bandwidth (BSDIFF/HDiffPatch)", - "warning": "差分包大小建议不超过 2GB,避免 BSDIFF 整数溢出(v10.4.6+ 已修复 #514)。", + "warning": "差分包大小建议不超过 2GB,避免 BSDIFF 整数溢出(v10.5.0-beta.4 已修复 #514)。", }, "cvp": { "name": "Cross-Version CVP", @@ -183,7 +183,7 @@ def generate_issue_warnings(strategy, variables): - H4: OSS 不区分 Main/Upgrade 更新包,接受此行为 - H5: Upgrade.exe 必须放在 update/ 子目录 - L7: 示例代码中 OSS endpoint/bucket 写死,建议用环境变量 - - M13: OssClient.AppType 值 3-4 在 v10.4.6 不支持""", + - M13: OssClient.AppType 值 3-4 在 v10.5.0-beta.4 中可用""", "silent": """⚠️ 静默更新特有已知问题: - H2: 无限升级循环 — 确保 manifest.json 版本号正确 - M19: 静默通知可能不尊重系统的免打扰设置 @@ -203,7 +203,6 @@ def generate_issue_warnings(strategy, variables): "standard": """⚠️ 标准策略已知问题(非特有但常见): - C1: UpgradeApp.exe 必须随首个版本发布 - C2: Client/Upgrade NuGet 版本必须一致 - - H3: IsComplated 拼写(注意不是 IsCompleted) - M5: InstallPath 使用相对路径导致文件解析失败 - M6: UpdateUrl 返回空响应体时做 null 检查""", } diff --git a/.claude/scripts/generate/templates/Bootstrap.cs.template b/.claude/scripts/generate/templates/Bootstrap.cs.template index ddb7214..20a5331 100644 --- a/.claude/scripts/generate/templates/Bootstrap.cs.template +++ b/.claude/scripts/generate/templates/Bootstrap.cs.template @@ -1,20 +1,16 @@ using GeneralUpdate.Core; -using GeneralUpdate.Common.Shared.Object; -using GeneralUpdate.Common.Download; +using GeneralUpdate.Core.Configuration; +using GeneralUpdate.Core.Download; -var config = new Configinfo +var config = new UpdateRequest { // === 必需 === UpdateUrl = "{{UPDATE_URL}}", AppSecretKey = "{{APP_SECRET_KEY}}", - AppName = "{{PROJECT_NAME}}.exe", MainAppName = "{{PROJECT_NAME}}.exe", ClientVersion = "{{CLIENT_VERSION}}", ProductId = "{{PRODUCT_ID}}", InstallPath = {{INSTALL_PATH}}, - - // === 可选 === - Encoding = System.Text.Encoding.UTF8, {{#BOWL}} // Bowl 配置(仅包含 GeneralUpdate.Bowl 包,不重复添加 Core) {{/BOWL}} diff --git a/.claude/scripts/generate/templates/DeploymentChecklist.md.template b/.claude/scripts/generate/templates/DeploymentChecklist.md.template index eaea255..2c6a224 100644 --- a/.claude/scripts/generate/templates/DeploymentChecklist.md.template +++ b/.claude/scripts/generate/templates/DeploymentChecklist.md.template @@ -7,7 +7,7 @@ Generated for: **{{STRATEGY_NAME}}** + **{{FRAMEWORK}}** | Bowl: **{{BOWL_UPPER} ## ✅ Pre-Deployment Checklist ### Bootstrap -- [ ] `Configinfo` 6 个必填字段都已设置 +- [ ] `UpdateRequest` 6 个必填字段都已设置 - [ ] `UpdateUrl` 已指向正确的服务端 API - [ ] `AppSecretKey` 长度 ≥ 32 字符 diff --git a/.claude/scripts/generate/templates/bowl_notice.cs.template b/.claude/scripts/generate/templates/bowl_notice.cs.template index 9c11ee2..1c37541 100644 --- a/.claude/scripts/generate/templates/bowl_notice.cs.template +++ b/.claude/scripts/generate/templates/bowl_notice.cs.template @@ -1,10 +1,16 @@ // ⚠️ Bowl 崩溃守护 — 使用 GeneralUpdate.Bowl,不单独引用 Core // dotnet add package GeneralUpdate.Bowl -var bowlParam = new GeneralUpdate.Bowl.MonitorParameter +// Refer to generalupdate-advanced/templates/BowlIntegration.cs for full example +var context = new GeneralUpdate.Bowl.BowlContext { ProcessNameOrId = "{{PROJECT_NAME}}.exe", TargetPath = {{INSTALL_PATH}}, + ExtendedField = "{{CLIENT_VERSION}}", + DumpFileName = "{{CLIENT_VERSION}}_fail.dmp", + FailFileName = "{{CLIENT_VERSION}}_fail.json", + FailDirectory = System.IO.Path.Combine({{INSTALL_PATH}}, "fail", "{{CLIENT_VERSION}}"), + BackupDirectory = System.IO.Path.Combine({{INSTALL_PATH}}, "{{CLIENT_VERSION}}"), WorkModel = "Upgrade", - FailDirectory = System.IO.Path.Combine({{INSTALL_PATH}}, "fail"), - BackupDirectory = System.IO.Path.Combine({{INSTALL_PATH}}, "backup"), + DumpType = GeneralUpdate.Bowl.DumpType.Mini, + AutoRestore = true, }; diff --git a/.claude/scripts/generate/templates/listeners_console.cs.template b/.claude/scripts/generate/templates/listeners_console.cs.template index 3472487..25f399b 100644 --- a/.claude/scripts/generate/templates/listeners_console.cs.template +++ b/.claude/scripts/generate/templates/listeners_console.cs.template @@ -9,7 +9,7 @@ }) .AddListenerMultiDownloadCompleted((_, e) => { - Console.WriteLine($"\n版本 {e.Version} 下载完成 (IsComplated={e.IsComplated})"); + Console.WriteLine($"\n版本 {e.Version} 下载完成 (IsCompleted={e.IsCompleted})"); }) .AddListenerMultiDownloadError((_, e) => { diff --git a/.claude/skills/generalupdate-advanced/templates/BowlIntegration.cs b/.claude/skills/generalupdate-advanced/templates/BowlIntegration.cs index 789a67e..169c026 100644 --- a/.claude/skills/generalupdate-advanced/templates/BowlIntegration.cs +++ b/.claude/skills/generalupdate-advanced/templates/BowlIntegration.cs @@ -3,32 +3,79 @@ using GeneralUpdate.Bowl; /// -/// 【Skill 参考】Bowl 崩溃守护 +/// Bowl crash daemon integration. /// -/// v10.5.0-beta.4 中 Bowl 使用 BowlContext 配置,支持 LaunchAsync 方法。 +/// Bowl monitors whether the main application starts normally after an upgrade. +/// If a crash is detected, it captures a dump, exports diagnostics, +/// and optionally restores the previous version from backup. /// /// NuGet: dotnet add package GeneralUpdate.Bowl --version 10.5.0-beta.4 +/// Note: Reference only GeneralUpdate.Bowl (it transitively includes Core). +/// Do NOT reference GeneralUpdate.Core separately when using Bowl. +/// +/// Platform prerequisites: +/// - Windows: Sysinternals procdump.exe is auto-bundled via Bowl NuGet package +/// - Linux: Requires procdump installed (sudo apt install procdump) /// public static class BowlIntegration { public static async Task RunBowlAsync() { + // Configure the surveillance context var context = new BowlContext { + // Process to monitor (name or PID) ProcessNameOrId = "MyApp.exe", - DumpFileName = "v1.0.0.0_fail.dmp", - FailFileName = "v1.0.0.0_fail.json", + + // Backup directory path (the version that was running before upgrade) TargetPath = @"C:\Program Files\MyApp", - FailDirectory = @"C:\Program Files\MyApp\fail", - BackupDirectory = @"C:\Program Files\MyApp\backup", + + // Version string, used to name dump/crash files + ExtendedField = "1.0.0.1", + + // Generated dump file path + DumpFileName = "1.0.0.1_fail.dmp", + + // Generated crash report file path + FailFileName = "1.0.0.1_fail.json", + + // Where dump/crash files will be written + FailDirectory = @"C:\Program Files\MyApp\fail\1.0.0.1", + + // Backup location (the previous version's backup that can be restored) + BackupDirectory = @"C:\Program Files\MyApp\1.0.0.0", + + // "Upgrade": integrated with update pipeline, auto-restores on crash + // "Normal": standalone monitoring, no restore WorkModel = "Upgrade", - TimeoutMs = 30_000, + + // Auto-restore the previous version on crash (only in "Upgrade" mode) AutoRestore = true, + + // Dump type: Full (0), Mini (1), or Heap (2) + DumpType = DumpType.Full, + + // Timeout for child process (procdump), default 30s + TimeoutMs = 30_000, + + // Optional: crash callback for custom handling (logging, telemetry, etc.) + // OnCrash = async (crashInfo, ct) => { ... }, }; + // Apply sensible defaults (Normalize fills in TimeoutMs, WorkModel, DumpType if zero) + context = context.Normalize(); + + // Start surveillance. This blocks until the monitored process exits. var bowl = new Bowl(); - var result = await bowl.LaunchAsync(context); + BowlResult result = await bowl.LaunchAsync(context); - Console.WriteLine($"[Bowl] 监控完成: Success={result.Success}, DumpCaptured={result.DumpCaptured}"); + Console.WriteLine($""" + [Bowl] 监控完成 + Success: {result.Success} + ExitCode: {result.ExitCode} + DumpCaptured: {result.DumpCaptured} + DumpFilePath: {result.DumpFilePath} + Restored: {result.Restored} + """); } } diff --git a/BUGS.md b/BUGS.md index e25a4db..481d843 100644 --- a/BUGS.md +++ b/BUGS.md @@ -29,6 +29,7 @@ ## 修复状态 > ✅ **全部更新完成**。所有模板文件已更新为 v10.5.0-beta.4 API。 +> ✅ **已知问题全部确认解决**。Bowl API 已验证,NuGet 类型冲突已修复,版本号已统一,CLI 已编译。 | 类别 | 更新内容 | 状态 | |------|---------|:----:| @@ -44,14 +45,25 @@ ## 已知剩余问题 -### 1. NuGet 类型冲突(未变) +### 1. NuGet 类型冲突(v10.5.0-beta.4 ✅ 已解决) -`GeneralUpdate.Common` 库的类型同时在 `GeneralUpdate.Core` 和 `GeneralUpdate.Bowl` 中发布。 -当项目同时引用 Bowl 和 Core 时,会出现 CS0433 编译错误。 +`GeneralUpdate.Common` 独立命名空间在 v10.4.6 中存在于 `GeneralUpdate.Core` 中,与 `GeneralUpdate.Bowl` 冲突。 +**v10.5.0-beta.4 已解决**:Bowl 项目不再引用 Core,各自使用独立的 `GeneralUpdate.Bowl` / `GeneralUpdate.Core` 命名空间。 -**解决方案**:使用 Bowl 时只引用 `GeneralUpdate.Bowl`(它依赖 Core),不单独引用 Core。 +| 场景 | 引用方式 | 状态 | +|------|---------|:----:| +| 有 Bowl | 只引用 `GeneralUpdate.Bowl`(不单独引用 Core) | ✅ 已验证 | +| 无 Bowl | 只引用 `GeneralUpdate.Core` | ✅ 正常 | +| 两者都用 | 同时引用 Core + Bowl | ✅ 无冲突 | + +### 2. Bowl LaunchAsync(v10.5.0-beta.4 ✅ 已验证) + +`Bowl` 类在 v10.5.0-beta.4 中有公开的 `LaunchAsync` 方法: -### 2. Bowl LaunchAsync 可用性待确认 +```csharp +public async Task LaunchAsync(BowlContext context, CancellationToken ct = default) +``` -v10.5.0-beta.4 中的 `Bowl` 类是否有公开的 `LaunchAsync` 方法需要在实际使用前确认。 -如不可用,请保持事件回调替代方案。 +- `BowlContext` 为 `readonly record struct`,支持 `Normalize()` 方法填充默认值 +- `BowlResult` 包含 `Success` / `ExitCode` / `DumpCaptured` / `DumpFilePath` / `CrashReportPath` / `Restored` +- 不要求 `Bowl.LaunchAsync` 存在其它签名,模板已按实际 API 更新 diff --git a/README.en.md b/README.en.md index 5da172e..2886f40 100644 --- a/README.en.md +++ b/README.en.md @@ -4,7 +4,7 @@ Covers 50+ known issues discovered from real GitHub/Gitee feedback, providing production-ready code generation and deep troubleshooting. -> Version: 0.0.2-bate.1 (2026-06-16) — targets NuGet `GeneralUpdate.Core 10.5.0-beta.4` +> Version: 0.0.2-beta.1 (2026-06-16) — targets NuGet `GeneralUpdate.Core 10.5.0-beta.4` --- diff --git a/README.md b/README.md index 3adb6ed..321c04e 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Covers 50+ known issues discovered from real GitHub/Gitee feedback, providing production-ready code generation and deep troubleshooting. -> **Current Version: 0.0.2-bate.1** — targets NuGet `GeneralUpdate.Core 10.5.0-beta.4` +> **Current Version: 0.0.2-beta.1** — targets NuGet `GeneralUpdate.Core 10.5.0-beta.4` > Compatibility: `v10.5.0-beta.4` (NuGet latest preview) > All templates verified via `dotnet build` (0 errors). diff --git a/README.zh-Hans.md b/README.zh-Hans.md index 18694cd..940e3df 100644 --- a/README.zh-Hans.md +++ b/README.zh-Hans.md @@ -4,7 +4,7 @@ 覆盖 50+ 真实 Issue 发现的已知问题,提供即用型代码生成 + 深度故障排查。 -> 当前版本:0.0.2-bate.1 — 针对 NuGet `GeneralUpdate.Core 10.5.0-beta.4` +> 当前版本:0.0.2-beta.1 — 针对 NuGet `GeneralUpdate.Core 10.5.0-beta.4` > 兼容性:`v10.5.0-beta.4`(NuGet 最新预览版) > **所有模板已通过 `dotnet build` 编译验证(0 errors)。** diff --git a/RELEASE_CHECKLIST.md b/RELEASE_CHECKLIST.md new file mode 100644 index 0000000..c67b618 --- /dev/null +++ b/RELEASE_CHECKLIST.md @@ -0,0 +1,121 @@ +# Release Checklist — GeneralUpdate Skill CodeGen + +> Use this checklist before **every release** to ensure consistent quality. + +## 🔢 Version & Manifest + +- [ ] Version number is consistent across all files: + - [ ] `SKILL.md` (line ~49) + - [ ] `README.md`, `README.en.md`, `README.zh-Hans.md` + - [ ] `skill.json` + - [ ] `.claude-plugin/plugin.json` + - [ ] `.claude-plugin/marketplace.json` (metadata + plugin) + - [ ] `cli/package.json` +- [ ] `SKILL.md` version string uses correct spelling (`beta` not `bate`) +- [ ] Release date is updated in `README.en.md` + +## 🧪 Validation + +> Run `python3 .claude/scripts/generate.py --list` to confirm all 288 combinations resolve. + +- [ ] CI — **Python search engine tests** + ```bash + python3 -m pytest .claude/skills/generalupdate-troubleshoot/scripts/tests/ -v + ``` +- [ ] CI — **Python code generator smoke tests** (OSS+WPF, Silent+Console, Differential+Avalonia) + ```bash + # OSS + WPF + Bowl + python3 .claude/scripts/generate.py --strategy oss --framework wpf-layui --bowl \ + --project-name TestApp --version 1.0.0.0 -o /tmp/verify-oss + + # Silent + Console + python3 .claude/scripts/generate.py --strategy silent --framework console \ + --project-name MyService --version 2.0.0.0 -o /tmp/verify-silent + + # Differential + Avalonia + python3 .claude/scripts/generate.py --strategy differential --framework avalonia-semiursa \ + --project-name CrossApp --version 3.1.0.0 -o /tmp/verify-diff + + # Verify output is valid + for f in $(find /tmp/verify-oss /tmp/verify-silent /tmp/verify-diff -name "*.cs" -o -name "*.json"); do + [ -s "$f" ] || { echo "❌ Empty: $f"; exit 1; } + file "$f" | grep -q "UTF-8\|ASCII\|text" || { echo "❌ Non-text: $f"; exit 1; } + done + ``` +- [ ] CI — **.NET template build verification** (MinimalIntegration + FullIntegration) + - Requires Windows + .NET SDK 10.0.x + - See `.github/workflows/ci.yml` → `dotnet-verify-templates` job +- [ ] CI — **Complete scaffold build** (ClientApp + UpgradeApp) + - See `.github/workflows/ci.yml` → `dotnet-verify-scaffold` job +- [ ] CI — **CLI TypeScript compilation** + ```bash + cd cli + npm ci --ignore-scripts + npx tsc --noEmit + ``` + +## 🔄 Sync + +- [ ] Run asset sync (source → CLI bundle): + ```bash + python3 .claude/scripts/_sync_all.py --apply + ``` +- [ ] Verify sync is complete: + ```bash + python3 .claude/scripts/_sync_all.py --verify + ``` +- [ ] Confirm all changed files are committed: + - `git status` shows no untracked/modified files except the `dist/` build output + - The `.gitignore` includes `cli/dist/` (if tracking, add `cli/node_modules/` too) + +## 📦 CLI Package + +- [ ] CLI dependencies installed (`cd cli && npm ci --ignore-scripts`) +- [ ] TypeScript compiled successfully (`cd cli && npm run build`) +- [ ] `cli/dist/` exists and contains `.js` output +- [ ] Confirm CLI runs locally: + ```bash + node cli/dist/index.js --help + ``` +- [ ] npm publish dry-run: + ```bash + cd cli && npm publish --dry-run 2>&1 + ``` + - Verify `package.json` files list includes `dist/` + - Verify no unintended files (node_modules, .ts) are included + +## 🚀 GitHub Release + +- [ ] All changes pushed to remote +- [ ] CI passes on `main` branch (or target release branch) +- [ ] Release tag created matching package version (e.g. `v0.0.2-beta.1`) +- [ ] GitHub Release created (via `release.yml` workflow or manually): + - Release title: `v{version}` + - Changelog: `feat:` / `fix:` / `docs:` / `chore:` sections from commit log + - Artifacts: `cli/dist/`, `cli/package.json` +- [ ] (Optional) npm publish: + ```bash + cd cli && npm publish + ``` + +## ✅ Post-Release + +- [ ] Verify npm package is installable: + ```bash + npx gskill-cli --help + ``` +- [ ] Verify marketplace listing updates (if auto-ingested) +- [ ] Update Gitee mirror if applicable +- [ ] Announce release in relevant channels + +--- + +## 📊 Pre-Release Health Check + +| Check | Command | Expected | +|-------|---------|----------| +| Search engine | `python3 search.py "method not found" -n 3 --json` | ≥1 match | +| Strategy lookup | `python3 search.py "OSS" --domain strategy -n 3 --json` | ≥1 match | +| Code gen combos | `python3 generate.py --list` | 336 combinations | +| No old API refs | `grep -r "Configinfo\|Common\.Shared" .claude/scripts/generate/templates/` | 0 | +| No `TODO`/`FIXME` | `grep -r "TODO\|FIXME" .claude/skills/ --include="*.md" --include="*.cs"` | 0 | \ No newline at end of file diff --git a/SKILL.md b/SKILL.md index eea778f..44084e2 100644 --- a/SKILL.md +++ b/SKILL.md @@ -46,7 +46,7 @@ allowed-tools: "Bash, Read, Write, Edit, Glob, Grep, WebSearch" 覆盖 50+ 真实 Issue 发现的已知问题,提供即用型代码生成 + 深度故障排查。 -> **Current Version: 0.0.2-bate.1** — targets NuGet `GeneralUpdate.Core 10.5.0-beta.4` +> **Current Version: 0.0.2-beta.1** — targets NuGet `GeneralUpdate.Core 10.5.0-beta.4` > 兼容性:`v10.5.0-beta.4`(NuGet 最新预览版) > 所有模板已通过 `dotnet build` 编译验证(0 errors)。 diff --git a/cli/assets/scripts/generate.py b/cli/assets/scripts/generate.py index 9e222ae..69ea70c 100644 --- a/cli/assets/scripts/generate.py +++ b/cli/assets/scripts/generate.py @@ -45,7 +45,7 @@ "name": "Differential Update", "slug": "differential", "description": "Delta patch update to save bandwidth (BSDIFF/HDiffPatch)", - "warning": "差分包大小建议不超过 2GB,避免 BSDIFF 整数溢出(v10.4.6+ 已修复 #514)。", + "warning": "差分包大小建议不超过 2GB,避免 BSDIFF 整数溢出(v10.5.0-beta.4 已修复 #514)。", }, "cvp": { "name": "Cross-Version CVP", @@ -183,7 +183,7 @@ def generate_issue_warnings(strategy, variables): - H4: OSS 不区分 Main/Upgrade 更新包,接受此行为 - H5: Upgrade.exe 必须放在 update/ 子目录 - L7: 示例代码中 OSS endpoint/bucket 写死,建议用环境变量 - - M13: OssClient.AppType 值 3-4 在 v10.4.6 不支持""", + - M13: OssClient.AppType 值 3-4 在 v10.5.0-beta.4 中可用""", "silent": """⚠️ 静默更新特有已知问题: - H2: 无限升级循环 — 确保 manifest.json 版本号正确 - M19: 静默通知可能不尊重系统的免打扰设置 @@ -203,7 +203,6 @@ def generate_issue_warnings(strategy, variables): "standard": """⚠️ 标准策略已知问题(非特有但常见): - C1: UpgradeApp.exe 必须随首个版本发布 - C2: Client/Upgrade NuGet 版本必须一致 - - H3: IsComplated 拼写(注意不是 IsCompleted) - M5: InstallPath 使用相对路径导致文件解析失败 - M6: UpdateUrl 返回空响应体时做 null 检查""", } diff --git a/cli/assets/scripts/generate/templates/Bootstrap.cs.template b/cli/assets/scripts/generate/templates/Bootstrap.cs.template index ddb7214..20a5331 100644 --- a/cli/assets/scripts/generate/templates/Bootstrap.cs.template +++ b/cli/assets/scripts/generate/templates/Bootstrap.cs.template @@ -1,20 +1,16 @@ using GeneralUpdate.Core; -using GeneralUpdate.Common.Shared.Object; -using GeneralUpdate.Common.Download; +using GeneralUpdate.Core.Configuration; +using GeneralUpdate.Core.Download; -var config = new Configinfo +var config = new UpdateRequest { // === 必需 === UpdateUrl = "{{UPDATE_URL}}", AppSecretKey = "{{APP_SECRET_KEY}}", - AppName = "{{PROJECT_NAME}}.exe", MainAppName = "{{PROJECT_NAME}}.exe", ClientVersion = "{{CLIENT_VERSION}}", ProductId = "{{PRODUCT_ID}}", InstallPath = {{INSTALL_PATH}}, - - // === 可选 === - Encoding = System.Text.Encoding.UTF8, {{#BOWL}} // Bowl 配置(仅包含 GeneralUpdate.Bowl 包,不重复添加 Core) {{/BOWL}} diff --git a/cli/assets/scripts/generate/templates/DeploymentChecklist.md.template b/cli/assets/scripts/generate/templates/DeploymentChecklist.md.template index eaea255..2c6a224 100644 --- a/cli/assets/scripts/generate/templates/DeploymentChecklist.md.template +++ b/cli/assets/scripts/generate/templates/DeploymentChecklist.md.template @@ -7,7 +7,7 @@ Generated for: **{{STRATEGY_NAME}}** + **{{FRAMEWORK}}** | Bowl: **{{BOWL_UPPER} ## ✅ Pre-Deployment Checklist ### Bootstrap -- [ ] `Configinfo` 6 个必填字段都已设置 +- [ ] `UpdateRequest` 6 个必填字段都已设置 - [ ] `UpdateUrl` 已指向正确的服务端 API - [ ] `AppSecretKey` 长度 ≥ 32 字符 diff --git a/cli/assets/scripts/generate/templates/bowl_notice.cs.template b/cli/assets/scripts/generate/templates/bowl_notice.cs.template index 9c11ee2..1c37541 100644 --- a/cli/assets/scripts/generate/templates/bowl_notice.cs.template +++ b/cli/assets/scripts/generate/templates/bowl_notice.cs.template @@ -1,10 +1,16 @@ // ⚠️ Bowl 崩溃守护 — 使用 GeneralUpdate.Bowl,不单独引用 Core // dotnet add package GeneralUpdate.Bowl -var bowlParam = new GeneralUpdate.Bowl.MonitorParameter +// Refer to generalupdate-advanced/templates/BowlIntegration.cs for full example +var context = new GeneralUpdate.Bowl.BowlContext { ProcessNameOrId = "{{PROJECT_NAME}}.exe", TargetPath = {{INSTALL_PATH}}, + ExtendedField = "{{CLIENT_VERSION}}", + DumpFileName = "{{CLIENT_VERSION}}_fail.dmp", + FailFileName = "{{CLIENT_VERSION}}_fail.json", + FailDirectory = System.IO.Path.Combine({{INSTALL_PATH}}, "fail", "{{CLIENT_VERSION}}"), + BackupDirectory = System.IO.Path.Combine({{INSTALL_PATH}}, "{{CLIENT_VERSION}}"), WorkModel = "Upgrade", - FailDirectory = System.IO.Path.Combine({{INSTALL_PATH}}, "fail"), - BackupDirectory = System.IO.Path.Combine({{INSTALL_PATH}}, "backup"), + DumpType = GeneralUpdate.Bowl.DumpType.Mini, + AutoRestore = true, }; diff --git a/cli/assets/scripts/generate/templates/listeners_console.cs.template b/cli/assets/scripts/generate/templates/listeners_console.cs.template index 3472487..25f399b 100644 --- a/cli/assets/scripts/generate/templates/listeners_console.cs.template +++ b/cli/assets/scripts/generate/templates/listeners_console.cs.template @@ -9,7 +9,7 @@ }) .AddListenerMultiDownloadCompleted((_, e) => { - Console.WriteLine($"\n版本 {e.Version} 下载完成 (IsComplated={e.IsComplated})"); + Console.WriteLine($"\n版本 {e.Version} 下载完成 (IsCompleted={e.IsCompleted})"); }) .AddListenerMultiDownloadError((_, e) => { diff --git a/cli/assets/skills/generalupdate-advanced/templates/BowlIntegration.cs b/cli/assets/skills/generalupdate-advanced/templates/BowlIntegration.cs index 789a67e..169c026 100644 --- a/cli/assets/skills/generalupdate-advanced/templates/BowlIntegration.cs +++ b/cli/assets/skills/generalupdate-advanced/templates/BowlIntegration.cs @@ -3,32 +3,79 @@ using GeneralUpdate.Bowl; /// -/// 【Skill 参考】Bowl 崩溃守护 +/// Bowl crash daemon integration. /// -/// v10.5.0-beta.4 中 Bowl 使用 BowlContext 配置,支持 LaunchAsync 方法。 +/// Bowl monitors whether the main application starts normally after an upgrade. +/// If a crash is detected, it captures a dump, exports diagnostics, +/// and optionally restores the previous version from backup. /// /// NuGet: dotnet add package GeneralUpdate.Bowl --version 10.5.0-beta.4 +/// Note: Reference only GeneralUpdate.Bowl (it transitively includes Core). +/// Do NOT reference GeneralUpdate.Core separately when using Bowl. +/// +/// Platform prerequisites: +/// - Windows: Sysinternals procdump.exe is auto-bundled via Bowl NuGet package +/// - Linux: Requires procdump installed (sudo apt install procdump) /// public static class BowlIntegration { public static async Task RunBowlAsync() { + // Configure the surveillance context var context = new BowlContext { + // Process to monitor (name or PID) ProcessNameOrId = "MyApp.exe", - DumpFileName = "v1.0.0.0_fail.dmp", - FailFileName = "v1.0.0.0_fail.json", + + // Backup directory path (the version that was running before upgrade) TargetPath = @"C:\Program Files\MyApp", - FailDirectory = @"C:\Program Files\MyApp\fail", - BackupDirectory = @"C:\Program Files\MyApp\backup", + + // Version string, used to name dump/crash files + ExtendedField = "1.0.0.1", + + // Generated dump file path + DumpFileName = "1.0.0.1_fail.dmp", + + // Generated crash report file path + FailFileName = "1.0.0.1_fail.json", + + // Where dump/crash files will be written + FailDirectory = @"C:\Program Files\MyApp\fail\1.0.0.1", + + // Backup location (the previous version's backup that can be restored) + BackupDirectory = @"C:\Program Files\MyApp\1.0.0.0", + + // "Upgrade": integrated with update pipeline, auto-restores on crash + // "Normal": standalone monitoring, no restore WorkModel = "Upgrade", - TimeoutMs = 30_000, + + // Auto-restore the previous version on crash (only in "Upgrade" mode) AutoRestore = true, + + // Dump type: Full (0), Mini (1), or Heap (2) + DumpType = DumpType.Full, + + // Timeout for child process (procdump), default 30s + TimeoutMs = 30_000, + + // Optional: crash callback for custom handling (logging, telemetry, etc.) + // OnCrash = async (crashInfo, ct) => { ... }, }; + // Apply sensible defaults (Normalize fills in TimeoutMs, WorkModel, DumpType if zero) + context = context.Normalize(); + + // Start surveillance. This blocks until the monitored process exits. var bowl = new Bowl(); - var result = await bowl.LaunchAsync(context); + BowlResult result = await bowl.LaunchAsync(context); - Console.WriteLine($"[Bowl] 监控完成: Success={result.Success}, DumpCaptured={result.DumpCaptured}"); + Console.WriteLine($""" + [Bowl] 监控完成 + Success: {result.Success} + ExitCode: {result.ExitCode} + DumpCaptured: {result.DumpCaptured} + DumpFilePath: {result.DumpFilePath} + Restored: {result.Restored} + """); } } diff --git a/cli/package-lock.json b/cli/package-lock.json new file mode 100644 index 0000000..7c654ac --- /dev/null +++ b/cli/package-lock.json @@ -0,0 +1,348 @@ +{ + "name": "gskill-cli", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "gskill-cli", + "version": "0.1.0", + "dependencies": { + "chalk": "^5.3.0", + "commander": "^12.0.0", + "ora": "^8.0.0", + "prompts": "^2.4.2" + }, + "bin": { + "gskill": "dist/index.js" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "@types/prompts": "^2.4.0", + "typescript": "^5.4.0" + } + }, + "node_modules/@types/node": { + "version": "20.19.43", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz", + "integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/prompts": { + "version": "2.4.9", + "resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.4.9.tgz", + "integrity": "sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "kleur": "^3.0.3" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "license": "MIT" + }, + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/log-symbols": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", + "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "is-unicode-supported": "^1.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", + "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "cli-cursor": "^5.0.0", + "cli-spinners": "^2.9.2", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.0.0", + "log-symbols": "^6.0.0", + "stdin-discarder": "^0.2.2", + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "license": "MIT" + }, + "node_modules/stdin-discarder": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", + "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/cli/src/commands/uninstall.ts b/cli/src/commands/uninstall.ts index 6459496..780ee4b 100644 --- a/cli/src/commands/uninstall.ts +++ b/cli/src/commands/uninstall.ts @@ -98,11 +98,11 @@ export async function uninstallCommand(options: UninstallOptions): Promise if (aiType === 'all') { for (const type of initialDetected) { - const removed = await removeSkillDir(baseDir, type); + const removed = await removeSkillDir(baseDir, type as Exclude); allRemoved.push(...removed); } } else { - const removed = await removeSkillDir(baseDir, aiType); + const removed = await removeSkillDir(baseDir, aiType as Exclude); allRemoved.push(...removed); } diff --git a/skill.json b/skill.json index fa167ae..ac70fff 100644 --- a/skill.json +++ b/skill.json @@ -2,7 +2,7 @@ "name": "generalupdate-skill", "displayName": "GeneralUpdate Skill CodeGen", "description": "AI-powered skill suite for integrating GeneralUpdate (.NET auto-update) into any .NET application. Generates dual-project scaffolding (Client+Upgrade), full-state update UI (6 frameworks), 6 update strategies (Client-Server/OSS/Silent/Differential/CVP/Push), advanced extension points (Bowl crash daemon, IPC replacement, AOT), and deep troubleshooting (50+ known issues). All templates target NuGet v10.5.0-beta.4.", - "version": "0.0.1-beta.1", + "version": "0.0.2-beta.1", "author": "JusterZhu", "license": "Apache-2.0", "homepage": "https://github.com/GeneralLibrary/GeneralUpdate",