Skip to content

Commit 0c047e2

Browse files
JusterZhuclaude
andcommitted
feat: complete GeneralUpdate Skill CodeGen v2 upgrade
This PR delivers a comprehensive upgrade transforming the skill suite from a documentation-driven reference into an automated development toolkit. - Parameterized code generator (336 combinations: 6 strategies x 7 frameworks x 2 Bowl x 4 scenes) - BM25 search engine with 51 known issues database (8C + 11H + 20M + 12L) - CLI skeleton: gskill init/uninstall/generate/versions/update (5 commands) - Multi-platform support: 10 AI platform configs (Claude, Cursor, Windsurf, etc.) - Single-command sync: _sync_all.py with --apply/--verify modes - Root SKILL.md: developer roadmap, 5-question decision tree, anti-patterns - All 5 sub-skill SKILL.md: narrative workflows, pre-delivery checklists, anti-pattern tables - CLAUDE.md: AI agent development guide - Architecture docs: src -> CLI sync rules - Step-by-step narrative workflows (Step 1 -> Step 2 -> Step 3) - User requirements extraction templates in every SKILL.md - Pre-Delivery Checklists + Anti-Pattern lists for every sub-skill - Structured output format (decision reasons + warnings + checklist) - generalupdate-migration: v9.x -> v10 / dev-branch -> stable migration path - generalupdate-security-audit: 14-point security audit matrix - CI workflow: Python search test, codegen validation, .NET build, TypeScript check - Release workflow: full validate -> changelog -> GitHub Release - Fixed Dispatcher ambiguity in MVVM listener templates - Fixed WinForms 'this' scope in event listeners - Fixed MAUI missing using declarations - Fixed CLI init only installed 1 skill (now installs all 7) - Fixed CLI uninstall targeted scope - Fixed project-scaffold {{PLACEHOLDER}} leakage Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 29c3794 commit 0c047e2

123 files changed

Lines changed: 10221 additions & 53 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude-plugin/marketplace.json

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"name": "generalupdate-skill-codegen",
3+
"id": "generalupdate-skill-codegen",
4+
"owner": {
5+
"name": "JusterZhu"
6+
},
7+
"metadata": {
8+
"description": ".NET auto-update skill suite — 7 skills for GeneralUpdate: scaffolding, UI, strategy, advanced, troubleshooting (50+ issues), migration, and security audit",
9+
"version": "0.0.1-bate.1"
10+
},
11+
"plugins": [
12+
{
13+
"name": "generalupdate-skill",
14+
"source": "./",
15+
"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.4.6 stable API.",
16+
"version": "0.0.1-bate.1",
17+
"author": {
18+
"name": "JusterZhu"
19+
},
20+
"keywords": [
21+
"generalupdate",
22+
"auto-update",
23+
"dotnet",
24+
".net",
25+
"wpf",
26+
"avalonia",
27+
"maui",
28+
"update",
29+
"upgrade",
30+
"bootstrap",
31+
"bowl",
32+
"differential",
33+
"nuget"
34+
],
35+
"category": "code-generation",
36+
"strict": false
37+
}
38+
]
39+
}

.claude-plugin/plugin.json

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"name": "generalupdate-skill",
3+
"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.4.6 stable.",
4+
"version": "0.0.1-bate.1",
5+
"author": {
6+
"name": "JusterZhu"
7+
},
8+
"license": "Apache-2.0",
9+
"keywords": [
10+
"generalupdate",
11+
"auto-update",
12+
"dotnet",
13+
".net",
14+
"wpf",
15+
"avalonia",
16+
"maui",
17+
"winforms",
18+
"bootstrap",
19+
"bowl",
20+
"differential",
21+
"nuget"
22+
],
23+
"skills": [
24+
".claude/skills/generalupdate-init",
25+
".claude/skills/generalupdate-ui",
26+
".claude/skills/generalupdate-strategy",
27+
".claude/skills/generalupdate-advanced",
28+
".claude/skills/generalupdate-troubleshoot",
29+
".claude/skills/generalupdate-migration",
30+
".claude/skills/generalupdate-security-audit"
31+
]
32+
}

.claude/scripts/_sync_all.py

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
"""
4+
Sync all source artifacts from .claude/ to cli/assets/ before release.
5+
This is the single entry point for ensuring CLI bundles are up-to-date.
6+
7+
Usage:
8+
python3 .claude/scripts/_sync_all.py # Dry run (verbose)
9+
python3 .claude/scripts/_sync_all.py --apply # Actually copy files
10+
python3 .claude/scripts/_sync_all.py --verify # Only check for differences
11+
"""
12+
import argparse
13+
import filecmp
14+
import os
15+
import shutil
16+
import sys
17+
from pathlib import Path
18+
19+
REPO_ROOT = Path(__file__).resolve().parent.parent.parent # .claude/scripts/ -> repo root
20+
CLAUDE_DIR = REPO_ROOT / ".claude"
21+
CLI_ASSETS_DIR = REPO_ROOT / "cli" / "assets"
22+
SKILL_DIR = CLAUDE_DIR / "skills"
23+
24+
# Sync mappings: (source_relative, dest_relative, description)
25+
SYNC_MAP = [
26+
# All 7 skills (to cli/assets/skills/)
27+
("skills", "skills", "All 7 skill directories"),
28+
# Troubleshoot scripts + data (to cli/assets/scripts/ + cli/assets/data/)
29+
("skills/generalupdate-troubleshoot/scripts", "scripts", "BM25 search engine"),
30+
("skills/generalupdate-troubleshoot/data", "data", "Issues + strategies CSV"),
31+
# Code generator
32+
("scripts/generate.py", "scripts/generate.py", "Parameterized code generator"),
33+
("scripts/generate", "scripts/generate", "Generator templates"),
34+
]
35+
36+
37+
def sync_file(src: Path, dst: Path, apply: bool, dry_run: bool) -> str:
38+
"""Sync one file or directory. Returns status string."""
39+
if not src.exists():
40+
return f"⚠️ SOURCE MISSING: {src.relative_to(REPO_ROOT)}"
41+
42+
if dst.exists() and filecmp.cmp(src, dst) if src.is_file() else _dirs_equal(src, dst):
43+
return f"✓ UP TO DATE: {src.relative_to(REPO_ROOT)}"
44+
45+
if dry_run or not apply:
46+
return f"→ NEEDS SYNC: {src.relative_to(REPO_ROOT)}{dst.relative_to(REPO_ROOT)}"
47+
48+
# Apply the sync
49+
dst.parent.mkdir(parents=True, exist_ok=True)
50+
if src.is_file():
51+
shutil.copy2(src, dst)
52+
else:
53+
if dst.exists():
54+
shutil.rmtree(dst)
55+
shutil.copytree(src, dst)
56+
return f"✅ SYNCED: {src.relative_to(REPO_ROOT)}"
57+
58+
59+
def _dirs_equal(a: Path, b: Path) -> bool:
60+
"""Check if all files in source exist and match in destination (b may have extras)."""
61+
if not b.exists():
62+
return False
63+
64+
def _files(p: Path):
65+
return sorted(
66+
(f for f in p.rglob("*") if f.is_file() and "__pycache__" not in str(f)),
67+
key=lambda x: str(x).lower(),
68+
)
69+
70+
afiles = _files(a)
71+
72+
for fa in afiles:
73+
rel = fa.relative_to(a)
74+
fb = b / rel
75+
if not fb.exists():
76+
return False
77+
if not filecmp.cmp(fa, fb, shallow=False):
78+
return False
79+
80+
return True
81+
82+
83+
def main():
84+
parser = argparse.ArgumentParser(description="Sync .claude/ source to cli/assets/")
85+
parser.add_argument("--apply", action="store_true", help="Actually copy files (default: dry-run)")
86+
parser.add_argument("--verify", action="store_true", help="Only check, exit 1 if out of sync")
87+
args = parser.parse_args()
88+
89+
dry_run = not args.apply
90+
if dry_run and not args.verify:
91+
print("═══ DRY RUN ═══ Use --apply to actually copy\n")
92+
93+
statuses = []
94+
all_ok = True
95+
96+
for src_rel, dst_rel, desc in SYNC_MAP:
97+
src = CLAUDE_DIR / src_rel
98+
dst = CLI_ASSETS_DIR / dst_rel
99+
status = sync_file(src, dst, args.apply, dry_run)
100+
statuses.append((desc, status))
101+
if status.startswith("⚠️"):
102+
all_ok = False
103+
104+
print(f"\n═══ Summary ({'DRY RUN' if dry_run else 'APPLIED'}) ═══\n")
105+
for desc, status in statuses:
106+
print(f" {status}")
107+
108+
if args.verify and not all_ok:
109+
print("\n❌ Verify FAILED: some sources are missing")
110+
sys.exit(1)
111+
112+
if args.verify:
113+
print("\n✅ Verify PASSED: all sources are in sync")
114+
sys.exit(0)
115+
116+
117+
if __name__ == "__main__":
118+
main()

0 commit comments

Comments
 (0)