agent-ecosystem/src/main/services/extensions/skills/SkillReviewService.ts
iliya 4b4dccd13d feat: add skills management features and integrate skills API
- Introduced skills catalog management with functionalities to list, get details, preview, and apply skill changes.
- Implemented IPC handlers for skills-related actions, enhancing communication between renderer and main processes.
- Updated the UI to include a dedicated Skills panel within the extension store, improving user access to skills management.
- Added new constants and types for skills API integration, ensuring a structured approach to skills handling.
- Enhanced state management to support skills loading, error handling, and detail fetching.
2026-03-11 21:46:56 +02:00

73 lines
2.2 KiB
TypeScript

import * as fs from 'node:fs/promises';
import * as path from 'node:path';
import { createLogger } from '@shared/utils/logger';
import type { SkillDraftFile, SkillReviewFileChange } from '@shared/types/extensions';
import type { ImportedSkillSourceFile } from './SkillImportService';
const logger = createLogger('Extensions:SkillReview');
export class SkillReviewService {
async buildTextChanges(
targetSkillDir: string,
files: SkillDraftFile[]
): Promise<SkillReviewFileChange[]> {
return Promise.all(
files.map(async (file) => {
const absolutePath = path.join(targetSkillDir, file.relativePath);
const oldContent = await this.readUtf8IfExists(absolutePath);
return {
relativePath: file.relativePath,
absolutePath,
action: oldContent === null ? 'create' : 'update',
oldContent,
newContent: file.content,
isBinary: false,
} satisfies SkillReviewFileChange;
})
);
}
async buildImportChanges(
targetSkillDir: string,
files: ImportedSkillSourceFile[]
): Promise<SkillReviewFileChange[]> {
return Promise.all(
files.map(async (file) => {
const destPath = path.join(targetSkillDir, file.relativePath);
const exists = await this.pathExists(destPath);
const oldContent = file.isBinary ? null : await this.readUtf8IfExists(destPath);
return {
relativePath: file.relativePath,
absolutePath: destPath,
action: exists ? 'update' : 'create',
oldContent,
newContent: file.isBinary ? null : file.content,
isBinary: file.isBinary,
} satisfies SkillReviewFileChange;
})
);
}
private async readUtf8IfExists(filePath: string): Promise<string | null> {
try {
return await fs.readFile(filePath, 'utf8');
} catch (error) {
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
return null;
}
logger.warn(`Failed to read existing file ${filePath}`, error);
return null;
}
}
private async pathExists(targetPath: string): Promise<boolean> {
try {
await fs.stat(targetPath);
return true;
} catch {
return false;
}
}
}