Skip to content

Commit 99f12f6

Browse files
JusterZhuclaude
andauthored
feat: complete GeneralUpdate Skill CodeGen v2 — 7 skills, BM25 search, 336 codegen combos, CLI (#15)
* 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> * chore: add .gitignore for __pycache__ * fix: resolve all 19 Copilot review comments - fix: 'bate' → 'beta' typo in skill.json, plugin.json, marketplace.json - fix: skill.json version desc v10.4.6 → v10.5.0-beta.4 - fix: template.ts missing readFile import, platform path hardcoding - fix: init.ts --ai all now routes to generateAllPlatformFiles - fix: generate.ts command injection (execSync→spawnSync+argv) - fix: extract.ts path injection (exec→execFile) - fix: _sync_all.py filecmp shallow=False + --verify detects NEEDS SYNC - fix: release.yml Windows paths on Linux runner - fix: sync CLI assets after source changes Co-Authored-By: Claude <noreply@anthropic.com --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 29c3794 commit 99f12f6

121 files changed

Lines changed: 10381 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-beta.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.5.0-beta.4.",
16+
"version": "0.0.1-beta.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.5.0-beta.4.",
4+
"version": "0.0.1-beta.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: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
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():
43+
if src.is_file():
44+
up_to_date = filecmp.cmp(src, dst, shallow=False)
45+
else:
46+
up_to_date = _dirs_equal(src, dst)
47+
if up_to_date:
48+
return f"✓ UP TO DATE: {src.relative_to(REPO_ROOT)}"
49+
50+
if dry_run or not apply:
51+
return f"→ NEEDS SYNC: {src.relative_to(REPO_ROOT)}{dst.relative_to(REPO_ROOT)}"
52+
53+
# Apply the sync
54+
dst.parent.mkdir(parents=True, exist_ok=True)
55+
if src.is_file():
56+
shutil.copy2(src, dst)
57+
else:
58+
if dst.exists():
59+
shutil.rmtree(dst)
60+
shutil.copytree(src, dst)
61+
return f"✅ SYNCED: {src.relative_to(REPO_ROOT)}"
62+
63+
64+
def _dirs_equal(a: Path, b: Path) -> bool:
65+
"""Check if all files in source exist and match in destination (b may have extras)."""
66+
if not b.exists():
67+
return False
68+
69+
def _files(p: Path):
70+
return sorted(
71+
(f for f in p.rglob("*") if f.is_file() and "__pycache__" not in str(f)),
72+
key=lambda x: str(x).lower(),
73+
)
74+
75+
afiles = _files(a)
76+
77+
for fa in afiles:
78+
rel = fa.relative_to(a)
79+
fb = b / rel
80+
if not fb.exists():
81+
return False
82+
if not filecmp.cmp(fa, fb, shallow=False):
83+
return False
84+
85+
return True
86+
87+
88+
def main():
89+
parser = argparse.ArgumentParser(description="Sync .claude/ source to cli/assets/")
90+
parser.add_argument("--apply", action="store_true", help="Actually copy files (default: dry-run)")
91+
parser.add_argument("--verify", action="store_true", help="Only check, exit 1 if out of sync")
92+
args = parser.parse_args()
93+
94+
dry_run = not args.apply
95+
if dry_run and not args.verify:
96+
print("═══ DRY RUN ═══ Use --apply to actually copy\n")
97+
98+
statuses = []
99+
all_ok = True
100+
101+
for src_rel, dst_rel, desc in SYNC_MAP:
102+
src = CLAUDE_DIR / src_rel
103+
dst = CLI_ASSETS_DIR / dst_rel
104+
status = sync_file(src, dst, args.apply, dry_run)
105+
statuses.append((desc, status))
106+
if status.startswith("⚠️"):
107+
all_ok = False
108+
109+
print(f"\n═══ Summary ({'DRY RUN' if dry_run else 'APPLIED'}) ═══\n")
110+
for desc, status in statuses:
111+
print(f" {status}")
112+
113+
if args.verify:
114+
needs_sync = any(status.startswith("→") for _, status in statuses)
115+
if not all_ok or needs_sync:
116+
print("\n❌ Verify FAILED: sources are out of sync")
117+
sys.exit(1)
118+
print("\n✅ Verify PASSED: all sources are in sync")
119+
sys.exit(0)
120+
121+
122+
if __name__ == "__main__":
123+
main()

0 commit comments

Comments
 (0)