Skip to content

Commit 118717b

Browse files
JusterZhuJusterZhuclaude
authored
feat: GeneralUpdate Claude Code 技能套件(完整版) (#7)
* fix: resolve all 10 Copilot review comments 1. SemiUrsaClientView.axaml: Remove conv:StatusToVisibleConverter refs, use CanExecute for button visibility 2. DownloadViewModels.cs: Sync VersionText on stats change, clear SpeedText when not downloading 3. RealDownloadService.cs: Replace LaunchAsync() in CheckForUpdates with direct HTTP /Upgrade/Verification call (true check-only mode) 4. FullIntegration.cs: Add missing using directives (Event, Configuration), add hash length guard for truncation, fix speed unit duplication 5. reference.md: Fix framework version table (remove .NET Framework + .NET 8 conflation, use proper target framework monikers) 6. MinimalIntegration.cs: Fix System.Version comment accuracy 7. manifest.json: Remove JSON-invalid comment block, keep pure valid JSON Co-Authored-By: Claude <noreply@anthropic.com> * fix: address Copilot review comments — API contracts, filenames, and API references - Fix #1: RULES.md SetOption(Client) -> SetOption(AppType.Client) - Fix #2: RULES.md manifest.json -> generalupdate.manifest.json - Fix #3: backend-api.instructions.md add response wrapper { code, message, body } - Fix #4: troubleshoot curl endpoint /api/update/check -> POST /Upgrade/Verification - Fix #5: cursor/generalupdate-init.mdc manifest.json -> generalupdate.manifest.json - Fix #6: clinerules/01-generalupdate-init.md manifest.json -> generalupdate.manifest.json - Fix #7: troubleshoot LongPathSupport -> generic .NET long path guidance - Fix #8: troubleshoot ZipSecurity -> entry path validation behavior - Fix #9: troubleshoot SignalRRetryPolicy -> retry intent description Co-Authored-By: Claude <noreply@anthropic.com> * i18n: convert all Chinese comments and docs to English, make skills bilingual All code comments, XML docs, console log strings, UI labels, and documentation now use English (with bilingual status labels where helpful). Converted files include: - All 5 SKILL.md files (init/ui/strategy/advanced/troubleshoot) - All 6 strategy example .cs files - All 4 advanced template .cs files - All 3 project scaffold files - All 10+ UI template files (XAML/AXAML/CS) - reference.md and troubleshooting reference - All adapter files (.cursor/rules/, .clinerules/, .github/, RULES.md) Skills now support both English and Chinese-speaking developers through bilingual status labels in UI templates. Co-Authored-By: Claude <noreply@anthropic.com> * fix: resolve all 6 Copilot review comments on PR #7 1. MinimalIntegration.cs: Fix System.Version comment accuracy 2. RealDownloadService.cs: Accept _updateUrl as-is (no /Upgrade/Verification append), add tenantId, use TryGetProperty for response parsing, add productId param, lowercase platform values 3. NamedPipeIPC.cs: Use Environment.ProcessId for unique pipe name, enforce timeoutMs via linked CancellationTokenSource with TimeoutException 4. clinerules/05: Fix curl appType from 1 to 0, fix manifest path --------- Co-authored-by: JusterZhu <juster.zhu@example.com> Co-authored-by: Claude <noreply@anthropic.com>
1 parent 231c1c2 commit 118717b

31 files changed

Lines changed: 806 additions & 977 deletions

.claude/skills/generalupdate-advanced/templates/BowlIntegration.cs

Lines changed: 17 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,65 +2,44 @@
22
using GeneralUpdate.Core.Models;
33

44
/// <summary>
5-
/// 【Skill 自动生成】Bowl 崩溃守护集成
6-
///
7-
/// Bowl 是一个跨平台的崩溃监控助手,在升级完成后监控主应用的启动情况。
8-
/// 如果主应用崩溃,Bowl 会:
9-
/// 1. 生成 MiniDump 文件
10-
/// 2. 写入 CrashReport.json(崩溃诊断报告)
11-
/// 3. 可选:从备份自动回滚
12-
/// 4. 触发 OnCrash 回调
13-
///
14-
/// 使用方式:
15-
/// 在 Upgrade 完成后启动 Bowl(由 StartAppAsync 自动处理)
16-
/// 或者在主应用启动后手动调用 Bowl.LaunchAsync()
5+
/// [Skill Generated] Bowl crash daemon integration.
6+
/// Bowl monitors the main app after update. On crash it generates:
7+
/// - MiniDump (.dmp)
8+
/// - Crash report (.json)
9+
/// - System diagnostics (event log / drivers / system info)
10+
/// - Auto-restore from backup (optional)
1711
///
1812
/// NuGet: dotnet add package GeneralUpdate.Bowl
1913
///
20-
/// ⚠️ 注意事项:
21-
/// 1. Bowl 目前仅在 Windows 上充分测试
22-
/// 2. 回滚依赖于更新前的备份(BackupEnabled = true
23-
/// 3. 备份保留最多 3 个版本
24-
/// 4. Bowl 需要使用 procdump 工具(Windows
14+
/// Notes:
15+
/// - Bowl is fully tested on Windows only
16+
/// - Rollback depends on BackupEnabled = true
17+
/// - Keeps only the 3 most recent backups
18+
/// - Requires procdump tool (Windows)
2519
/// </summary>
2620
public static class BowlIntegration
2721
{
28-
/// <summary>
29-
/// 启动 Bowl 崩溃守护
30-
/// </summary>
3122
public static async Task StartBowlAsync(string appPath, string installPath)
3223
{
33-
Console.WriteLine("[Bowl] 启动崩溃守护进程...");
24+
Console.WriteLine("[Bowl] Starting crash daemon...");
3425

3526
var bowl = new Bowl();
36-
37-
// 注册崩溃回调
3827
bowl.OnCrash += (crashReport) =>
3928
{
40-
Console.WriteLine($"[Bowl] 检测到崩溃!");
41-
Console.WriteLine($"[Bowl] 原因: {crashReport.CrashReason}");
42-
Console.WriteLine($"[Bowl] Dump 文件: {crashReport.DumpFilePath}");
29+
Console.WriteLine($"[Bowl] Crash detected!");
30+
Console.WriteLine($"[Bowl] Reason: {crashReport.CrashReason}");
31+
Console.WriteLine($"[Bowl] Dump file: {crashReport.DumpFilePath}");
4332

44-
// 自动回滚(前提是有备份)
4533
if (crashReport.AutoRestore)
46-
{
47-
Console.WriteLine("[Bowl] 正在回滚到备份版本...");
48-
// Bowl 会自动从备份目录恢复
49-
}
34+
Console.WriteLine("[Bowl] Restoring from backup...");
5035
};
5136

52-
// 启动监控
5337
await bowl.LaunchAsync(new BowlOptions
5438
{
55-
// 要监控的主应用路径
5639
TargetAppPath = appPath,
57-
// 安装目录(用于定位备份)
5840
InstallPath = installPath,
59-
// 启用自动回滚
6041
AutoRestore = true,
61-
// 崩溃报告输出目录
62-
ReportOutputPath = Path.Combine(
63-
installPath, "CrashReports")
42+
ReportOutputPath = Path.Combine(installPath, "CrashReports")
6443
});
6544
}
6645
}

.claude/skills/generalupdate-advanced/templates/CustomHooks.cs

Lines changed: 22 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,98 +2,70 @@
22
using GeneralUpdate.Core.Models;
33

44
/// <summary>
5-
/// 【Skill 自动生成】自定义生命周期 Hooks
5+
/// [Skill Generated] Custom lifecycle hooks.
6+
/// Implements IUpdateHooks for full lifecycle control.
7+
/// All methods have default implementations (return null/true) — override only what you need.
68
///
7-
/// 实现 IUpdateHooks 接口,在更新的各个生命周期阶段插入自定义逻辑。
8-
/// 所有方法都有默认实现(返回 null/true),只需重写需要的方法。
9-
///
10-
/// 使用方式:
9+
/// Usage:
1110
/// .Hooks<MyCustomHooks>()
1211
/// </summary>
1312
public class MyCustomHooks : IUpdateHooks
1413
{
15-
/// <summary>
16-
/// 更新开始前调用。返回 false 中止更新。
17-
/// 可用于:检查磁盘空间、检查是否在营业时间、用户确认等。
18-
/// </summary>
14+
/// <summary>Called before update starts. Return false to abort.</summary>
1915
public async Task<bool> OnBeforeUpdateAsync(UpdateContext context)
2016
{
21-
Console.WriteLine($"[Hooks] 开始更新: {context.CurrentVersion} {context.LastVersion}");
17+
Console.WriteLine($"[Hooks] Update starting: {context.CurrentVersion} -> {context.LastVersion}");
2218

23-
// 检查磁盘空间
19+
// Check disk space
2420
var drive = new DriveInfo(Path.GetPathRoot(context.InstallPath)!);
25-
if (drive.AvailableFreeSpace < 100 * 1024 * 1024) // 100MB 最低要求
21+
if (drive.AvailableFreeSpace < 100 * 1024 * 1024)
2622
{
27-
Console.WriteLine("[Hooks] 磁盘空间不足,中止更新");
23+
Console.WriteLine("[Hooks] Insufficient disk space, aborting");
2824
return false;
2925
}
3026

31-
return true; // true = 继续更新
27+
return true;
3228
}
3329

34-
/// <summary>
35-
/// 下载完成后调用(在 Client 进程)
36-
/// 可用于:下载后扫描、日志记录、通知 UI
37-
/// </summary>
30+
/// <summary>Called after download completes (Client process).</summary>
3831
public async Task OnDownloadCompletedAsync(UpdateContext context)
3932
{
40-
Console.WriteLine($"[Hooks] 下载完成: {context.LastVersion}");
41-
// 可以在这里触发 UI 通知
33+
Console.WriteLine($"[Hooks] Download complete: {context.LastVersion}");
4234
await Task.CompletedTask;
4335
}
4436

45-
/// <summary>
46-
/// 更新完成后调用(在 Upgrade 进程,替换文件后)
47-
/// 可用于:清理临时文件、更新数据库 schema、迁移用户配置
48-
/// </summary>
37+
/// <summary>Called after update applies (Upgrade process). Clean up temp files, migrate configs.</summary>
4938
public async Task OnAfterUpdateAsync(UpdateContext context)
5039
{
51-
Console.WriteLine($"[Hooks] 更新完成: {context.LastVersion}");
52-
53-
// 清理临时文件
40+
Console.WriteLine($"[Hooks] Update complete: {context.LastVersion}");
5441
var tempDir = context.UpdatePath;
5542
if (Directory.Exists(tempDir))
56-
{
57-
try { Directory.Delete(tempDir, true); }
58-
catch { /* 忽略清理中的错误 */ }
59-
}
60-
43+
try { Directory.Delete(tempDir, true); } catch { }
6144
await Task.CompletedTask;
6245
}
6346

64-
/// <summary>
65-
/// 更新过程出错时调用
66-
/// 可用于:错误日志、通知管理员、触发回滚
67-
/// </summary>
47+
/// <summary>Called on update error. Log the error, notify admin, trigger rollback.</summary>
6848
public async Task OnUpdateErrorAsync(UpdateContext context, Exception exception)
6949
{
70-
Console.WriteLine($"[Hooks] 更新失败: {exception.Message}");
71-
// 记录错误日志
72-
File.WriteAllText(
73-
Path.Combine(context.InstallPath, "update_error.log"),
50+
Console.WriteLine($"[Hooks] Update failed: {exception.Message}");
51+
File.WriteAllText(Path.Combine(context.InstallPath, "update_error.log"),
7452
$"[{DateTime.UtcNow}] {exception}");
7553
await Task.CompletedTask;
7654
}
7755

78-
/// <summary>
79-
/// 启动主应用前调用(在 Upgrade 进程)
80-
/// 可用于:修改配置文件、设置环境变量、检查版本兼容性
81-
/// 返回 false 阻止主应用启动
82-
/// </summary>
56+
/// <summary>Called before starting the main app. Return false to prevent launch.</summary>
8357
public async Task<bool> OnBeforeStartAppAsync(UpdateContext context)
8458
{
85-
Console.WriteLine($"[Hooks] 准备启动主应用: {context.MainAppName}");
59+
Console.WriteLine($"[Hooks] Preparing to launch: {context.MainAppName}");
8660

87-
// Linux/MacOS 上设置可执行权限
61+
// Set executable permissions on Linux/macOS
8862
if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
8963
{
9064
var appPath = Path.Combine(context.InstallPath, context.MainAppName ?? "");
9165
if (File.Exists(appPath))
92-
{
9366
await UnixPermissionHooks.SetExecutablePermissionAsync(appPath);
94-
}
9567
}
9668

97-
return true; // true = 启动主应用
69+
return true;
9870
}
9971
}

.claude/skills/generalupdate-advanced/templates/CustomStrategy.cs

Lines changed: 18 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2,74 +2,52 @@
22
using GeneralUpdate.Core.Pipeline;
33

44
/// <summary>
5-
/// 【Skill 自动生成】自定义平台更新策略
5+
/// [Skill Generated] Custom platform update strategy.
6+
/// Completely replaces default strategies (WindowsStrategy / LinuxStrategy / MacStrategy).
67
///
7-
/// 完全替换 GeneralUpdate 的默认策略(WindowsStrategy / LinuxStrategy / MacStrategy)。
8-
/// 适用于需要完全控制更新行为的场景。
9-
///
10-
/// 使用方式:
8+
/// Usage:
119
/// .Strategy<MyCustomStrategy>()
12-
///
13-
/// IStrategy 接口主要方法:
14-
/// - ExecuteAsync(UpdateContext):执行策略主体
15-
/// - StartAppAsync(UpdateContext):启动主应用
1610
/// </summary>
1711
public class MyCustomStrategy : AbstractStrategy
1812
{
19-
/// <summary>
20-
/// 自定义策略入口
21-
/// </summary>
2213
public override async Task ExecuteAsync(UpdateContext context)
2314
{
24-
Console.WriteLine("[CustomStrategy] 执行自定义更新策略");
15+
Console.WriteLine("[CustomStrategy] Executing custom update strategy");
2516

26-
// 1. 前置检查
17+
// 1. Pre-update check
2718
if (await Hooks.SafeOnBeforeUpdateAsync(context) == false)
2819
{
29-
Console.WriteLine("[CustomStrategy] 前置检查未通过,中止更新");
20+
Console.WriteLine("[CustomStrategy] Pre-check failed, aborting");
3021
return;
3122
}
3223

33-
// 2. 对每个版本执行管道
24+
// 2. Process each version through the pipeline
3425
foreach (var version in context.UpdateVersions)
3526
{
36-
Console.WriteLine($"[CustomStrategy] 处理版本: {version.Version}");
27+
Console.WriteLine($"[CustomStrategy] Processing version: {version.Version}");
3728

38-
// 2a. 构建管道(可自定义)
3929
var pipeline = new PipelineBuilder(context)
40-
.UseMiddleware<HashMiddleware>() // SHA256 校验
41-
.UseMiddleware<CompressMiddleware>() // 解压 ZIP
30+
.UseMiddleware<HashMiddleware>()
31+
.UseMiddleware<CompressMiddleware>()
4232
.Build();
4333

44-
// 2b. 执行管道
4534
await pipeline.ExecuteAsync(context, version);
46-
47-
Console.WriteLine($"[CustomStrategy] 版本 {version.Version} 处理完成");
35+
Console.WriteLine($"[CustomStrategy] Version {version.Version} done");
4836
}
4937

50-
// 3. 后置处理
38+
// 3. Post-update
5139
await Hooks.SafeOnAfterUpdateAsync(context);
5240

53-
// 4. 启动主应用
41+
// 4. Start main app
5442
await StartAppAsync(context);
5543
}
5644

57-
/// <summary>
58-
/// 启动主应用
59-
/// </summary>
6045
public override async Task StartAppAsync(UpdateContext context)
6146
{
62-
Console.WriteLine("[CustomStrategy] 启动主应用");
63-
64-
var appPath = Path.Combine(
65-
context.InstallPath,
66-
context.MainAppName ?? "MyApp.exe");
67-
47+
Console.WriteLine("[CustomStrategy] Starting main app");
48+
var appPath = Path.Combine(context.InstallPath, context.MainAppName ?? "MyApp.exe");
6849
if (!File.Exists(appPath))
69-
{
70-
throw new FileNotFoundException(
71-
$"主应用不存在: {appPath}");
72-
}
50+
throw new FileNotFoundException($"App not found: {appPath}");
7351

7452
var process = Process.Start(new ProcessStartInfo
7553
{
@@ -79,17 +57,11 @@ public override async Task StartAppAsync(UpdateContext context)
7957
});
8058

8159
if (process == null)
82-
{
83-
throw new InvalidOperationException(
84-
$"无法启动主应用: {appPath}");
85-
}
60+
throw new InvalidOperationException($"Failed to start: {appPath}");
8661

87-
Console.WriteLine($"[CustomStrategy] 主应用已启动 (PID: {process.Id})");
62+
Console.WriteLine($"[CustomStrategy] App started (PID: {process.Id})");
8863
}
8964

90-
/// <summary>
91-
/// 实现原样退出
92-
/// </summary>
9365
public override async Task ExecuteAsync(UpdateContext context, string pipeHandle)
9466
{
9567
await ExecuteAsync(context);

0 commit comments

Comments
 (0)