fix: remove gray-matter dependency, use inline frontmatter parser

gray-matter was excluded from VSIX via .vscodeignore, causing runtime
   module not found error. Replaced with a zero-dependency inline parser.

   Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
DwainTR
2026-03-12 19:51:15 +03:00
parent 8448807ae5
commit 5ebbccf601
3 changed files with 4049 additions and 30 deletions

4019
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -15,7 +15,7 @@
"categories": ["AI", "Other"], "categories": ["AI", "Other"],
"keywords": ["copilot", "superpowers", "skills", "tdd", "brainstorming", "debugging"], "keywords": ["copilot", "superpowers", "skills", "tdd", "brainstorming", "debugging"],
"icon": "images/icon.png", "icon": "images/icon.png",
"activationEvents": [], "activationEvents": ["onStartupFinished"],
"main": "./out/extension.js", "main": "./out/extension.js",
"contributes": { "contributes": {
"chatParticipants": [ "chatParticipants": [
@@ -65,9 +65,6 @@
"package": "vsce package", "package": "vsce package",
"publish": "vsce publish" "publish": "vsce publish"
}, },
"dependencies": {
"gray-matter": "^4.0.3"
},
"devDependencies": { "devDependencies": {
"@types/node": "^20.0.0", "@types/node": "^20.0.0",
"@types/vscode": "^1.90.0", "@types/vscode": "^1.90.0",

View File

@@ -2,7 +2,6 @@ import * as fs from 'fs';
import * as os from 'os'; import * as os from 'os';
import * as path from 'path'; import * as path from 'path';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import matter from 'gray-matter';
import { Skill, SkillMap } from './types'; import { Skill, SkillMap } from './types';
const OUTPUT_CHANNEL_NAME = 'Superpowers'; const OUTPUT_CHANNEL_NAME = 'Superpowers';
@@ -16,32 +15,36 @@ function log(message: string): void {
} }
/** Parse a SKILL.md file. Returns null and logs a warning on failure. */ /** Parse a SKILL.md file. Returns null and logs a warning on failure. */
function parseSkillFile(filePath: string, source: 'bundled' | 'custom'): Skill | null { function parseFrontmatter(raw: string): { data: Record<string, string>; content: string } {
let raw: string; const match = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
try { if (!match) { return { data: {}, content: raw }; }
raw = fs.readFileSync(filePath, 'utf-8'); const data: Record<string, string> = {};
} catch (e) { for (const line of match[1].split('\n')) {
log(`WARNING: Could not read file ${filePath}: ${String(e)}`); const colonIdx = line.indexOf(':');
return null; if (colonIdx === -1) { continue; }
} const key = line.slice(0, colonIdx).trim();
let value = line.slice(colonIdx + 1).trim();
let parsed: matter.GrayMatterFile<string>; if (/^["']/.test(value) && value.length > 1) { value = value.slice(1, value.endsWith('"') || value.endsWith("'") ? -1 :
try { value.length); }
parsed = matter(raw); if (key) { data[key] = value; }
} catch (e) { }
log(`WARNING: Could not parse frontmatter in ${filePath}: ${String(e)}`); return { data, content: match[2].trim() };
return null; }
}
const { name, description } = parsed.data as Record<string, string>;
if (!name || !description) {
log(`WARNING: Missing required frontmatter fields (name, description) in ${filePath} — skipping`);
return null;
}
return { name, description, content: parsed.content.trim(), source };
}
function parseSkillFile(filePath: string, source: 'bundled' | 'custom'): Skill | null {
let raw: string;
try { raw = fs.readFileSync(filePath, 'utf-8'); } catch (e) {
log(`WARNING: Could not read file ${filePath}: ${String(e)}`);
return null;
}
const { data, content } = parseFrontmatter(raw);
const { name, description } = data;
if (!name || !description) {
log(`WARNING: Missing required frontmatter (name, description) in ${filePath} — skipping`);
return null;
}
return { name, description, content, source };
}
/** Resolve the custom skills directory path (cross-platform). */ /** Resolve the custom skills directory path (cross-platform). */
function resolveCustomPath(configuredPath: string): string { function resolveCustomPath(configuredPath: string): string {
if (configuredPath && configuredPath !== '') { if (configuredPath && configuredPath !== '') {