Skip to main content
Glama

π“‚€π“’π“‹Ήπ”Έβ„•π•Œπ”Ήπ•€π•Šπ“‹Ήπ“’π“‚€ - Intelligent Guidance for

by Hive-Academy
subtask-query.service.tsβ€’4.16 kB
import { Injectable, Inject } from '@nestjs/common'; import { Subtask } from 'generated/prisma'; import { ISubtaskRepository } from '../repositories/interfaces/subtask.repository.interface'; import { IndividualSubtaskOperationsInput } from '../schemas/individual-subtask-operations.schema'; export interface SubtaskWithDependencies { subtask: Subtask; } export interface NextSubtaskResult { nextSubtask: Subtask | null; message: string; blockedSubtasks?: Array<{ id: number; name: string; pendingDependencies: string[]; }>; } /** * SubtaskQueryService * * Responsible for: * - Getting subtask details * - Finding next available subtasks * - Sequence-based subtask discovery * - Handling in-progress subtask detection */ @Injectable() export class SubtaskQueryService { constructor( @Inject('ISubtaskRepository') private readonly subtaskRepository: ISubtaskRepository, ) {} /** * Get specific subtask details */ async getSubtask(input: IndividualSubtaskOperationsInput): Promise<Subtask> { const { taskId, subtaskId } = input; if (!subtaskId) { throw new Error('Subtask ID is required for subtask retrieval'); } const subtask = await this.subtaskRepository.findById(subtaskId); if (!subtask || subtask.taskId !== taskId) { throw new Error(`Subtask ${subtaskId} not found for task ${taskId}`); } return subtask; } /** * Get next subtask in sequence based on status * * Handles cases where only taskId is provided by finding the next subtask * based on sequence number and status. */ async getNextSubtask( input: IndividualSubtaskOperationsInput, ): Promise<NextSubtaskResult> { const { taskId, status } = input; // Always use sequence-based approach since dependencies are removed return await this.findNextSubtaskBySequence(taskId, status); } /** * NEW: Find next subtask based on sequence number and completion status * * This method: * 1. FIRST checks for any in-progress subtasks (critical for workflow integrity) * 2. Finds the last completed subtask by sequence number * 3. Finds the next subtask in sequence that's not completed * 4. Returns the next available subtask or explains why none are available */ async findNextSubtaskBySequence( taskId: number, _status?: string | string[], ): Promise<NextSubtaskResult> { try { // Get all subtasks for this task, ordered by sequence number const allSubtasks = await this.subtaskRepository.findByTaskId(taskId); if (allSubtasks.length === 0) { return { nextSubtask: null, message: 'No subtasks found for this task', }; } // Sort by sequence number to ensure correct order const sortedSubtasks = allSubtasks.sort( (a, b) => a.sequenceNumber - b.sequenceNumber, ); // 🚨 CRITICAL: Check for in-progress subtasks FIRST const inProgressSubtasks = sortedSubtasks.filter( (s) => s.status === 'in-progress', ); if (inProgressSubtasks.length > 0) { // Return first in-progress subtask, don't start new ones const inProgressSubtask = inProgressSubtasks[0]; return { nextSubtask: inProgressSubtask, message: `Resuming in-progress subtask: '${inProgressSubtask.name}' (sequence ${inProgressSubtask.sequenceNumber}) - complete this before starting new subtasks`, }; } // Find the next subtask that's not completed or in-progress const nextSubtask = sortedSubtasks.find( (s) => s.status !== 'completed' && s.status !== 'in-progress', ); if (!nextSubtask) { return { nextSubtask: null, message: 'All subtasks have been completed', }; } return { nextSubtask, message: `Next available subtask: '${nextSubtask.name}' (sequence ${nextSubtask.sequenceNumber}) in batch ${nextSubtask.batchId}`, }; } catch (error: any) { return { nextSubtask: null, message: `Error finding next subtask: ${error.message}`, }; } } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Hive-Academy/Anubis-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server