Spaces:
Sleeping
Sleeping
File size: 3,295 Bytes
a5d1c1b 67978ff a5d1c1b 67978ff a5d1c1b 61b1da1 a5d1c1b 67978ff a5d1c1b 67978ff a5d1c1b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | import fs from 'node:fs';
import path from 'node:path';
import os from 'node:os';
import { cacheService } from './cache-service.js';
export interface MaterializeResult {
skillId: string;
targetAgent: string;
destinationPath: string;
filesCopied: number;
}
export class MaterializeService {
materialize(
workspaceRoot: string,
skillId: string,
options?: {
target?: 'agents' | 'gemini' | 'cursor' | 'claude' | 'auto';
global?: boolean;
}
): MaterializeResult {
const targetAgent = options?.target && options.target !== 'auto' ? options.target : 'agents';
const isGlobal = !!options?.global;
// Locate skill in cache
const skillDirRel = `skills/${skillId}`;
const allCached = cacheService.listCachedFiles(workspaceRoot);
const skillFiles = allCached.filter(
(f) => f === `${skillDirRel}/SKILL.md` || f === `${skillDirRel}.md` || f.startsWith(`${skillDirRel}/`)
);
if (skillFiles.length === 0) {
throw new Error(`Skill '${skillId}' not found in local cache. Run 'evb sync' to update.`);
}
let destDir = '';
let primaryFile = '';
if (targetAgent === 'agents') {
const base = isGlobal ? path.join(os.homedir(), '.agents', 'skills') : path.join(workspaceRoot, '.agents', 'skills');
destDir = path.join(base, skillId);
primaryFile = path.join(destDir, 'SKILL.md');
} else if (targetAgent === 'gemini') {
const base = isGlobal ? path.join(os.homedir(), '.gemini', 'skills') : path.join(workspaceRoot, '.gemini', 'skills');
destDir = path.join(base, skillId);
primaryFile = path.join(destDir, 'SKILL.md');
} else if (targetAgent === 'cursor') {
const base = isGlobal ? path.join(os.homedir(), '.cursor', 'rules') : path.join(workspaceRoot, '.cursor', 'rules');
destDir = base;
primaryFile = path.join(destDir, `${skillId}.mdc`);
} else if (targetAgent === 'claude') {
const base = isGlobal ? path.join(os.homedir(), '.claude', 'skills') : path.join(workspaceRoot, '.claude', 'skills');
destDir = path.join(base, skillId);
primaryFile = path.join(destDir, 'SKILL.md');
}
fs.mkdirSync(destDir, { recursive: true });
let filesCopied = 0;
for (const file of skillFiles) {
const content = cacheService.readCachedFile(workspaceRoot, file);
if (content === null) continue;
if (targetAgent === 'cursor') {
// For Cursor, write primary mdc rule
if (file.endsWith('SKILL.md') || file === `${skillDirRel}.md`) {
fs.writeFileSync(primaryFile, content, 'utf8');
filesCopied++;
}
} else {
// For universal .agents, Gemini & Claude, copy directory structure
const subPath = file.startsWith(`${skillDirRel}/`)
? file.slice(`${skillDirRel}/`.length)
: 'SKILL.md';
const targetFilePath = path.join(destDir, subPath);
fs.mkdirSync(path.dirname(targetFilePath), { recursive: true });
fs.writeFileSync(targetFilePath, content, 'utf8');
filesCopied++;
}
}
return {
skillId,
targetAgent,
destinationPath: targetAgent === 'cursor' ? primaryFile : destDir,
filesCopied,
};
}
}
export const materializeService = new MaterializeService();
|