mirror of
https://github.com/dotnet/skills.git
synced 2026-09-20 09:49:54 +08:00
Add Claude plugin manifests (#1071)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -4,6 +4,8 @@ on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "eng/version/**"
|
||||
- "plugins/*/plugin.json"
|
||||
- "plugins/*/.claude-plugin/plugin.json"
|
||||
- ".github/workflows/plugin-versioning-tests.yml"
|
||||
- ".github/workflows/version-bump-command.yml"
|
||||
- ".github/workflows/weekly-version-sync.yml"
|
||||
@@ -12,6 +14,8 @@ on:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "eng/version/**"
|
||||
- "plugins/*/plugin.json"
|
||||
- "plugins/*/.claude-plugin/plugin.json"
|
||||
- ".github/workflows/plugin-versioning-tests.yml"
|
||||
- ".github/workflows/version-bump-command.yml"
|
||||
- ".github/workflows/weekly-version-sync.yml"
|
||||
|
||||
@@ -145,10 +145,7 @@ jobs:
|
||||
# that predates some of these files (e.g. has no global.json in its head commit) doesn't fail
|
||||
# the whole command on a "pathspec did not match" error.
|
||||
git checkout HEAD -- eng/version/Sync-PluginVersions.ps1 || true
|
||||
git add plugins/*/plugin.json plugins/*/.codex-plugin/plugin.json
|
||||
# The optional Claude manifest may match zero plugins in the future; keep this add
|
||||
# non-fatal so an empty glob can't fail the step.
|
||||
git add plugins/*/.claude-plugin/plugin.json 2>/dev/null || true
|
||||
git add plugins/*/plugin.json plugins/*/.codex-plugin/plugin.json plugins/*/.claude-plugin/plugin.json
|
||||
git commit -m "Stamp plugin versions via /version-bump"
|
||||
git push origin "HEAD:${HEAD_REF}"
|
||||
|
||||
|
||||
@@ -72,8 +72,7 @@ jobs:
|
||||
$body = @(
|
||||
"Automated weekly version sync. The following plugins changed since their"
|
||||
"last release checkpoint; this PR stamps the computed version into their"
|
||||
"``plugin.json`` and ``.codex-plugin/plugin.json`` (and ``.claude-plugin/plugin.json``"
|
||||
"where a plugin has one)."
|
||||
"``plugin.json``, ``.codex-plugin/plugin.json``, and ``.claude-plugin/plugin.json``."
|
||||
""
|
||||
"Each patch advances once per published checkpoint with pending content."
|
||||
""
|
||||
@@ -92,10 +91,7 @@ jobs:
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git switch -c "$SYNC_BRANCH"
|
||||
git add plugins/*/plugin.json plugins/*/.codex-plugin/plugin.json
|
||||
# The optional Claude manifest may match zero plugins in the future; keep this add
|
||||
# non-fatal so an empty glob can't fail the step.
|
||||
git add plugins/*/.claude-plugin/plugin.json 2>/dev/null || true
|
||||
git add plugins/*/plugin.json plugins/*/.codex-plugin/plugin.json plugins/*/.claude-plugin/plugin.json
|
||||
git commit -m "Weekly plugin version sync"
|
||||
git push --force origin "$SYNC_BRANCH"
|
||||
|
||||
|
||||
+13
-8
@@ -24,6 +24,10 @@ This ensures that every contribution area has accountable reviewers and that PRs
|
||||
plugins/
|
||||
<plugin>/
|
||||
plugin.json
|
||||
.claude-plugin/
|
||||
plugin.json
|
||||
.codex-plugin/
|
||||
plugin.json
|
||||
skills/
|
||||
<skill-name>/
|
||||
SKILL.md
|
||||
@@ -48,7 +52,9 @@ If your skill does not fit any existing plugin, consider creating a new one.
|
||||
|
||||
To create a new plugin:
|
||||
|
||||
1. Add `plugins/<plugin-name>/plugin.json` and a `skills/` directory beneath it.
|
||||
1. Add `plugins/<plugin-name>/plugin.json`, identical copies at
|
||||
`plugins/<plugin-name>/.claude-plugin/plugin.json` and
|
||||
`plugins/<plugin-name>/.codex-plugin/plugin.json`, and a `skills/` directory beneath them.
|
||||
2. Add a matching entry in `.github/plugin/marketplace.json`, `.claude-plugin/marketplace.json`, `.cursor-plugin/marketplace.json`, and `.agents/plugins/marketplace.json`. Keep plugin entries consistent across all marketplace manifests (including `plugins[].source` format) to reduce drift and make future updates safer.
|
||||
Also add a `plugins/<plugin-name>/version.json` (copy an existing one) so the plugin participates in automated versioning. Start its `plugin.json` version at `0.1.0`.
|
||||
3. Add a CODEOWNERS entry for the new plugin and its tests (see [Code ownership](#code-ownership)).
|
||||
@@ -71,19 +77,18 @@ Place experimental skills under `plugins/dotnet-experimental/skills/` with match
|
||||
|
||||
## Plugin versioning
|
||||
|
||||
Each plugin is versioned independently. The same version is duplicated across every manifest a
|
||||
consumer reads: `plugins/<plugin>/plugin.json` and `plugins/<plugin>/.codex-plugin/plugin.json`
|
||||
(both present for every plugin), plus an optional `plugins/<plugin>/.claude-plugin/plugin.json`
|
||||
that only plugins needing an inline Claude manifest carry (e.g. `dotnet-msbuild`'s binlog MCP
|
||||
server). Consumers (Copilot CLI, Claude, Codex, Cursor) read the version directly from this
|
||||
repository.
|
||||
Each plugin is versioned independently. Every plugin carries the manifests its consumers read:
|
||||
`plugins/<plugin>/plugin.json`, `plugins/<plugin>/.codex-plugin/plugin.json`, and
|
||||
`plugins/<plugin>/.claude-plugin/plugin.json`. The Claude manifest is an exact generated copy of
|
||||
the root manifest. Consumers (Copilot CLI, Claude, Codex, Cursor) read the version directly from
|
||||
this repository.
|
||||
|
||||
Each `plugins/<plugin>/version.json` declares the plugin's major/minor release base and the files
|
||||
that count as effective plugin content. A calculated manifest version transition is a release
|
||||
checkpoint; an arbitrary patch edit is not. When effective content on `main` differs from the
|
||||
latest valid checkpoint, the **patch** advances once.
|
||||
The generated manifests
|
||||
(`plugin.json`, `.codex-plugin/plugin.json`, and `.claude-plugin/plugin.json` where present) and
|
||||
(`plugin.json`, `.codex-plugin/plugin.json`, and `.claude-plugin/plugin.json`) and
|
||||
`version.json` itself are excluded from content comparison via the `pathFilters`, so editing only
|
||||
manifest metadata (anything other than a deliberate base bump in `version.json`) does **not** change
|
||||
the patch number and is **not** picked up by `/version-bump` or the weekly sync. Touch a skill or
|
||||
|
||||
@@ -16,9 +16,10 @@
|
||||
branch can make old commits newly reachable without changing the plugin on main, and
|
||||
raw DAG height would incorrectly treat that graph-only event as a new release.
|
||||
|
||||
The computed version (e.g. "0.1.4") is materialized into BOTH manifests a plugin ships:
|
||||
The computed version (e.g. "0.1.4") is materialized into every manifest a plugin ships:
|
||||
plugins/<name>/plugin.json
|
||||
plugins/<name>/.codex-plugin/plugin.json
|
||||
plugins/<name>/.claude-plugin/plugin.json
|
||||
|
||||
This one script backs both versioning entry points:
|
||||
* version-bump-command.yml -> -BaseCommit <currentMain> -HeadCommit <prHead> -PredictMerge -OnlyChanged -Write (admin /version-bump)
|
||||
@@ -46,7 +47,8 @@
|
||||
plugin.json (i.e. plugins that actually drifted).
|
||||
|
||||
.PARAMETER Write
|
||||
Materialize the computed version into both manifests. Without it the script is read-only.
|
||||
Materialize the computed version into every manifest and synchronize the Claude manifest with
|
||||
the root manifest. Without it the script is read-only.
|
||||
|
||||
.OUTPUTS
|
||||
A JSON array on stdout: [{ "plugin", "current", "computed", "changed" }, ...].
|
||||
@@ -85,13 +87,9 @@ $checkpointValidationStartCache = @{}
|
||||
Set-Location -LiteralPath $repoRoot
|
||||
|
||||
# The files excluded from release-bearing content for every plugin: the stamped manifests (which
|
||||
# are outputs, not inputs) plus version.json itself. plugin.json and .codex-plugin/plugin.json exist
|
||||
# for every plugin; .claude-plugin/plugin.json is optional (only plugins that need an inline Claude
|
||||
# manifest, e.g. dotnet-msbuild's binlog MCP server, carry one). Excluding a manifest a given plugin
|
||||
# doesn't have is a harmless no-op for that plugin, and keeping it in the universal list means any
|
||||
# plugin that later adds a .claude-plugin manifest is already release-neutral. This is the single
|
||||
# source of truth, mirrored by each plugin's version.json `pathFilters`, by
|
||||
# Test-EffectiveContentChange, and by the canonical-filter guard in the main loop.
|
||||
# are outputs, not inputs) plus version.json itself. This is the single source of truth, mirrored
|
||||
# by each plugin's version.json `pathFilters`, by Test-EffectiveContentChange, and by the
|
||||
# canonical-filter guard in the main loop.
|
||||
$ContentExcludedFiles = @('plugin.json', '.codex-plugin/plugin.json', '.claude-plugin/plugin.json', 'version.json')
|
||||
|
||||
# The canonical `pathFilters` array every plugin's version.json must contain: include the whole
|
||||
@@ -335,7 +333,7 @@ function Get-AuthoritativeVersion {
|
||||
}
|
||||
|
||||
# Plugins whose version-affecting files changed between two commits. The stamped manifests
|
||||
# (plugin.json, .codex-plugin/plugin.json, and the optional .claude-plugin/plugin.json) are output,
|
||||
# (plugin.json, .codex-plugin/plugin.json, and .claude-plugin/plugin.json) are output,
|
||||
# not input, so they're excluded; everything else under the plugin counts — including version.json,
|
||||
# since a base bump (0.1 -> 0.2) with no other change must still be detected so /version-bump can
|
||||
# stamp the reset patch.
|
||||
@@ -392,10 +390,8 @@ foreach ($name in $Plugins) {
|
||||
$pluginDir = Join-Path $pluginsRoot $name
|
||||
$manifest = Join-Path $pluginDir 'plugin.json'
|
||||
$codexManifest = Join-Path $pluginDir '.codex-plugin' 'plugin.json'
|
||||
# Optional third manifest: some clients (e.g. Claude Code) need an inline plugin.json rather than
|
||||
# the reference form the Codex manifest uses, so a plugin may carry .claude-plugin/plugin.json.
|
||||
# Only plugins that need it have one (dotnet-msbuild today), so it's stamped when present rather
|
||||
# than required.
|
||||
# Claude Code needs an inline plugin.json. The root manifest is authoritative because the two
|
||||
# formats are identical; -Write creates or replaces the Claude copy when it is missing or stale.
|
||||
$claudeManifest = Join-Path $pluginDir '.claude-plugin' 'plugin.json'
|
||||
|
||||
# A shipped plugin (one with a plugin.json) must define a version base; fail loudly rather than
|
||||
@@ -420,14 +416,9 @@ foreach ($name in $Plugins) {
|
||||
# Read the Codex manifest too so we detect (and repair) the case where the two manifests have
|
||||
# drifted apart — e.g. a hand-edit updated one but not the other.
|
||||
$currentCodex = (Get-Content $codexManifest -Raw | ConvertFrom-Json).version
|
||||
# The optional Claude manifest, read only when the plugin carries one. Track presence separately
|
||||
# from the version value: keying "is it present?" off $currentClaude would conflate an absent file
|
||||
# with a present-but-malformed one (missing/empty "version"). By gating on $hasClaudeManifest, a
|
||||
# present manifest is always considered and stamped — and a missing/empty "version" fails loudly
|
||||
# (the strict-mode read or Set-ManifestVersion throws) rather than being silently skipped.
|
||||
$hasClaudeManifest = Test-Path $claudeManifest
|
||||
$currentClaude = if ($hasClaudeManifest) {
|
||||
(Get-Content $claudeManifest -Raw | ConvertFrom-Json).version
|
||||
$rootManifestContent = [IO.File]::ReadAllText($manifest)
|
||||
$claudeManifestContent = if (Test-Path $claudeManifest) {
|
||||
[IO.File]::ReadAllText($claudeManifest)
|
||||
} else { $null }
|
||||
|
||||
# The version.json base must be major.minor (e.g. "0.1"). Validate it before either
|
||||
@@ -487,22 +478,18 @@ foreach ($name in $Plugins) {
|
||||
throw "Computed version '$computed' for plugin '$name' is not a valid major.minor.patch — check plugins/$name/version.json"
|
||||
}
|
||||
|
||||
# Both required manifests are guaranteed to exist (guarded above); the Claude manifest is optional.
|
||||
# A mismatch in any present manifest — vs. the computed version — means the plugin drifted and
|
||||
# needs a rewrite. Gate the Claude check on presence (not on its version value) so a present-but-
|
||||
# malformed manifest still forces a rewrite and fails loudly at stamp time.
|
||||
# The Claude manifest must be an exact copy of the root manifest. Treat a missing or stale copy
|
||||
# as drift so both the weekly sync and /version-bump can repair older branches automatically.
|
||||
$changed = ($computed -ne $current) -or ($computed -ne $currentCodex) -or
|
||||
($hasClaudeManifest -and $computed -ne $currentClaude)
|
||||
($claudeManifestContent -cne $rootManifestContent)
|
||||
|
||||
if ($OnlyChanged -and -not $changed) { continue }
|
||||
|
||||
if ($Write -and $changed) {
|
||||
[void](Set-ManifestVersion -Path $manifest -Version $computed)
|
||||
[void](Set-ManifestVersion -Path $codexManifest -Version $computed)
|
||||
# Stamp the optional Claude manifest only when the plugin actually has one.
|
||||
if ($hasClaudeManifest) {
|
||||
[void](Set-ManifestVersion -Path $claudeManifest -Version $computed)
|
||||
}
|
||||
[void](New-Item -ItemType Directory -Path (Split-Path $claudeManifest -Parent) -Force)
|
||||
[IO.File]::WriteAllText($claudeManifest, [IO.File]::ReadAllText($manifest))
|
||||
}
|
||||
|
||||
$results.Add([ordered]@{
|
||||
|
||||
@@ -45,6 +45,7 @@ function New-TestRepository {
|
||||
$repo = Join-Path $testRoot $Name
|
||||
[void](New-Item -ItemType Directory -Path (Join-Path $repo 'eng/version') -Force)
|
||||
[void](New-Item -ItemType Directory -Path (Join-Path $repo 'plugins/sample/.codex-plugin') -Force)
|
||||
[void](New-Item -ItemType Directory -Path (Join-Path $repo 'plugins/sample/.claude-plugin') -Force)
|
||||
[void](New-Item -ItemType Directory -Path (Join-Path $repo 'plugins/sample/skills/example') -Force)
|
||||
$testScript = Join-Path $repo 'eng/version/Sync-PluginVersions.ps1'
|
||||
Copy-Item -LiteralPath $sourceScript -Destination $testScript
|
||||
@@ -77,6 +78,8 @@ function New-TestRepository {
|
||||
'@ | Set-Content -LiteralPath (Join-Path $repo 'plugins/sample/plugin.json')
|
||||
Copy-Item -LiteralPath (Join-Path $repo 'plugins/sample/plugin.json') `
|
||||
-Destination (Join-Path $repo 'plugins/sample/.codex-plugin/plugin.json')
|
||||
Copy-Item -LiteralPath (Join-Path $repo 'plugins/sample/plugin.json') `
|
||||
-Destination (Join-Path $repo 'plugins/sample/.claude-plugin/plugin.json')
|
||||
'initial content' | Set-Content -LiteralPath (Join-Path $repo 'plugins/sample/skills/example/SKILL.md')
|
||||
|
||||
[void](Invoke-Git $repo init -b main)
|
||||
@@ -103,12 +106,13 @@ function Set-ManifestVersions {
|
||||
param([string] $Repository, [string] $Version)
|
||||
Set-JsonVersion -Path (Join-Path $Repository 'plugins/sample/plugin.json') -Version $Version
|
||||
Set-JsonVersion -Path (Join-Path $Repository 'plugins/sample/.codex-plugin/plugin.json') -Version $Version
|
||||
Set-JsonVersion -Path (Join-Path $Repository 'plugins/sample/.claude-plugin/plugin.json') -Version $Version
|
||||
}
|
||||
|
||||
function Commit-ManifestVersions {
|
||||
param([string] $Repository, [string] $Version)
|
||||
Set-ManifestVersions -Repository $Repository -Version $Version
|
||||
[void](Invoke-Git $Repository add plugins/sample/plugin.json plugins/sample/.codex-plugin/plugin.json)
|
||||
[void](Invoke-Git $Repository add plugins/sample/plugin.json plugins/sample/.codex-plugin/plugin.json plugins/sample/.claude-plugin/plugin.json)
|
||||
[void](Invoke-Git $Repository commit -m "Stamp sample $Version")
|
||||
}
|
||||
|
||||
@@ -147,7 +151,7 @@ function Test-BatchedChangesAdvanceOnce {
|
||||
Assert-Equal 2 @($report[0].commits).Count 'Both first-parent changes must be attributed.'
|
||||
|
||||
[void](Invoke-Sync $repo -Write)
|
||||
[void](Invoke-Git $repo add plugins/sample/plugin.json plugins/sample/.codex-plugin/plugin.json)
|
||||
[void](Invoke-Git $repo add plugins/sample/plugin.json plugins/sample/.codex-plugin/plugin.json plugins/sample/.claude-plugin/plugin.json)
|
||||
[void](Invoke-Git $repo commit -m 'Publish batched changes')
|
||||
Assert-Equal 0 @(Invoke-Sync $repo).Count 'Published content must not drift.'
|
||||
}
|
||||
@@ -204,7 +208,7 @@ function Test-BaseResetRejectsManualPatch {
|
||||
$repo = New-TestRepository 'base-reset-manual-patch'
|
||||
Set-JsonVersion -Path (Join-Path $repo 'plugins/sample/version.json') -Version '1.0'
|
||||
Set-ManifestVersions -Repository $repo -Version '1.0.5'
|
||||
[void](Invoke-Git $repo add plugins/sample/version.json plugins/sample/plugin.json plugins/sample/.codex-plugin/plugin.json)
|
||||
[void](Invoke-Git $repo add plugins/sample/version.json plugins/sample/plugin.json plugins/sample/.codex-plugin/plugin.json plugins/sample/.claude-plugin/plugin.json)
|
||||
[void](Invoke-Git $repo commit -m 'Start sample 1.0 with an invalid patch')
|
||||
|
||||
$report = @(Invoke-Sync $repo)
|
||||
@@ -255,7 +259,7 @@ function Test-MatchingMainBaseDoesNotReset {
|
||||
[void](Invoke-Git $repo switch main)
|
||||
Set-JsonVersion -Path (Join-Path $repo 'plugins/sample/version.json') -Version '0.2'
|
||||
Set-ManifestVersions -Repository $repo -Version '0.2.0'
|
||||
[void](Invoke-Git $repo add plugins/sample/version.json plugins/sample/plugin.json plugins/sample/.codex-plugin/plugin.json)
|
||||
[void](Invoke-Git $repo add plugins/sample/version.json plugins/sample/plugin.json plugins/sample/.codex-plugin/plugin.json plugins/sample/.claude-plugin/plugin.json)
|
||||
[void](Invoke-Git $repo commit -m 'Publish main 0.2 release')
|
||||
$currentMain = Invoke-Git $repo rev-parse HEAD
|
||||
[void](Invoke-Git $repo switch feature)
|
||||
@@ -273,7 +277,7 @@ function Test-ConcurrentPredictionsReconcile {
|
||||
$headA = Invoke-Git $repo rev-parse HEAD
|
||||
$reportA = @(Invoke-Sync $repo -BaseCommit $initialMain -HeadCommit $headA -PredictMerge -Write)
|
||||
Assert-Equal '0.1.5' $reportA[0].computed 'Feature A prediction must be 0.1.5.'
|
||||
[void](Invoke-Git $repo add plugins/sample/plugin.json plugins/sample/.codex-plugin/plugin.json)
|
||||
[void](Invoke-Git $repo add plugins/sample/plugin.json plugins/sample/.codex-plugin/plugin.json plugins/sample/.claude-plugin/plugin.json)
|
||||
[void](Invoke-Git $repo commit -m 'Stamp feature A')
|
||||
|
||||
[void](Invoke-Git $repo switch main)
|
||||
@@ -282,7 +286,7 @@ function Test-ConcurrentPredictionsReconcile {
|
||||
$headB = Invoke-Git $repo rev-parse HEAD
|
||||
$reportB = @(Invoke-Sync $repo -BaseCommit $initialMain -HeadCommit $headB -PredictMerge -Write)
|
||||
Assert-Equal '0.1.5' $reportB[0].computed 'Feature B prediction must also be 0.1.5.'
|
||||
[void](Invoke-Git $repo add plugins/sample/plugin.json plugins/sample/.codex-plugin/plugin.json)
|
||||
[void](Invoke-Git $repo add plugins/sample/plugin.json plugins/sample/.codex-plugin/plugin.json plugins/sample/.claude-plugin/plugin.json)
|
||||
[void](Invoke-Git $repo commit -m 'Stamp feature B')
|
||||
|
||||
[void](Invoke-Git $repo switch main)
|
||||
@@ -327,6 +331,59 @@ function Test-LegacyHistoryRemainsTrusted {
|
||||
'Manifest transitions before checkpoint validation must remain a trusted migration baseline.'
|
||||
}
|
||||
|
||||
function Test-MissingClaudeManifestIsRepaired {
|
||||
$repo = New-TestRepository 'missing-claude-manifest'
|
||||
$claudeManifest = Join-Path $repo 'plugins/sample/.claude-plugin/plugin.json'
|
||||
Remove-Item -LiteralPath $claudeManifest
|
||||
|
||||
$report = @(Invoke-Sync $repo)
|
||||
Assert-Equal 1 $report.Count 'A missing Claude manifest must be reported as drift.'
|
||||
|
||||
[void](Invoke-Sync $repo -Write)
|
||||
Assert-Equal $true (Test-Path $claudeManifest) 'Version sync must recreate a missing Claude manifest.'
|
||||
Assert-Equal $true ([string]::Equals(
|
||||
[IO.File]::ReadAllText((Join-Path $repo 'plugins/sample/plugin.json')),
|
||||
[IO.File]::ReadAllText($claudeManifest),
|
||||
[StringComparison]::Ordinal)) `
|
||||
'The recreated Claude manifest must exactly match the root manifest.'
|
||||
}
|
||||
|
||||
function Test-ClaudeManifestCaseDriftIsRepaired {
|
||||
$repo = New-TestRepository 'claude-manifest-case-drift'
|
||||
$rootManifest = Join-Path $repo 'plugins/sample/plugin.json'
|
||||
$claudeManifest = Join-Path $repo 'plugins/sample/.claude-plugin/plugin.json'
|
||||
$content = [IO.File]::ReadAllText($claudeManifest).Replace('Test plugin.', 'test plugin.')
|
||||
[IO.File]::WriteAllText($claudeManifest, $content)
|
||||
|
||||
$report = @(Invoke-Sync $repo)
|
||||
Assert-Equal 1 $report.Count 'Case-only Claude manifest drift must be reported.'
|
||||
|
||||
[void](Invoke-Sync $repo -Write)
|
||||
Assert-Equal $true ([string]::Equals(
|
||||
[IO.File]::ReadAllText($rootManifest),
|
||||
[IO.File]::ReadAllText($claudeManifest),
|
||||
[StringComparison]::Ordinal)) `
|
||||
'Version sync must repair case-only Claude manifest drift.'
|
||||
}
|
||||
|
||||
function Test-RepositoryClaudeManifests {
|
||||
$repository = (Resolve-Path (Join-Path $PSScriptRoot '..' '..')).Path
|
||||
$pluginDirectories = Get-ChildItem (Join-Path $repository 'plugins') -Directory |
|
||||
Where-Object { Test-Path (Join-Path $_.FullName 'plugin.json') }
|
||||
|
||||
foreach ($pluginDirectory in $pluginDirectories) {
|
||||
$rootManifest = Join-Path $pluginDirectory.FullName 'plugin.json'
|
||||
$claudeManifest = Join-Path $pluginDirectory.FullName '.claude-plugin/plugin.json'
|
||||
Assert-Equal $true (Test-Path $claudeManifest) `
|
||||
"Plugin '$($pluginDirectory.Name)' must carry .claude-plugin/plugin.json."
|
||||
Assert-Equal $true ([string]::Equals(
|
||||
[IO.File]::ReadAllText($rootManifest),
|
||||
[IO.File]::ReadAllText($claudeManifest),
|
||||
[StringComparison]::Ordinal)) `
|
||||
"Plugin '$($pluginDirectory.Name)' must keep its Claude manifest synchronized with plugin.json."
|
||||
}
|
||||
}
|
||||
|
||||
[void](New-Item -ItemType Directory -Path $testRoot)
|
||||
try {
|
||||
Test-BatchedChangesAdvanceOnce
|
||||
@@ -342,6 +399,9 @@ try {
|
||||
Test-ManualManifestInflationIsRejected
|
||||
Test-ManualManifestDowngradeIsRejected
|
||||
Test-LegacyHistoryRemainsTrusted
|
||||
Test-MissingClaudeManifestIsRepaired
|
||||
Test-ClaudeManifestCaseDriftIsRepaired
|
||||
Test-RepositoryClaudeManifests
|
||||
Write-Host "Passed $script:assertions plugin-version assertions."
|
||||
}
|
||||
finally {
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "dotnet-advanced",
|
||||
"version": "0.2.1",
|
||||
"description": "Advanced .NET and C# skills for niche scenarios that are not part of the core dotnet plugin.",
|
||||
"skills": ["./skills/"]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "dotnet-ai",
|
||||
"version": "0.1.6",
|
||||
"description": "AI and ML skills for .NET: technology selection, LLM integration, agentic workflows, RAG pipelines, MCP, and classic ML with ML.NET.",
|
||||
"skills": ["./skills/"]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "dotnet-aspnetcore",
|
||||
"version": "0.1.1",
|
||||
"description": "ASP.NET Core web development skills including middleware, endpoints, real-time communication, and API patterns.",
|
||||
"skills": ["./skills/"]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "dotnet-blazor",
|
||||
"version": "0.1.1",
|
||||
"description": "Skills for Blazor development: component authoring, interactivity, and web application patterns.",
|
||||
"skills": ["./skills/"]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "dotnet-data",
|
||||
"version": "0.1.5",
|
||||
"description": "Skills for .NET data access and Entity Framework related tasks.",
|
||||
"skills": ["./skills/"]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "dotnet-diag",
|
||||
"version": "0.1.1",
|
||||
"description": "Skills for .NET performance investigations, debugging, and incident analysis.",
|
||||
"skills": ["./skills/"],
|
||||
"agents": ["./agents/optimizing-dotnet-performance.agent.md"]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "dotnet-experimental",
|
||||
"version": "0.1.1",
|
||||
"description": "Experimental skills under active evaluation that may change or graduate to stable plugins.",
|
||||
"skills": ["./skills/"]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "dotnet-maui",
|
||||
"version": "0.1.16",
|
||||
"description": "Skills for .NET MAUI development: environment setup, diagnostics, troubleshooting, navigation, data binding, dependency injection, layout, and theming.",
|
||||
"skills": ["./skills/"]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "dotnet-nuget",
|
||||
"version": "0.1.1",
|
||||
"description": "NuGet and .NET package management skills: dependency management and modernization.",
|
||||
"skills": ["./skills/"]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "dotnet-template-engine",
|
||||
"version": "0.1.3",
|
||||
"description": ".NET Template Engine skills for dotnet new: create projects (console app, class library, web API, Blazor, MAUI), discover and search templates, inspect template parameters and frameworks (net8.0, net9.0, net10.0), scaffold solutions, author and validate custom templates, install template packages from NuGet.",
|
||||
"skills": ["./skills/"],
|
||||
"agents": ["./agents/template-engine.agent.md"]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "dotnet-test-migration",
|
||||
"version": "0.1.7",
|
||||
"description": "Skills and an orchestrator agent for migrating .NET test frameworks and platforms: MSTest and xUnit version upgrades, xUnit-to-MSTest conversion, and VSTest to Microsoft.Testing.Platform.",
|
||||
"skills": ["./skills/"],
|
||||
"agents": [
|
||||
"./agents/test-migration.agent.md"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "dotnet-test",
|
||||
"version": "0.2.18",
|
||||
"description": "Skills for running, generating, analyzing, and improving .NET tests: test execution, filtering, platform detection, coverage, testability, and MSTest workflows.",
|
||||
"skills": ["./skills/"],
|
||||
"agents": [
|
||||
"./agents/code-testing-generator.agent.md",
|
||||
"./agents/code-testing-researcher.agent.md",
|
||||
"./agents/code-testing-planner.agent.md",
|
||||
"./agents/code-testing-implementer.agent.md",
|
||||
"./agents/code-testing-builder.agent.md",
|
||||
"./agents/code-testing-tester.agent.md",
|
||||
"./agents/code-testing-fixer.agent.md",
|
||||
"./agents/code-testing-linter.agent.md",
|
||||
"./agents/testability-migration.agent.md",
|
||||
"./agents/test-quality-auditor.agent.md"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "dotnet-upgrade",
|
||||
"version": "0.1.1",
|
||||
"description": "Skills for migrating and upgrading .NET projects across framework versions, language features, and compatibility targets.",
|
||||
"skills": ["./skills/"]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "dotnet",
|
||||
"version": "0.2.3",
|
||||
"description": "C# language server (LSP) integration for coding agents and high-level .NET development skills.",
|
||||
"skills": ["./skills/"],
|
||||
"lspServers": "./lsp.json"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "dotnet11",
|
||||
"version": "0.1.1",
|
||||
"description": "Skills for .NET 11 APIs and language features.",
|
||||
"skills": ["./skills/"]
|
||||
}
|
||||
Reference in New Issue
Block a user