From 00e07961f0e44b4ef6a66a06c5bb62da581aa02a Mon Sep 17 00:00:00 2001 From: Chunan Ye Date: Wed, 29 Jul 2026 10:53:05 -0700 Subject: [PATCH 1/6] chore: add new plugin bootstrap script --- package.json | 5 ++- scripts/package.json | 3 +- scripts/src/plugin/bootstrap.ts | 76 +++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 scripts/src/plugin/bootstrap.ts diff --git a/package.json b/package.json index c0a09596a..3537930d9 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "test:skills:integration": "cd tests && npm run test:integration --", "postinstall": "cd scripts && npm install", "dashboard:collect": "cd scripts && npm run dashboard:collect", - "dashboard": "cd scripts && npm run dashboard" + "dashboard": "cd scripts && npm run dashboard", + "plugin:new": "cd scripts && npm run plugin:new" }, "engines": { "node": ">=22.14.0" @@ -28,4 +29,4 @@ "ts-node": "^10.9.2", "typescript": "^6.0.3" } -} +} \ No newline at end of file diff --git a/scripts/package.json b/scripts/package.json index bce94c982..dfbfe581a 100644 --- a/scripts/package.json +++ b/scripts/package.json @@ -18,7 +18,8 @@ "lint:fix": "eslint --fix", "dashboard:collect": "node --import tsx src/dashboard/compose.ts", "generateMcpAllowlists": "node --import tsx src/generate-mcp-allowlists.ts", - "vally": "node --import tsx src/vally/cli.ts" + "vally": "node --import tsx src/vally/cli.ts", + "plugin:new": "node --import tsx src/plugin/bootstrap.ts" }, "devDependencies": { "@eslint/js": "^10.0.0", diff --git a/scripts/src/plugin/bootstrap.ts b/scripts/src/plugin/bootstrap.ts new file mode 100644 index 000000000..20cf41e90 --- /dev/null +++ b/scripts/src/plugin/bootstrap.ts @@ -0,0 +1,76 @@ +import * as fs from "node:fs"; +import * as path from "node:path"; +import { fileURLToPath } from "node:url"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +function main() { + const pluginName = "new-plugin"; + const pluginManifestBase = { + name: pluginName, + description: "", + version: "0.0.0-placeholder", + author: { + name: "Microsoft", + url: "https://www.microsoft.com" + }, + homepage: "https://github.com/microsoft/github-copilot-for-azure", + repository: "https://github.com/microsoft/GitHub-Copilot-for-Azure", + license: "MIT", + keywords: [ + "azure", + "cloud" + ], + skills: "./skills/" + }; + const copilotPluginManifest = { + ...pluginManifestBase + }; + const claudeCodePluginManifest = { + ...pluginManifestBase, + hooks: "./hooks/claude-hooks.json" + }; + const cursorPluginManifest = { + ...pluginManifestBase, + hooks: "./hooks/cursor-hooks.json" + }; + const repoRoot = path.resolve(__dirname, "../../.."); + const azureSkillsPluginRoot = path.join(repoRoot, `plugins/azure-skills`); + const pluginRoot = path.join(repoRoot, `plugins/${pluginName}`); + + // Plugin root + fs.mkdirSync(pluginRoot); + + // Plugin manifests + fs.mkdirSync(path.join(pluginRoot, ".plugin")); + fs.writeFileSync(path.join(pluginRoot, ".plugin/plugin.json"), JSON.stringify(copilotPluginManifest, null, 2)); + fs.mkdirSync(path.join(pluginRoot, ".claude-plugin")); + fs.writeFileSync(path.join(pluginRoot, ".claude-plugin/plugin.json"), JSON.stringify(claudeCodePluginManifest, null, 2)); + fs.mkdirSync(path.join(pluginRoot, ".cursor-plugin")); + fs.writeFileSync(path.join(pluginRoot, ".cursor-plugin/plugin.json"), JSON.stringify(cursorPluginManifest, null, 2)); + + // skills + fs.mkdirSync(path.join(pluginRoot, "skills")); + + // License + fs.copyFileSync(path.join(azureSkillsPluginRoot, "LICENSE"), path.join(pluginRoot, "LICENSE")); + + // Readme + fs.writeFileSync(path.join(pluginRoot, "README.md"), ""); + + // Version + const versionManifest = { + $schema: "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json", + version: "1.0", + pathFilters: ["."] + }; + fs.writeFileSync(path.join(pluginRoot, "version.json"), JSON.stringify(versionManifest, null, 2)); + + // Hooks + fs.cpSync(path.join(azureSkillsPluginRoot, "hooks"), path.join(pluginRoot, "hooks"), { recursive: true }); + + console.log("Bootstrapped new-plugin at plugins/new-plugin"); +} + +main(); \ No newline at end of file From ca53911c90ed6a4c86148bec3e204e0b71787310 Mon Sep 17 00:00:00 2001 From: Chunan Ye Date: Wed, 29 Jul 2026 11:03:09 -0700 Subject: [PATCH 2/6] fix lint --- scripts/src/plugin/bootstrap.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/src/plugin/bootstrap.ts b/scripts/src/plugin/bootstrap.ts index 20cf41e90..71fcf0416 100644 --- a/scripts/src/plugin/bootstrap.ts +++ b/scripts/src/plugin/bootstrap.ts @@ -36,7 +36,7 @@ function main() { hooks: "./hooks/cursor-hooks.json" }; const repoRoot = path.resolve(__dirname, "../../.."); - const azureSkillsPluginRoot = path.join(repoRoot, `plugins/azure-skills`); + const azureSkillsPluginRoot = path.join(repoRoot, "plugins/azure-skills"); const pluginRoot = path.join(repoRoot, `plugins/${pluginName}`); // Plugin root From e84d0aab6acf8073e2042127ef2209861268c24b Mon Sep 17 00:00:00 2001 From: JasonYeMSFT Date: Wed, 29 Jul 2026 11:07:07 -0700 Subject: [PATCH 3/6] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- scripts/src/plugin/bootstrap.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/src/plugin/bootstrap.ts b/scripts/src/plugin/bootstrap.ts index 71fcf0416..91d88285c 100644 --- a/scripts/src/plugin/bootstrap.ts +++ b/scripts/src/plugin/bootstrap.ts @@ -9,7 +9,7 @@ function main() { const pluginName = "new-plugin"; const pluginManifestBase = { name: pluginName, - description: "", + description: "", version: "0.0.0-placeholder", author: { name: "Microsoft", From 9f2bcad89e4b9ef6858c9bcdbac167253bebe041 Mon Sep 17 00:00:00 2001 From: Chunan Ye Date: Wed, 29 Jul 2026 11:10:45 -0700 Subject: [PATCH 4/6] write blank mcp config --- scripts/src/plugin/bootstrap.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/src/plugin/bootstrap.ts b/scripts/src/plugin/bootstrap.ts index 91d88285c..66f4dc19a 100644 --- a/scripts/src/plugin/bootstrap.ts +++ b/scripts/src/plugin/bootstrap.ts @@ -53,6 +53,9 @@ function main() { // skills fs.mkdirSync(path.join(pluginRoot, "skills")); + // MCP server declaration + fs.writeFileSync(path.join(pluginRoot, ".mcp.json"), JSON.stringify({ mcpServers: {} }, null, 2)); + // License fs.copyFileSync(path.join(azureSkillsPluginRoot, "LICENSE"), path.join(pluginRoot, "LICENSE")); From df9fd8b6aeed8fee48b07dc7cd25654b776a7dbb Mon Sep 17 00:00:00 2001 From: Chunan Ye Date: Wed, 29 Jul 2026 11:14:17 -0700 Subject: [PATCH 5/6] use pluginName constant variable add mcpServers to base plugin manifest --- scripts/src/plugin/bootstrap.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/src/plugin/bootstrap.ts b/scripts/src/plugin/bootstrap.ts index 66f4dc19a..fd2c0686b 100644 --- a/scripts/src/plugin/bootstrap.ts +++ b/scripts/src/plugin/bootstrap.ts @@ -22,7 +22,8 @@ function main() { "azure", "cloud" ], - skills: "./skills/" + skills: "./skills/", + mcpServers: "./.mcp.json" }; const copilotPluginManifest = { ...pluginManifestBase @@ -73,7 +74,7 @@ function main() { // Hooks fs.cpSync(path.join(azureSkillsPluginRoot, "hooks"), path.join(pluginRoot, "hooks"), { recursive: true }); - console.log("Bootstrapped new-plugin at plugins/new-plugin"); + console.log(`Bootstrapped ${pluginName} at plugins/${pluginName}`); } main(); \ No newline at end of file From 7226a7a16fa60538ee7516b7fa53eafdde652b25 Mon Sep 17 00:00:00 2001 From: Chunan Ye Date: Mon, 3 Aug 2026 10:19:54 -0700 Subject: [PATCH 6/6] skip hooks bootstrap --- scripts/src/plugin/bootstrap.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/src/plugin/bootstrap.ts b/scripts/src/plugin/bootstrap.ts index fd2c0686b..c230d7984 100644 --- a/scripts/src/plugin/bootstrap.ts +++ b/scripts/src/plugin/bootstrap.ts @@ -71,8 +71,7 @@ function main() { }; fs.writeFileSync(path.join(pluginRoot, "version.json"), JSON.stringify(versionManifest, null, 2)); - // Hooks - fs.cpSync(path.join(azureSkillsPluginRoot, "hooks"), path.join(pluginRoot, "hooks"), { recursive: true }); + // Hooks will be copied at build time console.log(`Bootstrapped ${pluginName} at plugins/${pluginName}`); }