Skip to content

Commit 59d1c8b

Browse files
Copilotaaronpowell
andcommitted
Convert all prompts to skills and update plugin manifests
Co-authored-by: aaronpowell <434140+aaronpowell@users.noreply.github.com>
1 parent f4f0dc3 commit 59d1c8b

179 files changed

Lines changed: 26388 additions & 115 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

eng/migrate-prompts-to-skills.mjs

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#!/usr/bin/env node
2+
3+
import fs from "fs";
4+
import path from "path";
5+
import { ROOT_FOLDER, PROMPTS_DIR, SKILLS_DIR } from "./constants.mjs";
6+
import { parseFrontmatter } from "./yaml-parser.mjs";
7+
8+
/**
9+
* Convert a prompt file to a skill folder
10+
* @param {string} promptFilePath - Full path to the prompt file
11+
* @returns {object} Result with success status and details
12+
*/
13+
function convertPromptToSkill(promptFilePath) {
14+
const filename = path.basename(promptFilePath);
15+
const baseName = filename.replace(".prompt.md", "");
16+
17+
console.log(`\nConverting: ${baseName}`);
18+
19+
// Parse the prompt file frontmatter
20+
const frontmatter = parseFrontmatter(promptFilePath);
21+
const content = fs.readFileSync(promptFilePath, "utf8");
22+
23+
// Extract the content after frontmatter
24+
const frontmatterEndMatch = content.match(/^---\n[\s\S]*?\n---\n/);
25+
const mainContent = frontmatterEndMatch
26+
? content.substring(frontmatterEndMatch[0].length).trim()
27+
: content.trim();
28+
29+
// Create skill folder
30+
const skillFolderPath = path.join(SKILLS_DIR, baseName);
31+
if (fs.existsSync(skillFolderPath)) {
32+
console.log(` ⚠️ Skill folder already exists: ${baseName}`);
33+
return { success: false, reason: "already-exists", name: baseName };
34+
}
35+
36+
fs.mkdirSync(skillFolderPath, { recursive: true });
37+
38+
// Build new frontmatter for SKILL.md
39+
const skillFrontmatter = {
40+
name: baseName,
41+
description: frontmatter?.description || `Skill converted from ${filename}`,
42+
};
43+
44+
// Build SKILL.md content
45+
const skillContent = `---
46+
name: ${skillFrontmatter.name}
47+
description: '${skillFrontmatter.description.replace(/'/g, "'\\''")}'
48+
---
49+
50+
${mainContent}
51+
`;
52+
53+
// Write SKILL.md
54+
const skillFilePath = path.join(skillFolderPath, "SKILL.md");
55+
fs.writeFileSync(skillFilePath, skillContent, "utf8");
56+
57+
console.log(` ✓ Created skill: ${baseName}`);
58+
return { success: true, name: baseName, path: skillFolderPath };
59+
}
60+
61+
/**
62+
* Main migration function
63+
*/
64+
function main() {
65+
console.log("=".repeat(60));
66+
console.log("Starting Prompt to Skills Migration");
67+
console.log("=".repeat(60));
68+
69+
// Check if prompts directory exists
70+
if (!fs.existsSync(PROMPTS_DIR)) {
71+
console.error(`Error: Prompts directory not found: ${PROMPTS_DIR}`);
72+
process.exit(1);
73+
}
74+
75+
// Get all prompt files
76+
const promptFiles = fs
77+
.readdirSync(PROMPTS_DIR)
78+
.filter((file) => file.endsWith(".prompt.md"))
79+
.map((file) => path.join(PROMPTS_DIR, file));
80+
81+
console.log(`Found ${promptFiles.length} prompt files to convert\n`);
82+
83+
const results = {
84+
success: [],
85+
alreadyExists: [],
86+
failed: [],
87+
};
88+
89+
// Convert each prompt
90+
for (const promptFile of promptFiles) {
91+
try {
92+
const result = convertPromptToSkill(promptFile);
93+
if (result.success) {
94+
results.success.push(result.name);
95+
} else if (result.reason === "already-exists") {
96+
results.alreadyExists.push(result.name);
97+
} else {
98+
results.failed.push(result.name);
99+
}
100+
} catch (error) {
101+
const baseName = path.basename(promptFile, ".prompt.md");
102+
console.error(` ✗ Error converting ${baseName}: ${error.message}`);
103+
results.failed.push(baseName);
104+
}
105+
}
106+
107+
// Print summary
108+
console.log("\n" + "=".repeat(60));
109+
console.log("Migration Summary");
110+
console.log("=".repeat(60));
111+
console.log(`✓ Successfully converted: ${results.success.length}`);
112+
console.log(`⚠ Already existed: ${results.alreadyExists.length}`);
113+
console.log(`✗ Failed: ${results.failed.length}`);
114+
console.log(`Total processed: ${promptFiles.length}`);
115+
116+
if (results.failed.length > 0) {
117+
console.log("\nFailed conversions:");
118+
results.failed.forEach((name) => console.log(` - ${name}`));
119+
}
120+
121+
if (results.alreadyExists.length > 0) {
122+
console.log("\nSkipped (already exist):");
123+
results.alreadyExists.forEach((name) => console.log(` - ${name}`));
124+
}
125+
126+
console.log("\n✅ Migration complete!");
127+
console.log(
128+
"\nNext steps:\n" +
129+
"1. Run 'npm run skill:validate' to validate all new skills\n" +
130+
"2. Update plugin manifests to reference skills instead of commands\n" +
131+
"3. Remove prompts directory after testing\n"
132+
);
133+
}
134+
135+
// Run migration
136+
main();
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
#!/usr/bin/env node
2+
3+
import fs from "fs";
4+
import path from "path";
5+
import { PLUGINS_DIR } from "./constants.mjs";
6+
7+
/**
8+
* Convert commands references to skills references in a plugin.json
9+
* @param {string} pluginJsonPath - Path to the plugin.json file
10+
* @returns {object} Result with success status and details
11+
*/
12+
function updatePluginManifest(pluginJsonPath) {
13+
const pluginDir = path.dirname(path.dirname(path.dirname(pluginJsonPath)));
14+
const pluginName = path.basename(pluginDir);
15+
16+
console.log(`\nProcessing plugin: ${pluginName}`);
17+
18+
// Read and parse plugin.json
19+
let plugin;
20+
try {
21+
const content = fs.readFileSync(pluginJsonPath, "utf8");
22+
plugin = JSON.parse(content);
23+
} catch (error) {
24+
console.log(` ✗ Error reading/parsing: ${error.message}`);
25+
return { success: false, name: pluginName, reason: "parse-error" };
26+
}
27+
28+
// Check if plugin has commands field
29+
if (!plugin.commands || !Array.isArray(plugin.commands)) {
30+
console.log(` ℹ No commands field found`);
31+
return { success: false, name: pluginName, reason: "no-commands" };
32+
}
33+
34+
const commandCount = plugin.commands.length;
35+
console.log(` Found ${commandCount} command(s) to convert`);
36+
37+
// Convert commands to skills format
38+
// Commands: "./commands/foo.md" → Skills: "./skills/foo/"
39+
const skills = plugin.commands.map((cmd) => {
40+
const basename = path.basename(cmd, ".md");
41+
return `./skills/${basename}/`;
42+
});
43+
44+
// Initialize skills array if it doesn't exist
45+
if (!plugin.skills) {
46+
plugin.skills = [];
47+
}
48+
49+
// Add converted commands to skills array
50+
plugin.skills.push(...skills);
51+
52+
// Remove commands field
53+
delete plugin.commands;
54+
55+
// Write updated plugin.json
56+
try {
57+
fs.writeFileSync(
58+
pluginJsonPath,
59+
JSON.stringify(plugin, null, 2) + "\n",
60+
"utf8"
61+
);
62+
console.log(` ✓ Converted ${commandCount} command(s) to skills`);
63+
return { success: true, name: pluginName, count: commandCount };
64+
} catch (error) {
65+
console.log(` ✗ Error writing file: ${error.message}`);
66+
return { success: false, name: pluginName, reason: "write-error" };
67+
}
68+
}
69+
70+
/**
71+
* Main function to update all plugin manifests
72+
*/
73+
function main() {
74+
console.log("=".repeat(60));
75+
console.log("Updating Plugin Manifests: Commands → Skills");
76+
console.log("=".repeat(60));
77+
78+
// Check if plugins directory exists
79+
if (!fs.existsSync(PLUGINS_DIR)) {
80+
console.error(`Error: Plugins directory not found: ${PLUGINS_DIR}`);
81+
process.exit(1);
82+
}
83+
84+
// Find all plugin.json files
85+
const pluginDirs = fs
86+
.readdirSync(PLUGINS_DIR, { withFileTypes: true })
87+
.filter((entry) => entry.isDirectory())
88+
.map((entry) => entry.name);
89+
90+
console.log(`Found ${pluginDirs.length} plugin directory(ies)\n`);
91+
92+
const results = {
93+
updated: [],
94+
noCommands: [],
95+
failed: [],
96+
};
97+
98+
// Process each plugin
99+
for (const dirName of pluginDirs) {
100+
const pluginJsonPath = path.join(
101+
PLUGINS_DIR,
102+
dirName,
103+
".github/plugin",
104+
"plugin.json"
105+
);
106+
107+
if (!fs.existsSync(pluginJsonPath)) {
108+
console.log(`\nSkipping ${dirName}: no plugin.json found`);
109+
continue;
110+
}
111+
112+
const result = updatePluginManifest(pluginJsonPath);
113+
if (result.success) {
114+
results.updated.push({ name: result.name, count: result.count });
115+
} else if (result.reason === "no-commands") {
116+
results.noCommands.push(result.name);
117+
} else {
118+
results.failed.push(result.name);
119+
}
120+
}
121+
122+
// Print summary
123+
console.log("\n" + "=".repeat(60));
124+
console.log("Update Summary");
125+
console.log("=".repeat(60));
126+
console.log(`✓ Updated plugins: ${results.updated.length}`);
127+
console.log(`ℹ No commands field: ${results.noCommands.length}`);
128+
console.log(`✗ Failed: ${results.failed.length}`);
129+
console.log(`Total processed: ${pluginDirs.length}`);
130+
131+
if (results.updated.length > 0) {
132+
console.log("\nUpdated plugins:");
133+
results.updated.forEach(({ name, count }) =>
134+
console.log(` - ${name} (${count} command(s) → skills)`)
135+
);
136+
}
137+
138+
if (results.failed.length > 0) {
139+
console.log("\nFailed updates:");
140+
results.failed.forEach((name) => console.log(` - ${name}`));
141+
}
142+
143+
console.log("\n✅ Plugin manifest updates complete!");
144+
console.log(
145+
"\nNext steps:\n" +
146+
"1. Run 'npm run plugin:validate' to validate all updated plugins\n" +
147+
"2. Test that plugins work correctly\n"
148+
);
149+
}
150+
151+
// Run the update
152+
main();

plugins/awesome-copilot/.github/plugin/plugin.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@
1717
"agents": [
1818
"./agents/meta-agentic-project-scaffold.md"
1919
],
20-
"commands": [
21-
"./commands/suggest-awesome-github-copilot-skills.md",
22-
"./commands/suggest-awesome-github-copilot-instructions.md",
23-
"./commands/suggest-awesome-github-copilot-prompts.md",
24-
"./commands/suggest-awesome-github-copilot-agents.md"
20+
"skills": [
21+
"./skills/suggest-awesome-github-copilot-skills/",
22+
"./skills/suggest-awesome-github-copilot-instructions/",
23+
"./skills/suggest-awesome-github-copilot-prompts/",
24+
"./skills/suggest-awesome-github-copilot-agents/"
2525
]
2626
}

plugins/azure-cloud-development/.github/plugin/plugin.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@
2626
"./agents/terraform-azure-planning.md",
2727
"./agents/terraform-azure-implement.md"
2828
],
29-
"commands": [
30-
"./commands/azure-resource-health-diagnose.md",
31-
"./commands/az-cost-optimize.md"
29+
"skills": [
30+
"./skills/azure-resource-health-diagnose/",
31+
"./skills/az-cost-optimize/"
3232
]
3333
}

plugins/clojure-interactive-programming/.github/plugin/plugin.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"agents": [
1616
"./agents/clojure-interactive-programming.md"
1717
],
18-
"commands": [
19-
"./commands/remember-interactive-programming.md"
18+
"skills": [
19+
"./skills/remember-interactive-programming/"
2020
]
2121
}

plugins/context-engineering/.github/plugin/plugin.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
"agents": [
1818
"./agents/context-architect.md"
1919
],
20-
"commands": [
21-
"./commands/context-map.md",
22-
"./commands/what-context-needed.md",
23-
"./commands/refactor-plan.md"
20+
"skills": [
21+
"./skills/context-map/",
22+
"./skills/what-context-needed/",
23+
"./skills/refactor-plan/"
2424
]
2525
}

plugins/csharp-dotnet-development/.github/plugin/plugin.json

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@
1616
"agents": [
1717
"./agents/expert-dotnet-software-engineer.md"
1818
],
19-
"commands": [
20-
"./commands/csharp-async.md",
21-
"./commands/aspnet-minimal-api-openapi.md",
22-
"./commands/csharp-xunit.md",
23-
"./commands/csharp-nunit.md",
24-
"./commands/csharp-mstest.md",
25-
"./commands/csharp-tunit.md",
26-
"./commands/dotnet-best-practices.md",
27-
"./commands/dotnet-upgrade.md"
19+
"skills": [
20+
"./skills/csharp-async/",
21+
"./skills/aspnet-minimal-api-openapi/",
22+
"./skills/csharp-xunit/",
23+
"./skills/csharp-nunit/",
24+
"./skills/csharp-mstest/",
25+
"./skills/csharp-tunit/",
26+
"./skills/dotnet-best-practices/",
27+
"./skills/dotnet-upgrade/"
2828
]
2929
}

plugins/csharp-mcp-development/.github/plugin/plugin.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"agents": [
1818
"./agents/csharp-mcp-expert.md"
1919
],
20-
"commands": [
21-
"./commands/csharp-mcp-server-generator.md"
20+
"skills": [
21+
"./skills/csharp-mcp-server-generator/"
2222
]
2323
}

plugins/database-data-management/.github/plugin/plugin.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@
2121
"./agents/postgresql-dba.md",
2222
"./agents/ms-sql-dba.md"
2323
],
24-
"commands": [
25-
"./commands/sql-optimization.md",
26-
"./commands/sql-code-review.md",
27-
"./commands/postgresql-optimization.md",
28-
"./commands/postgresql-code-review.md"
24+
"skills": [
25+
"./skills/sql-optimization/",
26+
"./skills/sql-code-review/",
27+
"./skills/postgresql-optimization/",
28+
"./skills/postgresql-code-review/"
2929
]
3030
}

0 commit comments

Comments
 (0)