Skip to main content
Glama

Task Trellis MCP

claimTask.ts4.73 kB
import { isClaimable, TrellisObject, TrellisObjectStatus, TrellisObjectType, } from "../../models"; import { Repository } from "../../repositories"; import { checkPrerequisitesComplete } from "../../utils/checkPrerequisitesComplete"; import { checkHierarchicalPrerequisitesComplete } from "../../utils/checkHierarchicalPrerequisitesComplete"; import { filterUnavailableObjects } from "../../utils/filterUnavailableObjects"; import { sortTrellisObjects } from "../../utils/sortTrellisObjects"; import { updateParentHierarchy } from "../../utils/updateParentHierarchy"; export async function claimTask( repository: Repository, scope?: string, taskId?: string, force: boolean = false, ): Promise<{ content: Array<{ type: string; text: string }> }> { try { let claimedTask: TrellisObject; if (taskId) { claimedTask = await claimSpecificTask(taskId, force, repository); } else { claimedTask = await findNextAvailableTask(scope, repository); } const updatedTask = await updateTaskStatus(claimedTask, repository); return { content: [ { type: "text", text: `Successfully claimed task: ${JSON.stringify( { ...updatedTask, affectedFiles: Object.fromEntries(updatedTask.affectedFiles), }, null, 2, )}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Error claiming task: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } } async function claimSpecificTask( taskId: string, force: boolean, repository: Repository, ): Promise<TrellisObject> { const object = await repository.getObjectById(taskId); if (!object) { throw new Error(`Task with ID "${taskId}" not found`); } await validateTaskForClaiming(object, taskId, force, repository); return object; } async function findNextAvailableTask( scope: string | undefined, repository: Repository, ): Promise<TrellisObject> { const objects = await repository.getObjects( false, // includeClosed scope, TrellisObjectType.TASK, ); // Filter to get only available tasks const availableTasks = await filterUnavailableObjects(objects, repository); if (availableTasks.length === 0) { throw new Error("No available tasks to claim"); } // Sort by priority and return the top one const sortedTasks = sortTrellisObjects(availableTasks); return sortedTasks[0]; } async function updateTaskStatus( task: TrellisObject, repository: Repository, ): Promise<TrellisObject> { const updatedTask = { ...task, status: TrellisObjectStatus.IN_PROGRESS, }; await repository.saveObject(updatedTask); // Update parent hierarchy to in-progress (don't let errors fail the task claim) try { await updateParentHierarchy(task.parent, repository); } catch (error) { // Log but don't propagate parent hierarchy update errors console.warn("Failed to update parent hierarchy:", error); } // Re-read the object from repository to ensure proper Map reconstruction // This is needed because the in-memory object may not have the Map properly reconstructed const savedTask = await repository.getObjectById(task.id); if (!savedTask) { throw new Error(`Failed to retrieve saved task with ID "${task.id}"`); } return savedTask; } async function validateTaskForClaiming( task: TrellisObject, taskId: string, force: boolean, repository: Repository, ): Promise<void> { // Validate it's a task if (task.type !== TrellisObjectType.TASK) { throw new Error( `Object with ID "${taskId}" is not a task (type: ${task.type})`, ); } if (!force) { // Validate status is draft or open if (!isClaimable(task)) { throw new Error( `Task "${taskId}" cannot be claimed (status: ${task.status}). Task must be in draft or open status.`, ); } // Validate all prerequisites are complete (including hierarchical) const prerequisitesComplete = await checkHierarchicalPrerequisitesComplete( task, repository, ); if (!prerequisitesComplete) { // Determine if it's the task's own prerequisites or a parent's const ownPrerequisitesComplete = await checkPrerequisitesComplete( task, repository, ); if (ownPrerequisitesComplete) { throw new Error( `Task "${taskId}" cannot be claimed. Parent hierarchy has incomplete prerequisites.`, ); } else { throw new Error( `Task "${taskId}" cannot be claimed. Not all prerequisites are complete.`, ); } } } }

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/langadventurellc/task-trellis-mcp'

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