From 3a35eae8830b64579d7aa1908fbc458c9e11c2f5 Mon Sep 17 00:00:00 2001 From: Derek Pearson Date: Sun, 22 Mar 2026 06:52:55 -0400 Subject: [PATCH] feat(skills): add 11 new skill packs covering major frameworks and languages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New skill packs with auto-detection: - Java & Spring Boot (github/awesome-copilot, 9.1K installs) - .NET & C# (github/awesome-copilot, 8.1K installs) — scans for *.csproj/*.sln - Flutter (flutter/skills, official, 54.6K total) - Angular (analogjs/angular-skills, official, 33.5K total) - Vue.js (vuejs-ai/skills, official, 30.7K total) — triggers on nuxt.config.* - Svelte (sveltejs/ai-tools, official, 3.1K total) - Next.js (vercel-labs/vercel-plugin, official) — triggers on next.config.* - Docker (github/awesome-copilot, 8.3K installs) - Terraform (hashicorp/agent-skills, official, 9.4K total) - Django (vintasoftware/django-ai-plugins, 2.2K total) - PHP & Laravel (jeffallan/claude-skills, 10.1K total) Detection additions: - PROJECT_FILES: angular.json, next.config.*, nuxt.config.*, svelte.config.*, Dockerfile, docker-compose.*, main.tf, manage.py, requirements.txt - Extension scanning: *.csproj/*.sln/*.fsproj for .NET detection - LANGUAGE_MAP: manage.py and requirements.txt → python - GREENFIELD_STACKS: Angular, Vue, Svelte, Next.js, Flutter, Java, .NET, PHP, Django entries - 8 new detection tests (36 total, up from 28) --- src/resources/extensions/gsd/detection.ts | 33 +++- src/resources/extensions/gsd/skill-catalog.ts | 162 ++++++++++++++++++ .../extensions/gsd/tests/detection.test.ts | 94 ++++++++++ 3 files changed, 286 insertions(+), 3 deletions(-) diff --git a/src/resources/extensions/gsd/detection.ts b/src/resources/extensions/gsd/detection.ts index 014ecc510..a78186887 100644 --- a/src/resources/extensions/gsd/detection.ts +++ b/src/resources/extensions/gsd/detection.ts @@ -109,6 +109,24 @@ export const PROJECT_FILES = [ "metro.config.js", "metro.config.ts", "react-native.config.js", + // Frontend framework config files + "angular.json", + "next.config.js", + "next.config.ts", + "next.config.mjs", + "nuxt.config.ts", + "nuxt.config.js", + "svelte.config.js", + "svelte.config.ts", + // Container / DevOps config files + "Dockerfile", + "docker-compose.yml", + "docker-compose.yaml", + // Infrastructure as Code + "main.tf", + // Python framework markers + "manage.py", + "requirements.txt", ] as const; /** File extensions that indicate SQLite databases in the project. */ @@ -117,6 +135,9 @@ const SQLITE_EXTENSIONS = [".sqlite", ".sqlite3", ".db"] as const; /** File extensions that indicate SQL usage (migrations, schemas, seeds). */ const SQL_EXTENSIONS = [".sql"] as const; +/** File extensions that indicate .NET / C# projects. */ +const DOTNET_EXTENSIONS = [".csproj", ".sln", ".fsproj"] as const; + const LANGUAGE_MAP: Record = { "package.json": "javascript/typescript", "Cargo.toml": "rust", @@ -134,6 +155,8 @@ const LANGUAGE_MAP: Record = { "mix.exs": "elixir", "deno.json": "typescript/deno", "deno.jsonc": "typescript/deno", + "manage.py": "python", + "requirements.txt": "python", }; const MONOREPO_MARKERS = [ @@ -289,9 +312,9 @@ export function detectProjectSignals(basePath: string): ProjectSignals { } } - // SQLite / SQL file detection — scan root entries for database file extensions. - // Adds synthetic markers (e.g. "*.sqlite", "*.sql") to detectedFiles so - // skill catalog matchFiles can reference them. + // SQLite / SQL / .NET file detection — scan root entries for file extensions. + // Adds synthetic markers (e.g. "*.sqlite", "*.sql", "*.csproj") to detectedFiles + // so skill catalog matchFiles can reference them. try { const rootEntries = readdirSync(basePath); if (rootEntries.some((e) => SQLITE_EXTENSIONS.some((ext) => e.endsWith(ext)))) { @@ -300,6 +323,10 @@ export function detectProjectSignals(basePath: string): ProjectSignals { if (rootEntries.some((e) => SQL_EXTENSIONS.some((ext) => e.endsWith(ext)))) { detectedFiles.push("*.sql"); } + if (rootEntries.some((e) => DOTNET_EXTENSIONS.some((ext) => e.endsWith(ext)))) { + detectedFiles.push("*.csproj"); + if (!primaryLanguage) primaryLanguage = "csharp"; + } } catch { // unreadable root — skip extension scan } diff --git a/src/resources/extensions/gsd/skill-catalog.ts b/src/resources/extensions/gsd/skill-catalog.ts index d9148cdda..12f2102df 100644 --- a/src/resources/extensions/gsd/skill-catalog.ts +++ b/src/resources/extensions/gsd/skill-catalog.ts @@ -202,6 +202,98 @@ export const SKILL_CATALOG: SkillPack[] = [ skills: ["frontend-design"], matchLanguages: ["javascript/typescript"], }, + // ── Angular ─────────────────────────────────────────────────────────────── + { + label: "Angular", + description: "Angular components, signals, forms, routing, and testing", + repo: "analogjs/angular-skills", + skills: [ + "angular-component", + "angular-signals", + "angular-forms", + "angular-routing", + "angular-testing", + ], + matchFiles: ["angular.json"], + }, + // ── Vue.js / Nuxt ──────────────────────────────────────────────────────── + { + label: "Vue.js", + description: "Vue best practices, Pinia state, Vue Router, and testing", + repo: "vuejs-ai/skills", + skills: [ + "vue-best-practices", + "vue-pinia-best-practices", + "vue-router-best-practices", + "vue-testing-best-practices", + ], + matchFiles: ["nuxt.config.ts", "nuxt.config.js"], + }, + // ── Svelte / SvelteKit ──────────────────────────────────────────────────── + { + label: "Svelte", + description: "Svelte code patterns and SvelteKit best practices", + repo: "sveltejs/ai-tools", + skills: ["svelte-code-writer", "svelte-core-bestpractices"], + matchFiles: ["svelte.config.js", "svelte.config.ts"], + }, + // ── Next.js ─────────────────────────────────────────────────────────────── + { + label: "Next.js", + description: "Next.js app router, server components, and deployment patterns", + repo: "vercel-labs/vercel-plugin", + skills: ["nextjs"], + matchFiles: ["next.config.js", "next.config.ts", "next.config.mjs"], + }, + // ── Java / Spring Boot ──────────────────────────────────────────────────── + { + label: "Java & Spring Boot", + description: "Spring Boot best practices, DI, RESTful APIs, JPA, testing, and security", + repo: "github/awesome-copilot", + skills: ["java-springboot"], + matchLanguages: ["java", "java/kotlin"], + matchFiles: ["pom.xml", "build.gradle", "build.gradle.kts"], + }, + // ── .NET / C# ──────────────────────────────────────────────────────────── + { + label: ".NET & C#", + description: ".NET best practices, design patterns, and upgrade guidance", + repo: "github/awesome-copilot", + skills: ["dotnet-best-practices", "dotnet-design-pattern-review"], + matchLanguages: ["csharp"], + matchFiles: ["*.csproj"], + }, + // ── Flutter / Dart ──────────────────────────────────────────────────────── + { + label: "Flutter", + description: "Flutter layouts, architecture, state management, and testing", + repo: "flutter/skills", + skills: [ + "flutter-building-layouts", + "flutter-architecting-apps", + "flutter-managing-state", + "flutter-testing-apps", + ], + matchLanguages: ["dart/flutter"], + matchFiles: ["pubspec.yaml"], + }, + // ── PHP / Laravel ───────────────────────────────────────────────────────── + { + label: "PHP & Laravel", + description: "Laravel patterns, PHP best practices, and testing", + repo: "jeffallan/claude-skills", + skills: ["laravel-specialist", "php-pro"], + matchLanguages: ["php"], + matchFiles: ["composer.json"], + }, + // ── Django ──────────────────────────────────────────────────────────────── + { + label: "Django", + description: "Django expert patterns, models, views, and middleware", + repo: "vintasoftware/django-ai-plugins", + skills: ["django-expert"], + matchFiles: ["manage.py"], + }, // ── Rust ────────────────────────────────────────────────────────────────── { label: "Rust", @@ -303,6 +395,22 @@ export const SKILL_CATALOG: SkillPack[] = [ skills: ["deploy", "aws-lambda", "aws-serverless-deployment"], matchFiles: ["cdk.json", "samconfig.toml", "serverless.yml", "serverless.yaml"], }, + // ── Container / DevOps ───────────────────────────────────────────────────── + { + label: "Docker", + description: "Multi-stage Dockerfiles, layer optimization, and security hardening", + repo: "github/awesome-copilot", + skills: ["multi-stage-dockerfile"], + matchFiles: ["Dockerfile", "docker-compose.yml", "docker-compose.yaml"], + }, + // ── Infrastructure as Code ───────────────────────────────────────────────── + { + label: "Terraform", + description: "Terraform style guide, testing, and stack patterns", + repo: "hashicorp/agent-skills", + skills: ["terraform-style-guide", "terraform-test", "terraform-stacks"], + matchFiles: ["main.tf"], + }, // ── Essential (all projects) ──────────────────────────────────────────── { label: "Skill Discovery", @@ -427,6 +535,60 @@ export const GREENFIELD_STACKS: Array<{ description: "Azure deployment, AI, storage, diagnostics", packs: ["Azure"], }, + { + id: "angular", + label: "Angular", + description: "Angular components, signals, forms, routing", + packs: ["Angular", "Frontend Design & UX"], + }, + { + id: "vue", + label: "Vue.js / Nuxt", + description: "Vue.js with Pinia, Vue Router, and testing", + packs: ["Vue.js", "Frontend Design & UX"], + }, + { + id: "svelte", + label: "Svelte / SvelteKit", + description: "Svelte 5 and SvelteKit patterns", + packs: ["Svelte", "Frontend Design & UX"], + }, + { + id: "nextjs", + label: "Next.js", + description: "Next.js app router, React, and Vercel deployment", + packs: ["Next.js", "React & Web Frontend", "shadcn/ui"], + }, + { + id: "flutter", + label: "Flutter", + description: "Cross-platform Flutter/Dart development", + packs: ["Flutter"], + }, + { + id: "java", + label: "Java / Spring Boot", + description: "Spring Boot APIs, JPA, and testing", + packs: ["Java & Spring Boot"], + }, + { + id: "dotnet", + label: ".NET / C#", + description: "ASP.NET Core, Entity Framework, and design patterns", + packs: [".NET & C#"], + }, + { + id: "php", + label: "PHP / Laravel", + description: "Laravel patterns and PHP best practices", + packs: ["PHP & Laravel"], + }, + { + id: "django", + label: "Django", + description: "Django models, views, middleware, and Celery", + packs: ["Django", "Python"], + }, { id: "other", label: "Other / Skip", diff --git a/src/resources/extensions/gsd/tests/detection.test.ts b/src/resources/extensions/gsd/tests/detection.test.ts index 276ba0e6a..a6948ea0a 100644 --- a/src/resources/extensions/gsd/tests/detection.test.ts +++ b/src/resources/extensions/gsd/tests/detection.test.ts @@ -441,3 +441,97 @@ test("detectProjectSignals: no SQLite markers without matching files", () => { cleanup(dir); } }); + +test("detectProjectSignals: .NET project via .csproj extension", () => { + const dir = makeTempDir("signals-dotnet"); + try { + writeFileSync(join(dir, "MyApp.csproj"), "", "utf-8"); + const signals = detectProjectSignals(dir); + assert.ok(signals.detectedFiles.includes("*.csproj"), "should add synthetic *.csproj marker"); + assert.equal(signals.primaryLanguage, "csharp"); + } finally { + cleanup(dir); + } +}); + +test("detectProjectSignals: .NET project via .sln extension", () => { + const dir = makeTempDir("signals-sln"); + try { + writeFileSync(join(dir, "MyApp.sln"), "", "utf-8"); + const signals = detectProjectSignals(dir); + assert.ok(signals.detectedFiles.includes("*.csproj"), "should add synthetic *.csproj marker for .sln files"); + } finally { + cleanup(dir); + } +}); + +test("detectProjectSignals: Angular project via angular.json", () => { + const dir = makeTempDir("signals-angular"); + try { + writeFileSync(join(dir, "angular.json"), "{}", "utf-8"); + writeFileSync(join(dir, "package.json"), "{}", "utf-8"); + const signals = detectProjectSignals(dir); + assert.ok(signals.detectedFiles.includes("angular.json")); + assert.equal(signals.primaryLanguage, "javascript/typescript"); + } finally { + cleanup(dir); + } +}); + +test("detectProjectSignals: Next.js project via next.config.ts", () => { + const dir = makeTempDir("signals-nextjs"); + try { + writeFileSync(join(dir, "next.config.ts"), "export default {}", "utf-8"); + writeFileSync(join(dir, "package.json"), "{}", "utf-8"); + const signals = detectProjectSignals(dir); + assert.ok(signals.detectedFiles.includes("next.config.ts")); + } finally { + cleanup(dir); + } +}); + +test("detectProjectSignals: Flutter project via pubspec.yaml", () => { + const dir = makeTempDir("signals-flutter"); + try { + writeFileSync(join(dir, "pubspec.yaml"), "name: my_app", "utf-8"); + const signals = detectProjectSignals(dir); + assert.ok(signals.detectedFiles.includes("pubspec.yaml")); + assert.equal(signals.primaryLanguage, "dart/flutter"); + } finally { + cleanup(dir); + } +}); + +test("detectProjectSignals: Django project via manage.py", () => { + const dir = makeTempDir("signals-django"); + try { + writeFileSync(join(dir, "manage.py"), "#!/usr/bin/env python", "utf-8"); + const signals = detectProjectSignals(dir); + assert.ok(signals.detectedFiles.includes("manage.py")); + assert.equal(signals.primaryLanguage, "python"); + } finally { + cleanup(dir); + } +}); + +test("detectProjectSignals: Docker project via Dockerfile", () => { + const dir = makeTempDir("signals-docker"); + try { + writeFileSync(join(dir, "Dockerfile"), "FROM node:18", "utf-8"); + const signals = detectProjectSignals(dir); + assert.ok(signals.detectedFiles.includes("Dockerfile")); + } finally { + cleanup(dir); + } +}); + +test("detectProjectSignals: Terraform project via main.tf", () => { + const dir = makeTempDir("signals-terraform"); + try { + writeFileSync(join(dir, "main.tf"), 'provider "aws" {}', "utf-8"); + const signals = detectProjectSignals(dir); + assert.ok(signals.detectedFiles.includes("main.tf")); + } finally { + cleanup(dir); + } +});