mirror of
https://github.com/github/awesome-copilot.git
synced 2026-02-20 02:15:12 +00:00
Add tools catalog with YAML schema and website page
- Create website/data/tools.yml with 6 tools: - Awesome Copilot MCP Server - Awesome GitHub Copilot Browser (VS Code extension) - APM - Agent Package Manager (CLI) - Workspace Architect (npm CLI) - Prompt Registry (VS Code extension) - GitHub Node for Visual Studio - Add .schemas/tools.schema.json for YAML validation - Update eng/generate-website-data.mjs to generate tools.json - Add parseYamlFile() to eng/yaml-parser.mjs - Refactor tools.astro to use external TypeScript module - Create website/src/scripts/pages/tools.ts with: - FuzzySearch integration for search - Category filtering - Copy configuration functionality
This commit is contained in:
@@ -22,12 +22,14 @@ import {
|
||||
parseFrontmatter,
|
||||
parseCollectionYaml,
|
||||
parseSkillMetadata,
|
||||
parseYamlFile,
|
||||
} from "./yaml-parser.mjs";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
const WEBSITE_DATA_DIR = path.join(ROOT_FOLDER, "website", "public", "data");
|
||||
const WEBSITE_SOURCE_DATA_DIR = path.join(ROOT_FOLDER, "website", "data");
|
||||
|
||||
/**
|
||||
* Ensure the output directory exists
|
||||
@@ -435,6 +437,63 @@ function generateCollectionsData() {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate tools metadata from website/data/tools.yml
|
||||
*/
|
||||
function generateToolsData() {
|
||||
const toolsFile = path.join(WEBSITE_SOURCE_DATA_DIR, "tools.yml");
|
||||
|
||||
if (!fs.existsSync(toolsFile)) {
|
||||
console.warn("No tools.yml file found at", toolsFile);
|
||||
return { items: [], filters: { categories: [], tags: [] } };
|
||||
}
|
||||
|
||||
const data = parseYamlFile(toolsFile);
|
||||
|
||||
if (!data || !data.tools) {
|
||||
return { items: [], filters: { categories: [], tags: [] } };
|
||||
}
|
||||
|
||||
const allCategories = new Set();
|
||||
const allTags = new Set();
|
||||
|
||||
const tools = data.tools.map((tool) => {
|
||||
const category = tool.category || "Other";
|
||||
allCategories.add(category);
|
||||
|
||||
const tags = tool.tags || [];
|
||||
tags.forEach((t) => allTags.add(t));
|
||||
|
||||
return {
|
||||
id: tool.id,
|
||||
name: tool.name,
|
||||
description: tool.description || "",
|
||||
category: category,
|
||||
featured: tool.featured || false,
|
||||
requirements: tool.requirements || [],
|
||||
features: tool.features || [],
|
||||
links: tool.links || {},
|
||||
configuration: tool.configuration || null,
|
||||
tags: tags,
|
||||
};
|
||||
});
|
||||
|
||||
// Sort with featured first, then alphabetically
|
||||
const sortedTools = tools.sort((a, b) => {
|
||||
if (a.featured && !b.featured) return -1;
|
||||
if (!a.featured && b.featured) return 1;
|
||||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
|
||||
return {
|
||||
items: sortedTools,
|
||||
filters: {
|
||||
categories: Array.from(allCategories).sort(),
|
||||
tags: Array.from(allTags).sort(),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a combined index for search
|
||||
*/
|
||||
@@ -529,6 +588,10 @@ async function main() {
|
||||
const collections = collectionsData.items;
|
||||
console.log(`✓ Generated ${collections.length} collections (${collectionsData.filters.tags.length} tags)`);
|
||||
|
||||
const toolsData = generateToolsData();
|
||||
const tools = toolsData.items;
|
||||
console.log(`✓ Generated ${tools.length} tools (${toolsData.filters.categories.length} categories)`);
|
||||
|
||||
const searchIndex = generateSearchIndex(agents, prompts, instructions, skills, collections);
|
||||
console.log(`✓ Generated search index with ${searchIndex.length} items`);
|
||||
|
||||
@@ -558,6 +621,11 @@ async function main() {
|
||||
JSON.stringify(collectionsData, null, 2)
|
||||
);
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(WEBSITE_DATA_DIR, "tools.json"),
|
||||
JSON.stringify(toolsData, null, 2)
|
||||
);
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(WEBSITE_DATA_DIR, "search-index.json"),
|
||||
JSON.stringify(searchIndex, null, 2)
|
||||
@@ -572,6 +640,7 @@ async function main() {
|
||||
instructions: instructions.length,
|
||||
skills: skills.length,
|
||||
collections: collections.length,
|
||||
tools: tools.length,
|
||||
total: searchIndex.length,
|
||||
},
|
||||
};
|
||||
@@ -581,7 +650,7 @@ async function main() {
|
||||
JSON.stringify(manifest, null, 2)
|
||||
);
|
||||
|
||||
console.log(`\n✓ All data written to website/data/`);
|
||||
console.log(`\n✓ All data written to website/public/data/`);
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
|
||||
@@ -195,6 +195,22 @@ function parseSkillMetadata(skillPath) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a generic YAML file (used for tools.yml and other config files)
|
||||
* @param {string} filePath - Path to the YAML file
|
||||
* @returns {object|null} Parsed YAML object or null on error
|
||||
*/
|
||||
function parseYamlFile(filePath) {
|
||||
return safeFileOperation(
|
||||
() => {
|
||||
const content = fs.readFileSync(filePath, "utf8");
|
||||
return yaml.load(content, { schema: yaml.JSON_SCHEMA });
|
||||
},
|
||||
filePath,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
export {
|
||||
parseCollectionYaml,
|
||||
parseFrontmatter,
|
||||
@@ -202,5 +218,6 @@ export {
|
||||
extractMcpServers,
|
||||
extractMcpServerConfigs,
|
||||
parseSkillMetadata,
|
||||
parseYamlFile,
|
||||
safeFileOperation,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user