Enforce canonical plugin manifest ordering (#1601)

* Enforce canonical plugin manifest ordering

Sort existing plugin manifest spec arrays so plugin:clean no longer creates noisy diffs from out-of-order entries. Add validation to require alphabetical ordering and teach plugin:clean to normalize manifest arrays when cleaning materialized plugin content.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Aaron Powell
2026-05-04 12:00:50 +10:00
committed by GitHub
parent fb71887136
commit a1197525bd
26 changed files with 112 additions and 85 deletions

View File

@@ -42,6 +42,14 @@ export function restoreManifestFromMaterializedFiles(pluginPath) {
let changed = false; let changed = false;
for (const [field, spec] of Object.entries(MATERIALIZED_SPECS)) { for (const [field, spec] of Object.entries(MATERIALIZED_SPECS)) {
if (Array.isArray(plugin[field])) {
const sortedEntries = sortPluginEntries(plugin[field]);
if (!arraysEqual(plugin[field], sortedEntries)) {
plugin[field] = sortedEntries;
changed = true;
}
}
const materializedPath = path.join(pluginPath, spec.path); const materializedPath = path.join(pluginPath, spec.path);
if (!fs.existsSync(materializedPath) || !fs.statSync(materializedPath).isDirectory()) { if (!fs.existsSync(materializedPath) || !fs.statSync(materializedPath).isDirectory()) {
continue; continue;
@@ -132,6 +140,10 @@ function arraysEqual(left, right) {
return left.every((value, index) => value === right[index]); return left.every((value, index) => value === right[index]);
} }
function sortPluginEntries(entries) {
return [...entries].sort((left, right) => left.localeCompare(right));
}
function toPosixPath(filePath) { function toPosixPath(filePath) {
return filePath.split(path.sep).join("/"); return filePath.split(path.sep).join("/");
} }
@@ -165,7 +177,7 @@ function main() {
} else { } else {
console.log(`✅ Removed ${total} materialized file(s) from plugins.`); console.log(`✅ Removed ${total} materialized file(s) from plugins.`);
if (manifestsUpdated > 0) { if (manifestsUpdated > 0) {
console.log(`✅ Updated ${manifestsUpdated} plugin manifest(s) with folder trailing slashes.`); console.log(`✅ Updated ${manifestsUpdated} plugin manifest(s) to restore and normalize spec entries.`);
} }
} }
} }

View File

@@ -64,6 +64,18 @@ function validateKeywords(keywords) {
return null; return null;
} }
function arraysEqual(left, right) {
if (!Array.isArray(left) || !Array.isArray(right) || left.length !== right.length) {
return false;
}
return left.every((value, index) => value === right[index]);
}
function sortPluginEntries(entries) {
return [...entries].sort((left, right) => left.localeCompare(right));
}
function validateSpecPaths(plugin) { function validateSpecPaths(plugin) {
const errors = []; const errors = [];
const specs = { const specs = {
@@ -78,6 +90,9 @@ function validateSpecPaths(plugin) {
errors.push(`${field} must be an array`); errors.push(`${field} must be an array`);
continue; continue;
} }
if (!arraysEqual(arr, sortPluginEntries(arr))) {
errors.push(`${field} must be sorted alphabetically`);
}
for (let i = 0; i < arr.length; i++) { for (let i = 0; i < arr.length; i++) {
const p = arr[i]; const p = arr[i];
if (typeof p !== "string") { if (typeof p !== "string") {

View File

@@ -17,8 +17,8 @@
"repository": "https://github.com/github/awesome-copilot", "repository": "https://github.com/github/awesome-copilot",
"license": "MIT", "license": "MIT",
"agents": [ "agents": [
"./agents/ai-team-producer.md",
"./agents/ai-team-dev.md", "./agents/ai-team-dev.md",
"./agents/ai-team-producer.md",
"./agents/ai-team-qa.md" "./agents/ai-team-qa.md"
], ],
"skills": [ "skills": [

View File

@@ -18,8 +18,8 @@
"./agents/meta-agentic-project-scaffold.md" "./agents/meta-agentic-project-scaffold.md"
], ],
"skills": [ "skills": [
"./skills/suggest-awesome-github-copilot-skills/", "./skills/suggest-awesome-github-copilot-agents/",
"./skills/suggest-awesome-github-copilot-instructions/", "./skills/suggest-awesome-github-copilot-instructions/",
"./skills/suggest-awesome-github-copilot-agents/" "./skills/suggest-awesome-github-copilot-skills/"
] ]
} }

View File

@@ -18,18 +18,18 @@
"devops" "devops"
], ],
"agents": [ "agents": [
"./agents/azure-logic-apps-expert.md",
"./agents/azure-principal-architect.md", "./agents/azure-principal-architect.md",
"./agents/azure-saas-architect.md", "./agents/azure-saas-architect.md",
"./agents/azure-logic-apps-expert.md",
"./agents/azure-verified-modules-bicep.md", "./agents/azure-verified-modules-bicep.md",
"./agents/azure-verified-modules-terraform.md", "./agents/azure-verified-modules-terraform.md",
"./agents/terraform-azure-planning.md", "./agents/terraform-azure-implement.md",
"./agents/terraform-azure-implement.md" "./agents/terraform-azure-planning.md"
], ],
"skills": [ "skills": [
"./skills/azure-resource-health-diagnose/",
"./skills/az-cost-optimize/", "./skills/az-cost-optimize/",
"./skills/import-infrastructure-as-code/", "./skills/azure-pricing/",
"./skills/azure-pricing/" "./skills/azure-resource-health-diagnose/",
"./skills/import-infrastructure-as-code/"
] ]
} }

View File

@@ -16,8 +16,8 @@
"devops" "devops"
], ],
"agents": [ "agents": [
"./agents/cast-imaging-software-discovery.md",
"./agents/cast-imaging-impact-analysis.md", "./agents/cast-imaging-impact-analysis.md",
"./agents/cast-imaging-software-discovery.md",
"./agents/cast-imaging-structural-quality-advisor.md" "./agents/cast-imaging-structural-quality-advisor.md"
] ]
} }

View File

@@ -19,7 +19,7 @@
], ],
"skills": [ "skills": [
"./skills/context-map/", "./skills/context-map/",
"./skills/what-context-needed/", "./skills/refactor-plan/",
"./skills/refactor-plan/" "./skills/what-context-needed/"
] ]
} }

View File

@@ -17,12 +17,12 @@
"./agents/expert-dotnet-software-engineer.md" "./agents/expert-dotnet-software-engineer.md"
], ],
"skills": [ "skills": [
"./skills/csharp-async/",
"./skills/aspnet-minimal-api-openapi/", "./skills/aspnet-minimal-api-openapi/",
"./skills/csharp-xunit/", "./skills/csharp-async/",
"./skills/csharp-nunit/",
"./skills/csharp-mstest/", "./skills/csharp-mstest/",
"./skills/csharp-nunit/",
"./skills/csharp-tunit/", "./skills/csharp-tunit/",
"./skills/csharp-xunit/",
"./skills/dotnet-best-practices/", "./skills/dotnet-best-practices/",
"./skills/dotnet-upgrade/" "./skills/dotnet-upgrade/"
] ]

View File

@@ -18,13 +18,13 @@
"data-management" "data-management"
], ],
"agents": [ "agents": [
"./agents/postgresql-dba.md", "./agents/ms-sql-dba.md",
"./agents/ms-sql-dba.md" "./agents/postgresql-dba.md"
], ],
"skills": [ "skills": [
"./skills/sql-optimization/", "./skills/postgresql-code-review/",
"./skills/sql-code-review/",
"./skills/postgresql-optimization/", "./skills/postgresql-optimization/",
"./skills/postgresql-code-review/" "./skills/sql-code-review/",
"./skills/sql-optimization/"
] ]
} }

View File

@@ -14,9 +14,9 @@
"sdk" "sdk"
], ],
"skills": [ "skills": [
"./skills/dataverse-python-quickstart/",
"./skills/dataverse-python-advanced-patterns/", "./skills/dataverse-python-advanced-patterns/",
"./skills/dataverse-python-production-code/", "./skills/dataverse-python-production-code/",
"./skills/dataverse-python-quickstart/",
"./skills/dataverse-python-usecase-builder/" "./skills/dataverse-python-usecase-builder/"
] ]
} }

View File

@@ -15,7 +15,7 @@
"implementation" "implementation"
], ],
"agents": [ "agents": [
"./agents/task-researcher.md", "./agents/task-planner.md",
"./agents/task-planner.md" "./agents/task-researcher.md"
] ]
} }

View File

@@ -19,10 +19,10 @@
"governance" "governance"
], ],
"skills": [ "skills": [
"./skills/flowstudio-power-automate-mcp/",
"./skills/flowstudio-power-automate-debug/",
"./skills/flowstudio-power-automate-build/", "./skills/flowstudio-power-automate-build/",
"./skills/flowstudio-power-automate-monitoring/", "./skills/flowstudio-power-automate-debug/",
"./skills/flowstudio-power-automate-governance/" "./skills/flowstudio-power-automate-governance/",
"./skills/flowstudio-power-automate-mcp/",
"./skills/flowstudio-power-automate-monitoring/"
] ]
} }

View File

@@ -19,8 +19,8 @@
"vue" "vue"
], ],
"agents": [ "agents": [
"./agents/expert-react-frontend-engineer.md", "./agents/electron-angular-native.md",
"./agents/electron-angular-native.md" "./agents/expert-react-frontend-engineer.md"
], ],
"skills": [ "skills": [
"./skills/playwright-explore-website/", "./skills/playwright-explore-website/",

View File

@@ -1,20 +1,20 @@
{ {
"agents": [ "agents": [
"./agents/gem-orchestrator.md",
"./agents/gem-researcher.md",
"./agents/gem-planner.md",
"./agents/gem-implementer.md",
"./agents/gem-browser-tester.md", "./agents/gem-browser-tester.md",
"./agents/gem-devops.md",
"./agents/gem-reviewer.md",
"./agents/gem-documentation-writer.md",
"./agents/gem-debugger.md",
"./agents/gem-critic.md",
"./agents/gem-code-simplifier.md", "./agents/gem-code-simplifier.md",
"./agents/gem-designer.md", "./agents/gem-critic.md",
"./agents/gem-implementer-mobile.md", "./agents/gem-debugger.md",
"./agents/gem-designer-mobile.md", "./agents/gem-designer-mobile.md",
"./agents/gem-mobile-tester.md" "./agents/gem-designer.md",
"./agents/gem-devops.md",
"./agents/gem-documentation-writer.md",
"./agents/gem-implementer-mobile.md",
"./agents/gem-implementer.md",
"./agents/gem-mobile-tester.md",
"./agents/gem-orchestrator.md",
"./agents/gem-planner.md",
"./agents/gem-researcher.md",
"./agents/gem-reviewer.md"
], ],
"author": { "author": {
"email": "mubaidr@gmail.com", "email": "mubaidr@gmail.com",

View File

@@ -16,9 +16,9 @@
"javadoc" "javadoc"
], ],
"skills": [ "skills": [
"./skills/create-spring-boot-java-project/",
"./skills/java-docs/", "./skills/java-docs/",
"./skills/java-junit/", "./skills/java-junit/",
"./skills/java-springboot/", "./skills/java-springboot/"
"./skills/create-spring-boot-java-project/"
] ]
} }

View File

@@ -19,8 +19,8 @@
"./agents/mcp-m365-agent-expert.md" "./agents/mcp-m365-agent-expert.md"
], ],
"skills": [ "skills": [
"./skills/mcp-create-declarative-agent/",
"./skills/mcp-create-adaptive-cards/", "./skills/mcp-create-adaptive-cards/",
"./skills/mcp-create-declarative-agent/",
"./skills/mcp-deploy-manage-agents/" "./skills/mcp-deploy-manage-agents/"
] ]
} }

View File

@@ -23,6 +23,7 @@
"./agents/amplitude-experiment-implementation.md", "./agents/amplitude-experiment-implementation.md",
"./agents/apify-integration-expert.md", "./agents/apify-integration-expert.md",
"./agents/arm-migration.md", "./agents/arm-migration.md",
"./agents/comet-opik.md",
"./agents/diffblue-cover.md", "./agents/diffblue-cover.md",
"./agents/droid.md", "./agents/droid.md",
"./agents/dynatrace-expert.md", "./agents/dynatrace-expert.md",
@@ -36,9 +37,8 @@
"./agents/neon-migration-specialist.md", "./agents/neon-migration-specialist.md",
"./agents/neon-optimization-analyzer.md", "./agents/neon-optimization-analyzer.md",
"./agents/octopus-deploy-release-notes-mcp.md", "./agents/octopus-deploy-release-notes-mcp.md",
"./agents/stackhawk-security-onboarding.md",
"./agents/terraform.md",
"./agents/pagerduty-incident-responder.md", "./agents/pagerduty-incident-responder.md",
"./agents/comet-opik.md" "./agents/stackhawk-security-onboarding.md",
"./agents/terraform.md"
] ]
} }

View File

@@ -20,14 +20,14 @@
"go" "go"
], ],
"agents": [ "agents": [
"./agents/polyglot-test-generator.md",
"./agents/polyglot-test-researcher.md",
"./agents/polyglot-test-planner.md",
"./agents/polyglot-test-implementer.md",
"./agents/polyglot-test-builder.md", "./agents/polyglot-test-builder.md",
"./agents/polyglot-test-tester.md",
"./agents/polyglot-test-fixer.md", "./agents/polyglot-test-fixer.md",
"./agents/polyglot-test-linter.md" "./agents/polyglot-test-generator.md",
"./agents/polyglot-test-implementer.md",
"./agents/polyglot-test-linter.md",
"./agents/polyglot-test-planner.md",
"./agents/polyglot-test-researcher.md",
"./agents/polyglot-test-tester.md"
], ],
"skills": [ "skills": [
"./skills/polyglot-test-agent/" "./skills/polyglot-test-agent/"

View File

@@ -18,7 +18,7 @@
"./agents/power-platform-mcp-integration-expert.md" "./agents/power-platform-mcp-integration-expert.md"
], ],
"skills": [ "skills": [
"./skills/power-platform-mcp-connector-suite/", "./skills/mcp-copilot-studio-server-generator/",
"./skills/mcp-copilot-studio-server-generator/" "./skills/power-platform-mcp-connector-suite/"
] ]
} }

View File

@@ -18,22 +18,22 @@
"technical-spike" "technical-spike"
], ],
"agents": [ "agents": [
"./agents/task-planner.md",
"./agents/task-researcher.md",
"./agents/planner.md",
"./agents/plan.md",
"./agents/prd.md",
"./agents/implementation-plan.md", "./agents/implementation-plan.md",
"./agents/research-technical-spike.md" "./agents/plan.md",
"./agents/planner.md",
"./agents/prd.md",
"./agents/research-technical-spike.md",
"./agents/task-planner.md",
"./agents/task-researcher.md"
], ],
"skills": [ "skills": [
"./skills/breakdown-feature-implementation/",
"./skills/breakdown-feature-prd/",
"./skills/breakdown-epic-arch/", "./skills/breakdown-epic-arch/",
"./skills/breakdown-epic-pm/", "./skills/breakdown-epic-pm/",
"./skills/create-implementation-plan/", "./skills/breakdown-feature-implementation/",
"./skills/update-implementation-plan/", "./skills/breakdown-feature-prd/",
"./skills/create-github-issues-feature-from-implementation-plan/", "./skills/create-github-issues-feature-from-implementation-plan/",
"./skills/create-technical-spike/" "./skills/create-implementation-plan/",
"./skills/create-technical-spike/",
"./skills/update-implementation-plan/"
] ]
} }

View File

@@ -16,12 +16,12 @@
}, },
"repository": "https://github.com/github/awesome-copilot", "repository": "https://github.com/github/awesome-copilot",
"license": "MIT", "license": "MIT",
"agents": [ "agents": [
"./agents/react18-auditor.md", "./agents/react18-auditor.md",
"./agents/react18-batching-fixer.md",
"./agents/react18-class-surgeon.md",
"./agents/react18-commander.md", "./agents/react18-commander.md",
"./agents/react18-dep-surgeon.md", "./agents/react18-dep-surgeon.md",
"./agents/react18-class-surgeon.md",
"./agents/react18-batching-fixer.md",
"./agents/react18-test-guardian.md" "./agents/react18-test-guardian.md"
], ],
"skills": [ "skills": [

View File

@@ -15,8 +15,8 @@
"qa" "qa"
], ],
"agents": [ "agents": [
"./agents/qa-subagent.md",
"./agents/rug-orchestrator.md", "./agents/rug-orchestrator.md",
"./agents/swe-subagent.md", "./agents/swe-subagent.md"
"./agents/qa-subagent.md"
] ]
} }

View File

@@ -26,7 +26,7 @@
], ],
"skills": [ "skills": [
"./skills/salesforce-apex-quality/", "./skills/salesforce-apex-quality/",
"./skills/salesforce-flow-design/", "./skills/salesforce-component-standards/",
"./skills/salesforce-component-standards/" "./skills/salesforce-flow-design/"
] ]
} }

View File

@@ -18,12 +18,12 @@
"ai-ethics" "ai-ethics"
], ],
"agents": [ "agents": [
"./agents/se-ux-ui-designer.md",
"./agents/se-technical-writer.md",
"./agents/se-gitops-ci-specialist.md", "./agents/se-gitops-ci-specialist.md",
"./agents/se-product-manager-advisor.md", "./agents/se-product-manager-advisor.md",
"./agents/se-responsible-ai-code.md", "./agents/se-responsible-ai-code.md",
"./agents/se-security-reviewer.md",
"./agents/se-system-architecture-reviewer.md", "./agents/se-system-architecture-reviewer.md",
"./agents/se-security-reviewer.md" "./agents/se-technical-writer.md",
"./agents/se-ux-ui-designer.md"
] ]
} }

View File

@@ -18,16 +18,16 @@
"nunit" "nunit"
], ],
"agents": [ "agents": [
"./agents/tdd-red.md", "./agents/playwright-tester.md",
"./agents/tdd-green.md", "./agents/tdd-green.md",
"./agents/tdd-refactor.md", "./agents/tdd-red.md",
"./agents/playwright-tester.md" "./agents/tdd-refactor.md"
], ],
"skills": [ "skills": [
"./skills/playwright-explore-website/", "./skills/ai-prompt-engineering-safety-review/",
"./skills/playwright-generate-test/",
"./skills/csharp-nunit/", "./skills/csharp-nunit/",
"./skills/java-junit/", "./skills/java-junit/",
"./skills/ai-prompt-engineering-safety-review/" "./skills/playwright-explore-website/",
"./skills/playwright-generate-test/"
] ]
} }

View File

@@ -16,8 +16,8 @@
"microsoft-365" "microsoft-365"
], ],
"skills": [ "skills": [
"./skills/typespec-api-operations/",
"./skills/typespec-create-agent/", "./skills/typespec-create-agent/",
"./skills/typespec-create-api-plugin/", "./skills/typespec-create-api-plugin/"
"./skills/typespec-api-operations/"
] ]
} }