All files / core/roles role-repository.service.ts

100% Statements 33/33
100% Branches 12/12
100% Functions 5/5
100% Lines 31/31

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 665x 5x 5x 5x   5x     5x 117x   117x     11x 10x   9x       72x 65x   72x       75x 75x 75x   75x 75x 74x 74x     74x 74x 74x 74x 74x   73x             73x       2x 2x         73x        
import { Injectable } from '@nestjs/common';
import { readdir, readFile } from 'fs/promises';
import { join, basename, extname } from 'path';
import matter from 'gray-matter';
import { IRoleDefinition } from '@gs-squad-mcp/core/roles';
import { SquadConfigService } from '@gs-squad-mcp/core/config';
 
@Injectable()
export class RoleRepositoryService {
  private rolesCache: Map<string, IRoleDefinition> | null = null;
 
  constructor(private readonly configService: SquadConfigService) {}
 
  async getAllRoles(): Promise<IRoleDefinition[]> {
    if (this.rolesCache === null) {
      await this.loadRoles();
    }
    return Array.from(this.rolesCache!.values());
  }
 
  async getRoleById(roleId: string): Promise<IRoleDefinition | null> {
    if (this.rolesCache === null) {
      await this.loadRoles();
    }
    return this.rolesCache!.get(roleId) || null;
  }
 
  private async loadRoles(): Promise<void> {
    const config = this.configService.getConfig();
    const agentsPath = config.agentsDirectoryPath;
    const rolesMap = new Map<string, IRoleDefinition>();
 
    try {
      const files = await readdir(agentsPath);
      const markdownFiles = files.filter(
        (file) => extname(file) === '.md'
      );
 
      for (const file of markdownFiles) {
        const filePath = join(agentsPath, file);
        const roleId = basename(file, '.md');
        const content = await readFile(filePath, 'utf-8');
        const parsed = matter(content);
 
        const role: IRoleDefinition = {
          id: roleId,
          name: parsed.data.name || roleId,
          description: parsed.data.description || '',
          body: parsed.content.trim()
        };
 
        rolesMap.set(roleId, role);
      }
    } catch (error) {
      const errorMessage =
        error instanceof Error ? error.message : String(error);
      throw new Error(
        `Failed to load roles from ${agentsPath}: ${errorMessage}`
      );
    }
 
    this.rolesCache = rolesMap;
  }
}