mirror of
https://github.com/github/awesome-copilot.git
synced 2026-02-20 02:15:12 +00:00
feat: add hooks functionality with automated workflows
- Introduced hooks to enable automated workflows triggered by specific events during GitHub Copilot sessions. - Added documentation for hooks in AGENTS.md and README.md. - Created a new directory structure for hooks, including README.md and hooks.json files. - Implemented two example hooks: Session Auto-Commit and Session Logger. - Developed scripts for logging session events and auto-committing changes. - Enhanced validation and parsing for hook metadata. - Updated build and validation scripts to accommodate new hooks functionality.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
// YAML parser for collection files and frontmatter parsing using vfile-matter
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import yaml from "js-yaml";
|
||||
import path from "path";
|
||||
import { VFile } from "vfile";
|
||||
import { matter } from "vfile-matter";
|
||||
|
||||
@@ -173,7 +173,7 @@ function parseSkillMetadata(skillPath) {
|
||||
const relativePath = path.relative(skillPath, filePath);
|
||||
if (relativePath !== "SKILL.md") {
|
||||
// Normalize path separators to forward slashes for cross-platform consistency
|
||||
arrayOfFiles.push(relativePath.replace(/\\/g, '/'));
|
||||
arrayOfFiles.push(relativePath.replace(/\\/g, "/"));
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -195,6 +195,83 @@ function parseSkillMetadata(skillPath) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse hook metadata from a hook folder (similar to skills)
|
||||
* @param {string} hookPath - Path to the hook folder
|
||||
* @returns {object|null} Hook metadata or null on error
|
||||
*/
|
||||
function parseHookMetadata(hookPath) {
|
||||
return safeFileOperation(
|
||||
() => {
|
||||
const readmeFile = path.join(hookPath, "README.md");
|
||||
if (!fs.existsSync(readmeFile)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const frontmatter = parseFrontmatter(readmeFile);
|
||||
|
||||
// Validate required fields
|
||||
if (!frontmatter?.name || !frontmatter?.description) {
|
||||
console.warn(
|
||||
`Invalid hook at ${hookPath}: missing name or description in frontmatter`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Extract hook events from hooks.json if it exists
|
||||
let hookEvents = [];
|
||||
const hooksJsonPath = path.join(hookPath, "hooks.json");
|
||||
if (fs.existsSync(hooksJsonPath)) {
|
||||
try {
|
||||
const hooksJsonContent = fs.readFileSync(hooksJsonPath, "utf8");
|
||||
const hooksConfig = JSON.parse(hooksJsonContent);
|
||||
// Extract all hook event names from the hooks object
|
||||
if (hooksConfig.hooks && typeof hooksConfig.hooks === "object") {
|
||||
hookEvents = Object.keys(hooksConfig.hooks);
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
`Failed to parse hooks.json at ${hookPath}: ${error.message}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// List bundled assets (all files except README.md), recursing through subdirectories
|
||||
const getAllFiles = (dirPath, arrayOfFiles = []) => {
|
||||
const files = fs.readdirSync(dirPath);
|
||||
|
||||
files.forEach((file) => {
|
||||
const filePath = path.join(dirPath, file);
|
||||
if (fs.statSync(filePath).isDirectory()) {
|
||||
arrayOfFiles = getAllFiles(filePath, arrayOfFiles);
|
||||
} else {
|
||||
const relativePath = path.relative(hookPath, filePath);
|
||||
if (relativePath !== "README.md") {
|
||||
// Normalize path separators to forward slashes for cross-platform consistency
|
||||
arrayOfFiles.push(relativePath.replace(/\\/g, "/"));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return arrayOfFiles;
|
||||
};
|
||||
|
||||
const assets = getAllFiles(hookPath).sort();
|
||||
|
||||
return {
|
||||
name: frontmatter.name,
|
||||
description: frontmatter.description,
|
||||
hooks: hookEvents,
|
||||
tags: frontmatter.tags || [],
|
||||
assets,
|
||||
path: hookPath,
|
||||
};
|
||||
},
|
||||
hookPath,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a generic YAML file (used for tools.yml and other config files)
|
||||
* @param {string} filePath - Path to the YAML file
|
||||
@@ -212,12 +289,13 @@ function parseYamlFile(filePath) {
|
||||
}
|
||||
|
||||
export {
|
||||
extractAgentMetadata,
|
||||
extractMcpServerConfigs,
|
||||
extractMcpServers,
|
||||
parseCollectionYaml,
|
||||
parseFrontmatter,
|
||||
extractAgentMetadata,
|
||||
extractMcpServers,
|
||||
extractMcpServerConfigs,
|
||||
parseSkillMetadata,
|
||||
parseHookMetadata,
|
||||
parseYamlFile,
|
||||
safeFileOperation,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user