Merge pull request #372 from ShiroKSH/fix/eval-validation-windows

fix: harden eval and command validation
This commit is contained in:
Addy Osmani
2026-07-09 19:27:43 -07:00
committed by GitHub
6 changed files with 37 additions and 5 deletions
+1
View File
@@ -0,0 +1 @@
* text=auto eol=lf
+1 -1
View File
@@ -339,7 +339,7 @@ agent-skills/
│ ├── shipping-and-launch/ # Ship
│ └── using-agent-skills/ # Meta: how to use this pack
├── agents/ # 4 specialist personas
├── references/ # 5 supplementary checklists
├── references/ # 7 supplementary checklists
├── hooks/ # Session lifecycle hooks
├── .claude/commands/ # 8 slash commands (Claude Code)
├── .gemini/commands/ # 8 slash commands (Gemini CLI)
+1 -1
View File
@@ -7,7 +7,7 @@
Copilot supports creating agent skills using a `.github/skills`, `.claude/skills`, or `.agents/skills` directory in your repository.
```bash
mkdir -p .github
mkdir -p .github/skills/test-driven-development .github/skills/code-review-and-quality
# Create files for essential skills
cat /path/to/agent-skills/skills/test-driven-development/SKILL.md > .github/skills/test-driven-development/SKILL.md
+3
View File
@@ -132,6 +132,9 @@ The `references/` directory contains supplementary checklists:
| `performance-checklist.md` | performance-optimization |
| `security-checklist.md` | security-and-hardening |
| `accessibility-checklist.md` | frontend-ui-engineering |
| `definition-of-done.md` | all skills / every change |
| `observability-checklist.md` | observability-and-instrumentation |
| `orchestration-patterns.md` | context-engineering |
Load a reference when you need detailed patterns beyond what the skill covers.
+16 -3
View File
@@ -154,7 +154,7 @@ function loadSkills() {
const file = path.join(SKILLS_DIR, dir, 'SKILL.md');
if (!fs.existsSync(file)) continue;
const src = fs.readFileSync(file, 'utf8');
const m = src.match(/^---\n([\s\S]*?)\n---/);
const m = src.match(/^---[ \t]*\r?\n([\s\S]*?)\r?\n---[ \t]*(?:\r?\n|$)/);
if (!m) continue;
const name = (m[1].match(/^name:\s*(.+)$/m) || [])[1];
const description = (m[1].match(/^description:\s*(.+)$/m) || [])[1];
@@ -178,6 +178,19 @@ function loadCases() {
});
}
function resolveFixturePath(root, rel) {
if (path.isAbsolute(rel)) {
throw new Error(`fixture path must be relative: ${rel}`);
}
const resolvedRoot = path.resolve(root);
const resolvedPath = path.resolve(resolvedRoot, rel);
const back = path.relative(resolvedRoot, resolvedPath);
if (back === '' || back === '..' || back.startsWith(`..${path.sep}`) || path.isAbsolute(back)) {
throw new Error(`fixture path escapes workspace: ${rel}`);
}
return resolvedPath;
}
// ---------- tier 2 ----------
function runDeterministic() {
@@ -331,11 +344,11 @@ function materializeWorkspace(ev) {
// agent has real code to operate on rather than describing what it would do.
const workspace = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-skills-eval-'));
for (const rel of ev.files || []) {
const src = path.join(FIXTURES_DIR, rel);
const src = resolveFixturePath(FIXTURES_DIR, rel);
if (!fs.existsSync(src)) {
throw new Error(`fixture listed in files[] not found: evals/fixtures/${rel}`);
}
const dest = path.join(workspace, rel);
const dest = resolveFixturePath(workspace, rel);
fs.mkdirSync(path.dirname(dest), { recursive: true });
fs.cpSync(src, dest, { recursive: true });
}
+15
View File
@@ -145,6 +145,21 @@ function main() {
const descGemini = byTool.gemini[tomlStem];
const descAgy = byTool.antigravity[tomlStem];
const malformed = [
['.claude/commands', byTool.claude, claudeStem],
['.gemini/commands', byTool.gemini, tomlStem],
['commands/', byTool.antigravity, tomlStem],
].filter(([, commands, stem]) => Object.prototype.hasOwnProperty.call(commands, stem) && commands[stem] == null);
if (malformed.length) {
console.log(`${claudeStem}`);
for (const [toolDir, , stem] of malformed) {
console.log(` ${toolDir}/${stem} — missing or malformed description`);
}
errors++;
continue;
}
if (descClaude == null || descGemini == null || descAgy == null) {
// Missing file already flagged by parity check
continue;