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..c230d7984 --- /dev/null +++ b/scripts/src/plugin/bootstrap.ts @@ -0,0 +1,79 @@ +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/", + mcpServers: "./.mcp.json" + }; + 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")); + + // 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")); + + // 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 will be copied at build time + + console.log(`Bootstrapped ${pluginName} at plugins/${pluginName}`); +} + +main(); \ No newline at end of file